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