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