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"
47 #ifdef SLEEP_LED_ENABLE
48 #include "sleep_led.h"
53 #ifdef LUFA_DEBUG_SUART
54 #include "avr/suart.h"
58 #include "descriptor.h"
65 uint8_t keyboard_idle = 0;
66 /* 0: Boot Protocol, 1: Report Protocol(default) */
67 uint8_t keyboard_protocol = 1;
68 static uint8_t keyboard_led_stats = 0;
70 static report_keyboard_t keyboard_report_sent;
74 static uint8_t keyboard_leds(void);
75 static void send_keyboard(report_keyboard_t *report);
76 static void send_mouse(report_mouse_t *report);
77 static void send_system(uint16_t data);
78 static void send_consumer(uint16_t data);
79 host_driver_t lufa_driver = {
88 /*******************************************************************************
90 ******************************************************************************/
92 static void Console_Task(void)
94 /* Device must be connected and configured for the task to run */
95 if (USB_DeviceState != DEVICE_STATE_Configured)
98 uint8_t ep = Endpoint_GetCurrentEndpoint();
101 // TODO: impl receivechar()/recvchar()
102 Endpoint_SelectEndpoint(CONSOLE_OUT_EPNUM);
104 /* Check to see if a packet has been sent from the host */
105 if (Endpoint_IsOUTReceived())
107 /* Check to see if the packet contains data */
108 if (Endpoint_IsReadWriteAllowed())
110 /* Create a temporary buffer to hold the read in report from the host */
111 uint8_t ConsoleData[CONSOLE_EPSIZE];
113 /* Read Console Report Data */
114 Endpoint_Read_Stream_LE(&ConsoleData, sizeof(ConsoleData), NULL);
116 /* Process Console Report Data */
117 //ProcessConsoleHIDReport(ConsoleData);
120 /* Finalize the stream transfer to send the last packet */
126 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
127 if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
128 Endpoint_SelectEndpoint(ep);
133 while (Endpoint_IsReadWriteAllowed())
136 // flash senchar packet
137 if (Endpoint_IsINReady()) {
141 Endpoint_SelectEndpoint(ep);
144 static void Console_Task(void)
150 /*******************************************************************************
152 ******************************************************************************/
154 * Event Order of Plug in:
155 * 0) EVENT_USB_Device_Connect
156 * 1) EVENT_USB_Device_Suspend
157 * 2) EVENT_USB_Device_Reset
158 * 3) EVENT_USB_Device_Wake
160 void EVENT_USB_Device_Connect(void)
163 /* For battery powered device */
164 if (!USB_IsInitialized) {
167 USB_Device_EnableSOFEvents();
171 void EVENT_USB_Device_Disconnect(void)
174 /* For battery powered device */
175 USB_IsInitialized = false;
176 /* TODO: This doesn't work. After several plug in/outs can not be enumerated.
177 if (USB_IsInitialized) {
178 USB_Disable(); // Disable all interrupts
179 USB_Controller_Enable();
180 USB_INT_Enable(USB_INT_VBUSTI);
185 void EVENT_USB_Device_Reset(void)
192 void EVENT_USB_Device_Suspend()
197 hook_usb_suspend_entry();
200 void EVENT_USB_Device_WakeUp()
208 #ifdef CONSOLE_ENABLE
209 static bool console_flush = false;
210 #define CONSOLE_FLUSH_SET(b) do { \
211 uint8_t sreg = SREG; cli(); console_flush = b; SREG = sreg; \
215 void EVENT_USB_Device_StartOfFrame(void)
217 static uint8_t count;
218 if (++count % 50) return;
221 if (!console_flush) return;
223 console_flush = false;
227 /** Event handler for the USB_ConfigurationChanged event.
228 * This is fired when the host sets the current configuration of the USB device after enumeration.
230 * ATMega32u2 supports dual bank(ping-pong mode) only on endpoint 3 and 4,
231 * it is safe to use singl bank for all endpoints.
233 void EVENT_USB_Device_ConfigurationChanged(void)
238 bool ConfigSuccess = true;
240 /* Setup Keyboard HID Report Endpoints */
241 ConfigSuccess &= ENDPOINT_CONFIG(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
242 KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
245 /* Setup Mouse HID Report Endpoint */
246 ConfigSuccess &= ENDPOINT_CONFIG(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
247 MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE);
250 #ifdef EXTRAKEY_ENABLE
251 /* Setup Extra HID Report Endpoint */
252 ConfigSuccess &= ENDPOINT_CONFIG(EXTRAKEY_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
253 EXTRAKEY_EPSIZE, ENDPOINT_BANK_SINGLE);
256 #ifdef CONSOLE_ENABLE
257 /* Setup Console HID Report Endpoints */
258 ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
259 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
261 ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
262 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
267 /* Setup NKRO HID Report Endpoints */
268 ConfigSuccess &= ENDPOINT_CONFIG(NKRO_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
269 NKRO_EPSIZE, ENDPOINT_BANK_SINGLE);
274 Appendix G: HID Request Support Requirements
276 The following table enumerates the requests that need to be supported by various types of HID class devices.
278 Device type GetReport SetReport GetIdle SetIdle GetProtocol SetProtocol
279 ------------------------------------------------------------------------------------------
280 Boot Mouse Required Optional Optional Optional Required Required
281 Non-Boot Mouse Required Optional Optional Optional Optional Optional
282 Boot Keyboard Required Optional Required Required Required Required
283 Non-Boot Keybrd Required Optional Required Required Optional Optional
284 Other Device Required Optional Optional Optional Optional Optional
286 /** Event handler for the USB_ControlRequest event.
287 * This is fired before passing along unhandled control requests to the library for processing internally.
289 void EVENT_USB_Device_ControlRequest(void)
291 uint8_t* ReportData = NULL;
292 uint8_t ReportSize = 0;
294 /* Handle HID Class specific requests */
295 switch (USB_ControlRequest.bRequest)
297 case HID_REQ_GetReport:
298 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
300 Endpoint_ClearSETUP();
303 switch (USB_ControlRequest.wIndex) {
304 case KEYBOARD_INTERFACE:
306 ReportData = (uint8_t*)&keyboard_report_sent;
307 ReportSize = sizeof(keyboard_report_sent);
311 /* Write the report data to the control endpoint */
312 Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
315 xprintf("[r%d]", USB_ControlRequest.wIndex);
320 case HID_REQ_SetReport:
321 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
325 switch (USB_ControlRequest.wIndex) {
326 case KEYBOARD_INTERFACE:
330 Endpoint_ClearSETUP();
332 while (!(Endpoint_IsOUTReceived())) {
333 if (USB_DeviceState == DEVICE_STATE_Unattached)
336 keyboard_led_stats = Endpoint_Read_8();
339 Endpoint_ClearStatusStage();
341 xprintf("[L%d]", USB_ControlRequest.wIndex);
350 case HID_REQ_GetProtocol:
351 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
353 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
354 Endpoint_ClearSETUP();
355 while (!(Endpoint_IsINReady()));
356 Endpoint_Write_8(keyboard_protocol);
358 Endpoint_ClearStatusStage();
366 case HID_REQ_SetProtocol:
367 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
369 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
370 Endpoint_ClearSETUP();
371 Endpoint_ClearStatusStage();
373 keyboard_protocol = (USB_ControlRequest.wValue & 0xFF);
382 case HID_REQ_SetIdle:
383 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
385 Endpoint_ClearSETUP();
386 Endpoint_ClearStatusStage();
388 keyboard_idle = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
390 xprintf("[I%d]%d", USB_ControlRequest.wIndex, (USB_ControlRequest.wValue & 0xFF00) >> 8);
395 case HID_REQ_GetIdle:
396 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
398 Endpoint_ClearSETUP();
399 while (!(Endpoint_IsINReady()));
400 Endpoint_Write_8(keyboard_idle);
402 Endpoint_ClearStatusStage();
412 /*******************************************************************************
414 ******************************************************************************/
415 static uint8_t keyboard_leds(void)
417 return keyboard_led_stats;
420 static void send_keyboard(report_keyboard_t *report)
422 uint8_t timeout = 255;
424 if (USB_DeviceState != DEVICE_STATE_Configured)
427 /* Select the Keyboard Report Endpoint */
429 if (keyboard_protocol && keyboard_nkro) {
430 /* Report protocol - NKRO */
431 Endpoint_SelectEndpoint(NKRO_IN_EPNUM);
433 /* Check if write ready for a polling interval around 1ms */
434 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(8);
435 if (!Endpoint_IsReadWriteAllowed()) return;
437 /* Write Keyboard Report Data */
438 Endpoint_Write_Stream_LE(report, NKRO_EPSIZE, NULL);
444 Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
446 /* Check if write ready for a polling interval around 10ms */
447 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
448 if (!Endpoint_IsReadWriteAllowed()) return;
450 /* Write Keyboard Report Data */
451 Endpoint_Write_Stream_LE(report, KEYBOARD_EPSIZE, NULL);
454 /* Finalize the stream transfer to send the last packet */
457 keyboard_report_sent = *report;
460 static void send_mouse(report_mouse_t *report)
463 uint8_t timeout = 255;
465 if (USB_DeviceState != DEVICE_STATE_Configured)
468 /* Select the Mouse Report Endpoint */
469 Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
471 /* Check if write ready for a polling interval around 10ms */
472 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
473 if (!Endpoint_IsReadWriteAllowed()) return;
475 /* Write Mouse Report Data */
476 Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
478 /* Finalize the stream transfer to send the last packet */
483 static void send_system(uint16_t data)
485 uint8_t timeout = 255;
487 if (USB_DeviceState != DEVICE_STATE_Configured)
491 .report_id = REPORT_ID_SYSTEM,
494 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
496 /* Check if write ready for a polling interval around 10ms */
497 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
498 if (!Endpoint_IsReadWriteAllowed()) return;
500 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
504 static void send_consumer(uint16_t data)
506 uint8_t timeout = 255;
508 if (USB_DeviceState != DEVICE_STATE_Configured)
512 .report_id = REPORT_ID_CONSUMER,
515 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
517 /* Check if write ready for a polling interval around 10ms */
518 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
519 if (!Endpoint_IsReadWriteAllowed()) return;
521 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
526 /*******************************************************************************
528 ******************************************************************************/
529 #ifdef CONSOLE_ENABLE
530 #define SEND_TIMEOUT 5
531 int8_t sendchar(uint8_t c)
533 #ifdef LUFA_DEBUG_SUART
536 // Not wait once timeouted.
537 // Because sendchar() is called so many times, waiting each call causes big lag.
538 static bool timeouted = false;
540 // prevents Console_Task() from running during sendchar() runs.
541 // or char will be lost. These two function is mutually exclusive.
542 CONSOLE_FLUSH_SET(false);
544 if (USB_DeviceState != DEVICE_STATE_Configured)
547 uint8_t ep = Endpoint_GetCurrentEndpoint();
548 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
549 if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
553 if (timeouted && !Endpoint_IsReadWriteAllowed()) {
559 uint8_t timeout = SEND_TIMEOUT;
560 while (!Endpoint_IsReadWriteAllowed()) {
561 if (USB_DeviceState != DEVICE_STATE_Configured) {
564 if (Endpoint_IsStalled()) {
576 // send when bank is full
577 if (!Endpoint_IsReadWriteAllowed()) {
578 while (!(Endpoint_IsINReady()));
581 CONSOLE_FLUSH_SET(true);
584 Endpoint_SelectEndpoint(ep);
587 Endpoint_SelectEndpoint(ep);
591 int8_t sendchar(uint8_t c)
593 #ifdef LUFA_DEBUG_SUART
601 /*******************************************************************************
603 ******************************************************************************/
604 static void setup_mcu(void)
606 /* Disable watchdog if enabled by bootloader/fuses */
607 MCUSR &= ~(1 << WDRF);
610 /* Disable clock division */
611 clock_prescale_set(clock_div_1);
614 static void setup_usb(void)
616 // Leonardo needs. Without this USB device is not recognized.
622 USB_Device_EnableSOFEvents();
625 int main(void) __attribute__ ((weak));
630 #ifdef LUFA_DEBUG_SUART
631 SUART_OUT_DDR |= (1<<SUART_OUT_BIT);
632 SUART_OUT_PORT |= (1<<SUART_OUT_BIT);
634 print_set_sendchar(sendchar);
642 /* wait for USB startup & debug output */
643 while (USB_DeviceState != DEVICE_STATE_Configured) {
644 #if defined(INTERRUPT_CONTROL_ENDPOINT)
650 print("USB configured.\n");
654 host_set_driver(&lufa_driver);
655 #ifdef SLEEP_LED_ENABLE
659 print("Keyboard start.\n");
662 while (USB_DeviceState == DEVICE_STATE_Suspended) {
666 hook_usb_suspend_loop();
671 #if !defined(INTERRUPT_CONTROL_ENDPOINT)
679 __attribute__((weak))
680 void hook_early_init(void) {}
682 __attribute__((weak))
683 void hook_late_init(void) {}
685 static uint8_t _led_stats = 0;
686 __attribute__((weak))
687 void hook_usb_suspend_entry(void)
689 // Turn LED off to save power
690 // Set 0 with putting aside status before suspend and restore
691 // it after wakeup, then LED is updated at keyboard_task() in main loop
692 _led_stats = keyboard_led_stats;
693 keyboard_led_stats = 0;
694 led_set(keyboard_led_stats);
698 #ifdef SLEEP_LED_ENABLE
703 __attribute__((weak))
704 void hook_usb_suspend_loop(void)
706 suspend_power_down();
707 if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) {
708 USB_Device_SendRemoteWakeup();
712 __attribute__((weak))
713 void hook_usb_wakeup(void)
715 suspend_wakeup_init();
716 #ifdef SLEEP_LED_ENABLE
720 // Restore LED status
721 // BIOS/grub won't recognize/enumerate if led_set() takes long(around 40ms?)
722 // Converters fall into the case and miss wakeup event(timeout to reply?) in the end.
723 //led_set(host_keyboard_leds());
724 // Instead, restore stats and update at keyboard_task() in main loop
725 keyboard_led_stats = _led_stats;