]> git.donarmstrong.com Git - tmk_firmware.git/blob - protocol/lufa/lufa.c
Wait for USB starting up to make debug print available
[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     led_set(0x1f);  // all on
152 }
153
154 void EVENT_USB_Device_Disconnect(void)
155 {
156 }
157
158 void EVENT_USB_Device_Reset(void)
159 {
160 }
161
162 void EVENT_USB_Device_Suspend()
163 {
164 #ifdef SLEEP_LED_ENABLE
165     sleep_led_enable();
166 #endif
167 }
168
169 void EVENT_USB_Device_WakeUp()
170 {
171     suspend_wakeup_init();
172
173 #ifdef SLEEP_LED_ENABLE
174     sleep_led_disable();
175 #endif
176     led_set(host_keyboard_leds());
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 = 0;
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     else
365 #endif
366     {
367         Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
368     }
369
370     /* Check if Keyboard Endpoint Ready for Read/Write */
371     while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
372
373     /* Write Keyboard Report Data */
374 #ifdef NKRO_ENABLE
375     if (keyboard_nkro) {
376         Endpoint_Write_Stream_LE(report, NKRO_EPSIZE, NULL);
377     }
378     else
379 #endif
380     {
381         /* boot mode */
382         Endpoint_Write_Stream_LE(report, KEYBOARD_EPSIZE, NULL);
383     }
384
385     /* Finalize the stream transfer to send the last packet */
386     Endpoint_ClearIN();
387
388     keyboard_report_sent = *report;
389 }
390
391 static void send_mouse(report_mouse_t *report)
392 {
393 #ifdef MOUSE_ENABLE
394     uint8_t timeout = 0;
395
396     if (USB_DeviceState != DEVICE_STATE_Configured)
397         return;
398
399     /* Select the Mouse Report Endpoint */
400     Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
401
402     /* Check if Mouse Endpoint Ready for Read/Write */
403     while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
404
405     /* Write Mouse Report Data */
406     Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
407
408     /* Finalize the stream transfer to send the last packet */
409     Endpoint_ClearIN();
410 #endif
411 }
412
413 static void send_system(uint16_t data)
414 {
415     uint8_t timeout = 0;
416
417     if (USB_DeviceState != DEVICE_STATE_Configured)
418         return;
419
420     report_extra_t r = {
421         .report_id = REPORT_ID_SYSTEM,
422         .usage = data
423     };
424     Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
425     while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
426     Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
427     Endpoint_ClearIN();
428 }
429
430 static void send_consumer(uint16_t data)
431 {
432     uint8_t timeout = 0;
433
434     if (USB_DeviceState != DEVICE_STATE_Configured)
435         return;
436
437     report_extra_t r = {
438         .report_id = REPORT_ID_CONSUMER,
439         .usage = data
440     };
441     Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
442     while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
443     Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
444     Endpoint_ClearIN();
445 }
446
447
448 /*******************************************************************************
449  * sendchar
450  ******************************************************************************/
451 #ifdef CONSOLE_ENABLE
452 #define SEND_TIMEOUT 5
453 int8_t sendchar(uint8_t c)
454 {
455     // Not wait once timeouted.
456     // Because sendchar() is called so many times, waiting each call causes big lag.
457     static bool timeouted = false;
458
459     if (USB_DeviceState != DEVICE_STATE_Configured)
460         return -1;
461
462     uint8_t ep = Endpoint_GetCurrentEndpoint();
463     Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
464     if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
465         Endpoint_SelectEndpoint(ep);
466         return -1;
467     }
468
469     if (timeouted && !Endpoint_IsReadWriteAllowed()) {
470         Endpoint_SelectEndpoint(ep);
471         return - 1;
472     }
473
474     timeouted = false;
475
476     uint8_t timeout = SEND_TIMEOUT;
477     uint16_t prevFN = USB_Device_GetFrameNumber();
478     while (!Endpoint_IsReadWriteAllowed()) {
479         switch (USB_DeviceState) {
480         case DEVICE_STATE_Unattached:
481         case DEVICE_STATE_Suspended:
482             return -1;
483         }
484         if (Endpoint_IsStalled()) {
485             Endpoint_SelectEndpoint(ep);
486             return -1;
487         }
488         if (prevFN != USB_Device_GetFrameNumber()) {
489             if (!(timeout--)) {
490                 timeouted = true;
491                 Endpoint_SelectEndpoint(ep);
492                 return -1;
493             }
494             prevFN = USB_Device_GetFrameNumber();
495         }
496     }
497
498     Endpoint_Write_8(c);
499
500     // send when bank is full
501     if (!Endpoint_IsReadWriteAllowed())
502         Endpoint_ClearIN();
503
504     Endpoint_SelectEndpoint(ep);
505     return 0;
506 }
507 #else
508 int8_t sendchar(uint8_t c)
509 {
510     return 0;
511 }
512 #endif
513
514
515 /*******************************************************************************
516  * main
517  ******************************************************************************/
518 static void SetupHardware(void)
519 {
520     /* Disable watchdog if enabled by bootloader/fuses */
521     MCUSR &= ~(1 << WDRF);
522     wdt_disable();
523
524     /* Disable clock division */
525     clock_prescale_set(clock_div_1);
526
527     // Leonardo needs. Without this USB device is not recognized.
528     USB_Disable();
529
530     USB_Init();
531
532     // for Console_Task
533     USB_Device_EnableSOFEvents();
534     print_set_sendchar(sendchar);
535 }
536
537 int main(void)  __attribute__ ((weak));
538 int main(void)
539 {
540     SetupHardware();
541     sei();
542
543     /* wait for USB startup & debug output */
544     while (USB_DeviceState != DEVICE_STATE_Configured) {
545 #if defined(INTERRUPT_CONTROL_ENDPOINT)
546         ;
547 #else
548         USB_USBTask();
549 #endif
550     }
551     print("USB configured.\n");
552
553     /* init modules */
554     keyboard_init();
555     host_set_driver(&lufa_driver);
556 #ifdef SLEEP_LED_ENABLE
557     sleep_led_init();
558 #endif
559
560     print("Keyboard start.\n");
561     while (1) {
562         while (USB_DeviceState == DEVICE_STATE_Suspended) {
563             suspend_power_down();
564             if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) {
565                     USB_Device_SendRemoteWakeup();
566             }
567         }
568
569         keyboard_task();
570
571 #if !defined(INTERRUPT_CONTROL_ENDPOINT)
572         USB_USBTask();
573 #endif
574     }
575 }