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