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