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