]> git.donarmstrong.com Git - qmk_firmware.git/blob - tmk_core/protocol/lufa/lufa.c
core: Fix lufa suspend callback(#234)
[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 void EVENT_USB_Device_ConfigurationChanged(void)
222 {
223     bool ConfigSuccess = true;
224
225     /* Setup Keyboard HID Report Endpoints */
226     ConfigSuccess &= ENDPOINT_CONFIG(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
227                                      KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
228
229 #ifdef MOUSE_ENABLE
230     /* Setup Mouse HID Report Endpoint */
231     ConfigSuccess &= ENDPOINT_CONFIG(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
232                                      MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE);
233 #endif
234
235 #ifdef EXTRAKEY_ENABLE
236     /* Setup Extra HID Report Endpoint */
237     ConfigSuccess &= ENDPOINT_CONFIG(EXTRAKEY_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
238                                      EXTRAKEY_EPSIZE, ENDPOINT_BANK_SINGLE);
239 #endif
240
241 #ifdef CONSOLE_ENABLE
242     /* Setup Console HID Report Endpoints */
243     ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
244                                      CONSOLE_EPSIZE, ENDPOINT_BANK_DOUBLE);
245 #if 0
246     ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
247                                      CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
248 #endif
249 #endif
250
251 #ifdef NKRO_ENABLE
252     /* Setup NKRO HID Report Endpoints */
253     ConfigSuccess &= ENDPOINT_CONFIG(NKRO_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
254                                      NKRO_EPSIZE, ENDPOINT_BANK_SINGLE);
255 #endif
256 }
257
258 /*
259 Appendix G: HID Request Support Requirements
260
261 The following table enumerates the requests that need to be supported by various types of HID class devices.
262
263 Device type     GetReport   SetReport   GetIdle     SetIdle     GetProtocol SetProtocol
264 ------------------------------------------------------------------------------------------
265 Boot Mouse      Required    Optional    Optional    Optional    Required    Required
266 Non-Boot Mouse  Required    Optional    Optional    Optional    Optional    Optional
267 Boot Keyboard   Required    Optional    Required    Required    Required    Required
268 Non-Boot Keybrd Required    Optional    Required    Required    Optional    Optional
269 Other Device    Required    Optional    Optional    Optional    Optional    Optional
270 */
271 /** Event handler for the USB_ControlRequest event.
272  *  This is fired before passing along unhandled control requests to the library for processing internally.
273  */
274 void EVENT_USB_Device_ControlRequest(void)
275 {
276     uint8_t* ReportData = NULL;
277     uint8_t  ReportSize = 0;
278
279     /* Handle HID Class specific requests */
280     switch (USB_ControlRequest.bRequest)
281     {
282         case HID_REQ_GetReport:
283             if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
284             {
285                 Endpoint_ClearSETUP();
286
287                 // Interface
288                 switch (USB_ControlRequest.wIndex) {
289                 case KEYBOARD_INTERFACE:
290                     // TODO: test/check
291                     ReportData = (uint8_t*)&keyboard_report_sent;
292                     ReportSize = sizeof(keyboard_report_sent);
293                     break;
294                 }
295
296                 /* Write the report data to the control endpoint */
297                 Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
298                 Endpoint_ClearOUT();
299             }
300
301             break;
302         case HID_REQ_SetReport:
303             if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
304             {
305
306                 // Interface
307                 switch (USB_ControlRequest.wIndex) {
308                 case KEYBOARD_INTERFACE:
309 #ifdef NKRO_ENABLE
310                 case NKRO_INTERFACE:
311 #endif
312                     Endpoint_ClearSETUP();
313
314                     while (!(Endpoint_IsOUTReceived())) {
315                         if (USB_DeviceState == DEVICE_STATE_Unattached)
316                           return;
317                     }
318                     keyboard_led_stats = Endpoint_Read_8();
319
320                     Endpoint_ClearOUT();
321                     Endpoint_ClearStatusStage();
322                     break;
323                 }
324
325             }
326
327             break;
328
329         case HID_REQ_GetProtocol:
330             if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
331             {
332                 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
333                     Endpoint_ClearSETUP();
334                     while (!(Endpoint_IsINReady()));
335                     Endpoint_Write_8(keyboard_protocol);
336                     Endpoint_ClearIN();
337                     Endpoint_ClearStatusStage();
338                 }
339             }
340
341             break;
342         case HID_REQ_SetProtocol:
343             if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
344             {
345                 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
346                     Endpoint_ClearSETUP();
347                     Endpoint_ClearStatusStage();
348
349                     keyboard_protocol = ((USB_ControlRequest.wValue & 0xFF) != 0x00);
350 #ifdef NKRO_ENABLE
351                     keyboard_nkro = !!keyboard_protocol;
352 #endif
353                     clear_keyboard();
354                 }
355             }
356
357             break;
358         case HID_REQ_SetIdle:
359             if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
360             {
361                 Endpoint_ClearSETUP();
362                 Endpoint_ClearStatusStage();
363
364                 keyboard_idle = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
365             }
366
367             break;
368         case HID_REQ_GetIdle:
369             if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
370             {
371                 Endpoint_ClearSETUP();
372                 while (!(Endpoint_IsINReady()));
373                 Endpoint_Write_8(keyboard_idle);
374                 Endpoint_ClearIN();
375                 Endpoint_ClearStatusStage();
376             }
377
378             break;
379     }
380 }
381
382 /*******************************************************************************
383  * Host driver 
384  ******************************************************************************/
385 static uint8_t keyboard_leds(void)
386 {
387     return keyboard_led_stats;
388 }
389
390 static void send_keyboard(report_keyboard_t *report)
391 {
392     uint8_t timeout = 255;
393
394     if (USB_DeviceState != DEVICE_STATE_Configured)
395         return;
396
397     /* Select the Keyboard Report Endpoint */
398 #ifdef NKRO_ENABLE
399     if (keyboard_nkro) {
400         /* Report protocol - NKRO */
401         Endpoint_SelectEndpoint(NKRO_IN_EPNUM);
402
403         /* Check if write ready for a polling interval around 1ms */
404         while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(4);
405         if (!Endpoint_IsReadWriteAllowed()) return;
406
407         /* Write Keyboard Report Data */
408         Endpoint_Write_Stream_LE(report, NKRO_EPSIZE, NULL);
409     }
410     else
411 #endif
412     {
413         /* Boot protocol */
414         Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
415
416         /* Check if write ready for a polling interval around 10ms */
417         while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
418         if (!Endpoint_IsReadWriteAllowed()) return;
419
420         /* Write Keyboard Report Data */
421         Endpoint_Write_Stream_LE(report, KEYBOARD_EPSIZE, NULL);
422     }
423
424     /* Finalize the stream transfer to send the last packet */
425     Endpoint_ClearIN();
426
427     keyboard_report_sent = *report;
428 }
429
430 static void send_mouse(report_mouse_t *report)
431 {
432 #ifdef MOUSE_ENABLE
433     uint8_t timeout = 255;
434
435     if (USB_DeviceState != DEVICE_STATE_Configured)
436         return;
437
438     /* Select the Mouse Report Endpoint */
439     Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
440
441     /* Check if write ready for a polling interval around 10ms */
442     while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
443     if (!Endpoint_IsReadWriteAllowed()) return;
444
445     /* Write Mouse Report Data */
446     Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
447
448     /* Finalize the stream transfer to send the last packet */
449     Endpoint_ClearIN();
450 #endif
451 }
452
453 static void send_system(uint16_t data)
454 {
455     uint8_t timeout = 255;
456
457     if (USB_DeviceState != DEVICE_STATE_Configured)
458         return;
459
460     report_extra_t r = {
461         .report_id = REPORT_ID_SYSTEM,
462         .usage = data
463     };
464     Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
465
466     /* Check if write ready for a polling interval around 10ms */
467     while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
468     if (!Endpoint_IsReadWriteAllowed()) return;
469
470     Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
471     Endpoint_ClearIN();
472 }
473
474 static void send_consumer(uint16_t data)
475 {
476     uint8_t timeout = 255;
477
478     if (USB_DeviceState != DEVICE_STATE_Configured)
479         return;
480
481     report_extra_t r = {
482         .report_id = REPORT_ID_CONSUMER,
483         .usage = data
484     };
485     Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
486
487     /* Check if write ready for a polling interval around 10ms */
488     while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
489     if (!Endpoint_IsReadWriteAllowed()) return;
490
491     Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
492     Endpoint_ClearIN();
493 }
494
495
496 /*******************************************************************************
497  * sendchar
498  ******************************************************************************/
499 #ifdef CONSOLE_ENABLE
500 #define SEND_TIMEOUT 5
501 int8_t sendchar(uint8_t c)
502 {
503     // Not wait once timeouted.
504     // Because sendchar() is called so many times, waiting each call causes big lag.
505     static bool timeouted = false;
506
507     // prevents Console_Task() from running during sendchar() runs.
508     // or char will be lost. These two function is mutually exclusive.
509     CONSOLE_FLUSH_SET(false);
510
511     if (USB_DeviceState != DEVICE_STATE_Configured)
512         return -1;
513
514     uint8_t ep = Endpoint_GetCurrentEndpoint();
515     Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
516     if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
517         goto ERROR_EXIT;
518     }
519
520     if (timeouted && !Endpoint_IsReadWriteAllowed()) {
521         goto ERROR_EXIT;
522     }
523
524     timeouted = false;
525
526     uint8_t timeout = SEND_TIMEOUT;
527     while (!Endpoint_IsReadWriteAllowed()) {
528         if (USB_DeviceState != DEVICE_STATE_Configured) {
529             goto ERROR_EXIT;
530         }
531         if (Endpoint_IsStalled()) {
532             goto ERROR_EXIT;
533         }
534         if (!(timeout--)) {
535             timeouted = true;
536             goto ERROR_EXIT;
537         }
538         _delay_ms(1);
539     }
540
541     Endpoint_Write_8(c);
542
543     // send when bank is full
544     if (!Endpoint_IsReadWriteAllowed()) {
545         while (!(Endpoint_IsINReady()));
546         Endpoint_ClearIN();
547     } else {
548         CONSOLE_FLUSH_SET(true);
549     }
550
551     Endpoint_SelectEndpoint(ep);
552     return 0;
553 ERROR_EXIT:
554     Endpoint_SelectEndpoint(ep);
555     return -1;
556 }
557 #else
558 int8_t sendchar(uint8_t c)
559 {
560     return 0;
561 }
562 #endif
563
564
565 /*******************************************************************************
566  * main
567  ******************************************************************************/
568 static void setup_mcu(void)
569 {
570     /* Disable watchdog if enabled by bootloader/fuses */
571     MCUSR &= ~(1 << WDRF);
572     wdt_disable();
573
574     /* Disable clock division */
575     clock_prescale_set(clock_div_1);
576 }
577
578 static void setup_usb(void)
579 {
580     // Leonardo needs. Without this USB device is not recognized.
581     USB_Disable();
582
583     USB_Init();
584
585     // for Console_Task
586     USB_Device_EnableSOFEvents();
587     print_set_sendchar(sendchar);
588 }
589
590 int main(void)  __attribute__ ((weak));
591 int main(void)
592 {
593     setup_mcu();
594     keyboard_setup();
595     setup_usb();
596     sei();
597
598     /* wait for USB startup & debug output */
599     while (USB_DeviceState != DEVICE_STATE_Configured) {
600 #if defined(INTERRUPT_CONTROL_ENDPOINT)
601         ;
602 #else
603         USB_USBTask();
604 #endif
605     }
606     print("USB configured.\n");
607
608     /* init modules */
609     keyboard_init();
610     host_set_driver(&lufa_driver);
611 #ifdef SLEEP_LED_ENABLE
612     sleep_led_init();
613 #endif
614
615     print("Keyboard start.\n");
616     while (1) {
617         while (USB_DeviceState == DEVICE_STATE_Suspended) {
618             print("[s]");
619             suspend_power_down();
620             if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) {
621                     USB_Device_SendRemoteWakeup();
622             }
623         }
624
625         keyboard_task();
626
627 #if !defined(INTERRUPT_CONTROL_ENDPOINT)
628         USB_USBTask();
629 #endif
630     }
631 }