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