]> git.donarmstrong.com Git - qmk_firmware.git/blob - tmk_core/protocol/lufa/lufa.c
lufa: Fix endpoint bank mode for ATMega32u2
[qmk_firmware.git] / tmk_core / protocol / lufa / lufa.c
1 /* 
2  * Copyright 2012 Jun Wako <wakojun@gmail.com>
3  * This file is based on:
4  *     LUFA-120219/Demos/Device/Lowlevel/KeyboardMouse
5  *     LUFA-120219/Demos/Device/Lowlevel/GenericHID
6  */
7
8 /*
9              LUFA Library
10      Copyright (C) Dean Camera, 2012.
11
12   dean [at] fourwalledcubicle [dot] com
13            www.lufa-lib.org
14 */
15
16 /*
17   Copyright 2012  Dean Camera (dean [at] fourwalledcubicle [dot] com)
18   Copyright 2010  Denver Gingerich (denver [at] ossguy [dot] com)
19
20   Permission to use, copy, modify, distribute, and sell this
21   software and its documentation for any purpose is hereby granted
22   without fee, provided that the above copyright notice appear in
23   all copies and that both that the copyright notice and this
24   permission notice and warranty disclaimer appear in supporting
25   documentation, and that the name of the author not be used in
26   advertising or publicity pertaining to distribution of the
27   software without specific, written prior permission.
28
29   The author disclaim all warranties with regard to this
30   software, including all implied warranties of merchantability
31   and fitness.  In no event shall the author be liable for any
32   special, indirect or consequential damages or any damages
33   whatsoever resulting from loss of use, data or profits, whether
34   in an action of contract, negligence or other tortious action,
35   arising out of or in connection with the use or performance of
36   this software.
37 */
38
39 #include "report.h"
40 #include "host.h"
41 #include "host_driver.h"
42 #include "keyboard.h"
43 #include "action.h"
44 #include "led.h"
45 #include "sendchar.h"
46 #include "debug.h"
47 #ifdef SLEEP_LED_ENABLE
48 #include "sleep_led.h"
49 #endif
50 #include "suspend.h"
51
52 #include "descriptor.h"
53 #include "lufa.h"
54
55 uint8_t keyboard_idle = 0;
56 uint8_t keyboard_protocol = 1;
57 static uint8_t keyboard_led_stats = 0;
58
59 static report_keyboard_t keyboard_report_sent;
60
61
62 /* Host driver */
63 static uint8_t keyboard_leds(void);
64 static void send_keyboard(report_keyboard_t *report);
65 static void send_mouse(report_mouse_t *report);
66 static void send_system(uint16_t data);
67 static void send_consumer(uint16_t data);
68 host_driver_t lufa_driver = {
69     keyboard_leds,
70     send_keyboard,
71     send_mouse,
72     send_system,
73     send_consumer
74 };
75
76
77 /*******************************************************************************
78  * Console
79  ******************************************************************************/
80 #ifdef CONSOLE_ENABLE
81 static void Console_Task(void)
82 {
83     /* Device must be connected and configured for the task to run */
84     if (USB_DeviceState != DEVICE_STATE_Configured)
85         return;
86
87     uint8_t ep = Endpoint_GetCurrentEndpoint();
88
89 #if 0
90     // TODO: impl receivechar()/recvchar()
91     Endpoint_SelectEndpoint(CONSOLE_OUT_EPNUM);
92
93     /* Check to see if a packet has been sent from the host */
94     if (Endpoint_IsOUTReceived())
95     {
96         /* Check to see if the packet contains data */
97         if (Endpoint_IsReadWriteAllowed())
98         {
99             /* Create a temporary buffer to hold the read in report from the host */
100             uint8_t ConsoleData[CONSOLE_EPSIZE];
101  
102             /* Read Console Report Data */
103             Endpoint_Read_Stream_LE(&ConsoleData, sizeof(ConsoleData), NULL);
104  
105             /* Process Console Report Data */
106             //ProcessConsoleHIDReport(ConsoleData);
107         }
108
109         /* Finalize the stream transfer to send the last packet */
110         Endpoint_ClearOUT();
111     }
112 #endif
113
114     /* IN packet */
115     Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
116     if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
117         Endpoint_SelectEndpoint(ep);
118         return;
119     }
120
121     // fill empty bank
122     while (Endpoint_IsReadWriteAllowed())
123         Endpoint_Write_8(0);
124
125     // flash senchar packet
126     if (Endpoint_IsINReady()) {
127         Endpoint_ClearIN();
128     }
129
130     Endpoint_SelectEndpoint(ep);
131 }
132 #else
133 static void Console_Task(void)
134 {
135 }
136 #endif
137
138
139 /*******************************************************************************
140  * USB Events
141  ******************************************************************************/
142 /*
143  * Event Order of Plug in:
144  * 0) EVENT_USB_Device_Connect
145  * 1) EVENT_USB_Device_Suspend
146  * 2) EVENT_USB_Device_Reset
147  * 3) EVENT_USB_Device_Wake
148 */
149 void EVENT_USB_Device_Connect(void)
150 {
151     print("[C]");
152     /* For battery powered device */
153     if (!USB_IsInitialized) {
154         USB_Disable();
155         USB_Init();
156         USB_Device_EnableSOFEvents();
157     }
158 }
159
160 void EVENT_USB_Device_Disconnect(void)
161 {
162     print("[D]");
163     /* For battery powered device */
164     USB_IsInitialized = false;
165 /* TODO: This doesn't work. After several plug in/outs can not be enumerated. 
166     if (USB_IsInitialized) {
167         USB_Disable();  // Disable all interrupts
168         USB_Controller_Enable();
169         USB_INT_Enable(USB_INT_VBUSTI);
170     }
171 */
172 }
173
174 void EVENT_USB_Device_Reset(void)
175 {
176     print("[R]");
177 }
178
179 void EVENT_USB_Device_Suspend()
180 {
181     print("[S]");
182 #ifdef SLEEP_LED_ENABLE
183     sleep_led_enable();
184 #endif
185 }
186
187 void EVENT_USB_Device_WakeUp()
188 {
189     print("[W]");
190     suspend_wakeup_init();
191
192 #ifdef SLEEP_LED_ENABLE
193     sleep_led_disable();
194     // NOTE: converters may not accept this
195     led_set(host_keyboard_leds());
196 #endif
197 }
198
199 #ifdef CONSOLE_ENABLE
200 static bool console_flush = false;
201 #define CONSOLE_FLUSH_SET(b)   do { \
202     uint8_t sreg = SREG; cli(); console_flush = b; SREG = sreg; \
203 } while (0)
204
205 // called every 1ms
206 void EVENT_USB_Device_StartOfFrame(void)
207 {
208     static uint8_t count;
209     if (++count % 50) return;
210     count = 0;
211
212     if (!console_flush) return;
213     Console_Task();
214     console_flush = false;
215 }
216 #endif
217
218 /** Event handler for the USB_ConfigurationChanged event.
219  * This is fired when the host sets the current configuration of the USB device after enumeration.
220  *
221  * ATMega32u2 supports dual bank(ping-pong mode) only on endpoint 3 and 4,
222  * it is safe to use singl bank for all endpoints.
223  */
224 void EVENT_USB_Device_ConfigurationChanged(void)
225 {
226     bool ConfigSuccess = true;
227
228     /* Setup Keyboard HID Report Endpoints */
229     ConfigSuccess &= ENDPOINT_CONFIG(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
230                                      KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
231
232 #ifdef MOUSE_ENABLE
233     /* Setup Mouse HID Report Endpoint */
234     ConfigSuccess &= ENDPOINT_CONFIG(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
235                                      MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE);
236 #endif
237
238 #ifdef EXTRAKEY_ENABLE
239     /* Setup Extra HID Report Endpoint */
240     ConfigSuccess &= ENDPOINT_CONFIG(EXTRAKEY_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
241                                      EXTRAKEY_EPSIZE, ENDPOINT_BANK_SINGLE);
242 #endif
243
244 #ifdef CONSOLE_ENABLE
245     /* Setup Console HID Report Endpoints */
246     ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
247                                      CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
248 #if 0
249     ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
250                                      CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
251 #endif
252 #endif
253
254 #ifdef NKRO_ENABLE
255     /* Setup NKRO HID Report Endpoints */
256     ConfigSuccess &= ENDPOINT_CONFIG(NKRO_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
257                                      NKRO_EPSIZE, ENDPOINT_BANK_SINGLE);
258 #endif
259 }
260
261 /*
262 Appendix G: HID Request Support Requirements
263
264 The following table enumerates the requests that need to be supported by various types of HID class devices.
265
266 Device type     GetReport   SetReport   GetIdle     SetIdle     GetProtocol SetProtocol
267 ------------------------------------------------------------------------------------------
268 Boot Mouse      Required    Optional    Optional    Optional    Required    Required
269 Non-Boot Mouse  Required    Optional    Optional    Optional    Optional    Optional
270 Boot Keyboard   Required    Optional    Required    Required    Required    Required
271 Non-Boot Keybrd Required    Optional    Required    Required    Optional    Optional
272 Other Device    Required    Optional    Optional    Optional    Optional    Optional
273 */
274 /** Event handler for the USB_ControlRequest event.
275  *  This is fired before passing along unhandled control requests to the library for processing internally.
276  */
277 void EVENT_USB_Device_ControlRequest(void)
278 {
279     uint8_t* ReportData = NULL;
280     uint8_t  ReportSize = 0;
281
282     /* Handle HID Class specific requests */
283     switch (USB_ControlRequest.bRequest)
284     {
285         case HID_REQ_GetReport:
286             if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
287             {
288                 Endpoint_ClearSETUP();
289
290                 // Interface
291                 switch (USB_ControlRequest.wIndex) {
292                 case KEYBOARD_INTERFACE:
293                     // TODO: test/check
294                     ReportData = (uint8_t*)&keyboard_report_sent;
295                     ReportSize = sizeof(keyboard_report_sent);
296                     break;
297                 }
298
299                 /* Write the report data to the control endpoint */
300                 Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
301                 Endpoint_ClearOUT();
302             }
303
304             break;
305         case HID_REQ_SetReport:
306             if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
307             {
308
309                 // Interface
310                 switch (USB_ControlRequest.wIndex) {
311                 case KEYBOARD_INTERFACE:
312 #ifdef NKRO_ENABLE
313                 case NKRO_INTERFACE:
314 #endif
315                     Endpoint_ClearSETUP();
316
317                     while (!(Endpoint_IsOUTReceived())) {
318                         if (USB_DeviceState == DEVICE_STATE_Unattached)
319                           return;
320                     }
321                     keyboard_led_stats = Endpoint_Read_8();
322
323                     Endpoint_ClearOUT();
324                     Endpoint_ClearStatusStage();
325                     break;
326                 }
327
328             }
329
330             break;
331
332         case HID_REQ_GetProtocol:
333             if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
334             {
335                 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
336                     Endpoint_ClearSETUP();
337                     while (!(Endpoint_IsINReady()));
338                     Endpoint_Write_8(keyboard_protocol);
339                     Endpoint_ClearIN();
340                     Endpoint_ClearStatusStage();
341                 }
342             }
343
344             break;
345         case HID_REQ_SetProtocol:
346             if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
347             {
348                 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
349                     Endpoint_ClearSETUP();
350                     Endpoint_ClearStatusStage();
351
352                     keyboard_protocol = ((USB_ControlRequest.wValue & 0xFF) != 0x00);
353 #ifdef NKRO_ENABLE
354                     keyboard_nkro = !!keyboard_protocol;
355 #endif
356                     clear_keyboard();
357                 }
358             }
359
360             break;
361         case HID_REQ_SetIdle:
362             if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
363             {
364                 Endpoint_ClearSETUP();
365                 Endpoint_ClearStatusStage();
366
367                 keyboard_idle = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
368             }
369
370             break;
371         case HID_REQ_GetIdle:
372             if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
373             {
374                 Endpoint_ClearSETUP();
375                 while (!(Endpoint_IsINReady()));
376                 Endpoint_Write_8(keyboard_idle);
377                 Endpoint_ClearIN();
378                 Endpoint_ClearStatusStage();
379             }
380
381             break;
382     }
383 }
384
385 /*******************************************************************************
386  * Host driver 
387  ******************************************************************************/
388 static uint8_t keyboard_leds(void)
389 {
390     return keyboard_led_stats;
391 }
392
393 static void send_keyboard(report_keyboard_t *report)
394 {
395     uint8_t timeout = 255;
396
397     if (USB_DeviceState != DEVICE_STATE_Configured)
398         return;
399
400     /* Select the Keyboard Report Endpoint */
401 #ifdef NKRO_ENABLE
402     if (keyboard_nkro) {
403         /* Report protocol - NKRO */
404         Endpoint_SelectEndpoint(NKRO_IN_EPNUM);
405
406         /* Check if write ready for a polling interval around 1ms */
407         while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(4);
408         if (!Endpoint_IsReadWriteAllowed()) return;
409
410         /* Write Keyboard Report Data */
411         Endpoint_Write_Stream_LE(report, NKRO_EPSIZE, NULL);
412     }
413     else
414 #endif
415     {
416         /* Boot protocol */
417         Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
418
419         /* Check if write ready for a polling interval around 10ms */
420         while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
421         if (!Endpoint_IsReadWriteAllowed()) return;
422
423         /* Write Keyboard Report Data */
424         Endpoint_Write_Stream_LE(report, KEYBOARD_EPSIZE, NULL);
425     }
426
427     /* Finalize the stream transfer to send the last packet */
428     Endpoint_ClearIN();
429
430     keyboard_report_sent = *report;
431 }
432
433 static void send_mouse(report_mouse_t *report)
434 {
435 #ifdef MOUSE_ENABLE
436     uint8_t timeout = 255;
437
438     if (USB_DeviceState != DEVICE_STATE_Configured)
439         return;
440
441     /* Select the Mouse Report Endpoint */
442     Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
443
444     /* Check if write ready for a polling interval around 10ms */
445     while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
446     if (!Endpoint_IsReadWriteAllowed()) return;
447
448     /* Write Mouse Report Data */
449     Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
450
451     /* Finalize the stream transfer to send the last packet */
452     Endpoint_ClearIN();
453 #endif
454 }
455
456 static void send_system(uint16_t data)
457 {
458     uint8_t timeout = 255;
459
460     if (USB_DeviceState != DEVICE_STATE_Configured)
461         return;
462
463     report_extra_t r = {
464         .report_id = REPORT_ID_SYSTEM,
465         .usage = data
466     };
467     Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
468
469     /* Check if write ready for a polling interval around 10ms */
470     while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
471     if (!Endpoint_IsReadWriteAllowed()) return;
472
473     Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
474     Endpoint_ClearIN();
475 }
476
477 static void send_consumer(uint16_t data)
478 {
479     uint8_t timeout = 255;
480
481     if (USB_DeviceState != DEVICE_STATE_Configured)
482         return;
483
484     report_extra_t r = {
485         .report_id = REPORT_ID_CONSUMER,
486         .usage = data
487     };
488     Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
489
490     /* Check if write ready for a polling interval around 10ms */
491     while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
492     if (!Endpoint_IsReadWriteAllowed()) return;
493
494     Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
495     Endpoint_ClearIN();
496 }
497
498
499 /*******************************************************************************
500  * sendchar
501  ******************************************************************************/
502 #ifdef CONSOLE_ENABLE
503 #define SEND_TIMEOUT 5
504 int8_t sendchar(uint8_t c)
505 {
506     // Not wait once timeouted.
507     // Because sendchar() is called so many times, waiting each call causes big lag.
508     static bool timeouted = false;
509
510     // prevents Console_Task() from running during sendchar() runs.
511     // or char will be lost. These two function is mutually exclusive.
512     CONSOLE_FLUSH_SET(false);
513
514     if (USB_DeviceState != DEVICE_STATE_Configured)
515         return -1;
516
517     uint8_t ep = Endpoint_GetCurrentEndpoint();
518     Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
519     if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
520         goto ERROR_EXIT;
521     }
522
523     if (timeouted && !Endpoint_IsReadWriteAllowed()) {
524         goto ERROR_EXIT;
525     }
526
527     timeouted = false;
528
529     uint8_t timeout = SEND_TIMEOUT;
530     while (!Endpoint_IsReadWriteAllowed()) {
531         if (USB_DeviceState != DEVICE_STATE_Configured) {
532             goto ERROR_EXIT;
533         }
534         if (Endpoint_IsStalled()) {
535             goto ERROR_EXIT;
536         }
537         if (!(timeout--)) {
538             timeouted = true;
539             goto ERROR_EXIT;
540         }
541         _delay_ms(1);
542     }
543
544     Endpoint_Write_8(c);
545
546     // send when bank is full
547     if (!Endpoint_IsReadWriteAllowed()) {
548         while (!(Endpoint_IsINReady()));
549         Endpoint_ClearIN();
550     } else {
551         CONSOLE_FLUSH_SET(true);
552     }
553
554     Endpoint_SelectEndpoint(ep);
555     return 0;
556 ERROR_EXIT:
557     Endpoint_SelectEndpoint(ep);
558     return -1;
559 }
560 #else
561 int8_t sendchar(uint8_t c)
562 {
563     return 0;
564 }
565 #endif
566
567
568 /*******************************************************************************
569  * main
570  ******************************************************************************/
571 static void setup_mcu(void)
572 {
573     /* Disable watchdog if enabled by bootloader/fuses */
574     MCUSR &= ~(1 << WDRF);
575     wdt_disable();
576
577     /* Disable clock division */
578     clock_prescale_set(clock_div_1);
579 }
580
581 static void setup_usb(void)
582 {
583     // Leonardo needs. Without this USB device is not recognized.
584     USB_Disable();
585
586     USB_Init();
587
588     // for Console_Task
589     USB_Device_EnableSOFEvents();
590     print_set_sendchar(sendchar);
591 }
592
593 int main(void)  __attribute__ ((weak));
594 int main(void)
595 {
596     setup_mcu();
597     keyboard_setup();
598     setup_usb();
599     sei();
600
601     /* wait for USB startup & debug output */
602     while (USB_DeviceState != DEVICE_STATE_Configured) {
603 #if defined(INTERRUPT_CONTROL_ENDPOINT)
604         ;
605 #else
606         USB_USBTask();
607 #endif
608     }
609     print("USB configured.\n");
610
611     /* init modules */
612     keyboard_init();
613     host_set_driver(&lufa_driver);
614 #ifdef SLEEP_LED_ENABLE
615     sleep_led_init();
616 #endif
617
618     print("Keyboard start.\n");
619     while (1) {
620         while (USB_DeviceState == DEVICE_STATE_Suspended) {
621             print("[s]");
622             suspend_power_down();
623             if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) {
624                     USB_Device_SendRemoteWakeup();
625             }
626         }
627
628         keyboard_task();
629
630 #if !defined(INTERRUPT_CONTROL_ENDPOINT)
631         USB_USBTask();
632 #endif
633     }
634 }