]> git.gir.st - tmk_keyboard.git/blob - protocol/lufa/lufa.c
3d6b3ea00c33024caa13165f7a983208bc781dc2
[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
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_Init();
155 USB_Device_EnableSOFEvents();
156 }
157 }
158
159 void EVENT_USB_Device_Disconnect(void)
160 {
161 print("[D]");
162 /* For battery powered device */
163 /* TODO: This doesn't work. After several plug in/outs can not be enumerated.
164 if (USB_IsInitialized) {
165 USB_Disable(); // Disable all interrupts
166 USB_Controller_Enable();
167 USB_INT_Enable(USB_INT_VBUSTI);
168 }
169 */
170 }
171
172 void EVENT_USB_Device_Reset(void)
173 {
174 print("[R]");
175 }
176
177 void EVENT_USB_Device_Suspend()
178 {
179 print("[S]");
180 #ifdef SLEEP_LED_ENABLE
181 sleep_led_enable();
182 #endif
183 }
184
185 void EVENT_USB_Device_WakeUp()
186 {
187 print("[W]");
188 suspend_wakeup_init();
189
190 #ifdef SLEEP_LED_ENABLE
191 sleep_led_disable();
192 // NOTE: converters may not accept this
193 led_set(host_keyboard_leds());
194 #endif
195 }
196
197 void EVENT_USB_Device_StartOfFrame(void)
198 {
199 Console_Task();
200 }
201
202 /** Event handler for the USB_ConfigurationChanged event.
203 * This is fired when the host sets the current configuration of the USB device after enumeration.
204 */
205 void EVENT_USB_Device_ConfigurationChanged(void)
206 {
207 bool ConfigSuccess = true;
208
209 /* Setup Keyboard HID Report Endpoints */
210 ConfigSuccess &= ENDPOINT_CONFIG(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
211 KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
212
213 #ifdef MOUSE_ENABLE
214 /* Setup Mouse HID Report Endpoint */
215 ConfigSuccess &= ENDPOINT_CONFIG(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
216 MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE);
217 #endif
218
219 #ifdef EXTRAKEY_ENABLE
220 /* Setup Extra HID Report Endpoint */
221 ConfigSuccess &= ENDPOINT_CONFIG(EXTRAKEY_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
222 EXTRAKEY_EPSIZE, ENDPOINT_BANK_SINGLE);
223 #endif
224
225 #ifdef CONSOLE_ENABLE
226 /* Setup Console HID Report Endpoints */
227 ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
228 CONSOLE_EPSIZE, ENDPOINT_BANK_DOUBLE);
229 #if 0
230 ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
231 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
232 #endif
233 #endif
234
235 #ifdef NKRO_ENABLE
236 /* Setup NKRO HID Report Endpoints */
237 ConfigSuccess &= ENDPOINT_CONFIG(NKRO_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
238 NKRO_EPSIZE, ENDPOINT_BANK_SINGLE);
239 #endif
240 }
241
242 /*
243 Appendix G: HID Request Support Requirements
244
245 The following table enumerates the requests that need to be supported by various types of HID class devices.
246
247 Device type GetReport SetReport GetIdle SetIdle GetProtocol SetProtocol
248 ------------------------------------------------------------------------------------------
249 Boot Mouse Required Optional Optional Optional Required Required
250 Non-Boot Mouse Required Optional Optional Optional Optional Optional
251 Boot Keyboard Required Optional Required Required Required Required
252 Non-Boot Keybrd Required Optional Required Required Optional Optional
253 Other Device Required Optional Optional Optional Optional Optional
254 */
255 /** Event handler for the USB_ControlRequest event.
256 * This is fired before passing along unhandled control requests to the library for processing internally.
257 */
258 void EVENT_USB_Device_ControlRequest(void)
259 {
260 uint8_t* ReportData = NULL;
261 uint8_t ReportSize = 0;
262
263 /* Handle HID Class specific requests */
264 switch (USB_ControlRequest.bRequest)
265 {
266 case HID_REQ_GetReport:
267 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
268 {
269 Endpoint_ClearSETUP();
270
271 // Interface
272 switch (USB_ControlRequest.wIndex) {
273 case KEYBOARD_INTERFACE:
274 // TODO: test/check
275 ReportData = (uint8_t*)&keyboard_report_sent;
276 ReportSize = sizeof(keyboard_report_sent);
277 break;
278 }
279
280 /* Write the report data to the control endpoint */
281 Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
282 Endpoint_ClearOUT();
283 }
284
285 break;
286 case HID_REQ_SetReport:
287 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
288 {
289
290 // Interface
291 switch (USB_ControlRequest.wIndex) {
292 case KEYBOARD_INTERFACE:
293 #ifdef NKRO_ENABLE
294 case NKRO_INTERFACE:
295 #endif
296 Endpoint_ClearSETUP();
297
298 while (!(Endpoint_IsOUTReceived())) {
299 if (USB_DeviceState == DEVICE_STATE_Unattached)
300 return;
301 }
302 keyboard_led_stats = Endpoint_Read_8();
303
304 Endpoint_ClearOUT();
305 Endpoint_ClearStatusStage();
306 break;
307 }
308
309 }
310
311 break;
312
313 case HID_REQ_GetProtocol:
314 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
315 {
316 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
317 Endpoint_ClearSETUP();
318 while (!(Endpoint_IsINReady()));
319 Endpoint_Write_8(keyboard_protocol);
320 Endpoint_ClearIN();
321 Endpoint_ClearStatusStage();
322 }
323 }
324
325 break;
326 case HID_REQ_SetProtocol:
327 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
328 {
329 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
330 Endpoint_ClearSETUP();
331 Endpoint_ClearStatusStage();
332
333 keyboard_protocol = ((USB_ControlRequest.wValue & 0xFF) != 0x00);
334 #ifdef NKRO_ENABLE
335 keyboard_nkro = !!keyboard_protocol;
336 #endif
337 clear_keyboard();
338 }
339 }
340
341 break;
342 case HID_REQ_SetIdle:
343 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
344 {
345 Endpoint_ClearSETUP();
346 Endpoint_ClearStatusStage();
347
348 keyboard_idle = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
349 }
350
351 break;
352 case HID_REQ_GetIdle:
353 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
354 {
355 Endpoint_ClearSETUP();
356 while (!(Endpoint_IsINReady()));
357 Endpoint_Write_8(keyboard_idle);
358 Endpoint_ClearIN();
359 Endpoint_ClearStatusStage();
360 }
361
362 break;
363 }
364 }
365
366 /*******************************************************************************
367 * Host driver
368 ******************************************************************************/
369 static uint8_t keyboard_leds(void)
370 {
371 return keyboard_led_stats;
372 }
373
374 static void send_keyboard(report_keyboard_t *report)
375 {
376 uint8_t timeout = 255;
377
378 if (USB_DeviceState != DEVICE_STATE_Configured)
379 return;
380
381 /* Select the Keyboard Report Endpoint */
382 #ifdef NKRO_ENABLE
383 if (keyboard_nkro) {
384 /* Report protocol - NKRO */
385 Endpoint_SelectEndpoint(NKRO_IN_EPNUM);
386
387 /* Check if write ready for a polling interval around 1ms */
388 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(4);
389 if (!Endpoint_IsReadWriteAllowed()) return;
390
391 /* Write Keyboard Report Data */
392 Endpoint_Write_Stream_LE(report, NKRO_EPSIZE, NULL);
393 }
394 else
395 #endif
396 {
397 /* Boot protocol */
398 Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
399
400 /* Check if write ready for a polling interval around 10ms */
401 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
402 if (!Endpoint_IsReadWriteAllowed()) return;
403
404 /* Write Keyboard Report Data */
405 Endpoint_Write_Stream_LE(report, KEYBOARD_EPSIZE, NULL);
406 }
407
408 /* Finalize the stream transfer to send the last packet */
409 Endpoint_ClearIN();
410
411 keyboard_report_sent = *report;
412 }
413
414 static void send_mouse(report_mouse_t *report)
415 {
416 #ifdef MOUSE_ENABLE
417 uint8_t timeout = 255;
418
419 if (USB_DeviceState != DEVICE_STATE_Configured)
420 return;
421
422 /* Select the Mouse Report Endpoint */
423 Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
424
425 /* Check if write ready for a polling interval around 10ms */
426 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
427 if (!Endpoint_IsReadWriteAllowed()) return;
428
429 /* Write Mouse Report Data */
430 Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
431
432 /* Finalize the stream transfer to send the last packet */
433 Endpoint_ClearIN();
434 #endif
435 }
436
437 static void send_system(uint16_t data)
438 {
439 uint8_t timeout = 255;
440
441 if (USB_DeviceState != DEVICE_STATE_Configured)
442 return;
443
444 report_extra_t r = {
445 .report_id = REPORT_ID_SYSTEM,
446 .usage = data
447 };
448 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
449
450 /* Check if write ready for a polling interval around 10ms */
451 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
452 if (!Endpoint_IsReadWriteAllowed()) return;
453
454 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
455 Endpoint_ClearIN();
456 }
457
458 static void send_consumer(uint16_t data)
459 {
460 uint8_t timeout = 255;
461
462 if (USB_DeviceState != DEVICE_STATE_Configured)
463 return;
464
465 report_extra_t r = {
466 .report_id = REPORT_ID_CONSUMER,
467 .usage = data
468 };
469 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
470
471 /* Check if write ready for a polling interval around 10ms */
472 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
473 if (!Endpoint_IsReadWriteAllowed()) return;
474
475 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
476 Endpoint_ClearIN();
477 }
478
479
480 /*******************************************************************************
481 * sendchar
482 ******************************************************************************/
483 #ifdef CONSOLE_ENABLE
484 #define SEND_TIMEOUT 5
485 int8_t sendchar(uint8_t c)
486 {
487 // Not wait once timeouted.
488 // Because sendchar() is called so many times, waiting each call causes big lag.
489 static bool timeouted = false;
490
491 if (USB_DeviceState != DEVICE_STATE_Configured)
492 return -1;
493
494 uint8_t ep = Endpoint_GetCurrentEndpoint();
495 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
496 if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
497 goto ERROR_EXIT;
498 }
499
500 if (timeouted && !Endpoint_IsReadWriteAllowed()) {
501 goto ERROR_EXIT;
502 }
503
504 timeouted = false;
505
506 uint8_t timeout = SEND_TIMEOUT;
507 while (!Endpoint_IsReadWriteAllowed()) {
508 if (USB_DeviceState != DEVICE_STATE_Configured) {
509 goto ERROR_EXIT;
510 }
511 if (Endpoint_IsStalled()) {
512 goto ERROR_EXIT;
513 }
514 if (!(timeout--)) {
515 timeouted = true;
516 goto ERROR_EXIT;
517 }
518 _delay_ms(1);
519 }
520
521 Endpoint_Write_8(c);
522
523 // send when bank is full
524 if (!Endpoint_IsReadWriteAllowed())
525 Endpoint_ClearIN();
526
527 Endpoint_SelectEndpoint(ep);
528 return 0;
529 ERROR_EXIT:
530 Endpoint_SelectEndpoint(ep);
531 return -1;
532 }
533 #else
534 int8_t sendchar(uint8_t c)
535 {
536 return 0;
537 }
538 #endif
539
540
541 /*******************************************************************************
542 * main
543 ******************************************************************************/
544 static void SetupHardware(void)
545 {
546 /* Disable watchdog if enabled by bootloader/fuses */
547 MCUSR &= ~(1 << WDRF);
548 wdt_disable();
549
550 /* Disable clock division */
551 clock_prescale_set(clock_div_1);
552
553 // Leonardo needs. Without this USB device is not recognized.
554 USB_Disable();
555
556 USB_Init();
557
558 // for Console_Task
559 USB_Device_EnableSOFEvents();
560 print_set_sendchar(sendchar);
561 }
562
563 int main(void) __attribute__ ((weak));
564 int main(void)
565 {
566 SetupHardware();
567 sei();
568
569 /* wait for USB startup & debug output */
570 while (USB_DeviceState != DEVICE_STATE_Configured) {
571 #if defined(INTERRUPT_CONTROL_ENDPOINT)
572 ;
573 #else
574 USB_USBTask();
575 #endif
576 }
577 print("USB configured.\n");
578
579 /* init modules */
580 keyboard_init();
581 host_set_driver(&lufa_driver);
582 #ifdef SLEEP_LED_ENABLE
583 sleep_led_init();
584 #endif
585
586 print("Keyboard start.\n");
587 while (1) {
588 while (USB_DeviceState == DEVICE_STATE_Suspended) {
589 print("[s]");
590 suspend_power_down();
591 if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) {
592 USB_Device_SendRemoteWakeup();
593 }
594 }
595
596 keyboard_task();
597
598 #if !defined(INTERRUPT_CONTROL_ENDPOINT)
599 USB_USBTask();
600 #endif
601 }
602 }
Imprint / Impressum