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"
59 #ifdef LUFA_DEBUG_UART
64 #include "descriptor.h"
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 if (!console_is_ready())
126 // return immediately if called while interrupt
127 if (!(SREG & (1<<SREG_I)))
130 if (USB_DeviceState != DEVICE_STATE_Configured)
133 uint8_t ep = Endpoint_GetCurrentEndpoint();
135 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
136 if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
137 goto EXIT_RESTORE_EP;
140 // write from buffer to endpoint bank
141 while (!ringbuf_is_empty(&sendbuf) && Endpoint_IsReadWriteAllowed()) {
142 Endpoint_Write_8(ringbuf_get(&sendbuf));
144 // clear bank when it is full
145 if (!Endpoint_IsReadWriteAllowed() && Endpoint_IsINReady()) {
150 // write c to bank directly if there is no others in buffer
151 if (ringbuf_is_empty(&sendbuf) && Endpoint_IsReadWriteAllowed()) {
153 Endpoint_SelectEndpoint(ep);
158 Endpoint_SelectEndpoint(ep);
160 return ringbuf_put(&sendbuf, c);
163 static void console_flush(void)
165 if (!console_is_ready())
168 if (USB_DeviceState != DEVICE_STATE_Configured)
171 uint8_t ep = Endpoint_GetCurrentEndpoint();
173 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
174 if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
175 Endpoint_SelectEndpoint(ep);
179 // write from buffer to endpoint bank
180 while (!ringbuf_is_empty(&sendbuf) && Endpoint_IsReadWriteAllowed()) {
181 Endpoint_Write_8(ringbuf_get(&sendbuf));
183 // clear bank when it is full
184 if (!Endpoint_IsReadWriteAllowed() && Endpoint_IsINReady()) {
189 // clear bank when there are chars in bank
190 if (Endpoint_BytesInEndpoint() && Endpoint_IsINReady()) {
191 // Windows needs to fill packet with 0
192 while (Endpoint_IsReadWriteAllowed()) {
198 Endpoint_SelectEndpoint(ep);
201 static void console_task(void)
203 static uint16_t fn = 0;
204 if (fn == USB_Device_GetFrameNumber()) {
207 fn = USB_Device_GetFrameNumber();
213 /*******************************************************************************
215 ******************************************************************************/
217 * Event Order of Plug in:
218 * 0) EVENT_USB_Device_Connect
219 * 1) EVENT_USB_Device_Suspend
220 * 2) EVENT_USB_Device_Reset
221 * 3) EVENT_USB_Device_Wake
223 void EVENT_USB_Device_Connect(void)
228 /* For battery powered device */
229 if (!USB_IsInitialized) {
232 USB_Device_EnableSOFEvents();
236 void EVENT_USB_Device_Disconnect(void)
241 /* For battery powered device */
242 USB_IsInitialized = false;
243 /* TODO: This doesn't work. After several plug in/outs can not be enumerated.
244 if (USB_IsInitialized) {
245 USB_Disable(); // Disable all interrupts
246 USB_Controller_Enable();
247 USB_INT_Enable(USB_INT_VBUSTI);
252 void EVENT_USB_Device_Reset(void)
259 void EVENT_USB_Device_Suspend()
264 hook_usb_suspend_entry();
267 void EVENT_USB_Device_WakeUp()
276 void EVENT_USB_Device_StartOfFrame(void)
280 /** Event handler for the USB_ConfigurationChanged event.
281 * This is fired when the host sets the current configuration of the USB device after enumeration.
283 * ATMega32u2 supports dual bank(ping-pong mode) only on endpoint 3 and 4,
284 * it is safe to use singl bank for all endpoints.
286 void EVENT_USB_Device_ConfigurationChanged(void)
291 bool ConfigSuccess = true;
293 /* Setup Keyboard HID Report Endpoints */
294 ConfigSuccess &= ENDPOINT_CONFIG(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
295 KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
298 /* Setup Mouse HID Report Endpoint */
299 ConfigSuccess &= ENDPOINT_CONFIG(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
300 MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE);
303 #ifdef EXTRAKEY_ENABLE
304 /* Setup Extra HID Report Endpoint */
305 ConfigSuccess &= ENDPOINT_CONFIG(EXTRAKEY_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
306 EXTRAKEY_EPSIZE, ENDPOINT_BANK_SINGLE);
309 #ifdef CONSOLE_ENABLE
310 /* Setup Console HID Report Endpoints */
311 ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
312 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
314 ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
315 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
320 /* Setup NKRO HID Report Endpoints */
321 ConfigSuccess &= ENDPOINT_CONFIG(NKRO_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
322 NKRO_EPSIZE, ENDPOINT_BANK_SINGLE);
327 Appendix G: HID Request Support Requirements
329 The following table enumerates the requests that need to be supported by various types of HID class devices.
331 Device type GetReport SetReport GetIdle SetIdle GetProtocol SetProtocol
332 ------------------------------------------------------------------------------------------
333 Boot Mouse Required Optional Optional Optional Required Required
334 Non-Boot Mouse Required Optional Optional Optional Optional Optional
335 Boot Keyboard Required Optional Required Required Required Required
336 Non-Boot Keybrd Required Optional Required Required Optional Optional
337 Other Device Required Optional Optional Optional Optional Optional
339 /** Event handler for the USB_ControlRequest event.
340 * This is fired before passing along unhandled control requests to the library for processing internally.
342 void EVENT_USB_Device_ControlRequest(void)
344 uint8_t* ReportData = NULL;
345 uint8_t ReportSize = 0;
347 /* Handle HID Class specific requests */
348 switch (USB_ControlRequest.bRequest)
350 case HID_REQ_GetReport:
351 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
353 Endpoint_ClearSETUP();
356 switch (USB_ControlRequest.wIndex) {
357 case KEYBOARD_INTERFACE:
359 ReportData = (uint8_t*)&keyboard_report_sent;
360 ReportSize = sizeof(keyboard_report_sent);
364 /* Write the report data to the control endpoint */
365 Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
368 xprintf("[r%d]", USB_ControlRequest.wIndex);
373 case HID_REQ_SetReport:
374 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
378 switch (USB_ControlRequest.wIndex) {
379 case KEYBOARD_INTERFACE:
383 Endpoint_ClearSETUP();
385 while (!(Endpoint_IsOUTReceived())) {
386 if (USB_DeviceState == DEVICE_STATE_Unattached)
389 keyboard_led_stats = Endpoint_Read_8();
392 Endpoint_ClearStatusStage();
394 xprintf("[L%d]", USB_ControlRequest.wIndex);
403 case HID_REQ_GetProtocol:
404 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
406 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
407 Endpoint_ClearSETUP();
408 while (!(Endpoint_IsINReady()));
409 Endpoint_Write_8(keyboard_protocol);
411 Endpoint_ClearStatusStage();
419 case HID_REQ_SetProtocol:
420 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
422 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
423 Endpoint_ClearSETUP();
424 Endpoint_ClearStatusStage();
426 keyboard_protocol = (USB_ControlRequest.wValue & 0xFF);
435 case HID_REQ_SetIdle:
436 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
438 Endpoint_ClearSETUP();
439 Endpoint_ClearStatusStage();
441 keyboard_idle = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
443 xprintf("[I%d]%d", USB_ControlRequest.wIndex, (USB_ControlRequest.wValue & 0xFF00) >> 8);
448 case HID_REQ_GetIdle:
449 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
451 Endpoint_ClearSETUP();
452 while (!(Endpoint_IsINReady()));
453 Endpoint_Write_8(keyboard_idle);
455 Endpoint_ClearStatusStage();
465 /*******************************************************************************
467 ******************************************************************************/
468 static uint8_t keyboard_leds(void)
470 return keyboard_led_stats;
473 static void send_keyboard(report_keyboard_t *report)
475 uint8_t timeout = 128;
477 if (USB_DeviceState != DEVICE_STATE_Configured)
480 /* Select the Keyboard Report Endpoint */
482 if (keyboard_protocol && keyboard_nkro) {
483 /* Report protocol - NKRO */
484 Endpoint_SelectEndpoint(NKRO_IN_EPNUM);
486 /* Check if write ready for a polling interval around 1ms */
487 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(8);
488 if (!Endpoint_IsReadWriteAllowed()) return;
490 /* Write Keyboard Report Data */
491 Endpoint_Write_Stream_LE(report, NKRO_EPSIZE, NULL);
497 Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
499 /* Check if write ready for a polling interval around 10ms */
500 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(80);
501 if (!Endpoint_IsReadWriteAllowed()) return;
503 /* Write Keyboard Report Data */
504 Endpoint_Write_Stream_LE(report, KEYBOARD_EPSIZE, NULL);
507 /* Finalize the stream transfer to send the last packet */
510 keyboard_report_sent = *report;
513 static void send_mouse(report_mouse_t *report)
516 uint8_t timeout = 255;
518 if (USB_DeviceState != DEVICE_STATE_Configured)
521 /* Select the Mouse Report Endpoint */
522 Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
524 /* Check if write ready for a polling interval around 10ms */
525 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
526 if (!Endpoint_IsReadWriteAllowed()) return;
528 /* Write Mouse Report Data */
529 Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
531 /* Finalize the stream transfer to send the last packet */
536 static void send_system(uint16_t data)
538 #ifdef EXTRAKEY_ENABLE
539 uint8_t timeout = 255;
541 if (USB_DeviceState != DEVICE_STATE_Configured)
545 .report_id = REPORT_ID_SYSTEM,
546 .usage = data - SYSTEM_POWER_DOWN + 1
548 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
550 /* Check if write ready for a polling interval around 10ms */
551 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
552 if (!Endpoint_IsReadWriteAllowed()) return;
554 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
559 static void send_consumer(uint16_t data)
561 #ifdef EXTRAKEY_ENABLE
562 uint8_t timeout = 255;
564 if (USB_DeviceState != DEVICE_STATE_Configured)
568 .report_id = REPORT_ID_CONSUMER,
571 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
573 /* Check if write ready for a polling interval around 10ms */
574 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
575 if (!Endpoint_IsReadWriteAllowed()) return;
577 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
583 /*******************************************************************************
585 ******************************************************************************/
586 int8_t sendchar(uint8_t c)
588 #ifdef LUFA_DEBUG_SUART
592 #ifdef LUFA_DEBUG_UART
596 #ifdef CONSOLE_ENABLE
604 /*******************************************************************************
606 ******************************************************************************/
607 static void setup_mcu(void)
609 /* Disable watchdog if enabled by bootloader/fuses */
610 MCUSR &= ~(1 << WDRF);
613 /* Disable clock division */
614 clock_prescale_set(clock_div_1);
617 static void setup_usb(void)
619 // Leonardo needs. Without this USB device is not recognized.
624 USB_Device_EnableSOFEvents();
627 int main(void) __attribute__ ((weak));
632 #ifdef LUFA_DEBUG_SUART
633 SUART_OUT_DDR |= (1<<SUART_OUT_BIT);
634 SUART_OUT_PORT |= (1<<SUART_OUT_BIT);
637 #ifdef LUFA_DEBUG_UART
641 // setup sendchar: DO NOT USE print functions before this line
642 print_set_sendchar(sendchar);
643 host_set_driver(&lufa_driver);
645 print("\n\nKeyboard init.\n");
649 #ifdef SLEEP_LED_ENABLE
657 /* wait for USB startup */
658 while (USB_DeviceState != DEVICE_STATE_Configured) {
659 #if defined(INTERRUPT_CONTROL_ENDPOINT)
666 print("\nUSB configured.\n");
670 print("\nKeyboard start.\n");
672 while (USB_DeviceState == DEVICE_STATE_Suspended) {
673 hook_usb_suspend_loop();
678 #ifdef CONSOLE_ENABLE
682 #if !defined(INTERRUPT_CONTROL_ENDPOINT)
690 __attribute__((weak))
691 void hook_early_init(void) {}
693 __attribute__((weak))
694 void hook_late_init(void) {}
696 static uint8_t _led_stats = 0;
697 __attribute__((weak))
698 void hook_usb_suspend_entry(void)
700 // Turn off LED to save power and keep its status to resotre it later.
701 // LED status will be updated by keyboard_task() in main loop hopefully.
702 _led_stats = keyboard_led_stats;
703 keyboard_led_stats = 0;
705 // Calling long task here can prevent USB state transition
709 #ifdef SLEEP_LED_ENABLE
714 __attribute__((weak))
715 void hook_usb_suspend_loop(void)
717 #ifndef LUFA_DEBUG_UART
718 // This corrupts debug print when suspend
719 suspend_power_down();
721 if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) {
722 USB_Device_SendRemoteWakeup();
726 __attribute__((weak))
727 void hook_usb_wakeup(void)
729 suspend_wakeup_init();
730 #ifdef SLEEP_LED_ENABLE
734 // Restore LED status and update at keyboard_task() in main loop
735 keyboard_led_stats = _led_stats;
737 // Calling long task here can prevent USB state transition