2010-08-10 04:34:06 +00:00
/* USB Keyboard Plus Debug Channel Example for Teensy USB Development Board
* http : //www.pjrc.com/teensy/usb_keyboard.html
* Copyright ( c ) 2009 PJRC . COM , LLC
*
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ) , to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE .
*/
2010-11-18 13:35:49 +00:00
# include <stdint.h>
# include <stdbool.h>
2010-09-30 05:17:01 +00:00
# include <avr/io.h>
2010-09-23 11:23:50 +00:00
# include <avr/pgmspace.h>
# include <avr/interrupt.h>
2010-09-30 05:17:01 +00:00
# include "usb.h"
2010-09-23 11:23:50 +00:00
# include "usb_keyboard.h"
2010-09-30 05:17:01 +00:00
# include "usb_mouse.h"
2010-09-23 11:23:50 +00:00
# include "usb_debug.h"
2010-11-17 07:06:20 +00:00
# include "usb_extra.h"
2010-10-01 13:17:55 +00:00
# include "print.h"
2010-10-27 11:51:45 +00:00
# include "util.h"
2010-08-10 04:34:06 +00:00
/**************************************************************************
*
* Configurable Options
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// You can change these to give your code its own name.
2010-10-27 11:51:45 +00:00
# ifndef MANUFACTURER
# define STR_MANUFACTURER L"t.m.k."
# else
# define STR_MANUFACTURER LSTR(MANUFACTURER)
# endif
# ifndef PRODUCT
# define STR_PRODUCT L"t.m.k. keyboard"
# else
# define STR_PRODUCT LSTR(PRODUCT)
# endif
2010-08-10 04:34:06 +00:00
// Mac OS-X and Linux automatically load the correct drivers. On
// Windows, even though the driver is supplied by Microsoft, an
// INF file is needed to load the driver. These numbers need to
// match the INF file.
2010-10-27 11:51:45 +00:00
# ifndef VENDOR_ID
# define VENDOR_ID 0xFEED
# endif
# ifndef PRODUCT_ID
# define PRODUCT_ID 0xBABE
# endif
2010-08-10 04:34:06 +00:00
2011-12-21 16:05:28 +00:00
# ifndef DEVICE_VER
# define DEVICE_VER 0x0100
# endif
2010-08-10 04:34:06 +00:00
// USB devices are supposed to implment a halt feature, which is
// rarely (if ever) used. If you comment this line out, the halt
// code will be removed, saving 102 bytes of space (gcc 4.3.0).
// This is not strictly USB compliant, but works with all major
// operating systems.
# define SUPPORT_ENDPOINT_HALT
/**************************************************************************
*
* Endpoint Buffer Configuration
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define ENDPOINT0_SIZE 32
2010-11-18 13:35:49 +00:00
bool remote_wakeup = false ;
bool suspend = false ;
2010-09-30 05:17:01 +00:00
// 0:control endpoint is enabled automatically by controller.
2010-08-10 04:34:06 +00:00
static const uint8_t PROGMEM endpoint_config_table [ ] = {
2010-09-30 05:17:01 +00:00
// enable, UECFG0X(type, direction), UECFG1X(size, bank, allocation)
2010-12-07 16:47:57 +00:00
1 , EP_TYPE_INTERRUPT_IN , EP_SIZE ( KBD_SIZE ) | KBD_BUFFER , // 1
2011-09-17 13:39:50 +00:00
# ifdef MOUSE_ENABLE
2010-09-30 05:17:01 +00:00
1 , EP_TYPE_INTERRUPT_IN , EP_SIZE ( MOUSE_SIZE ) | MOUSE_BUFFER , // 2
2011-01-04 15:04:25 +00:00
# else
0 , // 2
# endif
2010-09-30 05:17:01 +00:00
1 , EP_TYPE_INTERRUPT_IN , EP_SIZE ( DEBUG_TX_SIZE ) | DEBUG_TX_BUFFER , // 3
2011-09-17 13:39:50 +00:00
# ifdef EXTRAKEY_ENABLE
2010-11-17 07:06:20 +00:00
1 , EP_TYPE_INTERRUPT_IN , EP_SIZE ( EXTRA_SIZE ) | EXTRA_BUFFER , // 4
2011-01-04 15:04:25 +00:00
# else
0 , // 4
# endif
2011-09-17 13:39:50 +00:00
# ifdef NKRO_ENABLE
2010-12-11 14:20:49 +00:00
1 , EP_TYPE_INTERRUPT_IN , EP_SIZE ( KBD2_SIZE ) | KBD2_BUFFER , // 5
2010-11-25 16:56:21 +00:00
# else
2011-01-04 15:04:25 +00:00
0 , // 5
2010-11-25 16:56:21 +00:00
# endif
2011-01-04 15:04:25 +00:00
0 , // 6
2010-08-10 04:34:06 +00:00
} ;
/**************************************************************************
*
* Descriptor Data
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Descriptors are the data that your computer reads when it auto-detects
// this USB device (called "enumeration" in USB lingo). The most commonly
// changed items are editable at the top of this file. Changing things
// in here should only be done by those who've read chapter 9 of the USB
// spec and relevant portions of any USB class specifications!
2012-11-13 01:04:35 +00:00
static const uint8_t PROGMEM device_descriptor [ ] = {
2010-08-10 04:34:06 +00:00
18 , // bLength
1 , // bDescriptorType
0x00 , 0x02 , // bcdUSB
0 , // bDeviceClass
0 , // bDeviceSubClass
0 , // bDeviceProtocol
ENDPOINT0_SIZE , // bMaxPacketSize0
LSB ( VENDOR_ID ) , MSB ( VENDOR_ID ) , // idVendor
LSB ( PRODUCT_ID ) , MSB ( PRODUCT_ID ) , // idProduct
2011-12-21 16:05:28 +00:00
LSB ( DEVICE_VER ) , MSB ( DEVICE_VER ) , // bcdDevice
2010-08-10 04:34:06 +00:00
1 , // iManufacturer
2 , // iProduct
0 , // iSerialNumber
1 // bNumConfigurations
} ;
// Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60
2012-11-13 01:04:35 +00:00
static const uint8_t PROGMEM keyboard_hid_report_desc [ ] = {
2010-08-10 04:34:06 +00:00
0x05 , 0x01 , // Usage Page (Generic Desktop),
0x09 , 0x06 , // Usage (Keyboard),
0xA1 , 0x01 , // Collection (Application),
0x75 , 0x01 , // Report Size (1),
0x95 , 0x08 , // Report Count (8),
0x05 , 0x07 , // Usage Page (Key Codes),
0x19 , 0xE0 , // Usage Minimum (224),
0x29 , 0xE7 , // Usage Maximum (231),
0x15 , 0x00 , // Logical Minimum (0),
0x25 , 0x01 , // Logical Maximum (1),
0x81 , 0x02 , // Input (Data, Variable, Absolute), ;Modifier byte
0x95 , 0x01 , // Report Count (1),
0x75 , 0x08 , // Report Size (8),
0x81 , 0x03 , // Input (Constant), ;Reserved byte
0x95 , 0x05 , // Report Count (5),
0x75 , 0x01 , // Report Size (1),
0x05 , 0x08 , // Usage Page (LEDs),
0x19 , 0x01 , // Usage Minimum (1),
0x29 , 0x05 , // Usage Maximum (5),
0x91 , 0x02 , // Output (Data, Variable, Absolute), ;LED report
0x95 , 0x01 , // Report Count (1),
0x75 , 0x03 , // Report Size (3),
0x91 , 0x03 , // Output (Constant), ;LED report padding
2010-12-07 16:47:57 +00:00
0x95 , KBD_REPORT_KEYS , // Report Count (),
2010-08-10 04:34:06 +00:00
0x75 , 0x08 , // Report Size (8),
0x15 , 0x00 , // Logical Minimum (0),
2010-12-07 16:47:57 +00:00
0x25 , 0xFF , // Logical Maximum(255),
2010-08-10 04:34:06 +00:00
0x05 , 0x07 , // Usage Page (Key Codes),
0x19 , 0x00 , // Usage Minimum (0),
2010-12-07 16:47:57 +00:00
0x29 , 0xFF , // Usage Maximum (255),
2010-08-10 04:34:06 +00:00
0x81 , 0x00 , // Input (Data, Array),
0xc0 // End Collection
} ;
2011-09-17 13:39:50 +00:00
# ifdef NKRO_ENABLE
2012-11-13 01:04:35 +00:00
static const uint8_t PROGMEM keyboard2_hid_report_desc [ ] = {
2010-12-11 14:20:49 +00:00
0x05 , 0x01 , // Usage Page (Generic Desktop),
0x09 , 0x06 , // Usage (Keyboard),
0xA1 , 0x01 , // Collection (Application),
// bitmap of modifiers
0x75 , 0x01 , // Report Size (1),
0x95 , 0x08 , // Report Count (8),
0x05 , 0x07 , // Usage Page (Key Codes),
0x19 , 0xE0 , // Usage Minimum (224),
0x29 , 0xE7 , // Usage Maximum (231),
0x15 , 0x00 , // Logical Minimum (0),
0x25 , 0x01 , // Logical Maximum (1),
0x81 , 0x02 , // Input (Data, Variable, Absolute), ;Modifier byte
// LED output report
0x95 , 0x05 , // Report Count (5),
0x75 , 0x01 , // Report Size (1),
0x05 , 0x08 , // Usage Page (LEDs),
0x19 , 0x01 , // Usage Minimum (1),
0x29 , 0x05 , // Usage Maximum (5),
0x91 , 0x02 , // Output (Data, Variable, Absolute),
0x95 , 0x01 , // Report Count (1),
0x75 , 0x03 , // Report Size (3),
0x91 , 0x03 , // Output (Constant),
// bitmap of keys
0x95 , KBD2_REPORT_KEYS * 8 , // Report Count (),
0x75 , 0x01 , // Report Size (1),
0x15 , 0x00 , // Logical Minimum (0),
0x25 , 0x01 , // Logical Maximum(1),
0x05 , 0x07 , // Usage Page (Key Codes),
0x19 , 0x00 , // Usage Minimum (0),
0x29 , KBD2_REPORT_KEYS * 8 - 1 , // Usage Maximum (),
0x81 , 0x02 , // Input (Data, Variable, Absolute),
0xc0 // End Collection
2010-12-07 16:47:57 +00:00
} ;
# endif
2010-08-10 04:34:06 +00:00
2011-09-17 13:39:50 +00:00
# ifdef MOUSE_ENABLE
2010-09-30 05:17:01 +00:00
// Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension
2010-10-01 13:17:55 +00:00
// http://www.microchip.com/forums/tm.aspx?high=&m=391435&mpage=1#391521
// http://www.keil.com/forum/15671/
// http://www.microsoft.com/whdc/device/input/wheel.mspx
2012-11-13 01:04:35 +00:00
static const uint8_t PROGMEM mouse_hid_report_desc [ ] = {
2011-05-31 12:17:56 +00:00
/* mouse */
0x05 , 0x01 , // USAGE_PAGE (Generic Desktop)
0x09 , 0x02 , // USAGE (Mouse)
0xa1 , 0x01 , // COLLECTION (Application)
//0x85, REPORT_ID_MOUSE, // REPORT_ID (1)
0x09 , 0x01 , // USAGE (Pointer)
0xa1 , 0x00 , // COLLECTION (Physical)
// ---------------------------- Buttons
0x05 , 0x09 , // USAGE_PAGE (Button)
0x19 , 0x01 , // USAGE_MINIMUM (Button 1)
0x29 , 0x05 , // USAGE_MAXIMUM (Button 5)
0x15 , 0x00 , // LOGICAL_MINIMUM (0)
0x25 , 0x01 , // LOGICAL_MAXIMUM (1)
0x75 , 0x01 , // REPORT_SIZE (1)
0x95 , 0x05 , // REPORT_COUNT (5)
0x81 , 0x02 , // INPUT (Data,Var,Abs)
0x75 , 0x03 , // REPORT_SIZE (3)
0x95 , 0x01 , // REPORT_COUNT (1)
0x81 , 0x03 , // INPUT (Cnst,Var,Abs)
// ---------------------------- X,Y position
0x05 , 0x01 , // USAGE_PAGE (Generic Desktop)
0x09 , 0x30 , // USAGE (X)
0x09 , 0x31 , // USAGE (Y)
0x15 , 0x81 , // LOGICAL_MINIMUM (-127)
0x25 , 0x7f , // LOGICAL_MAXIMUM (127)
0x75 , 0x08 , // REPORT_SIZE (8)
0x95 , 0x02 , // REPORT_COUNT (2)
0x81 , 0x06 , // INPUT (Data,Var,Rel)
// ---------------------------- Vertical wheel
0x09 , 0x38 , // USAGE (Wheel)
0x15 , 0x81 , // LOGICAL_MINIMUM (-127)
0x25 , 0x7f , // LOGICAL_MAXIMUM (127)
0x35 , 0x00 , // PHYSICAL_MINIMUM (0) - reset physical
0x45 , 0x00 , // PHYSICAL_MAXIMUM (0)
0x75 , 0x08 , // REPORT_SIZE (8)
0x95 , 0x01 , // REPORT_COUNT (1)
0x81 , 0x06 , // INPUT (Data,Var,Rel)
// ---------------------------- Horizontal wheel
0x05 , 0x0c , // USAGE_PAGE (Consumer Devices)
0x0a , 0x38 , 0x02 , // USAGE (AC Pan)
0x15 , 0x81 , // LOGICAL_MINIMUM (-127)
0x25 , 0x7f , // LOGICAL_MAXIMUM (127)
0x75 , 0x08 , // REPORT_SIZE (8)
0x95 , 0x01 , // REPORT_COUNT (1)
0x81 , 0x06 , // INPUT (Data,Var,Rel)
0xc0 , // END_COLLECTION
0xc0 , // END_COLLECTION
2010-09-30 05:17:01 +00:00
} ;
2011-01-04 15:04:25 +00:00
# endif
2010-09-30 05:17:01 +00:00
2012-11-13 01:04:35 +00:00
static const uint8_t PROGMEM debug_hid_report_desc [ ] = {
2010-08-10 04:34:06 +00:00
0x06 , 0x31 , 0xFF , // Usage Page 0xFF31 (vendor defined)
0x09 , 0x74 , // Usage 0x74
0xA1 , 0x53 , // Collection 0x53
0x75 , 0x08 , // report size = 8 bits
0x15 , 0x00 , // logical minimum = 0
0x26 , 0xFF , 0x00 , // logical maximum = 255
0x95 , DEBUG_TX_SIZE , // report count
0x09 , 0x75 , // usage
0x81 , 0x02 , // Input (array)
0xC0 // end collection
} ;
2011-09-17 13:39:50 +00:00
# ifdef EXTRAKEY_ENABLE
2010-11-18 13:35:49 +00:00
// audio controls & system controls
2010-11-17 07:06:20 +00:00
// http://www.microsoft.com/whdc/archive/w2kbd.mspx
2012-11-13 01:04:35 +00:00
static const uint8_t PROGMEM extra_hid_report_desc [ ] = {
2011-05-31 12:17:56 +00:00
/* system control */
0x05 , 0x01 , // USAGE_PAGE (Generic Desktop)
0x09 , 0x80 , // USAGE (System Control)
0xa1 , 0x01 , // COLLECTION (Application)
0x85 , REPORT_ID_SYSTEM , // REPORT_ID (2)
0x15 , 0x01 , // LOGICAL_MINIMUM (0x1)
0x25 , 0xb7 , // LOGICAL_MAXIMUM (0xb7)
0x19 , 0x01 , // USAGE_MINIMUM (0x1)
0x29 , 0xb7 , // USAGE_MAXIMUM (0xb7)
0x75 , 0x10 , // REPORT_SIZE (16)
0x95 , 0x01 , // REPORT_COUNT (1)
0x81 , 0x00 , // INPUT (Data,Array,Abs)
0xc0 , // END_COLLECTION
/* consumer */
2010-11-17 07:06:20 +00:00
0x05 , 0x0c , // USAGE_PAGE (Consumer Devices)
0x09 , 0x01 , // USAGE (Consumer Control)
0xa1 , 0x01 , // COLLECTION (Application)
2011-05-31 12:17:56 +00:00
0x85 , REPORT_ID_CONSUMER , // REPORT_ID (3)
0x15 , 0x01 , // LOGICAL_MINIMUM (0x1)
0x26 , 0x9c , 0x02 , // LOGICAL_MAXIMUM (0x29c)
0x19 , 0x01 , // USAGE_MINIMUM (0x1)
0x2a , 0x9c , 0x02 , // USAGE_MAXIMUM (0x29c)
0x75 , 0x10 , // REPORT_SIZE (16)
2010-11-17 07:06:20 +00:00
0x95 , 0x01 , // REPORT_COUNT (1)
2011-05-31 12:17:56 +00:00
0x81 , 0x00 , // INPUT (Data,Array,Abs)
2010-11-18 13:35:49 +00:00
0xc0 , // END_COLLECTION
2010-11-17 07:06:20 +00:00
} ;
2011-01-04 15:04:25 +00:00
# endif
# define KBD_HID_DESC_NUM 0
# define KBD_HID_DESC_OFFSET (9+(9+9+7)*KBD_HID_DESC_NUM+9)
2011-09-17 13:39:50 +00:00
# ifdef MOUSE_ENABLE
2011-01-04 15:04:25 +00:00
# define MOUSE_HID_DESC_NUM (KBD_HID_DESC_NUM + 1)
# define MOUSE_HID_DESC_OFFSET (9+(9+9+7)*MOUSE_HID_DESC_NUM+9)
# else
# define MOUSE_HID_DESC_NUM (KBD_HID_DESC_NUM + 0)
# endif
# define DEBUG_HID_DESC_NUM (MOUSE_HID_DESC_NUM + 1)
# define DEBUG_HID_DESC_OFFSET (9+(9+9+7)*DEBUG_HID_DESC_NUM+9)
2011-09-17 13:39:50 +00:00
# ifdef EXTRAKEY_ENABLE
2011-01-04 15:04:25 +00:00
# define EXTRA_HID_DESC_NUM (DEBUG_HID_DESC_NUM + 1)
# define EXTRA_HID_DESC_OFFSET (9+(9+9+7)*EXTRA_HID_DESC_NUM+9)
# else
# define EXTRA_HID_DESC_NUM (DEBUG_HID_DESC_NUM + 0)
# endif
2010-11-17 07:06:20 +00:00
2011-09-17 13:39:50 +00:00
# ifdef NKRO_ENABLE
2011-01-04 15:04:25 +00:00
# define KBD2_HID_DESC_NUM (EXTRA_HID_DESC_NUM + 1)
# define KBD2_HID_DESC_OFFSET (9+(9+9+7)*EXTRA_HID_DESC_NUM+9)
2010-11-25 16:56:21 +00:00
# else
2011-01-04 15:04:25 +00:00
# define KBD2_HID_DESC_NUM (EXTRA_HID_DESC_NUM + 0)
2010-11-25 16:56:21 +00:00
# endif
2011-01-04 15:04:25 +00:00
# define NUM_INTERFACES (KBD2_HID_DESC_NUM + 1)
# define CONFIG1_DESC_SIZE (9+(9+9+7)*NUM_INTERFACES)
2012-11-13 01:04:35 +00:00
static const uint8_t PROGMEM config1_descriptor [ CONFIG1_DESC_SIZE ] = {
2010-08-10 04:34:06 +00:00
// configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10
9 , // bLength;
2 , // bDescriptorType;
LSB ( CONFIG1_DESC_SIZE ) , // wTotalLength
MSB ( CONFIG1_DESC_SIZE ) ,
2010-11-24 13:17:35 +00:00
NUM_INTERFACES , // bNumInterfaces
2010-08-10 04:34:06 +00:00
1 , // bConfigurationValue
0 , // iConfiguration
2010-11-18 13:35:49 +00:00
0xA0 , // bmAttributes
2010-08-10 04:34:06 +00:00
50 , // bMaxPower
2010-09-30 05:17:01 +00:00
2010-08-10 04:34:06 +00:00
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9 , // bLength
4 , // bDescriptorType
2010-12-07 16:47:57 +00:00
KBD_INTERFACE , // bInterfaceNumber
2010-08-10 04:34:06 +00:00
0 , // bAlternateSetting
1 , // bNumEndpoints
0x03 , // bInterfaceClass (0x03 = HID)
0x01 , // bInterfaceSubClass (0x01 = Boot)
0x01 , // bInterfaceProtocol (0x01 = Keyboard)
2010-11-25 16:56:21 +00:00
0 , // iInterface
2010-09-30 05:17:01 +00:00
// HID descriptor, HID 1.11 spec, section 6.2.1
2010-08-10 04:34:06 +00:00
9 , // bLength
0x21 , // bDescriptorType
0x11 , 0x01 , // bcdHID
0 , // bCountryCode
1 , // bNumDescriptors
0x22 , // bDescriptorType
2010-09-23 11:23:50 +00:00
sizeof ( keyboard_hid_report_desc ) , // wDescriptorLength
2010-08-10 04:34:06 +00:00
0 ,
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7 , // bLength
5 , // bDescriptorType
2010-12-07 16:47:57 +00:00
KBD_ENDPOINT | 0x80 , // bEndpointAddress
2010-08-10 04:34:06 +00:00
0x03 , // bmAttributes (0x03=intr)
2010-12-07 16:47:57 +00:00
KBD_SIZE , 0 , // wMaxPacketSize
10 , // bInterval
2010-09-30 05:17:01 +00:00
2011-09-17 13:39:50 +00:00
# ifdef MOUSE_ENABLE
2010-09-30 05:17:01 +00:00
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9 , // bLength
4 , // bDescriptorType
MOUSE_INTERFACE , // bInterfaceNumber
0 , // bAlternateSetting
1 , // bNumEndpoints
0x03 , // bInterfaceClass (0x03 = HID)
2010-12-07 16:47:57 +00:00
// ThinkPad T23 BIOS doesn't work with boot mouse.
0x00 , // bInterfaceSubClass (0x01 = Boot)
0x00 , // bInterfaceProtocol (0x02 = Mouse)
/*
2010-09-30 05:17:01 +00:00
0x01 , // bInterfaceSubClass (0x01 = Boot)
0x02 , // bInterfaceProtocol (0x02 = Mouse)
2010-12-07 16:47:57 +00:00
*/
2010-11-25 16:56:21 +00:00
0 , // iInterface
2010-09-30 05:17:01 +00:00
// HID descriptor, HID 1.11 spec, section 6.2.1
9 , // bLength
0x21 , // bDescriptorType
0x11 , 0x01 , // bcdHID
0 , // bCountryCode
1 , // bNumDescriptors
0x22 , // bDescriptorType
sizeof ( mouse_hid_report_desc ) , // wDescriptorLength
0 ,
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7 , // bLength
5 , // bDescriptorType
MOUSE_ENDPOINT | 0x80 , // bEndpointAddress
0x03 , // bmAttributes (0x03=intr)
2010-10-13 13:45:22 +00:00
MOUSE_SIZE , 0 , // wMaxPacketSize
2010-09-30 05:17:01 +00:00
1 , // bInterval
2011-01-04 15:04:25 +00:00
# endif
2010-09-30 05:17:01 +00:00
2010-08-10 04:34:06 +00:00
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9 , // bLength
4 , // bDescriptorType
DEBUG_INTERFACE , // bInterfaceNumber
0 , // bAlternateSetting
1 , // bNumEndpoints
0x03 , // bInterfaceClass (0x03 = HID)
0x00 , // bInterfaceSubClass
0x00 , // bInterfaceProtocol
2010-11-25 16:56:21 +00:00
0 , // iInterface
2010-09-30 05:17:01 +00:00
// HID descriptor, HID 1.11 spec, section 6.2.1
2010-08-10 04:34:06 +00:00
9 , // bLength
0x21 , // bDescriptorType
0x11 , 0x01 , // bcdHID
0 , // bCountryCode
1 , // bNumDescriptors
0x22 , // bDescriptorType
sizeof ( debug_hid_report_desc ) , // wDescriptorLength
0 ,
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7 , // bLength
5 , // bDescriptorType
DEBUG_TX_ENDPOINT | 0x80 , // bEndpointAddress
0x03 , // bmAttributes (0x03=intr)
DEBUG_TX_SIZE , 0 , // wMaxPacketSize
2010-11-17 07:06:20 +00:00
1 , // bInterval
2011-09-17 13:39:50 +00:00
# ifdef EXTRAKEY_ENABLE
2010-11-17 07:06:20 +00:00
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9 , // bLength
4 , // bDescriptorType
EXTRA_INTERFACE , // bInterfaceNumber
0 , // bAlternateSetting
1 , // bNumEndpoints
0x03 , // bInterfaceClass (0x03 = HID)
0x00 , // bInterfaceSubClass
0x00 , // bInterfaceProtocol
2010-11-25 16:56:21 +00:00
0 , // iInterface
2010-11-17 07:06:20 +00:00
// HID descriptor, HID 1.11 spec, section 6.2.1
9 , // bLength
0x21 , // bDescriptorType
0x11 , 0x01 , // bcdHID
0 , // bCountryCode
1 , // bNumDescriptors
0x22 , // bDescriptorType
sizeof ( extra_hid_report_desc ) , // wDescriptorLength
0 ,
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7 , // bLength
5 , // bDescriptorType
EXTRA_ENDPOINT | 0x80 , // bEndpointAddress
0x03 , // bmAttributes (0x03=intr)
EXTRA_SIZE , 0 , // wMaxPacketSize
10 , // bInterval
2011-01-04 15:04:25 +00:00
# endif
2010-11-24 13:17:35 +00:00
2011-09-17 13:39:50 +00:00
# ifdef NKRO_ENABLE
2010-11-24 13:17:35 +00:00
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9 , // bLength
4 , // bDescriptorType
2010-12-07 16:47:57 +00:00
KBD2_INTERFACE , // bInterfaceNumber
2010-11-24 13:17:35 +00:00
0 , // bAlternateSetting
1 , // bNumEndpoints
0x03 , // bInterfaceClass (0x03 = HID)
0x00 , // bInterfaceSubClass (0x01 = Boot)
0x00 , // bInterfaceProtocol (0x01 = Keyboard)
2010-11-25 16:56:21 +00:00
0 , // iInterface
2010-11-24 13:17:35 +00:00
// HID descriptor, HID 1.11 spec, section 6.2.1
9 , // bLength
0x21 , // bDescriptorType
0x11 , 0x01 , // bcdHID
0 , // bCountryCode
1 , // bNumDescriptors
0x22 , // bDescriptorType
2010-12-07 16:47:57 +00:00
sizeof ( keyboard2_hid_report_desc ) , // wDescriptorLength
2010-11-24 13:17:35 +00:00
0 ,
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7 , // bLength
5 , // bDescriptorType
2010-12-07 16:47:57 +00:00
KBD2_ENDPOINT | 0x80 , // bEndpointAddress
2010-11-24 13:17:35 +00:00
0x03 , // bmAttributes (0x03=intr)
2010-12-07 16:47:57 +00:00
KBD2_SIZE , 0 , // wMaxPacketSize
2010-11-24 13:17:35 +00:00
1 , // bInterval
2010-11-25 16:56:21 +00:00
# endif
2010-08-10 04:34:06 +00:00
} ;
// If you're desperate for a little extra code memory, these strings
// can be completely removed if iManufacturer, iProduct, iSerialNumber
// in the device desciptor are changed to zeros.
struct usb_string_descriptor_struct {
uint8_t bLength ;
uint8_t bDescriptorType ;
int16_t wString [ ] ;
} ;
2012-11-13 01:04:35 +00:00
static const struct usb_string_descriptor_struct PROGMEM string0 = {
2010-08-10 04:34:06 +00:00
4 ,
3 ,
{ 0x0409 }
} ;
2012-11-13 01:04:35 +00:00
static const struct usb_string_descriptor_struct PROGMEM string1 = {
2010-08-10 04:34:06 +00:00
sizeof ( STR_MANUFACTURER ) ,
3 ,
STR_MANUFACTURER
} ;
2012-11-13 01:04:35 +00:00
static const struct usb_string_descriptor_struct PROGMEM string2 = {
2010-08-10 04:34:06 +00:00
sizeof ( STR_PRODUCT ) ,
3 ,
STR_PRODUCT
} ;
// This table defines which descriptor data is sent for each specific
// request from the host (in wValue and wIndex).
2012-11-13 01:04:35 +00:00
static const struct descriptor_list_struct {
2010-09-23 11:23:50 +00:00
uint16_t wValue ; // descriptor type
2010-08-10 04:34:06 +00:00
uint16_t wIndex ;
const uint8_t * addr ;
uint8_t length ;
} PROGMEM descriptor_list [ ] = {
2010-09-23 11:23:50 +00:00
// DEVICE descriptor
2010-08-10 04:34:06 +00:00
{ 0x0100 , 0x0000 , device_descriptor , sizeof ( device_descriptor ) } ,
2010-09-23 11:23:50 +00:00
// CONFIGURATION descriptor
2010-08-10 04:34:06 +00:00
{ 0x0200 , 0x0000 , config1_descriptor , sizeof ( config1_descriptor ) } ,
2010-11-24 13:17:35 +00:00
// HID/REPORT descriptors
2010-12-07 16:47:57 +00:00
{ 0x2100 , KBD_INTERFACE , config1_descriptor + KBD_HID_DESC_OFFSET , 9 } ,
{ 0x2200 , KBD_INTERFACE , keyboard_hid_report_desc , sizeof ( keyboard_hid_report_desc ) } ,
2011-09-17 13:39:50 +00:00
# ifdef MOUSE_ENABLE
2010-09-30 05:17:01 +00:00
{ 0x2100 , MOUSE_INTERFACE , config1_descriptor + MOUSE_HID_DESC_OFFSET , 9 } ,
2010-11-24 13:17:35 +00:00
{ 0x2200 , MOUSE_INTERFACE , mouse_hid_report_desc , sizeof ( mouse_hid_report_desc ) } ,
2011-01-04 15:04:25 +00:00
# endif
2010-08-10 04:34:06 +00:00
{ 0x2100 , DEBUG_INTERFACE , config1_descriptor + DEBUG_HID_DESC_OFFSET , 9 } ,
2010-11-24 13:17:35 +00:00
{ 0x2200 , DEBUG_INTERFACE , debug_hid_report_desc , sizeof ( debug_hid_report_desc ) } ,
2011-09-17 13:39:50 +00:00
# ifdef EXTRAKEY_ENABLE
2010-11-17 07:06:20 +00:00
{ 0x2100 , EXTRA_INTERFACE , config1_descriptor + EXTRA_HID_DESC_OFFSET , 9 } ,
2010-11-24 13:17:35 +00:00
{ 0x2200 , EXTRA_INTERFACE , extra_hid_report_desc , sizeof ( extra_hid_report_desc ) } ,
2011-01-04 15:04:25 +00:00
# endif
2011-09-17 13:39:50 +00:00
# ifdef NKRO_ENABLE
2010-12-07 16:47:57 +00:00
{ 0x2100 , KBD2_INTERFACE , config1_descriptor + KBD2_HID_DESC_OFFSET , 9 } ,
{ 0x2200 , KBD2_INTERFACE , keyboard2_hid_report_desc , sizeof ( keyboard2_hid_report_desc ) } ,
2010-11-25 16:56:21 +00:00
# endif
2010-11-24 13:17:35 +00:00
// STRING descriptors
2010-08-10 04:34:06 +00:00
{ 0x0300 , 0x0000 , ( const uint8_t * ) & string0 , 4 } ,
{ 0x0301 , 0x0409 , ( const uint8_t * ) & string1 , sizeof ( STR_MANUFACTURER ) } ,
2010-11-25 16:56:21 +00:00
{ 0x0302 , 0x0409 , ( const uint8_t * ) & string2 , sizeof ( STR_PRODUCT ) }
2010-08-10 04:34:06 +00:00
} ;
# define NUM_DESC_LIST (sizeof(descriptor_list) / sizeof(struct descriptor_list_struct))
/**************************************************************************
*
* Variables - these are the only non - stack RAM usage
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// zero when we are not configured, non-zero when enumerated
static volatile uint8_t usb_configuration = 0 ;
/**************************************************************************
*
* Public Functions - these are the API intended for the user
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// initialize USB
void usb_init ( void )
{
HW_CONFIG ( ) ;
USB_FREEZE ( ) ; // enable USB
PLL_CONFIG ( ) ; // config PLL
while ( ! ( PLLCSR & ( 1 < < PLOCK ) ) ) ; // wait for PLL lock
USB_CONFIG ( ) ; // start USB clock
UDCON = 0 ; // enable attach resistor
usb_configuration = 0 ;
2010-11-18 13:35:49 +00:00
UDIEN = ( 1 < < EORSTE ) | ( 1 < < SOFE ) | ( 1 < < SUSPE ) ;
2010-08-10 04:34:06 +00:00
sei ( ) ;
}
// return 0 if the USB is not configured, or the configuration
// number selected by the HOST
uint8_t usb_configured ( void )
{
2010-11-18 13:35:49 +00:00
return usb_configuration & & ! suspend ;
}
void usb_remote_wakeup ( void )
{
UDCON | = ( 1 < < RMWKUP ) ;
2010-08-10 04:34:06 +00:00
}
/**************************************************************************
*
* Private Functions - not intended for general user consumption . . . .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// USB Device Interrupt - handle all device-level events
// the transmit buffer flushing is triggered by the start of frame
//
ISR ( USB_GEN_vect )
{
2012-04-27 17:24:11 +00:00
uint8_t intbits , t ;
2010-08-10 04:34:06 +00:00
static uint8_t div4 = 0 ;
intbits = UDINT ;
UDINT = 0 ;
2010-11-18 13:35:49 +00:00
if ( intbits & ( 1 < < SUSPI ) ) {
suspend = true ;
} else {
suspend = false ;
}
2010-08-10 04:34:06 +00:00
if ( intbits & ( 1 < < EORSTI ) ) {
UENUM = 0 ;
UECONX = 1 ;
UECFG0X = EP_TYPE_CONTROL ;
UECFG1X = EP_SIZE ( ENDPOINT0_SIZE ) | EP_SINGLE_BUFFER ;
UEIENX = ( 1 < < RXSTPE ) ;
usb_configuration = 0 ;
}
if ( ( intbits & ( 1 < < SOFI ) ) & & usb_configuration ) {
t = debug_flush_timer ;
if ( t ) {
debug_flush_timer = - - t ;
if ( ! t ) {
UENUM = DEBUG_TX_ENDPOINT ;
while ( ( UEINTX & ( 1 < < RWAL ) ) ) {
UEDATX = 0 ;
}
UEINTX = 0x3A ;
}
}
2011-05-04 04:42:34 +00:00
/* TODO: should keep IDLE rate on each keyboard interface */
2011-09-17 13:39:50 +00:00
# ifdef NKRO_ENABLE
2011-05-04 04:42:34 +00:00
if ( ! keyboard_nkro & & usb_keyboard_idle_config & & ( + + div4 & 3 ) = = 0 ) {
2011-05-21 01:28:57 +00:00
# else
if ( usb_keyboard_idle_config & & ( + + div4 & 3 ) = = 0 ) {
# endif
2010-12-07 16:47:57 +00:00
UENUM = KBD_ENDPOINT ;
2010-08-10 04:34:06 +00:00
if ( UEINTX & ( 1 < < RWAL ) ) {
2010-11-03 08:33:20 +00:00
usb_keyboard_idle_count + + ;
if ( usb_keyboard_idle_count = = usb_keyboard_idle_config ) {
usb_keyboard_idle_count = 0 ;
2012-04-27 17:24:11 +00:00
/* TODO: fix keyboard_report inconsistency */
/* To avoid Mac SET_IDLE behaviour.
2011-03-09 15:50:27 +00:00
UEDATX = keyboard_report_prev - > mods ;
2010-08-10 04:34:06 +00:00
UEDATX = 0 ;
2011-03-09 15:50:27 +00:00
uint8_t keys = usb_keyboard_protocol ? KBD_REPORT_KEYS : 6 ;
2012-04-27 17:24:11 +00:00
for ( uint8_t i = 0 ; i < keys ; i + + ) {
2011-03-09 15:50:27 +00:00
UEDATX = keyboard_report_prev - > keys [ i ] ;
2010-08-10 04:34:06 +00:00
}
UEINTX = 0x3A ;
2012-04-27 17:24:11 +00:00
*/
2010-08-10 04:34:06 +00:00
}
}
}
}
}
// Misc functions to wait for ready and send/receive packets
static inline void usb_wait_in_ready ( void )
{
while ( ! ( UEINTX & ( 1 < < TXINI ) ) ) ;
}
static inline void usb_send_in ( void )
{
UEINTX = ~ ( 1 < < TXINI ) ;
}
static inline void usb_wait_receive_out ( void )
{
while ( ! ( UEINTX & ( 1 < < RXOUTI ) ) ) ;
}
static inline void usb_ack_out ( void )
{
UEINTX = ~ ( 1 < < RXOUTI ) ;
}
// USB Endpoint Interrupt - endpoint 0 is handled here. The
// other endpoints are manipulated by the user-callable
// functions, and the start-of-frame interrupt.
//
ISR ( USB_COM_vect )
{
uint8_t intbits ;
const uint8_t * list ;
const uint8_t * cfg ;
uint8_t i , n , len , en ;
uint8_t bmRequestType ;
uint8_t bRequest ;
uint16_t wValue ;
uint16_t wIndex ;
uint16_t wLength ;
uint16_t desc_val ;
const uint8_t * desc_addr ;
uint8_t desc_length ;
UENUM = 0 ;
intbits = UEINTX ;
if ( intbits & ( 1 < < RXSTPI ) ) {
bmRequestType = UEDATX ;
bRequest = UEDATX ;
wValue = UEDATX ;
wValue | = ( UEDATX < < 8 ) ;
wIndex = UEDATX ;
wIndex | = ( UEDATX < < 8 ) ;
wLength = UEDATX ;
wLength | = ( UEDATX < < 8 ) ;
UEINTX = ~ ( ( 1 < < RXSTPI ) | ( 1 < < RXOUTI ) | ( 1 < < TXINI ) ) ;
if ( bRequest = = GET_DESCRIPTOR ) {
list = ( const uint8_t * ) descriptor_list ;
for ( i = 0 ; ; i + + ) {
if ( i > = NUM_DESC_LIST ) {
UECONX = ( 1 < < STALLRQ ) | ( 1 < < EPEN ) ; //stall
return ;
}
desc_val = pgm_read_word ( list ) ;
if ( desc_val ! = wValue ) {
list + = sizeof ( struct descriptor_list_struct ) ;
continue ;
}
list + = 2 ;
desc_val = pgm_read_word ( list ) ;
if ( desc_val ! = wIndex ) {
list + = sizeof ( struct descriptor_list_struct ) - 2 ;
continue ;
}
list + = 2 ;
desc_addr = ( const uint8_t * ) pgm_read_word ( list ) ;
list + = 2 ;
desc_length = pgm_read_byte ( list ) ;
break ;
}
len = ( wLength < 256 ) ? wLength : 255 ;
if ( len > desc_length ) len = desc_length ;
do {
// wait for host ready for IN packet
do {
i = UEINTX ;
} while ( ! ( i & ( ( 1 < < TXINI ) | ( 1 < < RXOUTI ) ) ) ) ;
if ( i & ( 1 < < RXOUTI ) ) return ; // abort
// send IN packet
n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE ;
for ( i = n ; i ; i - - ) {
UEDATX = pgm_read_byte ( desc_addr + + ) ;
}
len - = n ;
usb_send_in ( ) ;
} while ( len | | n = = ENDPOINT0_SIZE ) ;
return ;
}
if ( bRequest = = SET_ADDRESS ) {
usb_send_in ( ) ;
usb_wait_in_ready ( ) ;
UDADDR = wValue | ( 1 < < ADDEN ) ;
return ;
}
if ( bRequest = = SET_CONFIGURATION & & bmRequestType = = 0 ) {
usb_configuration = wValue ;
usb_send_in ( ) ;
cfg = endpoint_config_table ;
2012-03-03 16:12:35 +00:00
for ( i = 1 ; i < = MAX_ENDPOINT ; i + + ) {
2010-08-10 04:34:06 +00:00
UENUM = i ;
en = pgm_read_byte ( cfg + + ) ;
2010-12-07 16:47:57 +00:00
if ( en ) {
UECONX = ( 1 < < EPEN ) ;
UECFG0X = pgm_read_byte ( cfg + + ) ;
UECFG1X = pgm_read_byte ( cfg + + ) ;
} else {
UECONX = 0 ;
2010-08-10 04:34:06 +00:00
}
}
2012-03-03 16:12:35 +00:00
UERST = UERST_MASK ;
2010-08-10 04:34:06 +00:00
UERST = 0 ;
return ;
}
if ( bRequest = = GET_CONFIGURATION & & bmRequestType = = 0x80 ) {
usb_wait_in_ready ( ) ;
UEDATX = usb_configuration ;
usb_send_in ( ) ;
return ;
}
if ( bRequest = = GET_STATUS ) {
usb_wait_in_ready ( ) ;
i = 0 ;
# ifdef SUPPORT_ENDPOINT_HALT
if ( bmRequestType = = 0x82 ) {
UENUM = wIndex ;
if ( UECONX & ( 1 < < STALLRQ ) ) i = 1 ;
UENUM = 0 ;
}
# endif
UEDATX = i ;
UEDATX = 0 ;
usb_send_in ( ) ;
return ;
}
2010-11-18 13:35:49 +00:00
if ( bRequest = = CLEAR_FEATURE | | bRequest = = SET_FEATURE ) {
# ifdef SUPPORT_ENDPOINT_HALT
if ( bmRequestType = = 0x02 & & wValue = = ENDPOINT_HALT ) {
2010-08-10 04:34:06 +00:00
i = wIndex & 0x7F ;
if ( i > = 1 & & i < = MAX_ENDPOINT ) {
usb_send_in ( ) ;
UENUM = i ;
if ( bRequest = = SET_FEATURE ) {
UECONX = ( 1 < < STALLRQ ) | ( 1 < < EPEN ) ;
} else {
UECONX = ( 1 < < STALLRQC ) | ( 1 < < RSTDT ) | ( 1 < < EPEN ) ;
UERST = ( 1 < < i ) ;
UERST = 0 ;
}
return ;
}
2010-11-18 13:35:49 +00:00
}
# endif
if ( bmRequestType = = 0x00 & & wValue = = DEVICE_REMOTE_WAKEUP ) {
if ( bRequest = = SET_FEATURE ) {
remote_wakeup = true ;
} else {
remote_wakeup = false ;
}
usb_send_in ( ) ;
return ;
}
2010-08-10 04:34:06 +00:00
}
2010-12-07 16:47:57 +00:00
if ( wIndex = = KBD_INTERFACE ) {
2010-08-10 04:34:06 +00:00
if ( bmRequestType = = 0xA1 ) {
if ( bRequest = = HID_GET_REPORT ) {
usb_wait_in_ready ( ) ;
2011-02-12 15:15:51 +00:00
UEDATX = keyboard_report - > mods ;
2010-08-10 04:34:06 +00:00
UEDATX = 0 ;
for ( i = 0 ; i < 6 ; i + + ) {
2011-02-12 15:15:51 +00:00
UEDATX = keyboard_report - > keys [ i ] ;
2010-08-10 04:34:06 +00:00
}
usb_send_in ( ) ;
return ;
}
if ( bRequest = = HID_GET_IDLE ) {
usb_wait_in_ready ( ) ;
2010-11-03 08:33:20 +00:00
UEDATX = usb_keyboard_idle_config ;
2010-08-10 04:34:06 +00:00
usb_send_in ( ) ;
return ;
}
if ( bRequest = = HID_GET_PROTOCOL ) {
usb_wait_in_ready ( ) ;
2010-11-03 08:33:20 +00:00
UEDATX = usb_keyboard_protocol ;
2010-08-10 04:34:06 +00:00
usb_send_in ( ) ;
return ;
}
}
if ( bmRequestType = = 0x21 ) {
if ( bRequest = = HID_SET_REPORT ) {
usb_wait_receive_out ( ) ;
2010-11-03 08:33:20 +00:00
usb_keyboard_leds = UEDATX ;
2010-08-10 04:34:06 +00:00
usb_ack_out ( ) ;
usb_send_in ( ) ;
return ;
}
if ( bRequest = = HID_SET_IDLE ) {
2010-11-03 08:33:20 +00:00
usb_keyboard_idle_config = ( wValue > > 8 ) ;
usb_keyboard_idle_count = 0 ;
2010-08-10 04:34:06 +00:00
//usb_wait_in_ready();
usb_send_in ( ) ;
return ;
}
if ( bRequest = = HID_SET_PROTOCOL ) {
2010-11-03 08:33:20 +00:00
usb_keyboard_protocol = wValue ;
2010-08-10 04:34:06 +00:00
//usb_wait_in_ready();
usb_send_in ( ) ;
return ;
}
}
}
2011-09-17 13:39:50 +00:00
# ifdef MOUSE_ENABLE
2010-09-30 05:17:01 +00:00
if ( wIndex = = MOUSE_INTERFACE ) {
if ( bmRequestType = = 0xA1 ) {
if ( bRequest = = HID_GET_REPORT ) {
2010-10-01 13:17:55 +00:00
if ( wValue = = HID_REPORT_INPUT ) {
2010-09-30 05:17:01 +00:00
usb_wait_in_ready ( ) ;
2011-01-02 14:52:13 +00:00
UEDATX = 0 ;
2010-09-30 05:17:01 +00:00
UEDATX = 0 ;
UEDATX = 0 ;
UEDATX = 0 ;
usb_send_in ( ) ;
return ;
2010-10-01 13:17:55 +00:00
}
if ( wValue = = HID_REPORT_FEATURE ) {
usb_wait_in_ready ( ) ;
UEDATX = 0x05 ;
usb_send_in ( ) ;
return ;
}
2010-09-30 05:17:01 +00:00
}
if ( bRequest = = HID_GET_PROTOCOL ) {
usb_wait_in_ready ( ) ;
2011-01-02 14:52:13 +00:00
UEDATX = usb_mouse_protocol ;
2010-09-30 05:17:01 +00:00
usb_send_in ( ) ;
return ;
}
}
if ( bmRequestType = = 0x21 ) {
if ( bRequest = = HID_SET_PROTOCOL ) {
2011-01-02 14:52:13 +00:00
usb_mouse_protocol = wValue ;
2010-09-30 05:17:01 +00:00
usb_send_in ( ) ;
return ;
}
}
}
2011-01-04 15:04:25 +00:00
# endif
2010-08-10 04:34:06 +00:00
if ( wIndex = = DEBUG_INTERFACE ) {
if ( bRequest = = HID_GET_REPORT & & bmRequestType = = 0xA1 ) {
len = wLength ;
do {
// wait for host ready for IN packet
do {
i = UEINTX ;
} while ( ! ( i & ( ( 1 < < TXINI ) | ( 1 < < RXOUTI ) ) ) ) ;
if ( i & ( 1 < < RXOUTI ) ) return ; // abort
// send IN packet
n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE ;
for ( i = n ; i ; i - - ) {
UEDATX = 0 ;
}
len - = n ;
usb_send_in ( ) ;
} while ( len | | n = = ENDPOINT0_SIZE ) ;
return ;
}
}
}
UECONX = ( 1 < < STALLRQ ) | ( 1 < < EPEN ) ; // stall
}