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