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