]> git.donarmstrong.com Git - tmk_firmware.git/blob - protocol/lufa/lufa.c
Fix LUFA host driver for unconfigured state
[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
225 /*
226 Appendix G: HID Request Support Requirements
227
228 The following table enumerates the requests that need to be supported by various types of HID class devices.
229
230 Device type     GetReport   SetReport   GetIdle     SetIdle     GetProtocol SetProtocol
231 ------------------------------------------------------------------------------------------
232 Boot Mouse      Required    Optional    Optional    Optional    Required    Required
233 Non-Boot Mouse  Required    Optional    Optional    Optional    Optional    Optional
234 Boot Keyboard   Required    Optional    Required    Required    Required    Required
235 Non-Boot Keybrd Required    Optional    Required    Required    Optional    Optional
236 Other Device    Required    Optional    Optional    Optional    Optional    Optional
237 */
238 /** Event handler for the USB_ControlRequest event.
239  *  This is fired before passing along unhandled control requests to the library for processing internally.
240  */
241 void EVENT_USB_Device_ControlRequest(void)
242 {
243     uint8_t* ReportData = NULL;
244     uint8_t  ReportSize = 0;
245
246     /* Handle HID Class specific requests */
247     switch (USB_ControlRequest.bRequest)
248     {
249         case HID_REQ_GetReport:
250             if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
251             {
252                 Endpoint_ClearSETUP();
253
254                 // Interface
255                 switch (USB_ControlRequest.wIndex) {
256                 case KEYBOARD_INTERFACE:
257                     // TODO: test/check
258                     ReportData = (uint8_t*)&keyboard_report_sent;
259                     ReportSize = sizeof(keyboard_report_sent);
260                     break;
261                 }
262
263                 /* Write the report data to the control endpoint */
264                 Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
265                 Endpoint_ClearOUT();
266             }
267
268             break;
269         case HID_REQ_SetReport:
270             if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
271             {
272
273                 // Interface
274                 switch (USB_ControlRequest.wIndex) {
275                 case KEYBOARD_INTERFACE:
276                     Endpoint_ClearSETUP();
277
278                     while (!(Endpoint_IsOUTReceived())) {
279                         if (USB_DeviceState == DEVICE_STATE_Unattached)
280                           return;
281                     }
282                     keyboard_led_stats = Endpoint_Read_8();
283
284                     Endpoint_ClearOUT();
285                     Endpoint_ClearStatusStage();
286                     break;
287                 }
288
289             }
290
291             break;
292
293         case HID_REQ_GetProtocol:
294             if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
295             {
296                 Endpoint_ClearSETUP();
297                 while (!(Endpoint_IsINReady()));
298                 Endpoint_Write_8(protocol_report);
299                 Endpoint_ClearIN();
300                 Endpoint_ClearStatusStage();
301             }
302
303             break;
304         case HID_REQ_SetProtocol:
305             if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
306             {
307                 Endpoint_ClearSETUP();
308                 Endpoint_ClearStatusStage();
309
310                 protocol_report = ((USB_ControlRequest.wValue & 0xFF) != 0x00);
311             }
312
313             break;
314         case HID_REQ_SetIdle:
315             if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
316             {
317                 Endpoint_ClearSETUP();
318                 Endpoint_ClearStatusStage();
319
320                 idle_duration = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
321             }
322
323             break;
324         case HID_REQ_GetIdle:
325             if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
326             {
327                 Endpoint_ClearSETUP();
328                 while (!(Endpoint_IsINReady()));
329                 Endpoint_Write_8(idle_duration);
330                 Endpoint_ClearIN();
331                 Endpoint_ClearStatusStage();
332             }
333
334             break;
335     }
336 }
337
338 /*******************************************************************************
339  * Host driver 
340  ******************************************************************************/
341 static uint8_t keyboard_leds(void)
342 {
343     return keyboard_led_stats;
344 }
345
346 static void send_keyboard(report_keyboard_t *report)
347 {
348     uint8_t timeout = 0;
349
350     if (USB_DeviceState != DEVICE_STATE_Configured)
351         return;
352
353     // TODO: handle NKRO report
354     /* Select the Keyboard Report Endpoint */
355     Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
356
357     /* Check if Keyboard Endpoint Ready for Read/Write */
358     while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
359
360     /* Write Keyboard Report Data */
361     Endpoint_Write_Stream_LE(report, sizeof(report_keyboard_t), NULL);
362
363     /* Finalize the stream transfer to send the last packet */
364     Endpoint_ClearIN();
365
366     keyboard_report_sent = *report;
367 }
368
369 static void send_mouse(report_mouse_t *report)
370 {
371 #ifdef MOUSE_ENABLE
372     uint8_t timeout = 0;
373
374     if (USB_DeviceState != DEVICE_STATE_Configured)
375         return;
376
377     /* Select the Mouse Report Endpoint */
378     Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
379
380     /* Check if Mouse Endpoint Ready for Read/Write */
381     while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
382
383     /* Write Mouse Report Data */
384     Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
385
386     /* Finalize the stream transfer to send the last packet */
387     Endpoint_ClearIN();
388 #endif
389 }
390
391 static void send_system(uint16_t data)
392 {
393     uint8_t timeout = 0;
394
395     if (USB_DeviceState != DEVICE_STATE_Configured)
396         return;
397
398     report_extra_t r = {
399         .report_id = REPORT_ID_SYSTEM,
400         .usage = data
401     };
402     Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
403     while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
404     Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
405     Endpoint_ClearIN();
406 }
407
408 static void send_consumer(uint16_t data)
409 {
410     uint8_t timeout = 0;
411
412     if (USB_DeviceState != DEVICE_STATE_Configured)
413         return;
414
415     report_extra_t r = {
416         .report_id = REPORT_ID_CONSUMER,
417         .usage = data
418     };
419     Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
420     while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
421     Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
422     Endpoint_ClearIN();
423 }
424
425
426 /*******************************************************************************
427  * sendchar
428  ******************************************************************************/
429 #ifdef CONSOLE_ENABLE
430 #define SEND_TIMEOUT 5
431 int8_t sendchar(uint8_t c)
432 {
433     // Not wait once timeouted.
434     // Because sendchar() is called so many times, waiting each call causes big lag.
435     static bool timeouted = false;
436
437     if (USB_DeviceState != DEVICE_STATE_Configured)
438         return -1;
439
440     uint8_t ep = Endpoint_GetCurrentEndpoint();
441     Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
442     if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
443         Endpoint_SelectEndpoint(ep);
444         return -1;
445     }
446
447     if (timeouted && !Endpoint_IsReadWriteAllowed()) {
448         Endpoint_SelectEndpoint(ep);
449         return - 1;
450     }
451
452     timeouted = false;
453
454     uint8_t timeout = SEND_TIMEOUT;
455     uint16_t prevFN = USB_Device_GetFrameNumber();
456     while (!Endpoint_IsReadWriteAllowed()) {
457         switch (USB_DeviceState) {
458         case DEVICE_STATE_Unattached:
459         case DEVICE_STATE_Suspended:
460             return -1;
461         }
462         if (Endpoint_IsStalled()) {
463             Endpoint_SelectEndpoint(ep);
464             return -1;
465         }
466         if (prevFN != USB_Device_GetFrameNumber()) {
467             if (!(timeout--)) {
468                 timeouted = true;
469                 Endpoint_SelectEndpoint(ep);
470                 return -1;
471             }
472             prevFN = USB_Device_GetFrameNumber();
473         }
474     }
475
476     Endpoint_Write_8(c);
477
478     // send when bank is full
479     if (!Endpoint_IsReadWriteAllowed())
480         Endpoint_ClearIN();
481
482     Endpoint_SelectEndpoint(ep);
483     return 0;
484 }
485 #else
486 int8_t sendchar(uint8_t c)
487 {
488     return 0;
489 }
490 #endif
491
492
493 /*******************************************************************************
494  * main
495  ******************************************************************************/
496 static void SetupHardware(void)
497 {
498     /* Disable watchdog if enabled by bootloader/fuses */
499     MCUSR &= ~(1 << WDRF);
500     wdt_disable();
501
502     /* Disable clock division */
503     clock_prescale_set(clock_div_1);
504
505     // Leonardo needs. Without this USB device is not recognized.
506     USB_Disable();
507
508     USB_Init();
509
510     // for Console_Task
511     USB_Device_EnableSOFEvents();
512 }
513
514 int main(void)  __attribute__ ((weak));
515 int main(void)
516 {
517     SetupHardware();
518     keyboard_init();
519     host_set_driver(&lufa_driver);
520 #ifdef SLEEP_LED_ENABLE
521     sleep_led_init();
522 #endif
523     sei();
524
525     while (1) {
526         while (USB_DeviceState == DEVICE_STATE_Suspended) {
527             suspend_power_down();
528             if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) {
529                     USB_Device_SendRemoteWakeup();
530             }
531         }
532
533         keyboard_task();
534
535 #if !defined(INTERRUPT_CONTROL_ENDPOINT)
536         USB_USBTask();
537 #endif
538     }
539 }