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