diff options
| author | tmk <hasu@tmk-kbd.com> | 2015-04-10 01:32:04 +0900 |
|---|---|---|
| committer | tmk <hasu@tmk-kbd.com> | 2015-04-10 01:32:04 +0900 |
| commit | 1a02ebcc612e9a9c0d87e02295c7258de3a70ccc (patch) | |
| tree | e517f3c70bb2d542797e57d13e9023c84af230fb /tmk_core/protocol/pjrc/usb.c | |
| parent | 6746e37088ce8ba03529c1226bd216705edb2b1f (diff) | |
| parent | a074364c3731d66b56d988c8a6c960a83ea0e0a1 (diff) | |
| download | qmk_firmware-1a02ebcc612e9a9c0d87e02295c7258de3a70ccc.tar.gz qmk_firmware-1a02ebcc612e9a9c0d87e02295c7258de3a70ccc.zip | |
Merge commit 'a074364c3731d66b56d988c8a6c960a83ea0e0a1' as 'tmk_core'
Diffstat (limited to 'tmk_core/protocol/pjrc/usb.c')
| -rw-r--r-- | tmk_core/protocol/pjrc/usb.c | 1002 |
1 files changed, 1002 insertions, 0 deletions
diff --git a/tmk_core/protocol/pjrc/usb.c b/tmk_core/protocol/pjrc/usb.c new file mode 100644 index 000000000..1e6ba8719 --- /dev/null +++ b/tmk_core/protocol/pjrc/usb.c | |||
| @@ -0,0 +1,1002 @@ | |||
| 1 | /* USB Keyboard Plus Debug Channel Example for Teensy USB Development Board | ||
| 2 | * http://www.pjrc.com/teensy/usb_keyboard.html | ||
| 3 | * Copyright (c) 2009 PJRC.COM, LLC | ||
| 4 | * | ||
| 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 6 | * of this software and associated documentation files (the "Software"), to deal | ||
| 7 | * in the Software without restriction, including without limitation the rights | ||
| 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 9 | * copies of the Software, and to permit persons to whom the Software is | ||
| 10 | * furnished to do so, subject to the following conditions: | ||
| 11 | * | ||
| 12 | * The above copyright notice and this permission notice shall be included in | ||
| 13 | * all copies or substantial portions of the Software. | ||
| 14 | * | ||
| 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 21 | * THE SOFTWARE. | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <stdint.h> | ||
| 25 | #include <stdbool.h> | ||
| 26 | #include <avr/io.h> | ||
| 27 | #include <avr/pgmspace.h> | ||
| 28 | #include <avr/interrupt.h> | ||
| 29 | #include "usb.h" | ||
| 30 | #include "usb_keyboard.h" | ||
| 31 | #include "usb_mouse.h" | ||
| 32 | #include "usb_debug.h" | ||
| 33 | #include "usb_extra.h" | ||
| 34 | #include "led.h" | ||
| 35 | #include "print.h" | ||
| 36 | #include "util.h" | ||
| 37 | #ifdef SLEEP_LED_ENABLE | ||
| 38 | #include "sleep_led.h" | ||
| 39 | #endif | ||
| 40 | #include "suspend.h" | ||
| 41 | #include "action.h" | ||
| 42 | #include "action_util.h" | ||
| 43 | |||
| 44 | |||
| 45 | /************************************************************************** | ||
| 46 | * | ||
| 47 | * Configurable Options | ||
| 48 | * | ||
| 49 | **************************************************************************/ | ||
| 50 | |||
| 51 | // You can change these to give your code its own name. | ||
| 52 | #ifndef MANUFACTURER | ||
| 53 | # define STR_MANUFACTURER L"t.m.k." | ||
| 54 | #else | ||
| 55 | # define STR_MANUFACTURER LSTR(MANUFACTURER) | ||
| 56 | #endif | ||
| 57 | #ifndef PRODUCT | ||
| 58 | # define STR_PRODUCT L"t.m.k. keyboard" | ||
| 59 | #else | ||
| 60 | # define STR_PRODUCT LSTR(PRODUCT) | ||
| 61 | #endif | ||
| 62 | |||
| 63 | |||
| 64 | // Mac OS-X and Linux automatically load the correct drivers. On | ||
| 65 | // Windows, even though the driver is supplied by Microsoft, an | ||
| 66 | // INF file is needed to load the driver. These numbers need to | ||
| 67 | // match the INF file. | ||
| 68 | #ifndef VENDOR_ID | ||
| 69 | # define VENDOR_ID 0xFEED | ||
| 70 | #endif | ||
| 71 | |||
| 72 | #ifndef PRODUCT_ID | ||
| 73 | # define PRODUCT_ID 0xBABE | ||
| 74 | #endif | ||
| 75 | |||
| 76 | #ifndef DEVICE_VER | ||
| 77 | # define DEVICE_VER 0x0100 | ||
| 78 | #endif | ||
| 79 | |||
| 80 | |||
| 81 | // USB devices are supposed to implment a halt feature, which is | ||
| 82 | // rarely (if ever) used. If you comment this line out, the halt | ||
| 83 | // code will be removed, saving 102 bytes of space (gcc 4.3.0). | ||
| 84 | // This is not strictly USB compliant, but works with all major | ||
| 85 | // operating systems. | ||
| 86 | #define SUPPORT_ENDPOINT_HALT | ||
| 87 | |||
| 88 | |||
| 89 | |||
| 90 | /************************************************************************** | ||
| 91 | * | ||
| 92 | * Endpoint Buffer Configuration | ||
| 93 | * | ||
| 94 | **************************************************************************/ | ||
| 95 | |||
| 96 | #define ENDPOINT0_SIZE 32 | ||
| 97 | |||
| 98 | bool remote_wakeup = false; | ||
| 99 | bool suspend = false; | ||
| 100 | |||
| 101 | // 0:control endpoint is enabled automatically by controller. | ||
| 102 | static const uint8_t PROGMEM endpoint_config_table[] = { | ||
| 103 | // enable, UECFG0X(type, direction), UECFG1X(size, bank, allocation) | ||
| 104 | 1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KBD_SIZE) | KBD_BUFFER, // 1 | ||
| 105 | #ifdef MOUSE_ENABLE | ||
| 106 | 1, EP_TYPE_INTERRUPT_IN, EP_SIZE(MOUSE_SIZE) | MOUSE_BUFFER, // 2 | ||
| 107 | #else | ||
| 108 | 0, // 2 | ||
| 109 | #endif | ||
| 110 | #ifdef CONSOLE_ENABLE | ||
| 111 | 1, EP_TYPE_INTERRUPT_IN, EP_SIZE(DEBUG_TX_SIZE) | DEBUG_TX_BUFFER, // 3 | ||
| 112 | #else | ||
| 113 | 0, | ||
| 114 | #endif | ||
| 115 | #ifdef EXTRAKEY_ENABLE | ||
| 116 | 1, EP_TYPE_INTERRUPT_IN, EP_SIZE(EXTRA_SIZE) | EXTRA_BUFFER, // 4 | ||
| 117 | #else | ||
| 118 | 0, // 4 | ||
| 119 | #endif | ||
| 120 | #ifdef NKRO_ENABLE | ||
| 121 | 1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KBD2_SIZE) | KBD2_BUFFER, // 5 | ||
| 122 | #else | ||
| 123 | 0, // 5 | ||
| 124 | #endif | ||
| 125 | 0, // 6 | ||
| 126 | }; | ||
| 127 | |||
| 128 | |||
| 129 | /************************************************************************** | ||
| 130 | * | ||
| 131 | * Descriptor Data | ||
| 132 | * | ||
| 133 | **************************************************************************/ | ||
| 134 | |||
| 135 | // Descriptors are the data that your computer reads when it auto-detects | ||
| 136 | // this USB device (called "enumeration" in USB lingo). The most commonly | ||
| 137 | // changed items are editable at the top of this file. Changing things | ||
| 138 | // in here should only be done by those who've read chapter 9 of the USB | ||
| 139 | // spec and relevant portions of any USB class specifications! | ||
| 140 | |||
| 141 | |||
| 142 | static const uint8_t PROGMEM device_descriptor[] = { | ||
| 143 | 18, // bLength | ||
| 144 | 1, // bDescriptorType | ||
| 145 | 0x00, 0x02, // bcdUSB | ||
| 146 | 0, // bDeviceClass | ||
| 147 | 0, // bDeviceSubClass | ||
| 148 | 0, // bDeviceProtocol | ||
| 149 | ENDPOINT0_SIZE, // bMaxPacketSize0 | ||
| 150 | LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor | ||
| 151 | LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct | ||
| 152 | LSB(DEVICE_VER), MSB(DEVICE_VER), // bcdDevice | ||
| 153 | 1, // iManufacturer | ||
| 154 | 2, // iProduct | ||
| 155 | 0, // iSerialNumber | ||
| 156 | 1 // bNumConfigurations | ||
| 157 | }; | ||
| 158 | |||
| 159 | // Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60 | ||
| 160 | static const uint8_t PROGMEM keyboard_hid_report_desc[] = { | ||
| 161 | 0x05, 0x01, // Usage Page (Generic Desktop), | ||
| 162 | 0x09, 0x06, // Usage (Keyboard), | ||
| 163 | 0xA1, 0x01, // Collection (Application), | ||
| 164 | 0x75, 0x01, // Report Size (1), | ||
| 165 | 0x95, 0x08, // Report Count (8), | ||
| 166 | 0x05, 0x07, // Usage Page (Key Codes), | ||
| 167 | 0x19, 0xE0, // Usage Minimum (224), | ||
| 168 | 0x29, 0xE7, // Usage Maximum (231), | ||
| 169 | 0x15, 0x00, // Logical Minimum (0), | ||
| 170 | 0x25, 0x01, // Logical Maximum (1), | ||
| 171 | 0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte | ||
| 172 | 0x95, 0x01, // Report Count (1), | ||
| 173 | 0x75, 0x08, // Report Size (8), | ||
| 174 | 0x81, 0x03, // Input (Constant), ;Reserved byte | ||
| 175 | 0x95, 0x05, // Report Count (5), | ||
| 176 | 0x75, 0x01, // Report Size (1), | ||
| 177 | 0x05, 0x08, // Usage Page (LEDs), | ||
| 178 | 0x19, 0x01, // Usage Minimum (1), | ||
| 179 | 0x29, 0x05, // Usage Maximum (5), | ||
| 180 | 0x91, 0x02, // Output (Data, Variable, Absolute), ;LED report | ||
| 181 | 0x95, 0x01, // Report Count (1), | ||
| 182 | 0x75, 0x03, // Report Size (3), | ||
| 183 | 0x91, 0x03, // Output (Constant), ;LED report padding | ||
| 184 | 0x95, KBD_REPORT_KEYS, // Report Count (), | ||
| 185 | 0x75, 0x08, // Report Size (8), | ||
| 186 | 0x15, 0x00, // Logical Minimum (0), | ||
| 187 | 0x25, 0xFF, // Logical Maximum(255), | ||
| 188 | 0x05, 0x07, // Usage Page (Key Codes), | ||
| 189 | 0x19, 0x00, // Usage Minimum (0), | ||
| 190 | 0x29, 0xFF, // Usage Maximum (255), | ||
| 191 | 0x81, 0x00, // Input (Data, Array), | ||
| 192 | 0xc0 // End Collection | ||
| 193 | }; | ||
| 194 | #ifdef NKRO_ENABLE | ||
| 195 | static const uint8_t PROGMEM keyboard2_hid_report_desc[] = { | ||
| 196 | 0x05, 0x01, // Usage Page (Generic Desktop), | ||
| 197 | 0x09, 0x06, // Usage (Keyboard), | ||
| 198 | 0xA1, 0x01, // Collection (Application), | ||
| 199 | // bitmap of modifiers | ||
| 200 | 0x75, 0x01, // Report Size (1), | ||
| 201 | 0x95, 0x08, // Report Count (8), | ||
| 202 | 0x05, 0x07, // Usage Page (Key Codes), | ||
| 203 | 0x19, 0xE0, // Usage Minimum (224), | ||
| 204 | 0x29, 0xE7, // Usage Maximum (231), | ||
| 205 | 0x15, 0x00, // Logical Minimum (0), | ||
| 206 | 0x25, 0x01, // Logical Maximum (1), | ||
| 207 | 0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte | ||
| 208 | // LED output report | ||
| 209 | 0x95, 0x05, // Report Count (5), | ||
| 210 | 0x75, 0x01, // Report Size (1), | ||
| 211 | 0x05, 0x08, // Usage Page (LEDs), | ||
| 212 | 0x19, 0x01, // Usage Minimum (1), | ||
| 213 | 0x29, 0x05, // Usage Maximum (5), | ||
| 214 | 0x91, 0x02, // Output (Data, Variable, Absolute), | ||
| 215 | 0x95, 0x01, // Report Count (1), | ||
| 216 | 0x75, 0x03, // Report Size (3), | ||
| 217 | 0x91, 0x03, // Output (Constant), | ||
| 218 | // bitmap of keys | ||
| 219 | 0x95, KBD2_REPORT_KEYS*8, // Report Count (), | ||
| 220 | 0x75, 0x01, // Report Size (1), | ||
| 221 | 0x15, 0x00, // Logical Minimum (0), | ||
| 222 | 0x25, 0x01, // Logical Maximum(1), | ||
| 223 | 0x05, 0x07, // Usage Page (Key Codes), | ||
| 224 | 0x19, 0x00, // Usage Minimum (0), | ||
| 225 | 0x29, KBD2_REPORT_KEYS*8-1, // Usage Maximum (), | ||
| 226 | 0x81, 0x02, // Input (Data, Variable, Absolute), | ||
| 227 | 0xc0 // End Collection | ||
| 228 | }; | ||
| 229 | #endif | ||
| 230 | |||
| 231 | #ifdef MOUSE_ENABLE | ||
| 232 | // Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension | ||
| 233 | // http://www.microchip.com/forums/tm.aspx?high=&m=391435&mpage=1#391521 | ||
| 234 | // http://www.keil.com/forum/15671/ | ||
| 235 | // http://www.microsoft.com/whdc/device/input/wheel.mspx | ||
| 236 | static const uint8_t PROGMEM mouse_hid_report_desc[] = { | ||
| 237 | /* mouse */ | ||
| 238 | 0x05, 0x01, // USAGE_PAGE (Generic Desktop) | ||
| 239 | 0x09, 0x02, // USAGE (Mouse) | ||
| 240 | 0xa1, 0x01, // COLLECTION (Application) | ||
| 241 | //0x85, REPORT_ID_MOUSE, // REPORT_ID (1) | ||
| 242 | 0x09, 0x01, // USAGE (Pointer) | ||
| 243 | 0xa1, 0x00, // COLLECTION (Physical) | ||
| 244 | // ---------------------------- Buttons | ||
| 245 | 0x05, 0x09, // USAGE_PAGE (Button) | ||
| 246 | 0x19, 0x01, // USAGE_MINIMUM (Button 1) | ||
| 247 | 0x29, 0x05, // USAGE_MAXIMUM (Button 5) | ||
| 248 | 0x15, 0x00, // LOGICAL_MINIMUM (0) | ||
| 249 | 0x25, 0x01, // LOGICAL_MAXIMUM (1) | ||
| 250 | 0x75, 0x01, // REPORT_SIZE (1) | ||
| 251 | 0x95, 0x05, // REPORT_COUNT (5) | ||
| 252 | 0x81, 0x02, // INPUT (Data,Var,Abs) | ||
| 253 | 0x75, 0x03, // REPORT_SIZE (3) | ||
| 254 | 0x95, 0x01, // REPORT_COUNT (1) | ||
| 255 | 0x81, 0x03, // INPUT (Cnst,Var,Abs) | ||
| 256 | // ---------------------------- X,Y position | ||
| 257 | 0x05, 0x01, // USAGE_PAGE (Generic Desktop) | ||
| 258 | 0x09, 0x30, // USAGE (X) | ||
| 259 | 0x09, 0x31, // USAGE (Y) | ||
| 260 | 0x15, 0x81, // LOGICAL_MINIMUM (-127) | ||
| 261 | 0x25, 0x7f, // LOGICAL_MAXIMUM (127) | ||
| 262 | 0x75, 0x08, // REPORT_SIZE (8) | ||
| 263 | 0x95, 0x02, // REPORT_COUNT (2) | ||
| 264 | 0x81, 0x06, // INPUT (Data,Var,Rel) | ||
| 265 | // ---------------------------- Vertical wheel | ||
| 266 | 0x09, 0x38, // USAGE (Wheel) | ||
| 267 | 0x15, 0x81, // LOGICAL_MINIMUM (-127) | ||
| 268 | 0x25, 0x7f, // LOGICAL_MAXIMUM (127) | ||
| 269 | 0x35, 0x00, // PHYSICAL_MINIMUM (0) - reset physical | ||
| 270 | 0x45, 0x00, // PHYSICAL_MAXIMUM (0) | ||
| 271 | 0x75, 0x08, // REPORT_SIZE (8) | ||
| 272 | 0x95, 0x01, // REPORT_COUNT (1) | ||
| 273 | 0x81, 0x06, // INPUT (Data,Var,Rel) | ||
| 274 | // ---------------------------- Horizontal wheel | ||
| 275 | 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) | ||
| 276 | 0x0a, 0x38, 0x02, // USAGE (AC Pan) | ||
| 277 | 0x15, 0x81, // LOGICAL_MINIMUM (-127) | ||
| 278 | 0x25, 0x7f, // LOGICAL_MAXIMUM (127) | ||
| 279 | 0x75, 0x08, // REPORT_SIZE (8) | ||
| 280 | 0x95, 0x01, // REPORT_COUNT (1) | ||
| 281 | 0x81, 0x06, // INPUT (Data,Var,Rel) | ||
| 282 | 0xc0, // END_COLLECTION | ||
| 283 | 0xc0, // END_COLLECTION | ||
| 284 | }; | ||
| 285 | #endif | ||
| 286 | |||
| 287 | static const uint8_t PROGMEM debug_hid_report_desc[] = { | ||
| 288 | 0x06, 0x31, 0xFF, // Usage Page 0xFF31 (vendor defined) | ||
| 289 | 0x09, 0x74, // Usage 0x74 | ||
| 290 | 0xA1, 0x53, // Collection 0x53 | ||
| 291 | 0x75, 0x08, // report size = 8 bits | ||
| 292 | 0x15, 0x00, // logical minimum = 0 | ||
| 293 | 0x26, 0xFF, 0x00, // logical maximum = 255 | ||
| 294 | 0x95, DEBUG_TX_SIZE, // report count | ||
| 295 | 0x09, 0x75, // usage | ||
| 296 | 0x81, 0x02, // Input (array) | ||
| 297 | 0xC0 // end collection | ||
| 298 | }; | ||
| 299 | |||
| 300 | #ifdef EXTRAKEY_ENABLE | ||
| 301 | // audio controls & system controls | ||
| 302 | // http://www.microsoft.com/whdc/archive/w2kbd.mspx | ||
| 303 | static const uint8_t PROGMEM extra_hid_report_desc[] = { | ||
| 304 | /* system control */ | ||
| 305 | 0x05, 0x01, // USAGE_PAGE (Generic Desktop) | ||
| 306 | 0x09, 0x80, // USAGE (System Control) | ||
| 307 | 0xa1, 0x01, // COLLECTION (Application) | ||
| 308 | 0x85, REPORT_ID_SYSTEM, // REPORT_ID (2) | ||
| 309 | 0x15, 0x01, // LOGICAL_MINIMUM (0x1) | ||
| 310 | 0x25, 0xb7, // LOGICAL_MAXIMUM (0xb7) | ||
| 311 | 0x19, 0x01, // USAGE_MINIMUM (0x1) | ||
| 312 | 0x29, 0xb7, // USAGE_MAXIMUM (0xb7) | ||
| 313 | 0x75, 0x10, // REPORT_SIZE (16) | ||
| 314 | 0x95, 0x01, // REPORT_COUNT (1) | ||
| 315 | 0x81, 0x00, // INPUT (Data,Array,Abs) | ||
| 316 | 0xc0, // END_COLLECTION | ||
| 317 | /* consumer */ | ||
| 318 | 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) | ||
| 319 | 0x09, 0x01, // USAGE (Consumer Control) | ||
| 320 | 0xa1, 0x01, // COLLECTION (Application) | ||
| 321 | 0x85, REPORT_ID_CONSUMER, // REPORT_ID (3) | ||
| 322 | 0x15, 0x01, // LOGICAL_MINIMUM (0x1) | ||
| 323 | 0x26, 0x9c, 0x02, // LOGICAL_MAXIMUM (0x29c) | ||
| 324 | 0x19, 0x01, // USAGE_MINIMUM (0x1) | ||
| 325 | 0x2a, 0x9c, 0x02, // USAGE_MAXIMUM (0x29c) | ||
| 326 | 0x75, 0x10, // REPORT_SIZE (16) | ||
| 327 | 0x95, 0x01, // REPORT_COUNT (1) | ||
| 328 | 0x81, 0x00, // INPUT (Data,Array,Abs) | ||
| 329 | 0xc0, // END_COLLECTION | ||
| 330 | }; | ||
| 331 | #endif | ||
| 332 | |||
| 333 | #define KBD_HID_DESC_NUM 0 | ||
| 334 | #define KBD_HID_DESC_OFFSET (9+(9+9+7)*KBD_HID_DESC_NUM+9) | ||
| 335 | |||
| 336 | #ifdef MOUSE_ENABLE | ||
| 337 | # define MOUSE_HID_DESC_NUM (KBD_HID_DESC_NUM + 1) | ||
| 338 | # define MOUSE_HID_DESC_OFFSET (9+(9+9+7)*MOUSE_HID_DESC_NUM+9) | ||
| 339 | #else | ||
| 340 | # define MOUSE_HID_DESC_NUM (KBD_HID_DESC_NUM + 0) | ||
| 341 | #endif | ||
| 342 | |||
| 343 | #ifdef CONSOLE_ENABLE | ||
| 344 | #define DEBUG_HID_DESC_NUM (MOUSE_HID_DESC_NUM + 1) | ||
| 345 | #define DEBUG_HID_DESC_OFFSET (9+(9+9+7)*DEBUG_HID_DESC_NUM+9) | ||
| 346 | #else | ||
| 347 | # define DEBUG_HID_DESC_NUM (MOUSE_HID_DESC_NUM + 0) | ||
| 348 | #endif | ||
| 349 | |||
| 350 | #ifdef EXTRAKEY_ENABLE | ||
| 351 | # define EXTRA_HID_DESC_NUM (DEBUG_HID_DESC_NUM + 1) | ||
| 352 | # define EXTRA_HID_DESC_OFFSET (9+(9+9+7)*EXTRA_HID_DESC_NUM+9) | ||
| 353 | #else | ||
| 354 | # define EXTRA_HID_DESC_NUM (DEBUG_HID_DESC_NUM + 0) | ||
| 355 | #endif | ||
| 356 | |||
| 357 | #ifdef NKRO_ENABLE | ||
| 358 | # define KBD2_HID_DESC_NUM (EXTRA_HID_DESC_NUM + 1) | ||
| 359 | # define KBD2_HID_DESC_OFFSET (9+(9+9+7)*EXTRA_HID_DESC_NUM+9) | ||
| 360 | #else | ||
| 361 | # define KBD2_HID_DESC_NUM (EXTRA_HID_DESC_NUM + 0) | ||
| 362 | #endif | ||
| 363 | |||
| 364 | #define NUM_INTERFACES (KBD2_HID_DESC_NUM + 1) | ||
| 365 | #define CONFIG1_DESC_SIZE (9+(9+9+7)*NUM_INTERFACES) | ||
| 366 | static const uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = { | ||
| 367 | // configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10 | ||
| 368 | 9, // bLength; | ||
| 369 | 2, // bDescriptorType; | ||
| 370 | LSB(CONFIG1_DESC_SIZE), // wTotalLength | ||
| 371 | MSB(CONFIG1_DESC_SIZE), | ||
| 372 | NUM_INTERFACES, // bNumInterfaces | ||
| 373 | 1, // bConfigurationValue | ||
| 374 | 0, // iConfiguration | ||
| 375 | 0xA0, // bmAttributes | ||
| 376 | 50, // bMaxPower | ||
| 377 | |||
| 378 | // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | ||
| 379 | 9, // bLength | ||
| 380 | 4, // bDescriptorType | ||
| 381 | KBD_INTERFACE, // bInterfaceNumber | ||
| 382 | 0, // bAlternateSetting | ||
| 383 | 1, // bNumEndpoints | ||
| 384 | 0x03, // bInterfaceClass (0x03 = HID) | ||
| 385 | 0x01, // bInterfaceSubClass (0x01 = Boot) | ||
| 386 | 0x01, // bInterfaceProtocol (0x01 = Keyboard) | ||
| 387 | 0, // iInterface | ||
| 388 | // HID descriptor, HID 1.11 spec, section 6.2.1 | ||
| 389 | 9, // bLength | ||
| 390 | 0x21, // bDescriptorType | ||
| 391 | 0x11, 0x01, // bcdHID | ||
| 392 | 0, // bCountryCode | ||
| 393 | 1, // bNumDescriptors | ||
| 394 | 0x22, // bDescriptorType | ||
| 395 | sizeof(keyboard_hid_report_desc), // wDescriptorLength | ||
| 396 | 0, | ||
| 397 | // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | ||
| 398 | 7, // bLength | ||
| 399 | 5, // bDescriptorType | ||
| 400 | KBD_ENDPOINT | 0x80, // bEndpointAddress | ||
| 401 | 0x03, // bmAttributes (0x03=intr) | ||
| 402 | KBD_SIZE, 0, // wMaxPacketSize | ||
| 403 | 10, // bInterval | ||
| 404 | |||
| 405 | #ifdef MOUSE_ENABLE | ||
| 406 | // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | ||
| 407 | 9, // bLength | ||
| 408 | 4, // bDescriptorType | ||
| 409 | MOUSE_INTERFACE, // bInterfaceNumber | ||
| 410 | 0, // bAlternateSetting | ||
| 411 | 1, // bNumEndpoints | ||
| 412 | 0x03, // bInterfaceClass (0x03 = HID) | ||
| 413 | // ThinkPad T23 BIOS doesn't work with boot mouse. | ||
| 414 | 0x00, // bInterfaceSubClass (0x01 = Boot) | ||
| 415 | 0x00, // bInterfaceProtocol (0x02 = Mouse) | ||
| 416 | /* | ||
| 417 | 0x01, // bInterfaceSubClass (0x01 = Boot) | ||
| 418 | 0x02, // bInterfaceProtocol (0x02 = Mouse) | ||
| 419 | */ | ||
| 420 | 0, // iInterface | ||
| 421 | // HID descriptor, HID 1.11 spec, section 6.2.1 | ||
| 422 | 9, // bLength | ||
| 423 | 0x21, // bDescriptorType | ||
| 424 | 0x11, 0x01, // bcdHID | ||
| 425 | 0, // bCountryCode | ||
| 426 | 1, // bNumDescriptors | ||
| 427 | 0x22, // bDescriptorType | ||
| 428 | sizeof(mouse_hid_report_desc), // wDescriptorLength | ||
| 429 | 0, | ||
| 430 | // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | ||
| 431 | 7, // bLength | ||
| 432 | 5, // bDescriptorType | ||
| 433 | MOUSE_ENDPOINT | 0x80, // bEndpointAddress | ||
| 434 | 0x03, // bmAttributes (0x03=intr) | ||
| 435 | MOUSE_SIZE, 0, // wMaxPacketSize | ||
| 436 | 1, // bInterval | ||
| 437 | #endif | ||
| 438 | |||
| 439 | #ifdef CONSOLE_ENABLE | ||
| 440 | // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | ||
| 441 | 9, // bLength | ||
| 442 | 4, // bDescriptorType | ||
| 443 | DEBUG_INTERFACE, // bInterfaceNumber | ||
| 444 | 0, // bAlternateSetting | ||
| 445 | 1, // bNumEndpoints | ||
| 446 | 0x03, // bInterfaceClass (0x03 = HID) | ||
| 447 | 0x00, // bInterfaceSubClass | ||
| 448 | 0x00, // bInterfaceProtocol | ||
| 449 | 0, // iInterface | ||
| 450 | // HID descriptor, HID 1.11 spec, section 6.2.1 | ||
| 451 | 9, // bLength | ||
| 452 | 0x21, // bDescriptorType | ||
| 453 | 0x11, 0x01, // bcdHID | ||
| 454 | 0, // bCountryCode | ||
| 455 | 1, // bNumDescriptors | ||
| 456 | 0x22, // bDescriptorType | ||
| 457 | sizeof(debug_hid_report_desc), // wDescriptorLength | ||
| 458 | 0, | ||
| 459 | // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | ||
| 460 | 7, // bLength | ||
| 461 | 5, // bDescriptorType | ||
| 462 | DEBUG_TX_ENDPOINT | 0x80, // bEndpointAddress | ||
| 463 | 0x03, // bmAttributes (0x03=intr) | ||
| 464 | DEBUG_TX_SIZE, 0, // wMaxPacketSize | ||
| 465 | 1, // bInterval | ||
| 466 | #endif | ||
| 467 | |||
| 468 | #ifdef EXTRAKEY_ENABLE | ||
| 469 | // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | ||
| 470 | 9, // bLength | ||
| 471 | 4, // bDescriptorType | ||
| 472 | EXTRA_INTERFACE, // bInterfaceNumber | ||
| 473 | 0, // bAlternateSetting | ||
| 474 | 1, // bNumEndpoints | ||
| 475 | 0x03, // bInterfaceClass (0x03 = HID) | ||
| 476 | 0x00, // bInterfaceSubClass | ||
| 477 | 0x00, // bInterfaceProtocol | ||
| 478 | 0, // iInterface | ||
| 479 | // HID descriptor, HID 1.11 spec, section 6.2.1 | ||
| 480 | 9, // bLength | ||
| 481 | 0x21, // bDescriptorType | ||
| 482 | 0x11, 0x01, // bcdHID | ||
| 483 | 0, // bCountryCode | ||
| 484 | 1, // bNumDescriptors | ||
| 485 | 0x22, // bDescriptorType | ||
| 486 | sizeof(extra_hid_report_desc), // wDescriptorLength | ||
| 487 | 0, | ||
| 488 | // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | ||
| 489 | 7, // bLength | ||
| 490 | 5, // bDescriptorType | ||
| 491 | EXTRA_ENDPOINT | 0x80, // bEndpointAddress | ||
| 492 | 0x03, // bmAttributes (0x03=intr) | ||
| 493 | EXTRA_SIZE, 0, // wMaxPacketSize | ||
| 494 | 10, // bInterval | ||
| 495 | #endif | ||
| 496 | |||
| 497 | #ifdef NKRO_ENABLE | ||
| 498 | // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | ||
| 499 | 9, // bLength | ||
| 500 | 4, // bDescriptorType | ||
| 501 | KBD2_INTERFACE, // bInterfaceNumber | ||
| 502 | 0, // bAlternateSetting | ||
| 503 | 1, // bNumEndpoints | ||
| 504 | 0x03, // bInterfaceClass (0x03 = HID) | ||
| 505 | 0x00, // bInterfaceSubClass (0x01 = Boot) | ||
| 506 | 0x00, // bInterfaceProtocol (0x01 = Keyboard) | ||
| 507 | 0, // iInterface | ||
| 508 | // HID descriptor, HID 1.11 spec, section 6.2.1 | ||
| 509 | 9, // bLength | ||
| 510 | 0x21, // bDescriptorType | ||
| 511 | 0x11, 0x01, // bcdHID | ||
| 512 | 0, // bCountryCode | ||
| 513 | 1, // bNumDescriptors | ||
| 514 | 0x22, // bDescriptorType | ||
| 515 | sizeof(keyboard2_hid_report_desc), // wDescriptorLength | ||
| 516 | 0, | ||
| 517 | // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | ||
| 518 | 7, // bLength | ||
| 519 | 5, // bDescriptorType | ||
| 520 | KBD2_ENDPOINT | 0x80, // bEndpointAddress | ||
| 521 | 0x03, // bmAttributes (0x03=intr) | ||
| 522 | KBD2_SIZE, 0, // wMaxPacketSize | ||
| 523 | 1, // bInterval | ||
| 524 | #endif | ||
| 525 | }; | ||
| 526 | |||
| 527 | // If you're desperate for a little extra code memory, these strings | ||
| 528 | // can be completely removed if iManufacturer, iProduct, iSerialNumber | ||
| 529 | // in the device desciptor are changed to zeros. | ||
| 530 | struct usb_string_descriptor_struct { | ||
| 531 | uint8_t bLength; | ||
| 532 | uint8_t bDescriptorType; | ||
| 533 | int16_t wString[]; | ||
| 534 | }; | ||
| 535 | static const struct usb_string_descriptor_struct PROGMEM string0 = { | ||
| 536 | 4, | ||
| 537 | 3, | ||
| 538 | {0x0409} | ||
| 539 | }; | ||
| 540 | static const struct usb_string_descriptor_struct PROGMEM string1 = { | ||
| 541 | sizeof(STR_MANUFACTURER), | ||
| 542 | 3, | ||
| 543 | STR_MANUFACTURER | ||
| 544 | }; | ||
| 545 | static const struct usb_string_descriptor_struct PROGMEM string2 = { | ||
| 546 | sizeof(STR_PRODUCT), | ||
| 547 | 3, | ||
| 548 | STR_PRODUCT | ||
| 549 | }; | ||
| 550 | |||
| 551 | // This table defines which descriptor data is sent for each specific | ||
| 552 | // request from the host (in wValue and wIndex). | ||
| 553 | static const struct descriptor_list_struct { | ||
| 554 | uint16_t wValue; // descriptor type | ||
| 555 | uint16_t wIndex; | ||
| 556 | const uint8_t *addr; | ||
| 557 | uint8_t length; | ||
| 558 | } PROGMEM descriptor_list[] = { | ||
| 559 | // DEVICE descriptor | ||
| 560 | {0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)}, | ||
| 561 | // CONFIGURATION descriptor | ||
| 562 | {0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)}, | ||
| 563 | // HID/REPORT descriptors | ||
| 564 | {0x2100, KBD_INTERFACE, config1_descriptor+KBD_HID_DESC_OFFSET, 9}, | ||
| 565 | {0x2200, KBD_INTERFACE, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)}, | ||
| 566 | #ifdef MOUSE_ENABLE | ||
| 567 | {0x2100, MOUSE_INTERFACE, config1_descriptor+MOUSE_HID_DESC_OFFSET, 9}, | ||
| 568 | {0x2200, MOUSE_INTERFACE, mouse_hid_report_desc, sizeof(mouse_hid_report_desc)}, | ||
| 569 | #endif | ||
| 570 | #ifdef CONSOLE_ENABLE | ||
| 571 | {0x2100, DEBUG_INTERFACE, config1_descriptor+DEBUG_HID_DESC_OFFSET, 9}, | ||
| 572 | {0x2200, DEBUG_INTERFACE, debug_hid_report_desc, sizeof(debug_hid_report_desc)}, | ||
| 573 | #endif | ||
| 574 | #ifdef EXTRAKEY_ENABLE | ||
| 575 | {0x2100, EXTRA_INTERFACE, config1_descriptor+EXTRA_HID_DESC_OFFSET, 9}, | ||
| 576 | {0x2200, EXTRA_INTERFACE, extra_hid_report_desc, sizeof(extra_hid_report_desc)}, | ||
| 577 | #endif | ||
| 578 | #ifdef NKRO_ENABLE | ||
| 579 | {0x2100, KBD2_INTERFACE, config1_descriptor+KBD2_HID_DESC_OFFSET, 9}, | ||
| 580 | {0x2200, KBD2_INTERFACE, keyboard2_hid_report_desc, sizeof(keyboard2_hid_report_desc)}, | ||
| 581 | #endif | ||
| 582 | // STRING descriptors | ||
| 583 | {0x0300, 0x0000, (const uint8_t *)&string0, 4}, | ||
| 584 | {0x0301, 0x0409, (const uint8_t *)&string1, sizeof(STR_MANUFACTURER)}, | ||
| 585 | {0x0302, 0x0409, (const uint8_t *)&string2, sizeof(STR_PRODUCT)} | ||
| 586 | }; | ||
| 587 | #define NUM_DESC_LIST (sizeof(descriptor_list)/sizeof(struct descriptor_list_struct)) | ||
| 588 | |||
| 589 | |||
| 590 | /************************************************************************** | ||
| 591 | * | ||
| 592 | * Variables - these are the only non-stack RAM usage | ||
| 593 | * | ||
| 594 | **************************************************************************/ | ||
| 595 | |||
| 596 | // zero when we are not configured, non-zero when enumerated | ||
| 597 | static volatile uint8_t usb_configuration=0; | ||
| 598 | |||
| 599 | |||
| 600 | /************************************************************************** | ||
| 601 | * | ||
| 602 | * Public Functions - these are the API intended for the user | ||
| 603 | * | ||
| 604 | **************************************************************************/ | ||
| 605 | |||
| 606 | |||
| 607 | // initialize USB | ||
| 608 | void usb_init(void) | ||
| 609 | { | ||
| 610 | HW_CONFIG(); | ||
| 611 | USB_FREEZE(); // enable USB | ||
| 612 | PLL_CONFIG(); // config PLL | ||
| 613 | while (!(PLLCSR & (1<<PLOCK))) ; // wait for PLL lock | ||
| 614 | USB_CONFIG(); // start USB clock | ||
| 615 | UDCON = 0; // enable attach resistor | ||
| 616 | usb_configuration = 0; | ||
| 617 | suspend = false; | ||
| 618 | UDIEN = (1<<EORSTE)|(1<<SOFE)|(1<<SUSPE)|(1<<WAKEUPE); | ||
| 619 | sei(); | ||
| 620 | } | ||
| 621 | |||
| 622 | // return 0 if the USB is not configured, or the configuration | ||
| 623 | // number selected by the HOST | ||
| 624 | uint8_t usb_configured(void) | ||
| 625 | { | ||
| 626 | return usb_configuration && !suspend; | ||
| 627 | } | ||
| 628 | |||
| 629 | void usb_remote_wakeup(void) | ||
| 630 | { | ||
| 631 | UDCON |= (1<<RMWKUP); | ||
| 632 | while (UDCON & (1<<RMWKUP)); | ||
| 633 | } | ||
| 634 | |||
| 635 | |||
| 636 | |||
| 637 | /************************************************************************** | ||
| 638 | * | ||
| 639 | * Private Functions - not intended for general user consumption.... | ||
| 640 | * | ||
| 641 | **************************************************************************/ | ||
| 642 | |||
| 643 | |||
| 644 | |||
| 645 | // USB Device Interrupt - handle all device-level events | ||
| 646 | // the transmit buffer flushing is triggered by the start of frame | ||
| 647 | // | ||
| 648 | ISR(USB_GEN_vect) | ||
| 649 | { | ||
| 650 | uint8_t intbits, t; | ||
| 651 | static uint8_t div4=0; | ||
| 652 | |||
| 653 | intbits = UDINT; | ||
| 654 | UDINT = 0; | ||
| 655 | if ((intbits & (1<<SUSPI)) && (UDIEN & (1<<SUSPE)) && usb_configuration) { | ||
| 656 | #ifdef SLEEP_LED_ENABLE | ||
| 657 | sleep_led_enable(); | ||
| 658 | #endif | ||
| 659 | UDIEN &= ~(1<<SUSPE); | ||
| 660 | UDIEN |= (1<<WAKEUPE); | ||
| 661 | suspend = true; | ||
| 662 | } | ||
| 663 | if ((intbits & (1<<WAKEUPI)) && (UDIEN & (1<<WAKEUPE)) && usb_configuration) { | ||
| 664 | suspend_wakeup_init(); | ||
| 665 | #ifdef SLEEP_LED_ENABLE | ||
| 666 | sleep_led_disable(); | ||
| 667 | // NOTE: converters may not accept this | ||
| 668 | led_set(host_keyboard_leds()); | ||
| 669 | #endif | ||
| 670 | |||
| 671 | UDIEN |= (1<<SUSPE); | ||
| 672 | UDIEN &= ~(1<<WAKEUPE); | ||
| 673 | suspend = false; | ||
| 674 | } | ||
| 675 | if (intbits & (1<<EORSTI)) { | ||
| 676 | UENUM = 0; | ||
| 677 | UECONX = 1; | ||
| 678 | UECFG0X = EP_TYPE_CONTROL; | ||
| 679 | UECFG1X = EP_SIZE(ENDPOINT0_SIZE) | EP_SINGLE_BUFFER; | ||
| 680 | UEIENX = (1<<RXSTPE); | ||
| 681 | usb_configuration = 0; | ||
| 682 | } | ||
| 683 | if ((intbits & (1<<SOFI)) && usb_configuration) { | ||
| 684 | t = debug_flush_timer; | ||
| 685 | if (t) { | ||
| 686 | debug_flush_timer = -- t; | ||
| 687 | if (!t) { | ||
| 688 | UENUM = DEBUG_TX_ENDPOINT; | ||
| 689 | while ((UEINTX & (1<<RWAL))) { | ||
| 690 | UEDATX = 0; | ||
| 691 | } | ||
| 692 | UEINTX = 0x3A; | ||
| 693 | } | ||
| 694 | } | ||
| 695 | /* TODO: should keep IDLE rate on each keyboard interface */ | ||
| 696 | #ifdef NKRO_ENABLE | ||
| 697 | if (!keyboard_nkro && keyboard_idle && (++div4 & 3) == 0) { | ||
| 698 | #else | ||
| 699 | if (keyboard_idle && (++div4 & 3) == 0) { | ||
| 700 | #endif | ||
| 701 | UENUM = KBD_ENDPOINT; | ||
| 702 | if (UEINTX & (1<<RWAL)) { | ||
| 703 | usb_keyboard_idle_count++; | ||
| 704 | if (usb_keyboard_idle_count == keyboard_idle) { | ||
| 705 | usb_keyboard_idle_count = 0; | ||
| 706 | /* TODO: fix keyboard_report inconsistency */ | ||
| 707 | /* To avoid Mac SET_IDLE behaviour. | ||
| 708 | UEDATX = keyboard_report_prev->mods; | ||
| 709 | UEDATX = 0; | ||
| 710 | uint8_t keys = keyboard_protocol ? KBD_REPORT_KEYS : 6; | ||
| 711 | for (uint8_t i=0; i<keys; i++) { | ||
| 712 | UEDATX = keyboard_report_prev->keys[i]; | ||
| 713 | } | ||
| 714 | UEINTX = 0x3A; | ||
| 715 | */ | ||
| 716 | } | ||
| 717 | } | ||
| 718 | } | ||
| 719 | } | ||
| 720 | } | ||
| 721 | |||
| 722 | |||
| 723 | |||
| 724 | // Misc functions to wait for ready and send/receive packets | ||
| 725 | static inline void usb_wait_in_ready(void) | ||
| 726 | { | ||
| 727 | while (!(UEINTX & (1<<TXINI))) ; | ||
| 728 | } | ||
| 729 | static inline void usb_send_in(void) | ||
| 730 | { | ||
| 731 | UEINTX = ~(1<<TXINI); | ||
| 732 | } | ||
| 733 | static inline void usb_wait_receive_out(void) | ||
| 734 | { | ||
| 735 | while (!(UEINTX & (1<<RXOUTI))) ; | ||
| 736 | } | ||
| 737 | static inline void usb_ack_out(void) | ||
| 738 | { | ||
| 739 | UEINTX = ~(1<<RXOUTI); | ||
| 740 | } | ||
| 741 | |||
| 742 | |||
| 743 | |||
| 744 | // USB Endpoint Interrupt - endpoint 0 is handled here. The | ||
| 745 | // other endpoints are manipulated by the user-callable | ||
| 746 | // functions, and the start-of-frame interrupt. | ||
| 747 | // | ||
| 748 | ISR(USB_COM_vect) | ||
| 749 | { | ||
| 750 | uint8_t intbits; | ||
| 751 | const uint8_t *list; | ||
| 752 | const uint8_t *cfg; | ||
| 753 | uint8_t i, n, len, en; | ||
| 754 | uint8_t bmRequestType; | ||
| 755 | uint8_t bRequest; | ||
| 756 | uint16_t wValue; | ||
| 757 | uint16_t wIndex; | ||
| 758 | uint16_t wLength; | ||
| 759 | uint16_t desc_val; | ||
| 760 | const uint8_t *desc_addr; | ||
| 761 | uint8_t desc_length; | ||
| 762 | |||
| 763 | UENUM = 0; | ||
| 764 | intbits = UEINTX; | ||
| 765 | if (intbits & (1<<RXSTPI)) { | ||
| 766 | bmRequestType = UEDATX; | ||
| 767 | bRequest = UEDATX; | ||
| 768 | wValue = UEDATX; | ||
| 769 | wValue |= (UEDATX << 8); | ||
| 770 | wIndex = UEDATX; | ||
| 771 | wIndex |= (UEDATX << 8); | ||
| 772 | wLength = UEDATX; | ||
| 773 | wLength |= (UEDATX << 8); | ||
| 774 | UEINTX = ~((1<<RXSTPI) | (1<<RXOUTI) | (1<<TXINI)); | ||
| 775 | if (bRequest == GET_DESCRIPTOR) { | ||
| 776 | list = (const uint8_t *)descriptor_list; | ||
| 777 | for (i=0; ; i++) { | ||
| 778 | if (i >= NUM_DESC_LIST) { | ||
| 779 | UECONX = (1<<STALLRQ)|(1<<EPEN); //stall | ||
| 780 | return; | ||
| 781 | } | ||
| 782 | desc_val = pgm_read_word(list); | ||
| 783 | if (desc_val != wValue) { | ||
| 784 | list += sizeof(struct descriptor_list_struct); | ||
| 785 | continue; | ||
| 786 | } | ||
| 787 | list += 2; | ||
| 788 | desc_val = pgm_read_word(list); | ||
| 789 | if (desc_val != wIndex) { | ||
| 790 | list += sizeof(struct descriptor_list_struct)-2; | ||
| 791 | continue; | ||
| 792 | } | ||
| 793 | list += 2; | ||
| 794 | desc_addr = (const uint8_t *)pgm_read_word(list); | ||
| 795 | list += 2; | ||
| 796 | desc_length = pgm_read_byte(list); | ||
| 797 | break; | ||
| 798 | } | ||
| 799 | len = (wLength < 256) ? wLength : 255; | ||
| 800 | if (len > desc_length) len = desc_length; | ||
| 801 | do { | ||
| 802 | // wait for host ready for IN packet | ||
| 803 | do { | ||
| 804 | i = UEINTX; | ||
| 805 | } while (!(i & ((1<<TXINI)|(1<<RXOUTI)))); | ||
| 806 | if (i & (1<<RXOUTI)) return; // abort | ||
| 807 | // send IN packet | ||
| 808 | n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE; | ||
| 809 | for (i = n; i; i--) { | ||
| 810 | UEDATX = pgm_read_byte(desc_addr++); | ||
| 811 | } | ||
| 812 | len -= n; | ||
| 813 | usb_send_in(); | ||
| 814 | } while (len || n == ENDPOINT0_SIZE); | ||
| 815 | return; | ||
| 816 | } | ||
| 817 | if (bRequest == SET_ADDRESS) { | ||
| 818 | usb_send_in(); | ||
| 819 | usb_wait_in_ready(); | ||
| 820 | UDADDR = wValue | (1<<ADDEN); | ||
| 821 | return; | ||
| 822 | } | ||
| 823 | if (bRequest == SET_CONFIGURATION && bmRequestType == 0) { | ||
| 824 | usb_configuration = wValue; | ||
| 825 | usb_send_in(); | ||
| 826 | cfg = endpoint_config_table; | ||
| 827 | for (i=1; i<=MAX_ENDPOINT; i++) { | ||
| 828 | UENUM = i; | ||
| 829 | en = pgm_read_byte(cfg++); | ||
| 830 | if (en) { | ||
| 831 | UECONX = (1<<EPEN); | ||
| 832 | UECFG0X = pgm_read_byte(cfg++); | ||
| 833 | UECFG1X = pgm_read_byte(cfg++); | ||
| 834 | } else { | ||
| 835 | UECONX = 0; | ||
| 836 | } | ||
| 837 | } | ||
| 838 | UERST = UERST_MASK; | ||
| 839 | UERST = 0; | ||
| 840 | return; | ||
| 841 | } | ||
| 842 | if (bRequest == GET_CONFIGURATION && bmRequestType == 0x80) { | ||
| 843 | usb_wait_in_ready(); | ||
| 844 | UEDATX = usb_configuration; | ||
| 845 | usb_send_in(); | ||
| 846 | return; | ||
| 847 | } | ||
| 848 | |||
| 849 | if (bRequest == GET_STATUS) { | ||
| 850 | usb_wait_in_ready(); | ||
| 851 | i = 0; | ||
| 852 | #ifdef SUPPORT_ENDPOINT_HALT | ||
| 853 | if (bmRequestType == 0x82) { | ||
| 854 | UENUM = wIndex; | ||
| 855 | if (UECONX & (1<<STALLRQ)) i = 1; | ||
| 856 | UENUM = 0; | ||
| 857 | } | ||
| 858 | #endif | ||
| 859 | UEDATX = i; | ||
| 860 | UEDATX = 0; | ||
| 861 | usb_send_in(); | ||
| 862 | return; | ||
| 863 | } | ||
| 864 | if (bRequest == CLEAR_FEATURE || bRequest == SET_FEATURE) { | ||
| 865 | #ifdef SUPPORT_ENDPOINT_HALT | ||
| 866 | if (bmRequestType == 0x02 && wValue == ENDPOINT_HALT) { | ||
| 867 | i = wIndex & 0x7F; | ||
| 868 | if (i >= 1 && i <= MAX_ENDPOINT) { | ||
| 869 | usb_send_in(); | ||
| 870 | UENUM = i; | ||
| 871 | if (bRequest == SET_FEATURE) { | ||
| 872 | UECONX = (1<<STALLRQ)|(1<<EPEN); | ||
| 873 | } else { | ||
| 874 | UECONX = (1<<STALLRQC)|(1<<RSTDT)|(1<<EPEN); | ||
| 875 | UERST = (1 << i); | ||
| 876 | UERST = 0; | ||
| 877 | } | ||
| 878 | return; | ||
| 879 | } | ||
| 880 | } | ||
| 881 | #endif | ||
| 882 | if (bmRequestType == 0x00 && wValue == DEVICE_REMOTE_WAKEUP) { | ||
| 883 | if (bRequest == SET_FEATURE) { | ||
| 884 | remote_wakeup = true; | ||
| 885 | } else { | ||
| 886 | remote_wakeup = false; | ||
| 887 | } | ||
| 888 | usb_send_in(); | ||
| 889 | return; | ||
| 890 | } | ||
| 891 | } | ||
| 892 | if (wIndex == KBD_INTERFACE) { | ||
| 893 | if (bmRequestType == 0xA1) { | ||
| 894 | if (bRequest == HID_GET_REPORT) { | ||
| 895 | usb_wait_in_ready(); | ||
| 896 | UEDATX = keyboard_report->mods; | ||
| 897 | UEDATX = 0; | ||
| 898 | for (i=0; i<6; i++) { | ||
| 899 | UEDATX = keyboard_report->keys[i]; | ||
| 900 | } | ||
| 901 | usb_send_in(); | ||
| 902 | return; | ||
| 903 | } | ||
| 904 | if (bRequest == HID_GET_IDLE) { | ||
| 905 | usb_wait_in_ready(); | ||
| 906 | UEDATX = keyboard_idle; | ||
| 907 | usb_send_in(); | ||
| 908 | return; | ||
| 909 | } | ||
| 910 | if (bRequest == HID_GET_PROTOCOL) { | ||
| 911 | usb_wait_in_ready(); | ||
| 912 | UEDATX = keyboard_protocol; | ||
| 913 | usb_send_in(); | ||
| 914 | return; | ||
| 915 | } | ||
| 916 | } | ||
| 917 | if (bmRequestType == 0x21) { | ||
| 918 | if (bRequest == HID_SET_REPORT) { | ||
| 919 | usb_wait_receive_out(); | ||
| 920 | usb_keyboard_leds = UEDATX; | ||
| 921 | usb_ack_out(); | ||
| 922 | usb_send_in(); | ||
| 923 | return; | ||
| 924 | } | ||
| 925 | if (bRequest == HID_SET_IDLE) { | ||
| 926 | keyboard_idle = (wValue >> 8); | ||
| 927 | usb_keyboard_idle_count = 0; | ||
| 928 | //usb_wait_in_ready(); | ||
| 929 | usb_send_in(); | ||
| 930 | return; | ||
| 931 | } | ||
| 932 | if (bRequest == HID_SET_PROTOCOL) { | ||
| 933 | keyboard_protocol = wValue; | ||
| 934 | #ifdef NKRO_ENABLE | ||
| 935 | keyboard_nkro = !!keyboard_protocol; | ||
| 936 | #endif | ||
| 937 | clear_keyboard(); | ||
| 938 | //usb_wait_in_ready(); | ||
| 939 | usb_send_in(); | ||
| 940 | return; | ||
| 941 | } | ||
| 942 | } | ||
| 943 | } | ||
| 944 | #ifdef MOUSE_ENABLE | ||
| 945 | if (wIndex == MOUSE_INTERFACE) { | ||
| 946 | if (bmRequestType == 0xA1) { | ||
| 947 | if (bRequest == HID_GET_REPORT) { | ||
| 948 | if (wValue == HID_REPORT_INPUT) { | ||
| 949 | usb_wait_in_ready(); | ||
| 950 | UEDATX = 0; | ||
| 951 | UEDATX = 0; | ||
| 952 | UEDATX = 0; | ||
| 953 | UEDATX = 0; | ||
| 954 | usb_send_in(); | ||
| 955 | return; | ||
| 956 | } | ||
| 957 | if (wValue == HID_REPORT_FEATURE) { | ||
| 958 | usb_wait_in_ready(); | ||
| 959 | UEDATX = 0x05; | ||
| 960 | usb_send_in(); | ||
| 961 | return; | ||
| 962 | } | ||
| 963 | } | ||
| 964 | if (bRequest == HID_GET_PROTOCOL) { | ||
| 965 | usb_wait_in_ready(); | ||
| 966 | UEDATX = usb_mouse_protocol; | ||
| 967 | usb_send_in(); | ||
| 968 | return; | ||
| 969 | } | ||
| 970 | } | ||
| 971 | if (bmRequestType == 0x21) { | ||
| 972 | if (bRequest == HID_SET_PROTOCOL) { | ||
| 973 | usb_mouse_protocol = wValue; | ||
| 974 | usb_send_in(); | ||
| 975 | return; | ||
| 976 | } | ||
| 977 | } | ||
| 978 | } | ||
| 979 | #endif | ||
| 980 | if (wIndex == DEBUG_INTERFACE) { | ||
| 981 | if (bRequest == HID_GET_REPORT && bmRequestType == 0xA1) { | ||
| 982 | len = wLength; | ||
| 983 | do { | ||
| 984 | // wait for host ready for IN packet | ||
| 985 | do { | ||
| 986 | i = UEINTX; | ||
| 987 | } while (!(i & ((1<<TXINI)|(1<<RXOUTI)))); | ||
| 988 | if (i & (1<<RXOUTI)) return; // abort | ||
| 989 | // send IN packet | ||
| 990 | n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE; | ||
| 991 | for (i = n; i; i--) { | ||
| 992 | UEDATX = 0; | ||
| 993 | } | ||
| 994 | len -= n; | ||
| 995 | usb_send_in(); | ||
| 996 | } while (len || n == ENDPOINT0_SIZE); | ||
| 997 | return; | ||
| 998 | } | ||
| 999 | } | ||
| 1000 | } | ||
| 1001 | UECONX = (1<<STALLRQ) | (1<<EPEN); // stall | ||
| 1002 | } | ||
