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