]> git.donarmstrong.com Git - tmk_firmware.git/blob - protocol/lufa/lufa.c
Merge pull request #112 from shayneholmes/ee_nkro_use_reserved_bit
[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                 case NKRO_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                 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
297                     Endpoint_ClearSETUP();
298                     while (!(Endpoint_IsINReady()));
299                     Endpoint_Write_8(keyboard_protocol);
300                     Endpoint_ClearIN();
301                     Endpoint_ClearStatusStage();
302                 }
303             }
304
305             break;
306         case HID_REQ_SetProtocol:
307             if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
308             {
309                 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
310                     Endpoint_ClearSETUP();
311                     Endpoint_ClearStatusStage();
312
313                     keyboard_protocol = ((USB_ControlRequest.wValue & 0xFF) != 0x00);
314 #ifdef NKRO_ENABLE
315                     keyboard_nkro = !!keyboard_protocol;
316 #endif
317                     clear_keyboard();
318                 }
319             }
320
321             break;
322         case HID_REQ_SetIdle:
323             if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
324             {
325                 Endpoint_ClearSETUP();
326                 Endpoint_ClearStatusStage();
327
328                 keyboard_idle = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
329             }
330
331             break;
332         case HID_REQ_GetIdle:
333             if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
334             {
335                 Endpoint_ClearSETUP();
336                 while (!(Endpoint_IsINReady()));
337                 Endpoint_Write_8(keyboard_idle);
338                 Endpoint_ClearIN();
339                 Endpoint_ClearStatusStage();
340             }
341
342             break;
343     }
344 }
345
346 /*******************************************************************************
347  * Host driver 
348  ******************************************************************************/
349 static uint8_t keyboard_leds(void)
350 {
351     return keyboard_led_stats;
352 }
353
354 static void send_keyboard(report_keyboard_t *report)
355 {
356     uint8_t timeout = 255;
357
358     if (USB_DeviceState != DEVICE_STATE_Configured)
359         return;
360
361     /* Select the Keyboard Report Endpoint */
362 #ifdef NKRO_ENABLE
363     if (keyboard_nkro) {
364         /* Report protocol - NKRO */
365         Endpoint_SelectEndpoint(NKRO_IN_EPNUM);
366
367         /* Check if write ready for a polling interval around 1ms */
368         while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(4);
369         if (!Endpoint_IsReadWriteAllowed()) return;
370
371         /* Write Keyboard Report Data */
372         Endpoint_Write_Stream_LE(report, NKRO_EPSIZE, NULL);
373     }
374     else
375 #endif
376     {
377         /* Boot protocol */
378         Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
379
380         /* Check if write ready for a polling interval around 10ms */
381         while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
382         if (!Endpoint_IsReadWriteAllowed()) return;
383
384         /* Write Keyboard Report Data */
385         Endpoint_Write_Stream_LE(report, KEYBOARD_EPSIZE, NULL);
386     }
387
388     /* Finalize the stream transfer to send the last packet */
389     Endpoint_ClearIN();
390
391     keyboard_report_sent = *report;
392 }
393
394 static void send_mouse(report_mouse_t *report)
395 {
396 #ifdef MOUSE_ENABLE
397     uint8_t timeout = 255;
398
399     if (USB_DeviceState != DEVICE_STATE_Configured)
400         return;
401
402     /* Select the Mouse Report Endpoint */
403     Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
404
405     /* Check if write ready for a polling interval around 10ms */
406     while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
407     if (!Endpoint_IsReadWriteAllowed()) return;
408
409     /* Write Mouse Report Data */
410     Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
411
412     /* Finalize the stream transfer to send the last packet */
413     Endpoint_ClearIN();
414 #endif
415 }
416
417 static void send_system(uint16_t data)
418 {
419     uint8_t timeout = 255;
420
421     if (USB_DeviceState != DEVICE_STATE_Configured)
422         return;
423
424     report_extra_t r = {
425         .report_id = REPORT_ID_SYSTEM,
426         .usage = data
427     };
428     Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
429
430     /* Check if write ready for a polling interval around 10ms */
431     while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
432     if (!Endpoint_IsReadWriteAllowed()) return;
433
434     Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
435     Endpoint_ClearIN();
436 }
437
438 static void send_consumer(uint16_t data)
439 {
440     uint8_t timeout = 255;
441
442     if (USB_DeviceState != DEVICE_STATE_Configured)
443         return;
444
445     report_extra_t r = {
446         .report_id = REPORT_ID_CONSUMER,
447         .usage = data
448     };
449     Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
450
451     /* Check if write ready for a polling interval around 10ms */
452     while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
453     if (!Endpoint_IsReadWriteAllowed()) return;
454
455     Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
456     Endpoint_ClearIN();
457 }
458
459
460 /*******************************************************************************
461  * sendchar
462  ******************************************************************************/
463 #ifdef CONSOLE_ENABLE
464 #define SEND_TIMEOUT 5
465 int8_t sendchar(uint8_t c)
466 {
467     // Not wait once timeouted.
468     // Because sendchar() is called so many times, waiting each call causes big lag.
469     static bool timeouted = false;
470
471     if (USB_DeviceState != DEVICE_STATE_Configured)
472         return -1;
473
474     uint8_t ep = Endpoint_GetCurrentEndpoint();
475     Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
476     if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
477         Endpoint_SelectEndpoint(ep);
478         return -1;
479     }
480
481     if (timeouted && !Endpoint_IsReadWriteAllowed()) {
482         Endpoint_SelectEndpoint(ep);
483         return - 1;
484     }
485
486     timeouted = false;
487
488     uint8_t timeout = SEND_TIMEOUT;
489     uint16_t prevFN = USB_Device_GetFrameNumber();
490     while (!Endpoint_IsReadWriteAllowed()) {
491         switch (USB_DeviceState) {
492         case DEVICE_STATE_Unattached:
493         case DEVICE_STATE_Suspended:
494             return -1;
495         }
496         if (Endpoint_IsStalled()) {
497             Endpoint_SelectEndpoint(ep);
498             return -1;
499         }
500         if (prevFN != USB_Device_GetFrameNumber()) {
501             if (!(timeout--)) {
502                 timeouted = true;
503                 Endpoint_SelectEndpoint(ep);
504                 return -1;
505             }
506             prevFN = USB_Device_GetFrameNumber();
507         }
508     }
509
510     Endpoint_Write_8(c);
511
512     // send when bank is full
513     if (!Endpoint_IsReadWriteAllowed())
514         Endpoint_ClearIN();
515
516     Endpoint_SelectEndpoint(ep);
517     return 0;
518 }
519 #else
520 int8_t sendchar(uint8_t c)
521 {
522     return 0;
523 }
524 #endif
525
526
527 /*******************************************************************************
528  * main
529  ******************************************************************************/
530 static void SetupHardware(void)
531 {
532     /* Disable watchdog if enabled by bootloader/fuses */
533     MCUSR &= ~(1 << WDRF);
534     wdt_disable();
535
536     /* Disable clock division */
537     clock_prescale_set(clock_div_1);
538
539     // Leonardo needs. Without this USB device is not recognized.
540     USB_Disable();
541
542     USB_Init();
543
544     // for Console_Task
545     USB_Device_EnableSOFEvents();
546     print_set_sendchar(sendchar);
547 }
548
549 int main(void)  __attribute__ ((weak));
550 int main(void)
551 {
552     SetupHardware();
553     sei();
554
555     /* wait for USB startup & debug output */
556     while (USB_DeviceState != DEVICE_STATE_Configured) {
557 #if defined(INTERRUPT_CONTROL_ENDPOINT)
558         ;
559 #else
560         USB_USBTask();
561 #endif
562     }
563     print("USB configured.\n");
564
565     /* init modules */
566     keyboard_init();
567     host_set_driver(&lufa_driver);
568 #ifdef SLEEP_LED_ENABLE
569     sleep_led_init();
570 #endif
571
572     print("Keyboard start.\n");
573     while (1) {
574         while (USB_DeviceState == DEVICE_STATE_Suspended) {
575             suspend_power_down();
576             if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) {
577                     USB_Device_SendRemoteWakeup();
578             }
579         }
580
581         keyboard_task();
582
583 #if !defined(INTERRUPT_CONTROL_ENDPOINT)
584         USB_USBTask();
585 #endif
586     }
587 }