]>
Commit | Line | Data |
---|---|---|
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 | } |