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 LUFA_DEBUG_SUART
56 #include "avr/suart.h"
60 #include "descriptor.h"
67 uint8_t keyboard_idle = 0;
68 /* 0: Boot Protocol, 1: Report Protocol(default) */
69 uint8_t keyboard_protocol = 1;
70 static uint8_t keyboard_led_stats = 0;
72 static report_keyboard_t keyboard_report_sent;
76 static uint8_t keyboard_leds(void);
77 static void send_keyboard(report_keyboard_t *report);
78 static void send_mouse(report_mouse_t *report);
79 static void send_system(uint16_t data);
80 static void send_consumer(uint16_t data);
81 host_driver_t lufa_driver = {
90 /*******************************************************************************
92 ******************************************************************************/
94 #define SENDBUF_SIZE 256
95 static uint8_t sbuf[SENDBUF_SIZE];
96 static ringbuf_t sendbuf = {
100 .size_mask = SENDBUF_SIZE - 1
103 // TODO: Around 2500ms delay often works anyhoo but proper startup would be better
104 // 1000ms delay of hid_listen affects this probably
105 /* wait for Console startup */
106 static bool console_is_ready(void)
108 static bool hid_listen_ready = false;
109 if (!hid_listen_ready) {
110 if (timer_read32() < 2500)
112 hid_listen_ready = true;
117 static bool console_putc(uint8_t c)
119 if (!console_is_ready())
122 // return immediately if called while interrupt
123 if (!(SREG & (1<<SREG_I)))
126 if (USB_DeviceState != DEVICE_STATE_Configured)
129 uint8_t ep = Endpoint_GetCurrentEndpoint();
131 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
132 if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
133 goto EXIT_RESTORE_EP;
136 // write from buffer to endpoint bank
137 while (!ringbuf_is_empty(&sendbuf) && Endpoint_IsReadWriteAllowed()) {
138 Endpoint_Write_8(ringbuf_get(&sendbuf));
140 // clear bank when it is full
141 if (!Endpoint_IsReadWriteAllowed() && Endpoint_IsINReady()) {
146 // write c to bank directly if there is no others in buffer
147 if (ringbuf_is_empty(&sendbuf) && Endpoint_IsReadWriteAllowed()) {
149 Endpoint_SelectEndpoint(ep);
154 Endpoint_SelectEndpoint(ep);
156 return ringbuf_put(&sendbuf, c);
159 static void console_flush(void)
161 if (!console_is_ready())
164 if (USB_DeviceState != DEVICE_STATE_Configured)
167 uint8_t ep = Endpoint_GetCurrentEndpoint();
169 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
170 if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
171 Endpoint_SelectEndpoint(ep);
175 // write from buffer to endpoint bank
176 while (!ringbuf_is_empty(&sendbuf) && Endpoint_IsReadWriteAllowed()) {
177 Endpoint_Write_8(ringbuf_get(&sendbuf));
179 // clear bank when it is full
180 if (!Endpoint_IsReadWriteAllowed() && Endpoint_IsINReady()) {
185 // clear bank when there are chars in bank
186 if (Endpoint_BytesInEndpoint() && Endpoint_IsINReady()) {
187 // Windows needs to fill packet with 0
188 while (Endpoint_IsReadWriteAllowed()) {
194 Endpoint_SelectEndpoint(ep);
197 static void console_task(void)
199 static uint16_t fn = 0;
200 if (fn == USB_Device_GetFrameNumber()) {
203 fn = USB_Device_GetFrameNumber();
209 /*******************************************************************************
211 ******************************************************************************/
213 * Event Order of Plug in:
214 * 0) EVENT_USB_Device_Connect
215 * 1) EVENT_USB_Device_Suspend
216 * 2) EVENT_USB_Device_Reset
217 * 3) EVENT_USB_Device_Wake
219 void EVENT_USB_Device_Connect(void)
222 /* For battery powered device */
223 if (!USB_IsInitialized) {
226 USB_Device_EnableSOFEvents();
230 void EVENT_USB_Device_Disconnect(void)
233 /* For battery powered device */
234 USB_IsInitialized = false;
235 /* TODO: This doesn't work. After several plug in/outs can not be enumerated.
236 if (USB_IsInitialized) {
237 USB_Disable(); // Disable all interrupts
238 USB_Controller_Enable();
239 USB_INT_Enable(USB_INT_VBUSTI);
244 void EVENT_USB_Device_Reset(void)
251 void EVENT_USB_Device_Suspend()
256 hook_usb_suspend_entry();
259 void EVENT_USB_Device_WakeUp()
268 void EVENT_USB_Device_StartOfFrame(void)
272 /** Event handler for the USB_ConfigurationChanged event.
273 * This is fired when the host sets the current configuration of the USB device after enumeration.
275 * ATMega32u2 supports dual bank(ping-pong mode) only on endpoint 3 and 4,
276 * it is safe to use singl bank for all endpoints.
278 void EVENT_USB_Device_ConfigurationChanged(void)
283 bool ConfigSuccess = true;
285 /* Setup Keyboard HID Report Endpoints */
286 ConfigSuccess &= ENDPOINT_CONFIG(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
287 KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
290 /* Setup Mouse HID Report Endpoint */
291 ConfigSuccess &= ENDPOINT_CONFIG(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
292 MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE);
295 #ifdef EXTRAKEY_ENABLE
296 /* Setup Extra HID Report Endpoint */
297 ConfigSuccess &= ENDPOINT_CONFIG(EXTRAKEY_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
298 EXTRAKEY_EPSIZE, ENDPOINT_BANK_SINGLE);
301 #ifdef CONSOLE_ENABLE
302 /* Setup Console HID Report Endpoints */
303 ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
304 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
306 ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
307 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
312 /* Setup NKRO HID Report Endpoints */
313 ConfigSuccess &= ENDPOINT_CONFIG(NKRO_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
314 NKRO_EPSIZE, ENDPOINT_BANK_SINGLE);
319 Appendix G: HID Request Support Requirements
321 The following table enumerates the requests that need to be supported by various types of HID class devices.
323 Device type GetReport SetReport GetIdle SetIdle GetProtocol SetProtocol
324 ------------------------------------------------------------------------------------------
325 Boot Mouse Required Optional Optional Optional Required Required
326 Non-Boot Mouse Required Optional Optional Optional Optional Optional
327 Boot Keyboard Required Optional Required Required Required Required
328 Non-Boot Keybrd Required Optional Required Required Optional Optional
329 Other Device Required Optional Optional Optional Optional Optional
331 /** Event handler for the USB_ControlRequest event.
332 * This is fired before passing along unhandled control requests to the library for processing internally.
334 void EVENT_USB_Device_ControlRequest(void)
336 uint8_t* ReportData = NULL;
337 uint8_t ReportSize = 0;
339 /* Handle HID Class specific requests */
340 switch (USB_ControlRequest.bRequest)
342 case HID_REQ_GetReport:
343 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
345 Endpoint_ClearSETUP();
348 switch (USB_ControlRequest.wIndex) {
349 case KEYBOARD_INTERFACE:
351 ReportData = (uint8_t*)&keyboard_report_sent;
352 ReportSize = sizeof(keyboard_report_sent);
356 /* Write the report data to the control endpoint */
357 Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
360 xprintf("[r%d]", USB_ControlRequest.wIndex);
365 case HID_REQ_SetReport:
366 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
370 switch (USB_ControlRequest.wIndex) {
371 case KEYBOARD_INTERFACE:
375 Endpoint_ClearSETUP();
377 while (!(Endpoint_IsOUTReceived())) {
378 if (USB_DeviceState == DEVICE_STATE_Unattached)
381 keyboard_led_stats = Endpoint_Read_8();
384 Endpoint_ClearStatusStage();
386 xprintf("[L%d]", USB_ControlRequest.wIndex);
395 case HID_REQ_GetProtocol:
396 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
398 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
399 Endpoint_ClearSETUP();
400 while (!(Endpoint_IsINReady()));
401 Endpoint_Write_8(keyboard_protocol);
403 Endpoint_ClearStatusStage();
411 case HID_REQ_SetProtocol:
412 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
414 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
415 Endpoint_ClearSETUP();
416 Endpoint_ClearStatusStage();
418 keyboard_protocol = (USB_ControlRequest.wValue & 0xFF);
427 case HID_REQ_SetIdle:
428 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
430 Endpoint_ClearSETUP();
431 Endpoint_ClearStatusStage();
433 keyboard_idle = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
435 xprintf("[I%d]%d", USB_ControlRequest.wIndex, (USB_ControlRequest.wValue & 0xFF00) >> 8);
440 case HID_REQ_GetIdle:
441 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
443 Endpoint_ClearSETUP();
444 while (!(Endpoint_IsINReady()));
445 Endpoint_Write_8(keyboard_idle);
447 Endpoint_ClearStatusStage();
457 /*******************************************************************************
459 ******************************************************************************/
460 static uint8_t keyboard_leds(void)
462 return keyboard_led_stats;
465 static void send_keyboard(report_keyboard_t *report)
467 uint8_t timeout = 128;
469 if (USB_DeviceState != DEVICE_STATE_Configured)
472 /* Select the Keyboard Report Endpoint */
474 if (keyboard_protocol && keyboard_nkro) {
475 /* Report protocol - NKRO */
476 Endpoint_SelectEndpoint(NKRO_IN_EPNUM);
478 /* Check if write ready for a polling interval around 1ms */
479 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(8);
480 if (!Endpoint_IsReadWriteAllowed()) return;
482 /* Write Keyboard Report Data */
483 Endpoint_Write_Stream_LE(report, NKRO_EPSIZE, NULL);
489 Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
491 /* Check if write ready for a polling interval around 10ms */
492 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(80);
493 if (!Endpoint_IsReadWriteAllowed()) return;
495 /* Write Keyboard Report Data */
496 Endpoint_Write_Stream_LE(report, KEYBOARD_EPSIZE, NULL);
499 /* Finalize the stream transfer to send the last packet */
502 keyboard_report_sent = *report;
505 static void send_mouse(report_mouse_t *report)
508 uint8_t timeout = 255;
510 if (USB_DeviceState != DEVICE_STATE_Configured)
513 /* Select the Mouse Report Endpoint */
514 Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
516 /* Check if write ready for a polling interval around 10ms */
517 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
518 if (!Endpoint_IsReadWriteAllowed()) return;
520 /* Write Mouse Report Data */
521 Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
523 /* Finalize the stream transfer to send the last packet */
528 static void send_system(uint16_t data)
530 #ifdef EXTRAKEY_ENABLE
531 uint8_t timeout = 255;
533 if (USB_DeviceState != DEVICE_STATE_Configured)
537 .report_id = REPORT_ID_SYSTEM,
540 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
542 /* Check if write ready for a polling interval around 10ms */
543 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
544 if (!Endpoint_IsReadWriteAllowed()) return;
546 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
551 static void send_consumer(uint16_t data)
553 #ifdef EXTRAKEY_ENABLE
554 uint8_t timeout = 255;
556 if (USB_DeviceState != DEVICE_STATE_Configured)
560 .report_id = REPORT_ID_CONSUMER,
563 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
565 /* Check if write ready for a polling interval around 10ms */
566 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
567 if (!Endpoint_IsReadWriteAllowed()) return;
569 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
575 /*******************************************************************************
577 ******************************************************************************/
578 #ifdef CONSOLE_ENABLE
579 int8_t sendchar(uint8_t c)
581 #ifdef LUFA_DEBUG_SUART
585 bool r = console_putc(c);
589 int8_t sendchar(uint8_t c)
591 #ifdef LUFA_DEBUG_SUART
599 /*******************************************************************************
601 ******************************************************************************/
602 static void setup_mcu(void)
604 /* Disable watchdog if enabled by bootloader/fuses */
605 MCUSR &= ~(1 << WDRF);
608 /* Disable clock division */
609 clock_prescale_set(clock_div_1);
612 static void setup_usb(void)
614 // Leonardo needs. Without this USB device is not recognized.
619 USB_Device_EnableSOFEvents();
622 int main(void) __attribute__ ((weak));
627 #ifdef LUFA_DEBUG_SUART
628 SUART_OUT_DDR |= (1<<SUART_OUT_BIT);
629 SUART_OUT_PORT |= (1<<SUART_OUT_BIT);
632 // setup sendchar: DO NOT USE print functions before this line
633 print_set_sendchar(sendchar);
634 host_set_driver(&lufa_driver);
636 print("Keyboard init.\n");
640 #ifdef SLEEP_LED_ENABLE
646 /* wait for USB startup */
647 while (USB_DeviceState != DEVICE_STATE_Configured) {
648 #if defined(INTERRUPT_CONTROL_ENDPOINT)
659 print("\nKeyboard start.\n");
661 while (USB_DeviceState == DEVICE_STATE_Suspended) {
665 hook_usb_suspend_loop();
670 #ifdef CONSOLE_ENABLE
674 #if !defined(INTERRUPT_CONTROL_ENDPOINT)
682 __attribute__((weak))
683 void hook_early_init(void) {}
685 __attribute__((weak))
686 void hook_late_init(void) {}
688 static uint8_t _led_stats = 0;
689 __attribute__((weak))
690 void hook_usb_suspend_entry(void)
692 // Turn LED off to save power
693 // Set 0 with putting aside status before suspend and restore
694 // it after wakeup, then LED is updated at keyboard_task() in main loop
695 _led_stats = keyboard_led_stats;
696 keyboard_led_stats = 0;
697 led_set(keyboard_led_stats);
701 #ifdef SLEEP_LED_ENABLE
706 __attribute__((weak))
707 void hook_usb_suspend_loop(void)
709 suspend_power_down();
710 if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) {
711 USB_Device_SendRemoteWakeup();
715 __attribute__((weak))
716 void hook_usb_wakeup(void)
718 suspend_wakeup_init();
719 #ifdef SLEEP_LED_ENABLE
723 // Restore LED status
724 // BIOS/grub won't recognize/enumerate if led_set() takes long(around 40ms?)
725 // Converters fall into the case and miss wakeup event(timeout to reply?) in the end.
726 //led_set(host_keyboard_leds());
727 // Instead, restore stats and update at keyboard_task() in main loop
728 keyboard_led_stats = _led_stats;