]> git.donarmstrong.com Git - tmk_firmware.git/blob - protocol/lufa/lufa.c
Revert lufa/lufa.c
[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 }
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 void EVENT_USB_Device_ConfigurationChanged(void)
188 {
189     bool ConfigSuccess = true;
190
191     /* Setup Keyboard HID Report Endpoints */
192     ConfigSuccess &= ENDPOINT_CONFIG(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
193                                      KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
194
195 #ifdef MOUSE_ENABLE
196     /* Setup Mouse HID Report Endpoint */
197     ConfigSuccess &= ENDPOINT_CONFIG(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
198                                      MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE);
199 #endif
200
201 #ifdef EXTRAKEY_ENABLE
202     /* Setup Extra HID Report Endpoint */
203     ConfigSuccess &= ENDPOINT_CONFIG(EXTRAKEY_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
204                                      EXTRAKEY_EPSIZE, ENDPOINT_BANK_SINGLE);
205 #endif
206
207 #ifdef CONSOLE_ENABLE
208     /* Setup Console HID Report Endpoints */
209     ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
210                                      CONSOLE_EPSIZE, ENDPOINT_BANK_DOUBLE);
211 #if 0
212     ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
213                                      CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
214 #endif
215 #endif
216
217 #ifdef NKRO_ENABLE
218     /* Setup NKRO HID Report Endpoints */
219     ConfigSuccess &= ENDPOINT_CONFIG(NKRO_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
220                                      NKRO_EPSIZE, ENDPOINT_BANK_SINGLE);
221 #endif
222 }
223
224 /*
225 Appendix G: HID Request Support Requirements
226
227 The following table enumerates the requests that need to be supported by various types of HID class devices.
228
229 Device type     GetReport   SetReport   GetIdle     SetIdle     GetProtocol SetProtocol
230 ------------------------------------------------------------------------------------------
231 Boot Mouse      Required    Optional    Optional    Optional    Required    Required
232 Non-Boot Mouse  Required    Optional    Optional    Optional    Optional    Optional
233 Boot Keyboard   Required    Optional    Required    Required    Required    Required
234 Non-Boot Keybrd Required    Optional    Required    Required    Optional    Optional
235 Other Device    Required    Optional    Optional    Optional    Optional    Optional
236 */
237 /** Event handler for the USB_ControlRequest event.
238  *  This is fired before passing along unhandled control requests to the library for processing internally.
239  */
240 void EVENT_USB_Device_ControlRequest(void)
241 {
242     uint8_t* ReportData = NULL;
243     uint8_t  ReportSize = 0;
244
245     /* Handle HID Class specific requests */
246     switch (USB_ControlRequest.bRequest)
247     {
248         case HID_REQ_GetReport:
249             if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
250             {
251                 Endpoint_ClearSETUP();
252
253                 // Interface
254                 switch (USB_ControlRequest.wIndex) {
255                 case KEYBOARD_INTERFACE:
256                     // TODO: test/check
257                     ReportData = (uint8_t*)&keyboard_report_sent;
258                     ReportSize = sizeof(keyboard_report_sent);
259                     break;
260                 }
261
262                 /* Write the report data to the control endpoint */
263                 Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
264                 Endpoint_ClearOUT();
265             }
266
267             break;
268         case HID_REQ_SetReport:
269             if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
270             {
271
272                 // Interface
273                 switch (USB_ControlRequest.wIndex) {
274                 case KEYBOARD_INTERFACE:
275 #ifdef NKRO_ENABLE
276                 case NKRO_INTERFACE:
277 #endif
278                     Endpoint_ClearSETUP();
279
280                     while (!(Endpoint_IsOUTReceived())) {
281                         if (USB_DeviceState == DEVICE_STATE_Unattached)
282                           return;
283                     }
284                     keyboard_led_stats = Endpoint_Read_8();
285
286                     Endpoint_ClearOUT();
287                     Endpoint_ClearStatusStage();
288                     break;
289                 }
290
291             }
292
293             break;
294
295         case HID_REQ_GetProtocol:
296             if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
297             {
298                 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
299                     Endpoint_ClearSETUP();
300                     while (!(Endpoint_IsINReady()));
301                     Endpoint_Write_8(keyboard_protocol);
302                     Endpoint_ClearIN();
303                     Endpoint_ClearStatusStage();
304                 }
305             }
306
307             break;
308         case HID_REQ_SetProtocol:
309             if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
310             {
311                 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
312                     Endpoint_ClearSETUP();
313                     Endpoint_ClearStatusStage();
314
315                     keyboard_protocol = ((USB_ControlRequest.wValue & 0xFF) != 0x00);
316 #ifdef NKRO_ENABLE
317                     keyboard_nkro = !!keyboard_protocol;
318 #endif
319                     clear_keyboard();
320                 }
321             }
322
323             break;
324         case HID_REQ_SetIdle:
325             if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
326             {
327                 Endpoint_ClearSETUP();
328                 Endpoint_ClearStatusStage();
329
330                 keyboard_idle = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
331             }
332
333             break;
334         case HID_REQ_GetIdle:
335             if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
336             {
337                 Endpoint_ClearSETUP();
338                 while (!(Endpoint_IsINReady()));
339                 Endpoint_Write_8(keyboard_idle);
340                 Endpoint_ClearIN();
341                 Endpoint_ClearStatusStage();
342             }
343
344             break;
345     }
346 }
347
348 /*******************************************************************************
349  * Host driver 
350  ******************************************************************************/
351 static uint8_t keyboard_leds(void)
352 {
353     return keyboard_led_stats;
354 }
355
356 static void send_keyboard(report_keyboard_t *report)
357 {
358     uint8_t timeout = 255;
359
360     if (USB_DeviceState != DEVICE_STATE_Configured)
361         return;
362
363     /* Select the Keyboard Report Endpoint */
364 #ifdef NKRO_ENABLE
365     if (keyboard_nkro) {
366         /* Report protocol - NKRO */
367         Endpoint_SelectEndpoint(NKRO_IN_EPNUM);
368
369         /* Check if write ready for a polling interval around 1ms */
370         while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(4);
371         if (!Endpoint_IsReadWriteAllowed()) return;
372
373         /* Write Keyboard Report Data */
374         Endpoint_Write_Stream_LE(report, NKRO_EPSIZE, NULL);
375     }
376     else
377 #endif
378     {
379         /* Boot protocol */
380         Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
381
382         /* Check if write ready for a polling interval around 10ms */
383         while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
384         if (!Endpoint_IsReadWriteAllowed()) return;
385
386         /* Write Keyboard Report Data */
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 }