]> git.donarmstrong.com Git - kiibohd-controller.git/blob - Output/pjrcUSB/avr/usb_keyboard_serial.c
f96ac0e6cb159f1262a4680e2a81cc0692f12a82
[kiibohd-controller.git] / Output / pjrcUSB / avr / usb_keyboard_serial.c
1 /* USB Keyboard and CDC Serial Device for Teensy USB Development Board
2  * Copyright (c) 2009 PJRC.COM, LLC
3  * Modifications by Jacob Alexander (2011-2014)
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
25 // Local Includes
26 #include "usb_keyboard_serial.h"
27 #include <print.h>
28
29
30 // ----- Variables -----
31
32 // zero when we are not configured, non-zero when enumerated
33 static volatile uint8_t usb_configuration = 0;
34
35 // the time remaining before we transmit any partially full
36 // packet, or send a zero length packet.
37 static volatile uint8_t transmit_flush_timer = 0;
38 static uint8_t transmit_previous_timeout = 0;
39
40 // serial port settings (baud rate, control signals, etc) set
41 // by the PC.  These are ignored, but kept in RAM.
42 static uint8_t cdc_line_coding[7] = {0x00, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x08};
43 static uint8_t cdc_line_rtsdtr = 0;
44
45
46
47 // ----- USB Keyboard Functions -----
48
49 // Sends normal keyboard out to host
50 // NOTE: Make sure to match the descriptor
51 void usb_keyboard_toHost()
52 {
53         uint8_t i;
54
55         // Modifiers
56         UEDATX = USBKeys_Modifiers;
57
58         // LED Report spacer
59         USBKeys_LEDs = 0;
60
61         // Normal Keys
62         for ( i = 0; i < 6; i++)
63         {
64                 UEDATX = USBKeys_Array[i];
65         }
66         UEINTX = 0x3A;
67 }
68
69 // Sends NKRO keyboard out to host
70 // NOTE: Make sure to match the descriptor
71 void usb_nkrokeyboard_toHost()
72 {
73         uint8_t i;
74
75         // Modifiers
76         /*
77         UEDATX = 0x02;
78         UEDATX = USBKeys_Modifiers;
79         UEINTX = 0x3A;
80         */
81
82         // Media Keys
83         UEDATX = 0x03;
84         UEDATX = 0;
85         UEINTX = 0x3A;
86
87         // Normal Keys
88         UEDATX = 0x04;
89         for ( i = 0; i < 6; i++)
90         {
91                 UEDATX = USBKeys_Array[i];
92         }
93         UEINTX = 0x3A;
94 }
95
96 // send the contents of USBKeys_Array and USBKeys_Modifiers
97 int8_t usb_keyboard_send()
98 {
99         uint8_t intr_state, timeout;
100
101         intr_state = SREG;
102         timeout = UDFNUML + 50;
103
104         // Ready to transmit keypresses?
105         do
106         {
107                 SREG = intr_state;
108
109                 // has the USB gone offline? or exceeded timeout?
110                 if ( !usb_configuration || UDFNUML == timeout )
111                         return -1;
112
113                 // get ready to try checking again
114                 intr_state = SREG;
115                 cli();
116
117                 // If not using Boot protocol, send NKRO
118                 UENUM = KEYBOARD_ENDPOINT;
119                 //UENUM = USBKeys_Protocol ? KEYBOARD_NKRO_ENDPOINT : KEYBOARD_ENDPOINT;
120         } while ( !( UEINTX & (1 << RWAL) ) );
121
122         // Send normal keyboard interrupt packet(s)
123         //switch ( USBKeys_Protocol )
124         //{
125         //}
126         usb_keyboard_toHost();
127
128         USBKeys_Idle_Count = 0;
129         SREG = intr_state;
130         return 0;
131 }
132
133
134
135 // ----- USB Virtual Serial Port (CDC) Functions -----
136
137 // get the next character, or -1 if nothing received
138 int16_t usb_serial_getchar(void)
139 {
140         uint8_t c, intr_state;
141
142         // interrupts are disabled so these functions can be
143         // used from the main program or interrupt context,
144         // even both in the same program!
145         intr_state = SREG;
146         cli();
147         if (!usb_configuration) {
148                 SREG = intr_state;
149                 return -1;
150         }
151         UENUM = CDC_RX_ENDPOINT;
152         retry:
153         c = UEINTX;
154         if (!(c & (1<<RWAL))) {
155                 // no data in buffer
156                 if (c & (1<<RXOUTI)) {
157                         UEINTX = 0x6B;
158                         goto retry;
159                 }
160                 SREG = intr_state;
161                 return -2;
162         }
163         // take one byte out of the buffer
164         c = UEDATX;
165         // if buffer completely used, release it
166         if (!(UEINTX & (1<<RWAL))) UEINTX = 0x6B;
167         SREG = intr_state;
168         return c;
169 }
170
171 // number of bytes available in the receive buffer
172 uint8_t usb_serial_available(void)
173 {
174         uint8_t n=0, i, intr_state;
175
176         intr_state = SREG;
177         cli();
178         if (usb_configuration) {
179                 UENUM = CDC_RX_ENDPOINT;
180                 n = UEBCLX;
181                 if (!n) {
182                         i = UEINTX;
183                         if (i & (1<<RXOUTI) && !(i & (1<<RWAL))) UEINTX = 0x6B;
184                 }
185         }
186         SREG = intr_state;
187         return n;
188 }
189
190 // discard any buffered input
191 void usb_serial_flush_input(void)
192 {
193         uint8_t intr_state;
194
195         if (usb_configuration) {
196                 intr_state = SREG;
197                 cli();
198                 UENUM = CDC_RX_ENDPOINT;
199                 while ((UEINTX & (1<<RWAL))) {
200                         UEINTX = 0x6B;
201                 }
202                 SREG = intr_state;
203         }
204 }
205
206 // transmit a character.  0 returned on success, -1 on error
207 int8_t usb_serial_putchar(uint8_t c)
208 {
209         uint8_t timeout, intr_state;
210
211         // if we're not online (enumerated and configured), error
212         if (!usb_configuration) return -1;
213         // interrupts are disabled so these functions can be
214         // used from the main program or interrupt context,
215         // even both in the same program!
216         intr_state = SREG;
217         cli();
218         UENUM = CDC_TX_ENDPOINT;
219         // if we gave up due to timeout before, don't wait again
220         if (transmit_previous_timeout) {
221                 if (!(UEINTX & (1<<RWAL))) {
222                         SREG = intr_state;
223                         return -1;
224                 }
225                 transmit_previous_timeout = 0;
226         }
227         // wait for the FIFO to be ready to accept data
228         timeout = UDFNUML + TRANSMIT_TIMEOUT;
229         while (1) {
230                 // are we ready to transmit?
231                 if (UEINTX & (1<<RWAL)) break;
232                 SREG = intr_state;
233                 // have we waited too long?  This happens if the user
234                 // is not running an application that is listening
235                 if (UDFNUML == timeout) {
236                         transmit_previous_timeout = 1;
237                         return -1;
238                 }
239                 // has the USB gone offline?
240                 if (!usb_configuration) return -1;
241                 // get ready to try checking again
242                 intr_state = SREG;
243                 cli();
244                 UENUM = CDC_TX_ENDPOINT;
245         }
246         // actually write the byte into the FIFO
247         UEDATX = c;
248         // if this completed a packet, transmit it now!
249         if (!(UEINTX & (1<<RWAL))) UEINTX = 0x3A;
250         transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT;
251         SREG = intr_state;
252         return 0;
253 }
254
255
256 // transmit a character, but do not wait if the buffer is full,
257 //   0 returned on success, -1 on buffer full or error
258 int8_t usb_serial_putchar_nowait(uint8_t c)
259 {
260         uint8_t intr_state;
261
262         if (!usb_configuration) return -1;
263         intr_state = SREG;
264         cli();
265         UENUM = CDC_TX_ENDPOINT;
266         if (!(UEINTX & (1<<RWAL))) {
267                 // buffer is full
268                 SREG = intr_state;
269                 return -2;
270         }
271         // actually write the byte into the FIFO
272         UEDATX = c;
273                 // if this completed a packet, transmit it now!
274         if (!(UEINTX & (1<<RWAL))) UEINTX = 0x3A;
275         transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT;
276         SREG = intr_state;
277         return 0;
278 }
279
280 // transmit a buffer.
281 //  0 returned on success, -1 on error
282 // This function is optimized for speed!  Each call takes approx 6.1 us overhead
283 // plus 0.25 us per byte.  12 Mbit/sec USB has 8.67 us per-packet overhead and
284 // takes 0.67 us per byte.  If called with 64 byte packet-size blocks, this function
285 // can transmit at full USB speed using 43% CPU time.  The maximum theoretical speed
286 // is 19 packets per USB frame, or 1216 kbytes/sec.  However, bulk endpoints have the
287 // lowest priority, so any other USB devices will likely reduce the speed.  Speed
288 // can also be limited by how quickly the PC-based software reads data, as the host
289 // controller in the PC will not allocate bandwitdh without a pending read request.
290 // (thanks to Victor Suarez for testing and feedback and initial code)
291
292 int8_t usb_serial_write(const char *buffer, uint16_t size)
293 {
294         uint8_t timeout, intr_state, write_size;
295
296         // if we're not online (enumerated and configured), error
297         if (!usb_configuration) return -1;
298         // interrupts are disabled so these functions can be
299         // used from the main program or interrupt context,
300         // even both in the same program!
301         intr_state = SREG;
302         cli();
303         UENUM = CDC_TX_ENDPOINT;
304         // if we gave up due to timeout before, don't wait again
305         /*
306         if (transmit_previous_timeout) {
307                 if (!(UEINTX & (1<<RWAL))) {
308                         SREG = intr_state;
309                         return -2;
310                 }
311                 transmit_previous_timeout = 0;
312         }
313         */
314         // each iteration of this loop transmits a packet
315         while (size) {
316                 // wait for the FIFO to be ready to accept data
317                 timeout = UDFNUML + TRANSMIT_TIMEOUT;
318                 while (1) {
319                         // are we ready to transmit?
320                         if (UEINTX & (1<<RWAL)) break;
321                         SREG = intr_state;
322                         // have we waited too long?  This happens if the user
323                         // is not running an application that is listening
324                         if (UDFNUML == timeout) {
325                                 transmit_previous_timeout = 1;
326                                 return -3;
327                         }
328                         // has the USB gone offline?
329                         if (!usb_configuration) return -4;
330                         // get ready to try checking again
331                         intr_state = SREG;
332                         cli();
333                         UENUM = CDC_TX_ENDPOINT;
334                 }
335
336                 // compute how many bytes will fit into the next packet
337                 write_size = CDC_TX_SIZE - UEBCLX;
338                 if (write_size > size) write_size = size;
339                 size -= write_size;
340
341                 // write the packet
342                 switch (write_size) {
343                         #if (CDC_TX_SIZE == 64)
344                         case 64: UEDATX = *buffer++;
345                         case 63: UEDATX = *buffer++;
346                         case 62: UEDATX = *buffer++;
347                         case 61: UEDATX = *buffer++;
348                         case 60: UEDATX = *buffer++;
349                         case 59: UEDATX = *buffer++;
350                         case 58: UEDATX = *buffer++;
351                         case 57: UEDATX = *buffer++;
352                         case 56: UEDATX = *buffer++;
353                         case 55: UEDATX = *buffer++;
354                         case 54: UEDATX = *buffer++;
355                         case 53: UEDATX = *buffer++;
356                         case 52: UEDATX = *buffer++;
357                         case 51: UEDATX = *buffer++;
358                         case 50: UEDATX = *buffer++;
359                         case 49: UEDATX = *buffer++;
360                         case 48: UEDATX = *buffer++;
361                         case 47: UEDATX = *buffer++;
362                         case 46: UEDATX = *buffer++;
363                         case 45: UEDATX = *buffer++;
364                         case 44: UEDATX = *buffer++;
365                         case 43: UEDATX = *buffer++;
366                         case 42: UEDATX = *buffer++;
367                         case 41: UEDATX = *buffer++;
368                         case 40: UEDATX = *buffer++;
369                         case 39: UEDATX = *buffer++;
370                         case 38: UEDATX = *buffer++;
371                         case 37: UEDATX = *buffer++;
372                         case 36: UEDATX = *buffer++;
373                         case 35: UEDATX = *buffer++;
374                         case 34: UEDATX = *buffer++;
375                         case 33: UEDATX = *buffer++;
376                         #endif
377                         #if (CDC_TX_SIZE >= 32)
378                         case 32: UEDATX = *buffer++;
379                         case 31: UEDATX = *buffer++;
380                         case 30: UEDATX = *buffer++;
381                         case 29: UEDATX = *buffer++;
382                         case 28: UEDATX = *buffer++;
383                         case 27: UEDATX = *buffer++;
384                         case 26: UEDATX = *buffer++;
385                         case 25: UEDATX = *buffer++;
386                         case 24: UEDATX = *buffer++;
387                         case 23: UEDATX = *buffer++;
388                         case 22: UEDATX = *buffer++;
389                         case 21: UEDATX = *buffer++;
390                         case 20: UEDATX = *buffer++;
391                         case 19: UEDATX = *buffer++;
392                         case 18: UEDATX = *buffer++;
393                         case 17: UEDATX = *buffer++;
394                         #endif
395                         #if (CDC_TX_SIZE >= 16)
396                         case 16: UEDATX = *buffer++;
397                         case 15: UEDATX = *buffer++;
398                         case 14: UEDATX = *buffer++;
399                         case 13: UEDATX = *buffer++;
400                         case 12: UEDATX = *buffer++;
401                         case 11: UEDATX = *buffer++;
402                         case 10: UEDATX = *buffer++;
403                         case  9: UEDATX = *buffer++;
404                         #endif
405                         case  8: UEDATX = *buffer++;
406                         case  7: UEDATX = *buffer++;
407                         case  6: UEDATX = *buffer++;
408                         case  5: UEDATX = *buffer++;
409                         case  4: UEDATX = *buffer++;
410                         case  3: UEDATX = *buffer++;
411                         case  2: UEDATX = *buffer++;
412                         default:
413                         case  1: UEDATX = *buffer++;
414                         case  0: break;
415                 }
416                 // if this completed a packet, transmit it now!
417                 if (!(UEINTX & (1<<RWAL))) UEINTX = 0x3A;
418                 transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT;
419                 SREG = intr_state;
420         }
421         return 0;
422 }
423
424 // immediately transmit any buffered output.
425 // This doesn't actually transmit the data - that is impossible!
426 // USB devices only transmit when the host allows, so the best
427 // we can do is release the FIFO buffer for when the host wants it
428 void usb_serial_flush_output(void)
429 {
430         uint8_t intr_state;
431
432         intr_state = SREG;
433         cli();
434         if (transmit_flush_timer) {
435                 UENUM = CDC_TX_ENDPOINT;
436                 UEINTX = 0x3A;
437                 transmit_flush_timer = 0;
438         }
439         SREG = intr_state;
440 }
441
442 // functions to read the various async serial settings.  These
443 // aren't actually used by USB at all (communication is always
444 // at full USB speed), but they are set by the host so we can
445 // set them properly if we're converting the USB to a real serial
446 // communication
447 uint32_t usb_serial_get_baud(void)
448 {
449         uint32_t *baud = (uint32_t*)cdc_line_coding;
450         return *baud;
451 }
452 uint8_t usb_serial_get_stopbits(void)
453 {
454         return cdc_line_coding[4];
455 }
456 uint8_t usb_serial_get_paritytype(void)
457 {
458         return cdc_line_coding[5];
459 }
460 uint8_t usb_serial_get_numbits(void)
461 {
462         return cdc_line_coding[6];
463 }
464 uint8_t usb_serial_get_control(void)
465 {
466         return cdc_line_rtsdtr;
467 }
468
469 // write the control signals, DCD, DSR, RI, etc
470 // There is no CTS signal.  If software on the host has transmitted
471 // data to you but you haven't been calling the getchar function,
472 // it remains buffered (either here or on the host) and can not be
473 // lost because you weren't listening at the right time, like it
474 // would in real serial communication.
475 int8_t usb_serial_set_control(uint8_t signals)
476 {
477         uint8_t intr_state;
478
479         intr_state = SREG;
480         cli();
481         if (!usb_configuration) {
482                 // we're not enumerated/configured
483                 SREG = intr_state;
484                 return -1;
485         }
486
487         UENUM = CDC_ACM_ENDPOINT;
488         if (!(UEINTX & (1<<RWAL))) {
489                 // unable to write
490                 // TODO; should this try to abort the previously
491                 // buffered message??
492                 SREG = intr_state;
493                 return -1;
494         }
495         UEDATX = 0xA1;
496         UEDATX = 0x20;
497         UEDATX = 0;
498         UEDATX = 0;
499         UEDATX = 0; // 0 seems to work nicely.  what if this is 1??
500         UEDATX = 0;
501         UEDATX = 1;
502         UEDATX = 0;
503         UEDATX = signals;
504         UEINTX = 0x3A;
505         SREG = intr_state;
506         return 0;
507 }
508
509
510
511 // ----- General USB Functions -----
512
513 // Set the avr into firmware reload mode
514 void usb_device_reload()
515 {
516         cli();
517         // Disable watchdog, if enabled
518         // Disable all peripherals
519
520         UDCON = 1;
521         USBCON = (1 << FRZCLK);  // Disable USB
522         UCSR1B = 0;
523         _delay_ms( 5 );
524
525 #if defined(__AVR_AT90USB162__)                // Teensy 1.0
526         EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0;
527         TIMSK0 = 0; TIMSK1 = 0; UCSR1B = 0;
528         DDRB = 0; DDRC = 0; DDRD = 0;
529         PORTB = 0; PORTC = 0; PORTD = 0;
530         asm volatile("jmp 0x3E00");
531 #elif defined(__AVR_ATmega32U4__)              // Teensy 2.0
532         EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
533         TIMSK0 = 0; TIMSK1 = 0; TIMSK3 = 0; TIMSK4 = 0; UCSR1B = 0; TWCR = 0;
534         DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; TWCR = 0;
535         PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0;
536         asm volatile("jmp 0x7E00");
537 #elif defined(__AVR_AT90USB646__)              // Teensy++ 1.0
538         EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
539         TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0;
540         DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0;
541         PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0;
542         asm volatile("jmp 0xFC00");
543 #elif defined(__AVR_AT90USB1286__)             // Teensy++ 2.0
544         EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
545         TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0;
546         DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0;
547         PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0;
548         asm volatile("jmp 0x1FC00");
549 #endif
550 }
551
552
553 // WDT Setup for software reset the chip
554 void wdt_init(void)
555 {
556         MCUSR = 0;
557         wdt_disable();
558 }
559
560
561 // initialize USB
562 void usb_init(void)
563 {
564         HW_CONFIG();
565         USB_FREEZE();                           // enable USB
566         PLL_CONFIG();                           // config PLL
567         while (!(PLLCSR & (1<<PLOCK))) ;        // wait for PLL lock
568         USB_CONFIG();                           // start USB clock
569         UDCON = 0;                              // enable attach resistor
570         usb_configuration = 0;
571         UDIEN = (1<<EORSTE) | (1<<SOFE);
572         sei();
573
574         // Disable watchdog timer after possible software reset
575         //wdt_init(); // XXX Not working...seems to be ok without this, not sure though
576 }
577
578 // return 0 if the USB is not configured, or the configuration
579 // number selected by the HOST
580 uint8_t usb_configured()
581 {
582         return usb_configuration;
583 }
584
585 // USB Device Interrupt - handle all device-level events
586 // the transmit buffer flushing is triggered by the start of frame
587 //
588 ISR( USB_GEN_vect )
589 {
590         uint8_t intbits, t_cdc;
591
592         intbits = UDINT;
593         UDINT = 0;
594         if ( intbits & (1 << EORSTI) )
595         {
596                 UENUM = 0;
597                 UECONX = 1;
598                 UECFG0X = EP_TYPE_CONTROL;
599                 UECFG1X = EP_SIZE(ENDPOINT0_SIZE) | EP_SINGLE_BUFFER;
600                 UEIENX = (1 << RXSTPE);
601                 usb_configuration = 0;
602                 cdc_line_rtsdtr = 0;
603         }
604         if ( (intbits & (1 << SOFI)) && usb_configuration )
605         {
606                 t_cdc = transmit_flush_timer;
607                 if ( t_cdc )
608                 {
609                         transmit_flush_timer = --t_cdc;
610                         if ( !t_cdc )
611                         {
612                                 UENUM = CDC_TX_ENDPOINT;
613                                 UEINTX = 0x3A;
614                         }
615                 }
616                 static uint8_t div4 = 0;
617                 if ( USBKeys_Idle_Config && (++div4 & 3) == 0 )
618                 {
619                         USBKeys_Idle_Count++;
620                         if ( USBKeys_Idle_Count == USBKeys_Idle_Config )
621                         {
622                                 // XXX TODO Is this even used? If so, when? -Jacob
623                                 // From hasu's code, this section looks like it could fix the Mac SET_IDLE problem
624                                 // Send normal keyboard interrupt packet(s)
625                                 //usb_keyboard_toHost();
626                                 print("IDLE");
627                         }
628                 }
629         }
630 }
631
632
633
634 // Misc functions to wait for ready and send/receive packets
635 static inline void usb_wait_in_ready(void)
636 {
637         while (!(UEINTX & (1<<TXINI))) ;
638 }
639 static inline void usb_send_in(void)
640 {
641         UEINTX = ~(1<<TXINI);
642 }
643 static inline void usb_wait_receive_out(void)
644 {
645         while (!(UEINTX & (1<<RXOUTI))) ;
646 }
647 static inline void usb_ack_out(void)
648 {
649         UEINTX = ~(1<<RXOUTI);
650 }
651
652
653
654 // USB Endpoint Interrupt - endpoint 0 is handled here.  The
655 // other endpoints are manipulated by the user-callable
656 // functions, and the start-of-frame interrupt.
657 //
658 ISR(USB_COM_vect)
659 {
660         uint8_t intbits;
661         const uint8_t *list;
662         const uint8_t *cfg;
663         uint8_t i, n, len, en;
664         uint8_t *p;
665         uint8_t bmRequestType;
666         uint8_t bRequest;
667         uint16_t wValue;
668         uint16_t wIndex;
669         uint16_t wLength;
670         uint16_t desc_val;
671         const uint8_t *desc_addr;
672         uint8_t desc_length;
673
674         UENUM = 0;
675         intbits = UEINTX;
676         if (intbits & (1<<RXSTPI)) {
677                 bmRequestType = UEDATX;
678                 bRequest = UEDATX;
679                 wValue = UEDATX;
680                 wValue |= (UEDATX << 8);
681                 wIndex = UEDATX;
682                 wIndex |= (UEDATX << 8);
683                 wLength = UEDATX;
684                 wLength |= (UEDATX << 8);
685                 UEINTX = ~((1<<RXSTPI) | (1<<RXOUTI) | (1<<TXINI));
686
687                 if ( bRequest == GET_DESCRIPTOR )
688                 {
689                         list = (const uint8_t *)descriptor_list;
690                         for ( i = 0; ; i++ )
691                         {
692                                 if ( i >= NUM_DESC_LIST )
693                                 {
694                                         UECONX = (1 << STALLRQ) | (1 << EPEN);  //stall
695                                         return;
696                                 }
697                                 desc_val = pgm_read_word(list);
698                                 if ( desc_val != wValue )
699                                 {
700                                         list += sizeof( struct descriptor_list_struct );
701                                         continue;
702                                 }
703                                 list += 2;
704                                 desc_val = pgm_read_word(list);
705                                 if ( desc_val != wIndex )
706                                 {
707                                         list += sizeof(struct descriptor_list_struct) - 2;
708                                         continue;
709                                 }
710                                 list += 2;
711                                 desc_addr = (const uint8_t *)pgm_read_word(list);
712                                 list += 2;
713                                 desc_length = pgm_read_byte(list);
714                                 break;
715                         }
716                         len = (wLength < 256) ? wLength : 255;
717                         if (len > desc_length) len = desc_length;
718                         do {
719                                 // wait for host ready for IN packet
720                                 do {
721                                         i = UEINTX;
722                                 } while (!(i & ((1<<TXINI)|(1<<RXOUTI))));
723                                 if (i & (1<<RXOUTI)) return;    // abort
724                                 // send IN packet
725                                 n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE;
726                                 for (i = n; i; i--) {
727                                         UEDATX = pgm_read_byte(desc_addr++);
728                                 }
729                                 len -= n;
730                                 usb_send_in();
731                         } while (len || n == ENDPOINT0_SIZE);
732                         return;
733                 }
734
735                 if (bRequest == SET_ADDRESS) {
736                         usb_send_in();
737                         usb_wait_in_ready();
738                         UDADDR = wValue | (1<<ADDEN);
739                         return;
740                 }
741
742                 if ( bRequest == SET_CONFIGURATION && bmRequestType == 0 )
743                 {
744                         usb_configuration = wValue;
745                         cdc_line_rtsdtr = 0;
746                         transmit_flush_timer = 0;
747                         usb_send_in();
748                         cfg = endpoint_config_table;
749                         // Setup each of the 6 additional endpoints (0th already configured)
750                         for ( i = 1; i < 6; i++ )
751                         {
752                                 UENUM = i;
753                                 en = pgm_read_byte(cfg++);
754                                 UECONX = en;
755                                 if (en)
756                                 {
757                                         UECFG0X = pgm_read_byte(cfg++);
758                                         UECFG1X = pgm_read_byte(cfg++);
759                                 }
760                         }
761                         UERST = 0x7E;
762                         UERST = 0;
763                         return;
764                 }
765
766                 if (bRequest == GET_CONFIGURATION && bmRequestType == 0x80) {
767                         usb_wait_in_ready();
768                         UEDATX = usb_configuration;
769                         usb_send_in();
770                         return;
771                 }
772
773                 //if ( wIndex == KEYBOARD_INTERFACE )
774                 if ( wIndex == KEYBOARD_INTERFACE || wIndex == KEYBOARD_NKRO_INTERFACE )
775                 {
776                         if ( bmRequestType == 0xA1)
777                         {
778                                 if ( bRequest == HID_GET_REPORT )
779                                 {
780                                         usb_wait_in_ready();
781
782                                         // XXX TODO Is this even used? If so, when? -Jacob
783                                         // Send normal keyboard interrupt packet(s)
784                                         usb_keyboard_toHost();
785                                         //print("GET REPORT");
786
787                                         usb_send_in();
788                                         return;
789                                 }
790                                 if ( bRequest == HID_GET_IDLE )
791                                 {
792                                         usb_wait_in_ready();
793                                         UEDATX = USBKeys_Idle_Config;
794                                         usb_send_in();
795                                         return;
796                                 }
797                                 if ( bRequest == HID_GET_PROTOCOL )
798                                 {
799                                         usb_wait_in_ready();
800                                         UEDATX = USBKeys_Protocol;
801                                         usb_send_in();
802                                         return;
803                                 }
804                         }
805                         if ( bmRequestType == 0x21 )
806                         {
807                                 if ( bRequest == HID_SET_REPORT )
808                                 {
809                                         usb_wait_receive_out();
810                                         USBKeys_LEDs = UEDATX;
811                                         usb_ack_out();
812                                         usb_send_in();
813                                         return;
814                                 }
815                                 if ( bRequest == HID_SET_IDLE )
816                                 {
817                                         USBKeys_Idle_Config = (wValue >> 8);
818                                         USBKeys_Idle_Count = 0;
819                                         //usb_wait_in_ready();
820                                         usb_send_in();
821                                         return;
822                                 }
823                                 if ( bRequest == HID_SET_PROTOCOL )
824                                 {
825                                         USBKeys_Protocol = wValue; // 0 - Boot Mode, 1 - NKRO Mode
826                                         //usb_wait_in_ready();
827                                         usb_send_in();
828                                         return;
829                                 }
830                         }
831                 }
832
833                 if (bRequest == CDC_GET_LINE_CODING && bmRequestType == 0xA1) {
834                         usb_wait_in_ready();
835                         p = cdc_line_coding;
836                         for (i=0; i<7; i++) {
837                                 UEDATX = *p++;
838                         }
839                         usb_send_in();
840                         return;
841                 }
842
843                 if (bRequest == CDC_SET_LINE_CODING && bmRequestType == 0x21) {
844                         usb_wait_receive_out();
845                         p = cdc_line_coding;
846                         for (i=0; i<7; i++) {
847                                 *p++ = UEDATX;
848                         }
849                         usb_ack_out();
850                         usb_send_in();
851                         return;
852                 }
853
854                 if (bRequest == CDC_SET_CONTROL_LINE_STATE && bmRequestType == 0x21) {
855                         cdc_line_rtsdtr = wValue;
856                         usb_wait_in_ready();
857                         usb_send_in();
858                         return;
859                 }
860
861                 if (bRequest == GET_STATUS) {
862                         usb_wait_in_ready();
863                         i = 0;
864                         if (bmRequestType == 0x82) {
865                                 UENUM = wIndex;
866                                 if (UECONX & (1<<STALLRQ)) i = 1;
867                                 UENUM = 0;
868                         }
869                         UEDATX = i;
870                         UEDATX = 0;
871                         usb_send_in();
872                         return;
873                 }
874
875                 if ((bRequest == CLEAR_FEATURE || bRequest == SET_FEATURE)
876                   && bmRequestType == 0x02 && wValue == 0) {
877                         i = wIndex & 0x7F;
878                         if (i >= 1 && i <= MAX_ENDPOINT) {
879                                 usb_send_in();
880                                 UENUM = i;
881                                 if (bRequest == SET_FEATURE) {
882                                         UECONX = (1<<STALLRQ)|(1<<EPEN);
883                                 } else {
884                                         UECONX = (1<<STALLRQC)|(1<<RSTDT)|(1<<EPEN);
885                                         UERST = (1 << i);
886                                         UERST = 0;
887                                 }
888                                 return;
889                         }
890                 }
891         }
892         UECONX = (1 << STALLRQ) | (1 << EPEN);  // stall
893 }
894