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
10 Copyright (C) Dean Camera, 2012.
12 dean [at] fourwalledcubicle [dot] com
17 Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
18 Copyright 2010 Denver Gingerich (denver [at] ossguy [dot] com)
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.
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
41 #include "host_driver.h"
48 #ifdef SLEEP_LED_ENABLE
49 #include "sleep_led.h"
55 #ifdef TMK_LUFA_DEBUG_SUART
56 #include "avr/suart.h"
59 #ifdef TMK_LUFA_DEBUG_UART
64 #include "descriptor.h"
68 //#define TMK_LUFA_DEBUG
71 uint8_t keyboard_idle = 0;
72 /* 0: Boot Protocol, 1: Report Protocol(default) */
73 uint8_t keyboard_protocol = 1;
74 static uint8_t keyboard_led_stats = 0;
76 static report_keyboard_t keyboard_report_sent;
80 static uint8_t keyboard_leds(void);
81 static void send_keyboard(report_keyboard_t *report);
82 static void send_mouse(report_mouse_t *report);
83 static void send_system(uint16_t data);
84 static void send_consumer(uint16_t data);
85 host_driver_t lufa_driver = {
94 /*******************************************************************************
96 ******************************************************************************/
98 #define SENDBUF_SIZE 256
99 static uint8_t sbuf[SENDBUF_SIZE];
100 static ringbuf_t sendbuf = {
104 .size_mask = SENDBUF_SIZE - 1
107 // TODO: Around 2500ms delay often works anyhoo but proper startup would be better
108 // 1000ms delay of hid_listen affects this probably
109 /* wait for Console startup */
110 static bool console_is_ready(void)
112 static bool hid_listen_ready = false;
113 if (!hid_listen_ready) {
114 if (timer_read32() < 2500)
116 hid_listen_ready = true;
121 static bool console_putc(uint8_t c)
123 // return immediately if called while interrupt
124 if (!(SREG & (1<<SREG_I)))
127 if (USB_DeviceState != DEVICE_STATE_Configured && !ringbuf_is_full(&sendbuf))
130 if (!console_is_ready() && !ringbuf_is_full(&sendbuf))
133 /* Data lost considerations:
134 * 1. When buffer is full at early satage of startup, we will have to start sending
135 * before console_is_ready() returns true. Data can be lost even if sending data
136 * seems to be successful on USB. hid_listen on host is not ready perhaps?
137 * Sometime first few packets are lost when buffer is full at startup.
138 * 2. When buffer is full and USB pipe is not ready, new coming data will be lost.
139 * 3. console_task() cannot send data in buffer while main loop is blocked.
142 const uint8_t CONSOLE_TIMOUT = 5; // 1 is too small, 2 seems to be enough for Linux
143 static uint8_t timeout = CONSOLE_TIMOUT;
144 uint16_t prev = timer_read();
147 uint8_t ep = Endpoint_GetCurrentEndpoint();
148 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
151 if (Endpoint_IsStalled() || !Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
152 goto EXIT_RESTORE_EP;
155 // write from buffer to endpoint bank
156 while (!ringbuf_is_empty(&sendbuf) && Endpoint_IsReadWriteAllowed()) {
157 Endpoint_Write_8(ringbuf_get(&sendbuf));
159 // clear bank when it is full
160 if (!Endpoint_IsReadWriteAllowed() && Endpoint_IsINReady()) {
162 timeout = CONSOLE_TIMOUT; // re-enable retry only when host can receive
166 // write c to bank directly if there is no others in buffer
167 if (ringbuf_is_empty(&sendbuf) && Endpoint_IsReadWriteAllowed()) {
172 // clear bank when there are chars in bank
173 if (Endpoint_BytesInEndpoint() && Endpoint_IsINReady()) {
174 // Windows needs to fill packet with 0
175 while (Endpoint_IsReadWriteAllowed()) {
179 timeout = CONSOLE_TIMOUT; // re-enable retry only when host can receive
183 Endpoint_SelectEndpoint(ep);
187 /* retry when buffer is full.
188 * once timeout this is disabled until host receives actually,
189 * otherwise this will block or make main loop execution sluggish.
191 if (ringbuf_is_full(&sendbuf) && timeout) {
192 uint16_t curr = timer_read();
201 Endpoint_SelectEndpoint(ep);
203 return ringbuf_put(&sendbuf, c);
206 static void console_flush(void)
208 if (!console_is_ready())
211 if (USB_DeviceState != DEVICE_STATE_Configured)
214 uint8_t ep = Endpoint_GetCurrentEndpoint();
216 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
217 if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
218 Endpoint_SelectEndpoint(ep);
222 // write from buffer to endpoint bank
223 while (!ringbuf_is_empty(&sendbuf) && Endpoint_IsReadWriteAllowed()) {
224 Endpoint_Write_8(ringbuf_get(&sendbuf));
226 // clear bank when it is full
227 if (!Endpoint_IsReadWriteAllowed() && Endpoint_IsINReady()) {
232 // clear bank when there are chars in bank
233 if (Endpoint_BytesInEndpoint() && Endpoint_IsINReady()) {
234 // Windows needs to fill packet with 0
235 while (Endpoint_IsReadWriteAllowed()) {
241 Endpoint_SelectEndpoint(ep);
244 static void console_task(void)
246 static uint16_t fn = 0;
247 if (fn == USB_Device_GetFrameNumber()) {
250 fn = USB_Device_GetFrameNumber();
256 /*******************************************************************************
258 ******************************************************************************/
260 * Event Order of Plug in:
261 * 0) EVENT_USB_Device_Connect
262 * 1) EVENT_USB_Device_Suspend
263 * 2) EVENT_USB_Device_Reset
264 * 3) EVENT_USB_Device_Wake
266 void EVENT_USB_Device_Connect(void)
268 #ifdef TMK_LUFA_DEBUG
271 /* For battery powered device */
272 if (!USB_IsInitialized) {
278 void EVENT_USB_Device_Disconnect(void)
280 #ifdef TMK_LUFA_DEBUG
283 /* For battery powered device */
284 USB_IsInitialized = false;
285 /* TODO: This doesn't work. After several plug in/outs can not be enumerated.
286 if (USB_IsInitialized) {
287 USB_Disable(); // Disable all interrupts
288 USB_Controller_Enable();
289 USB_INT_Enable(USB_INT_VBUSTI);
294 void EVENT_USB_Device_Reset(void)
296 #ifdef TMK_LUFA_DEBUG
301 void EVENT_USB_Device_Suspend()
303 #ifdef TMK_LUFA_DEBUG
306 hook_usb_suspend_entry();
309 void EVENT_USB_Device_WakeUp()
311 #ifdef TMK_LUFA_DEBUG
317 /** Event handler for the USB_ConfigurationChanged event.
318 * This is fired when the host sets the current configuration of the USB device after enumeration.
320 * ATMega32u2 supports dual bank(ping-pong mode) only on endpoint 3 and 4,
321 * it is safe to use singl bank for all endpoints.
323 void EVENT_USB_Device_ConfigurationChanged(void)
325 #ifdef TMK_LUFA_DEBUG
328 bool ConfigSuccess = true;
330 /* Setup Keyboard HID Report Endpoints */
331 ConfigSuccess &= ENDPOINT_CONFIG(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
332 KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
335 /* Setup Mouse HID Report Endpoint */
336 ConfigSuccess &= ENDPOINT_CONFIG(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
337 MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE);
340 #ifdef EXTRAKEY_ENABLE
341 /* Setup Extra HID Report Endpoint */
342 ConfigSuccess &= ENDPOINT_CONFIG(EXTRAKEY_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
343 EXTRAKEY_EPSIZE, ENDPOINT_BANK_SINGLE);
346 #ifdef CONSOLE_ENABLE
347 /* Setup Console HID Report Endpoints */
348 ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
349 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
351 ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
352 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
357 /* Setup NKRO HID Report Endpoints */
358 ConfigSuccess &= ENDPOINT_CONFIG(NKRO_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
359 NKRO_EPSIZE, ENDPOINT_BANK_SINGLE);
364 Appendix G: HID Request Support Requirements
366 The following table enumerates the requests that need to be supported by various types of HID class devices.
368 Device type GetReport SetReport GetIdle SetIdle GetProtocol SetProtocol
369 ------------------------------------------------------------------------------------------
370 Boot Mouse Required Optional Optional Optional Required Required
371 Non-Boot Mouse Required Optional Optional Optional Optional Optional
372 Boot Keyboard Required Optional Required Required Required Required
373 Non-Boot Keybrd Required Optional Required Required Optional Optional
374 Other Device Required Optional Optional Optional Optional Optional
376 /** Event handler for the USB_ControlRequest event.
377 * This is fired before passing along unhandled control requests to the library for processing internally.
379 void EVENT_USB_Device_ControlRequest(void)
381 uint8_t* ReportData = NULL;
382 uint8_t ReportSize = 0;
384 /* Handle HID Class specific requests */
385 switch (USB_ControlRequest.bRequest)
387 case HID_REQ_GetReport:
388 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
390 Endpoint_ClearSETUP();
393 switch (USB_ControlRequest.wIndex) {
394 case KEYBOARD_INTERFACE:
396 ReportData = (uint8_t*)&keyboard_report_sent;
397 ReportSize = sizeof(keyboard_report_sent);
401 /* Write the report data to the control endpoint */
402 Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
404 #ifdef TMK_LUFA_DEBUG
405 xprintf("[r%d]", USB_ControlRequest.wIndex);
410 case HID_REQ_SetReport:
411 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
415 switch (USB_ControlRequest.wIndex) {
416 case KEYBOARD_INTERFACE:
420 Endpoint_ClearSETUP();
422 while (!(Endpoint_IsOUTReceived())) {
423 if (USB_DeviceState == DEVICE_STATE_Unattached)
426 keyboard_led_stats = Endpoint_Read_8();
429 Endpoint_ClearStatusStage();
430 #ifdef TMK_LUFA_DEBUG
431 xprintf("[L%d]", USB_ControlRequest.wIndex);
440 case HID_REQ_GetProtocol:
441 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
443 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
444 Endpoint_ClearSETUP();
445 while (!(Endpoint_IsINReady()));
446 Endpoint_Write_8(keyboard_protocol);
448 Endpoint_ClearStatusStage();
449 #ifdef TMK_LUFA_DEBUG
456 case HID_REQ_SetProtocol:
457 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
459 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
460 Endpoint_ClearSETUP();
461 Endpoint_ClearStatusStage();
463 keyboard_protocol = (USB_ControlRequest.wValue & 0xFF);
465 #ifdef TMK_LUFA_DEBUG
472 case HID_REQ_SetIdle:
473 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
475 Endpoint_ClearSETUP();
476 Endpoint_ClearStatusStage();
478 keyboard_idle = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
479 #ifdef TMK_LUFA_DEBUG
480 xprintf("[I%d]%d", USB_ControlRequest.wIndex, (USB_ControlRequest.wValue & 0xFF00) >> 8);
485 case HID_REQ_GetIdle:
486 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
488 Endpoint_ClearSETUP();
489 while (!(Endpoint_IsINReady()));
490 Endpoint_Write_8(keyboard_idle);
492 Endpoint_ClearStatusStage();
493 #ifdef TMK_LUFA_DEBUG
502 /*******************************************************************************
504 ******************************************************************************/
505 static uint8_t keyboard_leds(void)
507 return keyboard_led_stats;
510 static void send_keyboard(report_keyboard_t *report)
512 uint8_t timeout = 128;
514 if (USB_DeviceState != DEVICE_STATE_Configured)
517 /* Select the Keyboard Report Endpoint */
519 if (keyboard_protocol && keyboard_nkro) {
520 /* Report protocol - NKRO */
521 Endpoint_SelectEndpoint(NKRO_IN_EPNUM);
523 /* Check if write ready for a polling interval around 1ms */
524 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(8);
525 if (!Endpoint_IsReadWriteAllowed()) return;
527 /* Write Keyboard Report Data */
528 Endpoint_Write_Stream_LE(report, NKRO_EPSIZE, NULL);
534 Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
536 /* Check if write ready for a polling interval around 10ms */
537 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(80);
538 if (!Endpoint_IsReadWriteAllowed()) return;
540 /* Write Keyboard Report Data */
541 Endpoint_Write_Stream_LE(report, KEYBOARD_EPSIZE, NULL);
544 /* Finalize the stream transfer to send the last packet */
547 keyboard_report_sent = *report;
550 static void send_mouse(report_mouse_t *report)
553 uint8_t timeout = 255;
555 if (USB_DeviceState != DEVICE_STATE_Configured)
558 /* Select the Mouse Report Endpoint */
559 Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
561 /* Check if write ready for a polling interval around 10ms */
562 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
563 if (!Endpoint_IsReadWriteAllowed()) return;
565 /* Write Mouse Report Data */
566 Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
568 /* Finalize the stream transfer to send the last packet */
573 static void send_system(uint16_t data)
575 #ifdef EXTRAKEY_ENABLE
576 uint8_t timeout = 255;
578 if (USB_DeviceState != DEVICE_STATE_Configured)
582 .report_id = REPORT_ID_SYSTEM,
583 .usage = data - SYSTEM_POWER_DOWN + 1
585 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
587 /* Check if write ready for a polling interval around 10ms */
588 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
589 if (!Endpoint_IsReadWriteAllowed()) return;
591 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
596 static void send_consumer(uint16_t data)
598 #ifdef EXTRAKEY_ENABLE
599 uint8_t timeout = 255;
601 if (USB_DeviceState != DEVICE_STATE_Configured)
605 .report_id = REPORT_ID_CONSUMER,
608 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
610 /* Check if write ready for a polling interval around 10ms */
611 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
612 if (!Endpoint_IsReadWriteAllowed()) return;
614 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
620 /*******************************************************************************
622 ******************************************************************************/
623 int8_t sendchar(uint8_t c)
625 #ifdef TMK_LUFA_DEBUG_SUART
629 #ifdef TMK_LUFA_DEBUG_UART
633 #ifdef CONSOLE_ENABLE
641 /*******************************************************************************
643 ******************************************************************************/
644 static void setup_mcu(void)
646 /* Disable watchdog if enabled by bootloader/fuses */
647 MCUSR &= ~(1 << WDRF);
650 /* Disable clock division */
651 clock_prescale_set(clock_div_1);
654 static void setup_usb(void)
656 // Leonardo needs. Without this USB device is not recognized.
662 int main(void) __attribute__ ((weak));
667 #ifdef TMK_LUFA_DEBUG_SUART
668 SUART_OUT_DDR |= (1<<SUART_OUT_BIT);
669 SUART_OUT_PORT |= (1<<SUART_OUT_BIT);
672 #ifdef TMK_LUFA_DEBUG_UART
676 // setup sendchar: DO NOT USE print functions before this line
677 print_set_sendchar(sendchar);
678 host_set_driver(&lufa_driver);
680 print("\n\nTMK:" STR(TMK_VERSION) "/LUFA\n\n");
684 #ifdef SLEEP_LED_ENABLE
692 #ifndef NO_USB_STARTUP_WAIT_LOOP
693 /* wait for USB startup */
694 while (USB_DeviceState != DEVICE_STATE_Configured) {
695 #if defined(INTERRUPT_CONTROL_ENDPOINT)
700 hook_usb_startup_wait_loop();
702 print("\nUSB configured.\n");
707 print("\nKeyboard start.\n");
709 #ifndef NO_USB_SUSPEND_LOOP
710 while (USB_DeviceState == DEVICE_STATE_Suspended) {
711 hook_usb_suspend_loop();
717 #ifdef CONSOLE_ENABLE
721 #if !defined(INTERRUPT_CONTROL_ENDPOINT)
729 __attribute__((weak))
730 void hook_early_init(void) {}
732 __attribute__((weak))
733 void hook_late_init(void) {}
735 static uint8_t _led_stats = 0;
736 __attribute__((weak))
737 void hook_usb_suspend_entry(void)
739 // Turn off LED to save power and keep its status to resotre it later.
740 // LED status will be updated by keyboard_task() in main loop hopefully.
741 _led_stats = keyboard_led_stats;
742 keyboard_led_stats = 0;
744 // Calling long task here can prevent USB state transition
748 #ifdef SLEEP_LED_ENABLE
753 __attribute__((weak))
754 void hook_usb_suspend_loop(void)
756 #ifndef TMK_LUFA_DEBUG_UART
757 // This corrupts debug print when suspend
758 suspend_power_down();
760 if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) {
761 USB_Device_SendRemoteWakeup();
765 __attribute__((weak))
766 void hook_usb_wakeup(void)
768 suspend_wakeup_init();
769 #ifdef SLEEP_LED_ENABLE
773 // Restore LED status and update at keyboard_task() in main loop
774 keyboard_led_stats = _led_stats;
776 // Calling long task here can prevent USB state transition
779 __attribute__((weak))
780 void hook_usb_startup_wait_loop(void) {}