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