]> git.donarmstrong.com Git - tmk_firmware.git/blob - protocol/lufa/lufa.c
Return when ready check loop is timeouted(Fix #115)
[tmk_firmware.git] / 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 static uint8_t idle_duration = 0;
56 static uint8_t protocol_report = 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 }
152
153 void EVENT_USB_Device_Disconnect(void)
154 {
155 }
156
157 void EVENT_USB_Device_Reset(void)
158 {
159 }
160
161 void EVENT_USB_Device_Suspend()
162 {
163 #ifdef SLEEP_LED_ENABLE
164     sleep_led_enable();
165 #endif
166 }
167
168 void EVENT_USB_Device_WakeUp()
169 {
170     suspend_wakeup_init();
171
172 #ifdef SLEEP_LED_ENABLE
173     sleep_led_disable();
174     // NOTE: converters may not accept this
175     led_set(host_keyboard_leds());
176 #endif
177 }
178
179 void EVENT_USB_Device_StartOfFrame(void)
180 {
181     Console_Task();
182 }
183
184 /** Event handler for the USB_ConfigurationChanged event.
185  * This is fired when the host sets the current configuration of the USB device after enumeration.
186  */
187 #if LUFA_VERSION_INTEGER < 0x120730
188     /* old API 120219 */
189     #define ENDPOINT_CONFIG(epnum, eptype, epdir, epsize, epbank)    Endpoint_ConfigureEndpoint(epnum, eptype, epdir, epsize, epbank)
190 #else
191     /* new API >= 120730 */
192     #define ENDPOINT_BANK_SINGLE 1
193     #define ENDPOINT_BANK_DOUBLE 2
194     #define ENDPOINT_CONFIG(epnum, eptype, epdir, epsize, epbank)    Endpoint_ConfigureEndpoint((epdir) | (epnum) , eptype, epsize, epbank)
195 #endif
196 void EVENT_USB_Device_ConfigurationChanged(void)
197 {
198     bool ConfigSuccess = true;
199
200     /* Setup Keyboard HID Report Endpoints */
201     ConfigSuccess &= ENDPOINT_CONFIG(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
202                                      KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
203
204 #ifdef MOUSE_ENABLE
205     /* Setup Mouse HID Report Endpoint */
206     ConfigSuccess &= ENDPOINT_CONFIG(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
207                                      MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE);
208 #endif
209
210 #ifdef EXTRAKEY_ENABLE
211     /* Setup Extra HID Report Endpoint */
212     ConfigSuccess &= ENDPOINT_CONFIG(EXTRAKEY_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
213                                      EXTRAKEY_EPSIZE, ENDPOINT_BANK_SINGLE);
214 #endif
215
216 #ifdef CONSOLE_ENABLE
217     /* Setup Console HID Report Endpoints */
218     ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
219                                      CONSOLE_EPSIZE, ENDPOINT_BANK_DOUBLE);
220     ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
221                                      CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
222 #endif
223
224 #ifdef NKRO_ENABLE
225     /* Setup NKRO HID Report Endpoints */
226     ConfigSuccess &= ENDPOINT_CONFIG(NKRO_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
227                                      NKRO_EPSIZE, ENDPOINT_BANK_SINGLE);
228 #endif
229 }
230
231 /*
232 Appendix G: HID Request Support Requirements
233
234 The following table enumerates the requests that need to be supported by various types of HID class devices.
235
236 Device type     GetReport   SetReport   GetIdle     SetIdle     GetProtocol SetProtocol
237 ------------------------------------------------------------------------------------------
238 Boot Mouse      Required    Optional    Optional    Optional    Required    Required
239 Non-Boot Mouse  Required    Optional    Optional    Optional    Optional    Optional
240 Boot Keyboard   Required    Optional    Required    Required    Required    Required
241 Non-Boot Keybrd Required    Optional    Required    Required    Optional    Optional
242 Other Device    Required    Optional    Optional    Optional    Optional    Optional
243 */
244 /** Event handler for the USB_ControlRequest event.
245  *  This is fired before passing along unhandled control requests to the library for processing internally.
246  */
247 void EVENT_USB_Device_ControlRequest(void)
248 {
249     uint8_t* ReportData = NULL;
250     uint8_t  ReportSize = 0;
251
252     /* Handle HID Class specific requests */
253     switch (USB_ControlRequest.bRequest)
254     {
255         case HID_REQ_GetReport:
256             if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
257             {
258                 Endpoint_ClearSETUP();
259
260                 // Interface
261                 switch (USB_ControlRequest.wIndex) {
262                 case KEYBOARD_INTERFACE:
263                     // TODO: test/check
264                     ReportData = (uint8_t*)&keyboard_report_sent;
265                     ReportSize = sizeof(keyboard_report_sent);
266                     break;
267                 }
268
269                 /* Write the report data to the control endpoint */
270                 Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
271                 Endpoint_ClearOUT();
272             }
273
274             break;
275         case HID_REQ_SetReport:
276             if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
277             {
278
279                 // Interface
280                 switch (USB_ControlRequest.wIndex) {
281                 case KEYBOARD_INTERFACE:
282                     Endpoint_ClearSETUP();
283
284                     while (!(Endpoint_IsOUTReceived())) {
285                         if (USB_DeviceState == DEVICE_STATE_Unattached)
286                           return;
287                     }
288                     keyboard_led_stats = Endpoint_Read_8();
289
290                     Endpoint_ClearOUT();
291                     Endpoint_ClearStatusStage();
292                     break;
293                 }
294
295             }
296
297             break;
298
299         case HID_REQ_GetProtocol:
300             if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
301             {
302                 Endpoint_ClearSETUP();
303                 while (!(Endpoint_IsINReady()));
304                 Endpoint_Write_8(protocol_report);
305                 Endpoint_ClearIN();
306                 Endpoint_ClearStatusStage();
307             }
308
309             break;
310         case HID_REQ_SetProtocol:
311             if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
312             {
313                 Endpoint_ClearSETUP();
314                 Endpoint_ClearStatusStage();
315
316                 protocol_report = ((USB_ControlRequest.wValue & 0xFF) != 0x00);
317             }
318
319             break;
320         case HID_REQ_SetIdle:
321             if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
322             {
323                 Endpoint_ClearSETUP();
324                 Endpoint_ClearStatusStage();
325
326                 idle_duration = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
327             }
328
329             break;
330         case HID_REQ_GetIdle:
331             if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
332             {
333                 Endpoint_ClearSETUP();
334                 while (!(Endpoint_IsINReady()));
335                 Endpoint_Write_8(idle_duration);
336                 Endpoint_ClearIN();
337                 Endpoint_ClearStatusStage();
338             }
339
340             break;
341     }
342 }
343
344 /*******************************************************************************
345  * Host driver 
346  ******************************************************************************/
347 static uint8_t keyboard_leds(void)
348 {
349     return keyboard_led_stats;
350 }
351
352 static void send_keyboard(report_keyboard_t *report)
353 {
354     uint8_t timeout = 255;
355
356     if (USB_DeviceState != DEVICE_STATE_Configured)
357         return;
358
359     /* Select the Keyboard Report Endpoint */
360 #ifdef NKRO_ENABLE
361     if (keyboard_nkro) {
362         Endpoint_SelectEndpoint(NKRO_IN_EPNUM);
363
364         /* Check if write ready for a polling interval around 1ms */
365         while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(4);
366         if (!Endpoint_IsReadWriteAllowed()) return;
367     }
368     else
369 #endif
370     {
371         Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
372
373         /* Check if write ready for a polling interval around 10ms */
374         while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
375         if (!Endpoint_IsReadWriteAllowed()) return;
376     }
377
378     /* Write Keyboard Report Data */
379 #ifdef NKRO_ENABLE
380     if (keyboard_nkro) {
381         Endpoint_Write_Stream_LE(report, NKRO_EPSIZE, NULL);
382     }
383     else
384 #endif
385     {
386         /* boot mode */
387         Endpoint_Write_Stream_LE(report, KEYBOARD_EPSIZE, NULL);
388     }
389
390     /* Finalize the stream transfer to send the last packet */
391     Endpoint_ClearIN();
392
393     keyboard_report_sent = *report;
394 }
395
396 static void send_mouse(report_mouse_t *report)
397 {
398 #ifdef MOUSE_ENABLE
399     uint8_t timeout = 255;
400
401     if (USB_DeviceState != DEVICE_STATE_Configured)
402         return;
403
404     /* Select the Mouse Report Endpoint */
405     Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
406
407     /* Check if write ready for a polling interval around 10ms */
408     while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
409     if (!Endpoint_IsReadWriteAllowed()) return;
410
411     /* Write Mouse Report Data */
412     Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
413
414     /* Finalize the stream transfer to send the last packet */
415     Endpoint_ClearIN();
416 #endif
417 }
418
419 static void send_system(uint16_t data)
420 {
421     uint8_t timeout = 255;
422
423     if (USB_DeviceState != DEVICE_STATE_Configured)
424         return;
425
426     report_extra_t r = {
427         .report_id = REPORT_ID_SYSTEM,
428         .usage = data
429     };
430     Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
431
432     /* Check if write ready for a polling interval around 10ms */
433     while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
434     if (!Endpoint_IsReadWriteAllowed()) return;
435
436     Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
437     Endpoint_ClearIN();
438 }
439
440 static void send_consumer(uint16_t data)
441 {
442     uint8_t timeout = 255;
443
444     if (USB_DeviceState != DEVICE_STATE_Configured)
445         return;
446
447     report_extra_t r = {
448         .report_id = REPORT_ID_CONSUMER,
449         .usage = data
450     };
451     Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
452
453     /* Check if write ready for a polling interval around 10ms */
454     while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
455     if (!Endpoint_IsReadWriteAllowed()) return;
456
457     Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
458     Endpoint_ClearIN();
459 }
460
461
462 /*******************************************************************************
463  * sendchar
464  ******************************************************************************/
465 #ifdef CONSOLE_ENABLE
466 #define SEND_TIMEOUT 5
467 int8_t sendchar(uint8_t c)
468 {
469     // Not wait once timeouted.
470     // Because sendchar() is called so many times, waiting each call causes big lag.
471     static bool timeouted = false;
472
473     if (USB_DeviceState != DEVICE_STATE_Configured)
474         return -1;
475
476     uint8_t ep = Endpoint_GetCurrentEndpoint();
477     Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
478     if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
479         Endpoint_SelectEndpoint(ep);
480         return -1;
481     }
482
483     if (timeouted && !Endpoint_IsReadWriteAllowed()) {
484         Endpoint_SelectEndpoint(ep);
485         return - 1;
486     }
487
488     timeouted = false;
489
490     uint8_t timeout = SEND_TIMEOUT;
491     uint16_t prevFN = USB_Device_GetFrameNumber();
492     while (!Endpoint_IsReadWriteAllowed()) {
493         switch (USB_DeviceState) {
494         case DEVICE_STATE_Unattached:
495         case DEVICE_STATE_Suspended:
496             return -1;
497         }
498         if (Endpoint_IsStalled()) {
499             Endpoint_SelectEndpoint(ep);
500             return -1;
501         }
502         if (prevFN != USB_Device_GetFrameNumber()) {
503             if (!(timeout--)) {
504                 timeouted = true;
505                 Endpoint_SelectEndpoint(ep);
506                 return -1;
507             }
508             prevFN = USB_Device_GetFrameNumber();
509         }
510     }
511
512     Endpoint_Write_8(c);
513
514     // send when bank is full
515     if (!Endpoint_IsReadWriteAllowed())
516         Endpoint_ClearIN();
517
518     Endpoint_SelectEndpoint(ep);
519     return 0;
520 }
521 #else
522 int8_t sendchar(uint8_t c)
523 {
524     return 0;
525 }
526 #endif
527
528
529 /*******************************************************************************
530  * main
531  ******************************************************************************/
532 static void SetupHardware(void)
533 {
534     /* Disable watchdog if enabled by bootloader/fuses */
535     MCUSR &= ~(1 << WDRF);
536     wdt_disable();
537
538     /* Disable clock division */
539     clock_prescale_set(clock_div_1);
540
541     // Leonardo needs. Without this USB device is not recognized.
542     USB_Disable();
543
544     USB_Init();
545
546     // for Console_Task
547     USB_Device_EnableSOFEvents();
548     print_set_sendchar(sendchar);
549 }
550
551 int main(void)  __attribute__ ((weak));
552 int main(void)
553 {
554     SetupHardware();
555     sei();
556
557     /* wait for USB startup & debug output */
558     while (USB_DeviceState != DEVICE_STATE_Configured) {
559 #if defined(INTERRUPT_CONTROL_ENDPOINT)
560         ;
561 #else
562         USB_USBTask();
563 #endif
564     }
565     print("USB configured.\n");
566
567     /* init modules */
568     keyboard_init();
569     host_set_driver(&lufa_driver);
570 #ifdef SLEEP_LED_ENABLE
571     sleep_led_init();
572 #endif
573
574     print("Keyboard start.\n");
575     while (1) {
576         while (USB_DeviceState == DEVICE_STATE_Suspended) {
577             suspend_power_down();
578             if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) {
579                     USB_Device_SendRemoteWakeup();
580             }
581         }
582
583         keyboard_task();
584
585 #if !defined(INTERRUPT_CONTROL_ENDPOINT)
586         USB_USBTask();
587 #endif
588     }
589 }