c16fd1775b83cc1c85066da8a53c1a97fc69b8c0
[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 }
Imprint / Impressum