]> git.gir.st - tmk_keyboard.git/blob - tmk_core/protocol/lufa/lufa.c
lufa: Fix endpoint bank mode for ATMega32u2
[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 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_Disable();
155 USB_Init();
156 USB_Device_EnableSOFEvents();
157 }
158 }
159
160 void EVENT_USB_Device_Disconnect(void)
161 {
162 print("[D]");
163 /* For battery powered device */
164 USB_IsInitialized = false;
165 /* TODO: This doesn't work. After several plug in/outs can not be enumerated.
166 if (USB_IsInitialized) {
167 USB_Disable(); // Disable all interrupts
168 USB_Controller_Enable();
169 USB_INT_Enable(USB_INT_VBUSTI);
170 }
171 */
172 }
173
174 void EVENT_USB_Device_Reset(void)
175 {
176 print("[R]");
177 }
178
179 void EVENT_USB_Device_Suspend()
180 {
181 print("[S]");
182 #ifdef SLEEP_LED_ENABLE
183 sleep_led_enable();
184 #endif
185 }
186
187 void EVENT_USB_Device_WakeUp()
188 {
189 print("[W]");
190 suspend_wakeup_init();
191
192 #ifdef SLEEP_LED_ENABLE
193 sleep_led_disable();
194 // NOTE: converters may not accept this
195 led_set(host_keyboard_leds());
196 #endif
197 }
198
199 #ifdef CONSOLE_ENABLE
200 static bool console_flush = false;
201 #define CONSOLE_FLUSH_SET(b) do { \
202 uint8_t sreg = SREG; cli(); console_flush = b; SREG = sreg; \
203 } while (0)
204
205 // called every 1ms
206 void EVENT_USB_Device_StartOfFrame(void)
207 {
208 static uint8_t count;
209 if (++count % 50) return;
210 count = 0;
211
212 if (!console_flush) return;
213 Console_Task();
214 console_flush = false;
215 }
216 #endif
217
218 /** Event handler for the USB_ConfigurationChanged event.
219 * This is fired when the host sets the current configuration of the USB device after enumeration.
220 *
221 * ATMega32u2 supports dual bank(ping-pong mode) only on endpoint 3 and 4,
222 * it is safe to use singl bank for all endpoints.
223 */
224 void EVENT_USB_Device_ConfigurationChanged(void)
225 {
226 bool ConfigSuccess = true;
227
228 /* Setup Keyboard HID Report Endpoints */
229 ConfigSuccess &= ENDPOINT_CONFIG(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
230 KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
231
232 #ifdef MOUSE_ENABLE
233 /* Setup Mouse HID Report Endpoint */
234 ConfigSuccess &= ENDPOINT_CONFIG(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
235 MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE);
236 #endif
237
238 #ifdef EXTRAKEY_ENABLE
239 /* Setup Extra HID Report Endpoint */
240 ConfigSuccess &= ENDPOINT_CONFIG(EXTRAKEY_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
241 EXTRAKEY_EPSIZE, ENDPOINT_BANK_SINGLE);
242 #endif
243
244 #ifdef CONSOLE_ENABLE
245 /* Setup Console HID Report Endpoints */
246 ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
247 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
248 #if 0
249 ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
250 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
251 #endif
252 #endif
253
254 #ifdef NKRO_ENABLE
255 /* Setup NKRO HID Report Endpoints */
256 ConfigSuccess &= ENDPOINT_CONFIG(NKRO_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
257 NKRO_EPSIZE, ENDPOINT_BANK_SINGLE);
258 #endif
259 }
260
261 /*
262 Appendix G: HID Request Support Requirements
263
264 The following table enumerates the requests that need to be supported by various types of HID class devices.
265
266 Device type GetReport SetReport GetIdle SetIdle GetProtocol SetProtocol
267 ------------------------------------------------------------------------------------------
268 Boot Mouse Required Optional Optional Optional Required Required
269 Non-Boot Mouse Required Optional Optional Optional Optional Optional
270 Boot Keyboard Required Optional Required Required Required Required
271 Non-Boot Keybrd Required Optional Required Required Optional Optional
272 Other Device Required Optional Optional Optional Optional Optional
273 */
274 /** Event handler for the USB_ControlRequest event.
275 * This is fired before passing along unhandled control requests to the library for processing internally.
276 */
277 void EVENT_USB_Device_ControlRequest(void)
278 {
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) != 0x00);
353 #ifdef NKRO_ENABLE
354 keyboard_nkro = !!keyboard_protocol;
355 #endif
356 clear_keyboard();
357 }
358 }
359
360 break;
361 case HID_REQ_SetIdle:
362 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
363 {
364 Endpoint_ClearSETUP();
365 Endpoint_ClearStatusStage();
366
367 keyboard_idle = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
368 }
369
370 break;
371 case HID_REQ_GetIdle:
372 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
373 {
374 Endpoint_ClearSETUP();
375 while (!(Endpoint_IsINReady()));
376 Endpoint_Write_8(keyboard_idle);
377 Endpoint_ClearIN();
378 Endpoint_ClearStatusStage();
379 }
380
381 break;
382 }
383 }
384
385 /*******************************************************************************
386 * Host driver
387 ******************************************************************************/
388 static uint8_t keyboard_leds(void)
389 {
390 return keyboard_led_stats;
391 }
392
393 static void send_keyboard(report_keyboard_t *report)
394 {
395 uint8_t timeout = 255;
396
397 if (USB_DeviceState != DEVICE_STATE_Configured)
398 return;
399
400 /* Select the Keyboard Report Endpoint */
401 #ifdef NKRO_ENABLE
402 if (keyboard_nkro) {
403 /* Report protocol - NKRO */
404 Endpoint_SelectEndpoint(NKRO_IN_EPNUM);
405
406 /* Check if write ready for a polling interval around 1ms */
407 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(4);
408 if (!Endpoint_IsReadWriteAllowed()) return;
409
410 /* Write Keyboard Report Data */
411 Endpoint_Write_Stream_LE(report, NKRO_EPSIZE, NULL);
412 }
413 else
414 #endif
415 {
416 /* Boot protocol */
417 Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
418
419 /* Check if write ready for a polling interval around 10ms */
420 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
421 if (!Endpoint_IsReadWriteAllowed()) return;
422
423 /* Write Keyboard Report Data */
424 Endpoint_Write_Stream_LE(report, KEYBOARD_EPSIZE, NULL);
425 }
426
427 /* Finalize the stream transfer to send the last packet */
428 Endpoint_ClearIN();
429
430 keyboard_report_sent = *report;
431 }
432
433 static void send_mouse(report_mouse_t *report)
434 {
435 #ifdef MOUSE_ENABLE
436 uint8_t timeout = 255;
437
438 if (USB_DeviceState != DEVICE_STATE_Configured)
439 return;
440
441 /* Select the Mouse Report Endpoint */
442 Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
443
444 /* Check if write ready for a polling interval around 10ms */
445 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
446 if (!Endpoint_IsReadWriteAllowed()) return;
447
448 /* Write Mouse Report Data */
449 Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
450
451 /* Finalize the stream transfer to send the last packet */
452 Endpoint_ClearIN();
453 #endif
454 }
455
456 static void send_system(uint16_t data)
457 {
458 uint8_t timeout = 255;
459
460 if (USB_DeviceState != DEVICE_STATE_Configured)
461 return;
462
463 report_extra_t r = {
464 .report_id = REPORT_ID_SYSTEM,
465 .usage = data
466 };
467 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
468
469 /* Check if write ready for a polling interval around 10ms */
470 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
471 if (!Endpoint_IsReadWriteAllowed()) return;
472
473 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
474 Endpoint_ClearIN();
475 }
476
477 static void send_consumer(uint16_t data)
478 {
479 uint8_t timeout = 255;
480
481 if (USB_DeviceState != DEVICE_STATE_Configured)
482 return;
483
484 report_extra_t r = {
485 .report_id = REPORT_ID_CONSUMER,
486 .usage = data
487 };
488 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
489
490 /* Check if write ready for a polling interval around 10ms */
491 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
492 if (!Endpoint_IsReadWriteAllowed()) return;
493
494 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
495 Endpoint_ClearIN();
496 }
497
498
499 /*******************************************************************************
500 * sendchar
501 ******************************************************************************/
502 #ifdef CONSOLE_ENABLE
503 #define SEND_TIMEOUT 5
504 int8_t sendchar(uint8_t c)
505 {
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 return 0;
564 }
565 #endif
566
567
568 /*******************************************************************************
569 * main
570 ******************************************************************************/
571 static void setup_mcu(void)
572 {
573 /* Disable watchdog if enabled by bootloader/fuses */
574 MCUSR &= ~(1 << WDRF);
575 wdt_disable();
576
577 /* Disable clock division */
578 clock_prescale_set(clock_div_1);
579 }
580
581 static void setup_usb(void)
582 {
583 // Leonardo needs. Without this USB device is not recognized.
584 USB_Disable();
585
586 USB_Init();
587
588 // for Console_Task
589 USB_Device_EnableSOFEvents();
590 print_set_sendchar(sendchar);
591 }
592
593 int main(void) __attribute__ ((weak));
594 int main(void)
595 {
596 setup_mcu();
597 keyboard_setup();
598 setup_usb();
599 sei();
600
601 /* wait for USB startup & debug output */
602 while (USB_DeviceState != DEVICE_STATE_Configured) {
603 #if defined(INTERRUPT_CONTROL_ENDPOINT)
604 ;
605 #else
606 USB_USBTask();
607 #endif
608 }
609 print("USB configured.\n");
610
611 /* init modules */
612 keyboard_init();
613 host_set_driver(&lufa_driver);
614 #ifdef SLEEP_LED_ENABLE
615 sleep_led_init();
616 #endif
617
618 print("Keyboard start.\n");
619 while (1) {
620 while (USB_DeviceState == DEVICE_STATE_Suspended) {
621 print("[s]");
622 suspend_power_down();
623 if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) {
624 USB_Device_SendRemoteWakeup();
625 }
626 }
627
628 keyboard_task();
629
630 #if !defined(INTERRUPT_CONTROL_ENDPOINT)
631 USB_USBTask();
632 #endif
633 }
634 }
Imprint / Impressum