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