Change PollingIntervalMS to 10ms(Fix #114)
[tmk_keyboard.git] / protocol / lufa / lufa.c
CommitLineData
dd93d291 1/*
2 * Copyright 2012 Jun Wako <wakojun@gmail.com>
3969ec09 3 * This file is based on:
4 * LUFA-120219/Demos/Device/Lowlevel/KeyboardMouse
5 * LUFA-120219/Demos/Device/Lowlevel/GenericHID
dd93d291 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"
f0c5f1b9 43#include "action.h"
f0c5f1b9 44#include "led.h"
3969ec09 45#include "sendchar.h"
46#include "debug.h"
f0c5f1b9 47#ifdef SLEEP_LED_ENABLE
48#include "sleep_led.h"
49#endif
afc3148e 50#include "suspend.h"
effa5914 51
52#include "descriptor.h"
dd93d291 53#include "lufa.h"
54
a112f361 55static uint8_t idle_duration = 0;
56static uint8_t protocol_report = 1;
dd93d291 57static uint8_t keyboard_led_stats = 0;
effa5914 58
effa5914 59static report_keyboard_t keyboard_report_sent;
a112f361 60
dd93d291 61
62/* Host driver */
63static uint8_t keyboard_leds(void);
64static void send_keyboard(report_keyboard_t *report);
65static void send_mouse(report_mouse_t *report);
66static void send_system(uint16_t data);
67static void send_consumer(uint16_t data);
c5060ea8 68host_driver_t lufa_driver = {
dd93d291 69 keyboard_leds,
70 send_keyboard,
71 send_mouse,
72 send_system,
73 send_consumer
74};
75
76
c5060ea8 77/*******************************************************************************
78 * Console
79 ******************************************************************************/
e075361b 80#ifdef CONSOLE_ENABLE
89470299 81static void Console_Task(void)
effa5914 82{
89470299 83 /* Device must be connected and configured for the task to run */
84 if (USB_DeviceState != DEVICE_STATE_Configured)
45ea1874 85 return;
89470299 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);
45ea1874 116 if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
117 Endpoint_SelectEndpoint(ep);
118 return;
119 }
e075361b 120
121 // fill empty bank
122 while (Endpoint_IsReadWriteAllowed())
123 Endpoint_Write_8(0);
124
89470299 125 // flash senchar packet
126 if (Endpoint_IsINReady()) {
127 Endpoint_ClearIN();
128 }
129
130 Endpoint_SelectEndpoint(ep);
effa5914 131}
e075361b 132#else
133static void Console_Task(void)
134{
135}
136#endif
effa5914 137
138
139/*******************************************************************************
140 * USB Events
141 ******************************************************************************/
42f6ff08 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*/
dd93d291 149void EVENT_USB_Device_Connect(void)
150{
151}
152
dd93d291 153void EVENT_USB_Device_Disconnect(void)
154{
155}
156
c8cfde01 157void EVENT_USB_Device_Reset(void)
158{
159}
160
161void EVENT_USB_Device_Suspend()
162{
f0c5f1b9 163#ifdef SLEEP_LED_ENABLE
164 sleep_led_enable();
165#endif
c8cfde01 166}
167
168void EVENT_USB_Device_WakeUp()
169{
afc3148e 170 suspend_wakeup_init();
42f6ff08 171
f0c5f1b9 172#ifdef SLEEP_LED_ENABLE
173 sleep_led_disable();
532e1004 174 // NOTE: converters may not accept this
f0c5f1b9 175 led_set(host_keyboard_leds());
532e1004 176#endif
c8cfde01 177}
178
89470299 179void EVENT_USB_Device_StartOfFrame(void)
180{
e075361b 181 Console_Task();
89470299 182}
183
dd93d291 184/** Event handler for the USB_ConfigurationChanged event.
185 * This is fired when the host sets the current configuration of the USB device after enumeration.
186 */
e9e4c0ed 187#if LUFA_VERSION_INTEGER < 0x120730
188 /* old API 120219 */
189 #define ENDPOINT_CONFIG(epnum, eptype, epdir, epsize, epbank) Endpoint_ConfigureEndpoint(epnum, eptype, epdir, epsize, epbank)
190#else
191 /* new API >= 120730 */
192 #define ENDPOINT_BANK_SINGLE 1
193 #define ENDPOINT_BANK_DOUBLE 2
194 #define ENDPOINT_CONFIG(epnum, eptype, epdir, epsize, epbank) Endpoint_ConfigureEndpoint((epdir) | (epnum) , eptype, epsize, epbank)
195#endif
dd93d291 196void EVENT_USB_Device_ConfigurationChanged(void)
197{
198 bool ConfigSuccess = true;
199
200 /* Setup Keyboard HID Report Endpoints */
e9e4c0ed 201 ConfigSuccess &= ENDPOINT_CONFIG(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
202 KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
dd93d291 203
f2ebac10 204#ifdef MOUSE_ENABLE
dd93d291 205 /* Setup Mouse HID Report Endpoint */
e9e4c0ed 206 ConfigSuccess &= ENDPOINT_CONFIG(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
207 MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE);
f2ebac10 208#endif
209
210#ifdef EXTRAKEY_ENABLE
211 /* Setup Extra HID Report Endpoint */
e9e4c0ed 212 ConfigSuccess &= ENDPOINT_CONFIG(EXTRAKEY_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
213 EXTRAKEY_EPSIZE, ENDPOINT_BANK_SINGLE);
f2ebac10 214#endif
3969ec09 215
e075361b 216#ifdef CONSOLE_ENABLE
a9a3610d 217 /* Setup Console HID Report Endpoints */
e9e4c0ed 218 ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
219 CONSOLE_EPSIZE, ENDPOINT_BANK_DOUBLE);
220 ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
221 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
e075361b 222#endif
daa4a423 223
224#ifdef NKRO_ENABLE
225 /* Setup NKRO HID Report Endpoints */
226 ConfigSuccess &= ENDPOINT_CONFIG(NKRO_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
227 NKRO_EPSIZE, ENDPOINT_BANK_SINGLE);
228#endif
dd93d291 229}
230
a9a3610d 231/*
232Appendix G: HID Request Support Requirements
233
234The following table enumerates the requests that need to be supported by various types of HID class devices.
235
236Device type GetReport SetReport GetIdle SetIdle GetProtocol SetProtocol
237------------------------------------------------------------------------------------------
238Boot Mouse Required Optional Optional Optional Required Required
239Non-Boot Mouse Required Optional Optional Optional Optional Optional
240Boot Keyboard Required Optional Required Required Required Required
241Non-Boot Keybrd Required Optional Required Required Optional Optional
242Other Device Required Optional Optional Optional Optional Optional
243*/
dd93d291 244/** Event handler for the USB_ControlRequest event.
245 * This is fired before passing along unhandled control requests to the library for processing internally.
246 */
247void EVENT_USB_Device_ControlRequest(void)
248{
3969ec09 249 uint8_t* ReportData = NULL;
250 uint8_t ReportSize = 0;
dd93d291 251
252 /* Handle HID Class specific requests */
253 switch (USB_ControlRequest.bRequest)
254 {
255 case HID_REQ_GetReport:
256 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
257 {
258 Endpoint_ClearSETUP();
259
3969ec09 260 // Interface
261 switch (USB_ControlRequest.wIndex) {
effa5914 262 case KEYBOARD_INTERFACE:
263 // TODO: test/check
dd93d291 264 ReportData = (uint8_t*)&keyboard_report_sent;
265 ReportSize = sizeof(keyboard_report_sent);
3969ec09 266 break;
dd93d291 267 }
268
269 /* Write the report data to the control endpoint */
270 Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
271 Endpoint_ClearOUT();
272 }
273
274 break;
275 case HID_REQ_SetReport:
276 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
277 {
dd93d291 278
3969ec09 279 // Interface
280 switch (USB_ControlRequest.wIndex) {
effa5914 281 case KEYBOARD_INTERFACE:
a112f361 282 Endpoint_ClearSETUP();
283
284 while (!(Endpoint_IsOUTReceived())) {
285 if (USB_DeviceState == DEVICE_STATE_Unattached)
286 return;
287 }
3969ec09 288 keyboard_led_stats = Endpoint_Read_8();
a112f361 289
290 Endpoint_ClearOUT();
291 Endpoint_ClearStatusStage();
f2ebac10 292 break;
3969ec09 293 }
dd93d291 294
a112f361 295 }
296
297 break;
298
299 case HID_REQ_GetProtocol:
300 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
301 {
302 Endpoint_ClearSETUP();
303 while (!(Endpoint_IsINReady()));
304 Endpoint_Write_8(protocol_report);
305 Endpoint_ClearIN();
306 Endpoint_ClearStatusStage();
307 }
308
309 break;
310 case HID_REQ_SetProtocol:
311 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
312 {
313 Endpoint_ClearSETUP();
314 Endpoint_ClearStatusStage();
315
316 protocol_report = ((USB_ControlRequest.wValue & 0xFF) != 0x00);
317 }
318
319 break;
320 case HID_REQ_SetIdle:
321 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
322 {
323 Endpoint_ClearSETUP();
324 Endpoint_ClearStatusStage();
325
326 idle_duration = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
327 }
328
329 break;
330 case HID_REQ_GetIdle:
331 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
332 {
333 Endpoint_ClearSETUP();
334 while (!(Endpoint_IsINReady()));
335 Endpoint_Write_8(idle_duration);
336 Endpoint_ClearIN();
dd93d291 337 Endpoint_ClearStatusStage();
338 }
339
340 break;
341 }
342}
343
dd93d291 344/*******************************************************************************
345 * Host driver
346 ******************************************************************************/
347static uint8_t keyboard_leds(void)
348{
349 return keyboard_led_stats;
350}
351
352static void send_keyboard(report_keyboard_t *report)
353{
45ea1874 354 uint8_t timeout = 0;
355
1eb67303 356 if (USB_DeviceState != DEVICE_STATE_Configured)
357 return;
358
dd93d291 359 /* Select the Keyboard Report Endpoint */
daa4a423 360#ifdef NKRO_ENABLE
361 if (keyboard_nkro) {
362 Endpoint_SelectEndpoint(NKRO_IN_EPNUM);
363 }
364 else
365#endif
366 {
367 Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
368 }
dd93d291 369
370 /* Check if Keyboard Endpoint Ready for Read/Write */
45ea1874 371 while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
7350b7c6 372
373 /* Write Keyboard Report Data */
daa4a423 374#ifdef NKRO_ENABLE
375 if (keyboard_nkro) {
376 Endpoint_Write_Stream_LE(report, NKRO_EPSIZE, NULL);
377 }
378 else
379#endif
380 {
381 /* boot mode */
382 Endpoint_Write_Stream_LE(report, KEYBOARD_EPSIZE, NULL);
383 }
7350b7c6 384
385 /* Finalize the stream transfer to send the last packet */
386 Endpoint_ClearIN();
dd93d291 387
dd93d291 388 keyboard_report_sent = *report;
389}
390
391static void send_mouse(report_mouse_t *report)
392{
f2ebac10 393#ifdef MOUSE_ENABLE
45ea1874 394 uint8_t timeout = 0;
395
1eb67303 396 if (USB_DeviceState != DEVICE_STATE_Configured)
397 return;
398
dd93d291 399 /* Select the Mouse Report Endpoint */
400 Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
401
402 /* Check if Mouse Endpoint Ready for Read/Write */
45ea1874 403 while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
dd93d291 404
7350b7c6 405 /* Write Mouse Report Data */
406 Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
407
408 /* Finalize the stream transfer to send the last packet */
409 Endpoint_ClearIN();
f2ebac10 410#endif
dd93d291 411}
412
413static void send_system(uint16_t data)
414{
45ea1874 415 uint8_t timeout = 0;
416
1eb67303 417 if (USB_DeviceState != DEVICE_STATE_Configured)
418 return;
419
a112f361 420 report_extra_t r = {
421 .report_id = REPORT_ID_SYSTEM,
422 .usage = data
423 };
e075361b 424 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
45ea1874 425 while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
7350b7c6 426 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
427 Endpoint_ClearIN();
dd93d291 428}
429
430static void send_consumer(uint16_t data)
431{
45ea1874 432 uint8_t timeout = 0;
433
1eb67303 434 if (USB_DeviceState != DEVICE_STATE_Configured)
435 return;
436
a112f361 437 report_extra_t r = {
438 .report_id = REPORT_ID_CONSUMER,
439 .usage = data
440 };
e075361b 441 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
45ea1874 442 while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
7350b7c6 443 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
444 Endpoint_ClearIN();
dd93d291 445}
3969ec09 446
447
448/*******************************************************************************
449 * sendchar
450 ******************************************************************************/
e075361b 451#ifdef CONSOLE_ENABLE
452#define SEND_TIMEOUT 5
3969ec09 453int8_t sendchar(uint8_t c)
454{
45ea1874 455 // Not wait once timeouted.
456 // Because sendchar() is called so many times, waiting each call causes big lag.
457 static bool timeouted = false;
458
3969ec09 459 if (USB_DeviceState != DEVICE_STATE_Configured)
45ea1874 460 return -1;
3969ec09 461
e075361b 462 uint8_t ep = Endpoint_GetCurrentEndpoint();
3d81d522 463 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
45ea1874 464 if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
465 Endpoint_SelectEndpoint(ep);
466 return -1;
467 }
468
469 if (timeouted && !Endpoint_IsReadWriteAllowed()) {
470 Endpoint_SelectEndpoint(ep);
471 return - 1;
472 }
473
474 timeouted = false;
3969ec09 475
89470299 476 uint8_t timeout = SEND_TIMEOUT;
3969ec09 477 uint16_t prevFN = USB_Device_GetFrameNumber();
89470299 478 while (!Endpoint_IsReadWriteAllowed()) {
3969ec09 479 switch (USB_DeviceState) {
480 case DEVICE_STATE_Unattached:
481 case DEVICE_STATE_Suspended:
482 return -1;
483 }
e075361b 484 if (Endpoint_IsStalled()) {
485 Endpoint_SelectEndpoint(ep);
3969ec09 486 return -1;
e075361b 487 }
3969ec09 488 if (prevFN != USB_Device_GetFrameNumber()) {
e075361b 489 if (!(timeout--)) {
45ea1874 490 timeouted = true;
e075361b 491 Endpoint_SelectEndpoint(ep);
3969ec09 492 return -1;
e075361b 493 }
3969ec09 494 prevFN = USB_Device_GetFrameNumber();
495 }
496 }
497
498 Endpoint_Write_8(c);
499
89470299 500 // send when bank is full
3969ec09 501 if (!Endpoint_IsReadWriteAllowed())
502 Endpoint_ClearIN();
503
e075361b 504 Endpoint_SelectEndpoint(ep);
505 return 0;
506}
507#else
508int8_t sendchar(uint8_t c)
509{
3969ec09 510 return 0;
511}
e075361b 512#endif
c5060ea8 513
514
515/*******************************************************************************
516 * main
517 ******************************************************************************/
518static void SetupHardware(void)
519{
520 /* Disable watchdog if enabled by bootloader/fuses */
521 MCUSR &= ~(1 << WDRF);
522 wdt_disable();
523
524 /* Disable clock division */
525 clock_prescale_set(clock_div_1);
526
527 // Leonardo needs. Without this USB device is not recognized.
528 USB_Disable();
529
530 USB_Init();
531
532 // for Console_Task
533 USB_Device_EnableSOFEvents();
7d692c49 534 print_set_sendchar(sendchar);
c5060ea8 535}
536
537int main(void) __attribute__ ((weak));
538int main(void)
539{
540 SetupHardware();
7d692c49 541 sei();
9d40be19 542
543 /* wait for USB startup & debug output */
544 while (USB_DeviceState != DEVICE_STATE_Configured) {
d267ee2a 545#if defined(INTERRUPT_CONTROL_ENDPOINT)
9d40be19 546 ;
547#else
548 USB_USBTask();
d267ee2a 549#endif
9d40be19 550 }
7d692c49 551 print("USB configured.\n");
552
9d40be19 553 /* init modules */
16a583d7 554 keyboard_init();
555 host_set_driver(&lufa_driver);
f0c5f1b9 556#ifdef SLEEP_LED_ENABLE
557 sleep_led_init();
558#endif
c5060ea8 559
7d692c49 560 print("Keyboard start.\n");
c5060ea8 561 while (1) {
c8cfde01 562 while (USB_DeviceState == DEVICE_STATE_Suspended) {
afc3148e 563 suspend_power_down();
564 if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) {
c8cfde01 565 USB_Device_SendRemoteWakeup();
c8cfde01 566 }
567 }
568
4ae979f6 569 keyboard_task();
c5060ea8 570
571#if !defined(INTERRUPT_CONTROL_ENDPOINT)
572 USB_USBTask();
573#endif
574 }
575}
Imprint / Impressum