]> git.friedersdorff.com Git - max/tmk_keyboard.git/blob - usb.c
change keymap.
[max/tmk_keyboard.git] / usb.c
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 <avr/io.h>
25 #include <avr/pgmspace.h>
26 #include <avr/interrupt.h>
27 #include "usb.h"
28 #include "usb_keyboard.h"
29 #include "usb_mouse.h"
30 #include "usb_debug.h"
31 #include "print.h"
32
33
34 /**************************************************************************
35  *
36  *  Configurable Options
37  *
38  **************************************************************************/
39
40 // You can change these to give your code its own name.
41 #define STR_MANUFACTURER        L"t.m.k."
42 #define STR_PRODUCT             L"t.m.k. keyboard"
43
44
45 // Mac OS-X and Linux automatically load the correct drivers.  On
46 // Windows, even though the driver is supplied by Microsoft, an
47 // INF file is needed to load the driver.  These numbers need to
48 // match the INF file.
49 #define VENDOR_ID               0xFEED
50 #define PRODUCT_ID              0xCAFE
51
52
53 // USB devices are supposed to implment a halt feature, which is
54 // rarely (if ever) used.  If you comment this line out, the halt
55 // code will be removed, saving 102 bytes of space (gcc 4.3.0).
56 // This is not strictly USB compliant, but works with all major
57 // operating systems.
58 #define SUPPORT_ENDPOINT_HALT
59
60
61
62 /**************************************************************************
63  *
64  *  Endpoint Buffer Configuration
65  *
66  **************************************************************************/
67
68 #define ENDPOINT0_SIZE          32
69
70 // 0:control endpoint is enabled automatically by controller.
71 static const uint8_t PROGMEM endpoint_config_table[] = {
72         // enable, UECFG0X(type, direction), UECFG1X(size, bank, allocation)
73         1, EP_TYPE_INTERRUPT_IN,  EP_SIZE(KEYBOARD_SIZE) | KEYBOARD_BUFFER, // 1
74         1, EP_TYPE_INTERRUPT_IN,  EP_SIZE(MOUSE_SIZE)    | MOUSE_BUFFER,    // 2
75         1, EP_TYPE_INTERRUPT_IN,  EP_SIZE(DEBUG_TX_SIZE) | DEBUG_TX_BUFFER, // 3
76         0, // 4
77         0, // 5
78         0, // 6
79 };
80
81
82 /**************************************************************************
83  *
84  *  Descriptor Data
85  *
86  **************************************************************************/
87
88 // Descriptors are the data that your computer reads when it auto-detects
89 // this USB device (called "enumeration" in USB lingo).  The most commonly
90 // changed items are editable at the top of this file.  Changing things
91 // in here should only be done by those who've read chapter 9 of the USB
92 // spec and relevant portions of any USB class specifications!
93
94
95 static uint8_t PROGMEM device_descriptor[] = {
96         18,                                     // bLength
97         1,                                      // bDescriptorType
98         0x00, 0x02,                             // bcdUSB
99         0,                                      // bDeviceClass
100         0,                                      // bDeviceSubClass
101         0,                                      // bDeviceProtocol
102         ENDPOINT0_SIZE,                         // bMaxPacketSize0
103         LSB(VENDOR_ID), MSB(VENDOR_ID),         // idVendor
104         LSB(PRODUCT_ID), MSB(PRODUCT_ID),       // idProduct
105         0x00, 0x01,                             // bcdDevice
106         1,                                      // iManufacturer
107         2,                                      // iProduct
108         0,                                      // iSerialNumber
109         1                                       // bNumConfigurations
110 };
111
112 // Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60
113 static uint8_t PROGMEM keyboard_hid_report_desc[] = {
114         0x05, 0x01,          // Usage Page (Generic Desktop),
115         0x09, 0x06,          // Usage (Keyboard),
116         0xA1, 0x01,          // Collection (Application),
117         0x75, 0x01,          //   Report Size (1),
118         0x95, 0x08,          //   Report Count (8),
119         0x05, 0x07,          //   Usage Page (Key Codes),
120         0x19, 0xE0,          //   Usage Minimum (224),
121         0x29, 0xE7,          //   Usage Maximum (231),
122         0x15, 0x00,          //   Logical Minimum (0),
123         0x25, 0x01,          //   Logical Maximum (1),
124         0x81, 0x02,          //   Input (Data, Variable, Absolute), ;Modifier byte
125         0x95, 0x01,          //   Report Count (1),
126         0x75, 0x08,          //   Report Size (8),
127         0x81, 0x03,          //   Input (Constant),                 ;Reserved byte
128         0x95, 0x05,          //   Report Count (5),
129         0x75, 0x01,          //   Report Size (1),
130         0x05, 0x08,          //   Usage Page (LEDs),
131         0x19, 0x01,          //   Usage Minimum (1),
132         0x29, 0x05,          //   Usage Maximum (5),
133         0x91, 0x02,          //   Output (Data, Variable, Absolute), ;LED report
134         0x95, 0x01,          //   Report Count (1),
135         0x75, 0x03,          //   Report Size (3),
136         0x91, 0x03,          //   Output (Constant),                 ;LED report padding
137         0x95, 0x06,          //   Report Count (6),
138         0x75, 0x08,          //   Report Size (8),
139         0x15, 0x00,          //   Logical Minimum (0),
140         0x25, 0x68,          //   Logical Maximum(104),
141         0x05, 0x07,          //   Usage Page (Key Codes),
142         0x19, 0x00,          //   Usage Minimum (0),
143         0x29, 0x68,          //   Usage Maximum (104),
144         0x81, 0x00,          //   Input (Data, Array),
145         0xc0                 // End Collection
146 };
147
148 // Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension
149 // http://www.microchip.com/forums/tm.aspx?high=&m=391435&mpage=1#391521
150 // http://www.keil.com/forum/15671/
151 // http://www.microsoft.com/whdc/device/input/wheel.mspx
152 static uint8_t PROGMEM mouse_hid_report_desc[] = {
153     0x05, 0x01,                     // Usage Page (Generic Desktop)
154     0x09, 0x02,                     // Usage (Mouse)
155     0xA1, 0x01,                     // Collection (Application)
156     0x05, 0x09,                     //   Usage Page (Button)
157     0x19, 0x01,                     //   Usage Minimum (Button #1)
158     0x29, 0x03,                     //   Usage Maximum (Button #3)
159     0x15, 0x00,                     //   Logical Minimum (0)
160     0x25, 0x01,                     //   Logical Maximum (1)
161     0x95, 0x03,                     //   Report Count (3)
162     0x75, 0x01,                     //   Report Size (1)
163     0x81, 0x02,                     //   Input (Data, Variable, Absolute)
164     0x95, 0x01,                     //   Report Count (1)
165     0x75, 0x05,                     //   Report Size (5)
166     0x81, 0x03,                     //   Input (Constant)
167     0x05, 0x01,                     //   Usage Page (Generic Desktop)
168     0x09, 0x30,                     //   Usage (X)
169     0x09, 0x31,                     //   Usage (Y)
170     0x15, 0x81,                     //   Logical Minimum (-127)
171     0x25, 0x7F,                     //   Logical Maximum (127)
172     0x75, 0x08,                     //   Report Size (8),
173     0x95, 0x02,                     //   Report Count (2),
174     0x81, 0x06,                     //   Input (Data, Variable, Relative)
175     0x09, 0x38,                     //   Usage (Wheel)
176     0x95, 0x01,                     //   Report Count (1),
177     0x81, 0x06,                     //   Input (Data, Variable, Relative)
178     0xC0                            // End Collection
179 };
180
181 static uint8_t PROGMEM debug_hid_report_desc[] = {
182         0x06, 0x31, 0xFF,                       // Usage Page 0xFF31 (vendor defined)
183         0x09, 0x74,                             // Usage 0x74
184         0xA1, 0x53,                             // Collection 0x53
185         0x75, 0x08,                             // report size = 8 bits
186         0x15, 0x00,                             // logical minimum = 0
187         0x26, 0xFF, 0x00,                       // logical maximum = 255
188         0x95, DEBUG_TX_SIZE,                    // report count
189         0x09, 0x75,                             // usage
190         0x81, 0x02,                             // Input (array)
191         0xC0                                    // end collection
192 };
193
194 #define CONFIG1_DESC_SIZE        (9+(9+9+7)+(9+9+7)+(9+9+7))
195 #define KEYBOARD_HID_DESC_OFFSET (9+9)
196 #define MOUSE_HID_DESC_OFFSET    (9+(9+9+7)+9)
197 #define DEBUG_HID_DESC_OFFSET    (9+(9+9+7)+(9+9+7)+9)
198 static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
199         // configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10
200         9,                                      // bLength;
201         2,                                      // bDescriptorType;
202         LSB(CONFIG1_DESC_SIZE),                 // wTotalLength
203         MSB(CONFIG1_DESC_SIZE),
204         3,                                      // bNumInterfaces
205         1,                                      // bConfigurationValue
206         0,                                      // iConfiguration
207         0xC0,                                   // bmAttributes
208         50,                                     // bMaxPower
209
210         // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
211         9,                                      // bLength
212         4,                                      // bDescriptorType
213         KEYBOARD_INTERFACE,                     // bInterfaceNumber
214         0,                                      // bAlternateSetting
215         1,                                      // bNumEndpoints
216         0x03,                                   // bInterfaceClass (0x03 = HID)
217         0x01,                                   // bInterfaceSubClass (0x01 = Boot)
218         0x01,                                   // bInterfaceProtocol (0x01 = Keyboard)
219         0,                                      // iInterface
220         // HID descriptor, HID 1.11 spec, section 6.2.1
221         9,                                      // bLength
222         0x21,                                   // bDescriptorType
223         0x11, 0x01,                             // bcdHID
224         0,                                      // bCountryCode
225         1,                                      // bNumDescriptors
226         0x22,                                   // bDescriptorType
227         sizeof(keyboard_hid_report_desc),       // wDescriptorLength
228         0,
229         // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
230         7,                                      // bLength
231         5,                                      // bDescriptorType
232         KEYBOARD_ENDPOINT | 0x80,               // bEndpointAddress
233         0x03,                                   // bmAttributes (0x03=intr)
234         KEYBOARD_SIZE, 0,                       // wMaxPacketSize
235         1,                                      // bInterval
236
237         // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
238         9,                                      // bLength
239         4,                                      // bDescriptorType
240         MOUSE_INTERFACE,                        // bInterfaceNumber
241         0,                                      // bAlternateSetting
242         1,                                      // bNumEndpoints
243         0x03,                                   // bInterfaceClass (0x03 = HID)
244         0x01,                                   // bInterfaceSubClass (0x01 = Boot)
245         0x02,                                   // bInterfaceProtocol (0x02 = Mouse)
246         0,                                      // iInterface
247         // HID descriptor, HID 1.11 spec, section 6.2.1
248         9,                                      // bLength
249         0x21,                                   // bDescriptorType
250         0x11, 0x01,                             // bcdHID
251         0,                                      // bCountryCode
252         1,                                      // bNumDescriptors
253         0x22,                                   // bDescriptorType
254         sizeof(mouse_hid_report_desc),          // wDescriptorLength
255         0,
256         // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
257         7,                                      // bLength
258         5,                                      // bDescriptorType
259         MOUSE_ENDPOINT | 0x80,                  // bEndpointAddress
260         0x03,                                   // bmAttributes (0x03=intr)
261         4, 0,                                   // wMaxPacketSize
262         1,                                      // bInterval
263
264         // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
265         9,                                      // bLength
266         4,                                      // bDescriptorType
267         DEBUG_INTERFACE,                        // bInterfaceNumber
268         0,                                      // bAlternateSetting
269         1,                                      // bNumEndpoints
270         0x03,                                   // bInterfaceClass (0x03 = HID)
271         0x00,                                   // bInterfaceSubClass
272         0x00,                                   // bInterfaceProtocol
273         0,                                      // iInterface
274         // HID descriptor, HID 1.11 spec, section 6.2.1
275         9,                                      // bLength
276         0x21,                                   // bDescriptorType
277         0x11, 0x01,                             // bcdHID
278         0,                                      // bCountryCode
279         1,                                      // bNumDescriptors
280         0x22,                                   // bDescriptorType
281         sizeof(debug_hid_report_desc),          // wDescriptorLength
282         0,
283         // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
284         7,                                      // bLength
285         5,                                      // bDescriptorType
286         DEBUG_TX_ENDPOINT | 0x80,               // bEndpointAddress
287         0x03,                                   // bmAttributes (0x03=intr)
288         DEBUG_TX_SIZE, 0,                       // wMaxPacketSize
289         1                                       // bInterval
290 };
291
292 // If you're desperate for a little extra code memory, these strings
293 // can be completely removed if iManufacturer, iProduct, iSerialNumber
294 // in the device desciptor are changed to zeros.
295 struct usb_string_descriptor_struct {
296         uint8_t bLength;
297         uint8_t bDescriptorType;
298         int16_t wString[];
299 };
300 static struct usb_string_descriptor_struct PROGMEM string0 = {
301         4,
302         3,
303         {0x0409}
304 };
305 static struct usb_string_descriptor_struct PROGMEM string1 = {
306         sizeof(STR_MANUFACTURER),
307         3,
308         STR_MANUFACTURER
309 };
310 static struct usb_string_descriptor_struct PROGMEM string2 = {
311         sizeof(STR_PRODUCT),
312         3,
313         STR_PRODUCT
314 };
315
316 // This table defines which descriptor data is sent for each specific
317 // request from the host (in wValue and wIndex).
318 static struct descriptor_list_struct {
319         uint16_t        wValue;     // descriptor type
320         uint16_t        wIndex;
321         const uint8_t   *addr;
322         uint8_t         length;
323 } PROGMEM descriptor_list[] = {
324         // DEVICE descriptor
325         {0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)},
326         // CONFIGURATION descriptor
327         {0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)},
328         // HID REPORT
329         {0x2200, KEYBOARD_INTERFACE, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)},
330         {0x2100, KEYBOARD_INTERFACE, config1_descriptor+KEYBOARD_HID_DESC_OFFSET, 9},
331         // HID REPORT
332         {0x2200, MOUSE_INTERFACE, mouse_hid_report_desc, sizeof(mouse_hid_report_desc)},
333         {0x2100, MOUSE_INTERFACE, config1_descriptor+MOUSE_HID_DESC_OFFSET, 9},
334         // HID REPORT
335         {0x2200, DEBUG_INTERFACE, debug_hid_report_desc, sizeof(debug_hid_report_desc)},
336         {0x2100, DEBUG_INTERFACE, config1_descriptor+DEBUG_HID_DESC_OFFSET, 9},
337         // STRING descriptor
338         {0x0300, 0x0000, (const uint8_t *)&string0, 4},
339         {0x0301, 0x0409, (const uint8_t *)&string1, sizeof(STR_MANUFACTURER)},
340         {0x0302, 0x0409, (const uint8_t *)&string2, sizeof(STR_PRODUCT)}
341 };
342 #define NUM_DESC_LIST (sizeof(descriptor_list)/sizeof(struct descriptor_list_struct))
343
344
345 /**************************************************************************
346  *
347  *  Variables - these are the only non-stack RAM usage
348  *
349  **************************************************************************/
350
351 // zero when we are not configured, non-zero when enumerated
352 static volatile uint8_t usb_configuration=0;
353
354
355 /**************************************************************************
356  *
357  *  Public Functions - these are the API intended for the user
358  *
359  **************************************************************************/
360
361
362 // initialize USB
363 void usb_init(void)
364 {
365         HW_CONFIG();
366         USB_FREEZE();                           // enable USB
367         PLL_CONFIG();                           // config PLL
368         while (!(PLLCSR & (1<<PLOCK))) ;        // wait for PLL lock
369         USB_CONFIG();                           // start USB clock
370         UDCON = 0;                              // enable attach resistor
371         usb_configuration = 0;
372         UDIEN = (1<<EORSTE)|(1<<SOFE);
373         sei();
374 }
375
376 // return 0 if the USB is not configured, or the configuration
377 // number selected by the HOST
378 uint8_t usb_configured(void)
379 {
380         return usb_configuration;
381 }
382
383
384
385 /**************************************************************************
386  *
387  *  Private Functions - not intended for general user consumption....
388  *
389  **************************************************************************/
390
391
392
393 // USB Device Interrupt - handle all device-level events
394 // the transmit buffer flushing is triggered by the start of frame
395 //
396 ISR(USB_GEN_vect)
397 {
398         uint8_t intbits, t, i;
399         static uint8_t div4=0;
400
401         intbits = UDINT;
402         UDINT = 0;
403         if (intbits & (1<<EORSTI)) {
404                 UENUM = 0;
405                 UECONX = 1;
406                 UECFG0X = EP_TYPE_CONTROL;
407                 UECFG1X = EP_SIZE(ENDPOINT0_SIZE) | EP_SINGLE_BUFFER;
408                 UEIENX = (1<<RXSTPE);
409                 usb_configuration = 0;
410         }
411         if ((intbits & (1<<SOFI)) && usb_configuration) {
412                 t = debug_flush_timer;
413                 if (t) {
414                         debug_flush_timer = -- t;
415                         if (!t) {
416                                 UENUM = DEBUG_TX_ENDPOINT;
417                                 while ((UEINTX & (1<<RWAL))) {
418                                         UEDATX = 0;
419                                 }
420                                 UEINTX = 0x3A;
421                         }
422                 }
423                 if (keyboard_idle_config && (++div4 & 3) == 0) {
424                         UENUM = KEYBOARD_ENDPOINT;
425                         if (UEINTX & (1<<RWAL)) {
426                                 keyboard_idle_count++;
427                                 if (keyboard_idle_count == keyboard_idle_config) {
428                                         keyboard_idle_count = 0;
429                                         UEDATX = keyboard_modifier_keys;
430                                         UEDATX = 0;
431                                         for (i=0; i<6; i++) {
432                                                 UEDATX = keyboard_keys[i];
433                                         }
434                                         UEINTX = 0x3A;
435                                 }
436                         }
437                 }
438         }
439 }
440
441
442
443 // Misc functions to wait for ready and send/receive packets
444 static inline void usb_wait_in_ready(void)
445 {
446         while (!(UEINTX & (1<<TXINI))) ;
447 }
448 static inline void usb_send_in(void)
449 {
450         UEINTX = ~(1<<TXINI);
451 }
452 static inline void usb_wait_receive_out(void)
453 {
454         while (!(UEINTX & (1<<RXOUTI))) ;
455 }
456 static inline void usb_ack_out(void)
457 {
458         UEINTX = ~(1<<RXOUTI);
459 }
460
461
462
463 // USB Endpoint Interrupt - endpoint 0 is handled here.  The
464 // other endpoints are manipulated by the user-callable
465 // functions, and the start-of-frame interrupt.
466 //
467 ISR(USB_COM_vect)
468 {
469         uint8_t intbits;
470         const uint8_t *list;
471         const uint8_t *cfg;
472         uint8_t i, n, len, en;
473         uint8_t bmRequestType;
474         uint8_t bRequest;
475         uint16_t wValue;
476         uint16_t wIndex;
477         uint16_t wLength;
478         uint16_t desc_val;
479         const uint8_t *desc_addr;
480         uint8_t desc_length;
481
482         UENUM = 0;
483         intbits = UEINTX;
484         if (intbits & (1<<RXSTPI)) {
485                 bmRequestType = UEDATX;
486                 bRequest = UEDATX;
487                 wValue = UEDATX;
488                 wValue |= (UEDATX << 8);
489                 wIndex = UEDATX;
490                 wIndex |= (UEDATX << 8);
491                 wLength = UEDATX;
492                 wLength |= (UEDATX << 8);
493                 UEINTX = ~((1<<RXSTPI) | (1<<RXOUTI) | (1<<TXINI));
494                 if (bRequest == GET_DESCRIPTOR) {
495                         list = (const uint8_t *)descriptor_list;
496                         for (i=0; ; i++) {
497                                 if (i >= NUM_DESC_LIST) {
498                                         UECONX = (1<<STALLRQ)|(1<<EPEN);  //stall
499                                         return;
500                                 }
501                                 desc_val = pgm_read_word(list);
502                                 if (desc_val != wValue) {
503                                         list += sizeof(struct descriptor_list_struct);
504                                         continue;
505                                 }
506                                 list += 2;
507                                 desc_val = pgm_read_word(list);
508                                 if (desc_val != wIndex) {
509                                         list += sizeof(struct descriptor_list_struct)-2;
510                                         continue;
511                                 }
512                                 list += 2;
513                                 desc_addr = (const uint8_t *)pgm_read_word(list);
514                                 list += 2;
515                                 desc_length = pgm_read_byte(list);
516                                 break;
517                         }
518                         len = (wLength < 256) ? wLength : 255;
519                         if (len > desc_length) len = desc_length;
520                         do {
521                                 // wait for host ready for IN packet
522                                 do {
523                                         i = UEINTX;
524                                 } while (!(i & ((1<<TXINI)|(1<<RXOUTI))));
525                                 if (i & (1<<RXOUTI)) return;    // abort
526                                 // send IN packet
527                                 n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE;
528                                 for (i = n; i; i--) {
529                                         UEDATX = pgm_read_byte(desc_addr++);
530                                 }
531                                 len -= n;
532                                 usb_send_in();
533                         } while (len || n == ENDPOINT0_SIZE);
534                         return;
535                 }
536                 if (bRequest == SET_ADDRESS) {
537                         usb_send_in();
538                         usb_wait_in_ready();
539                         UDADDR = wValue | (1<<ADDEN);
540                         return;
541                 }
542                 if (bRequest == SET_CONFIGURATION && bmRequestType == 0) {
543                         usb_configuration = wValue;
544                         usb_send_in();
545                         cfg = endpoint_config_table;
546                         for (i=1; i<=6; i++) {
547                                 UENUM = i;
548                                 en = pgm_read_byte(cfg++);
549                                 UECONX = en;
550                                 if (en) {
551                                         UECFG0X = pgm_read_byte(cfg++);
552                                         UECFG1X = pgm_read_byte(cfg++);
553                                 }
554                         }
555                         UERST = 0x7E;
556                         UERST = 0;
557                         return;
558                 }
559                 if (bRequest == GET_CONFIGURATION && bmRequestType == 0x80) {
560                         usb_wait_in_ready();
561                         UEDATX = usb_configuration;
562                         usb_send_in();
563                         return;
564                 }
565
566                 if (bRequest == GET_STATUS) {
567                         usb_wait_in_ready();
568                         i = 0;
569                         #ifdef SUPPORT_ENDPOINT_HALT
570                         if (bmRequestType == 0x82) {
571                                 UENUM = wIndex;
572                                 if (UECONX & (1<<STALLRQ)) i = 1;
573                                 UENUM = 0;
574                         }
575                         #endif
576                         UEDATX = i;
577                         UEDATX = 0;
578                         usb_send_in();
579                         return;
580                 }
581                 #ifdef SUPPORT_ENDPOINT_HALT
582                 if ((bRequest == CLEAR_FEATURE || bRequest == SET_FEATURE)
583                   && bmRequestType == 0x02 && wValue == 0) {
584                         i = wIndex & 0x7F;
585                         if (i >= 1 && i <= MAX_ENDPOINT) {
586                                 usb_send_in();
587                                 UENUM = i;
588                                 if (bRequest == SET_FEATURE) {
589                                         UECONX = (1<<STALLRQ)|(1<<EPEN);
590                                 } else {
591                                         UECONX = (1<<STALLRQC)|(1<<RSTDT)|(1<<EPEN);
592                                         UERST = (1 << i);
593                                         UERST = 0;
594                                 }
595                                 return;
596                         }
597                 }
598                 #endif
599                 if (wIndex == KEYBOARD_INTERFACE) {
600                         if (bmRequestType == 0xA1) {
601                                 if (bRequest == HID_GET_REPORT) {
602                                         usb_wait_in_ready();
603                                         UEDATX = keyboard_modifier_keys;
604                                         UEDATX = 0;
605                                         for (i=0; i<6; i++) {
606                                                 UEDATX = keyboard_keys[i];
607                                         }
608                                         usb_send_in();
609                                         return;
610                                 }
611                                 if (bRequest == HID_GET_IDLE) {
612                                         usb_wait_in_ready();
613                                         UEDATX = keyboard_idle_config;
614                                         usb_send_in();
615                                         return;
616                                 }
617                                 if (bRequest == HID_GET_PROTOCOL) {
618                                         usb_wait_in_ready();
619                                         UEDATX = keyboard_protocol;
620                                         usb_send_in();
621                                         return;
622                                 }
623                         }
624                         if (bmRequestType == 0x21) {
625                                 if (bRequest == HID_SET_REPORT) {
626                                         usb_wait_receive_out();
627                                         keyboard_leds = UEDATX;
628                                         usb_ack_out();
629                                         usb_send_in();
630                                         return;
631                                 }
632                                 if (bRequest == HID_SET_IDLE) {
633                                         keyboard_idle_config = (wValue >> 8);
634                                         keyboard_idle_count = 0;
635                                         //usb_wait_in_ready();
636                                         usb_send_in();
637                                         return;
638                                 }
639                                 if (bRequest == HID_SET_PROTOCOL) {
640                                         keyboard_protocol = wValue;
641                                         //usb_wait_in_ready();
642                                         usb_send_in();
643                                         return;
644                                 }
645                         }
646                 }
647                 if (wIndex == MOUSE_INTERFACE) {
648                         if (bmRequestType == 0xA1) {
649 print("mouse: 0xA1\n");
650                                 if (bRequest == HID_GET_REPORT) {
651                                     if (wValue == HID_REPORT_INPUT) {
652 print("mouse: HID_GET_REPORT: input\n");
653                                         usb_wait_in_ready();
654                                         UEDATX = mouse_buttons;
655                                         UEDATX = 0;
656                                         UEDATX = 0;
657                                         UEDATX = 0;
658                                         usb_send_in();
659                                         return;
660                                     }
661                                     if (wValue == HID_REPORT_FEATURE) {
662 print("mouse: HID_GET_REPORT: feature\n");
663                                         usb_wait_in_ready();
664                                         UEDATX = 0x05;
665                                         usb_send_in();
666                                         return;
667                                     }
668                                 }
669                                 if (bRequest == HID_GET_PROTOCOL) {
670                                         usb_wait_in_ready();
671                                         UEDATX = mouse_protocol;
672                                         usb_send_in();
673                                         return;
674                                 }
675                         }
676                         if (bmRequestType == 0x21) {
677 print("mouse: 0x21\n");
678                                 if (bRequest == HID_SET_PROTOCOL) {
679                                         mouse_protocol = wValue;
680                                         usb_send_in();
681                                         return;
682                                 }
683                         }
684                 }
685                 if (wIndex == DEBUG_INTERFACE) {
686                         if (bRequest == HID_GET_REPORT && bmRequestType == 0xA1) {
687                                 len = wLength;
688                                 do {
689                                         // wait for host ready for IN packet
690                                         do {
691                                                 i = UEINTX;
692                                         } while (!(i & ((1<<TXINI)|(1<<RXOUTI))));
693                                         if (i & (1<<RXOUTI)) return;    // abort
694                                         // send IN packet
695                                         n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE;
696                                         for (i = n; i; i--) {
697                                                 UEDATX = 0;
698                                         }
699                                         len -= n;
700                                         usb_send_in();
701                                 } while (len || n == ENDPOINT0_SIZE);
702                                 return;
703                         }
704                 }
705         }
706         UECONX = (1<<STALLRQ) | (1<<EPEN);      // stall
707 }
708
709