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 #include "descriptor.h"
56 uint8_t keyboard_idle = 0;
57 /* 0: Boot Protocol, 1: Report Protocol(default) */
58 uint8_t keyboard_protocol = 1;
59 static uint8_t keyboard_led_stats = 0;
61 static report_keyboard_t keyboard_report_sent;
65 static uint8_t keyboard_leds(void);
66 static void send_keyboard(report_keyboard_t *report);
67 static void send_mouse(report_mouse_t *report);
68 static void send_system(uint16_t data);
69 static void send_consumer(uint16_t data);
70 host_driver_t lufa_driver = {
79 /*******************************************************************************
81 ******************************************************************************/
83 static void Console_Task(void)
85 /* Device must be connected and configured for the task to run */
86 if (USB_DeviceState != DEVICE_STATE_Configured)
89 uint8_t ep = Endpoint_GetCurrentEndpoint();
92 // TODO: impl receivechar()/recvchar()
93 Endpoint_SelectEndpoint(CONSOLE_OUT_EPNUM);
95 /* Check to see if a packet has been sent from the host */
96 if (Endpoint_IsOUTReceived())
98 /* Check to see if the packet contains data */
99 if (Endpoint_IsReadWriteAllowed())
101 /* Create a temporary buffer to hold the read in report from the host */
102 uint8_t ConsoleData[CONSOLE_EPSIZE];
104 /* Read Console Report Data */
105 Endpoint_Read_Stream_LE(&ConsoleData, sizeof(ConsoleData), NULL);
107 /* Process Console Report Data */
108 //ProcessConsoleHIDReport(ConsoleData);
111 /* Finalize the stream transfer to send the last packet */
117 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
118 if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
119 Endpoint_SelectEndpoint(ep);
124 while (Endpoint_IsReadWriteAllowed())
127 // flash senchar packet
128 if (Endpoint_IsINReady()) {
132 Endpoint_SelectEndpoint(ep);
135 static void Console_Task(void)
141 /*******************************************************************************
143 ******************************************************************************/
145 * Event Order of Plug in:
146 * 0) EVENT_USB_Device_Connect
147 * 1) EVENT_USB_Device_Suspend
148 * 2) EVENT_USB_Device_Reset
149 * 3) EVENT_USB_Device_Wake
151 void EVENT_USB_Device_Connect(void)
154 /* For battery powered device */
155 if (!USB_IsInitialized) {
158 USB_Device_EnableSOFEvents();
162 void EVENT_USB_Device_Disconnect(void)
165 /* For battery powered device */
166 USB_IsInitialized = false;
167 /* TODO: This doesn't work. After several plug in/outs can not be enumerated.
168 if (USB_IsInitialized) {
169 USB_Disable(); // Disable all interrupts
170 USB_Controller_Enable();
171 USB_INT_Enable(USB_INT_VBUSTI);
176 void EVENT_USB_Device_Reset(void)
181 void EVENT_USB_Device_Suspend()
184 hook_usb_suspend_entry();
187 void EVENT_USB_Device_WakeUp()
193 #ifdef CONSOLE_ENABLE
194 static bool console_flush = false;
195 #define CONSOLE_FLUSH_SET(b) do { \
196 uint8_t sreg = SREG; cli(); console_flush = b; SREG = sreg; \
200 void EVENT_USB_Device_StartOfFrame(void)
202 static uint8_t count;
203 if (++count % 50) return;
206 if (!console_flush) return;
208 console_flush = false;
212 /** Event handler for the USB_ConfigurationChanged event.
213 * This is fired when the host sets the current configuration of the USB device after enumeration.
215 * ATMega32u2 supports dual bank(ping-pong mode) only on endpoint 3 and 4,
216 * it is safe to use singl bank for all endpoints.
218 void EVENT_USB_Device_ConfigurationChanged(void)
220 bool ConfigSuccess = true;
222 /* Setup Keyboard HID Report Endpoints */
223 ConfigSuccess &= ENDPOINT_CONFIG(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
224 KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
227 /* Setup Mouse HID Report Endpoint */
228 ConfigSuccess &= ENDPOINT_CONFIG(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
229 MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE);
232 #ifdef EXTRAKEY_ENABLE
233 /* Setup Extra HID Report Endpoint */
234 ConfigSuccess &= ENDPOINT_CONFIG(EXTRAKEY_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
235 EXTRAKEY_EPSIZE, ENDPOINT_BANK_SINGLE);
238 #ifdef CONSOLE_ENABLE
239 /* Setup Console HID Report Endpoints */
240 ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
241 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
243 ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
244 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
249 /* Setup NKRO HID Report Endpoints */
250 ConfigSuccess &= ENDPOINT_CONFIG(NKRO_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
251 NKRO_EPSIZE, ENDPOINT_BANK_SINGLE);
256 Appendix G: HID Request Support Requirements
258 The following table enumerates the requests that need to be supported by various types of HID class devices.
260 Device type GetReport SetReport GetIdle SetIdle GetProtocol SetProtocol
261 ------------------------------------------------------------------------------------------
262 Boot Mouse Required Optional Optional Optional Required Required
263 Non-Boot Mouse Required Optional Optional Optional Optional Optional
264 Boot Keyboard Required Optional Required Required Required Required
265 Non-Boot Keybrd Required Optional Required Required Optional Optional
266 Other Device Required Optional Optional Optional Optional Optional
268 /** Event handler for the USB_ControlRequest event.
269 * This is fired before passing along unhandled control requests to the library for processing internally.
271 void EVENT_USB_Device_ControlRequest(void)
273 uint8_t* ReportData = NULL;
274 uint8_t ReportSize = 0;
276 /* Handle HID Class specific requests */
277 switch (USB_ControlRequest.bRequest)
279 case HID_REQ_GetReport:
280 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
282 Endpoint_ClearSETUP();
285 switch (USB_ControlRequest.wIndex) {
286 case KEYBOARD_INTERFACE:
288 ReportData = (uint8_t*)&keyboard_report_sent;
289 ReportSize = sizeof(keyboard_report_sent);
293 /* Write the report data to the control endpoint */
294 Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
299 case HID_REQ_SetReport:
300 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
304 switch (USB_ControlRequest.wIndex) {
305 case KEYBOARD_INTERFACE:
309 Endpoint_ClearSETUP();
311 while (!(Endpoint_IsOUTReceived())) {
312 if (USB_DeviceState == DEVICE_STATE_Unattached)
315 keyboard_led_stats = Endpoint_Read_8();
318 Endpoint_ClearStatusStage();
326 case HID_REQ_GetProtocol:
327 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
329 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
330 Endpoint_ClearSETUP();
331 while (!(Endpoint_IsINReady()));
332 Endpoint_Write_8(keyboard_protocol);
334 Endpoint_ClearStatusStage();
339 case HID_REQ_SetProtocol:
340 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
342 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
343 Endpoint_ClearSETUP();
344 Endpoint_ClearStatusStage();
346 keyboard_protocol = (USB_ControlRequest.wValue & 0xFF);
352 case HID_REQ_SetIdle:
353 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
355 Endpoint_ClearSETUP();
356 Endpoint_ClearStatusStage();
358 keyboard_idle = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
362 case HID_REQ_GetIdle:
363 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
365 Endpoint_ClearSETUP();
366 while (!(Endpoint_IsINReady()));
367 Endpoint_Write_8(keyboard_idle);
369 Endpoint_ClearStatusStage();
376 /*******************************************************************************
378 ******************************************************************************/
379 static uint8_t keyboard_leds(void)
381 return keyboard_led_stats;
384 static void send_keyboard(report_keyboard_t *report)
386 uint8_t timeout = 255;
388 if (USB_DeviceState != DEVICE_STATE_Configured)
391 /* Select the Keyboard Report Endpoint */
393 if (keyboard_protocol && keyboard_nkro) {
394 /* Report protocol - NKRO */
395 Endpoint_SelectEndpoint(NKRO_IN_EPNUM);
397 /* Check if write ready for a polling interval around 1ms */
398 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(4);
399 if (!Endpoint_IsReadWriteAllowed()) return;
401 /* Write Keyboard Report Data */
402 Endpoint_Write_Stream_LE(report, NKRO_EPSIZE, NULL);
408 Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
410 /* Check if write ready for a polling interval around 10ms */
411 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
412 if (!Endpoint_IsReadWriteAllowed()) return;
414 /* Write Keyboard Report Data */
415 Endpoint_Write_Stream_LE(report, KEYBOARD_EPSIZE, NULL);
418 /* Finalize the stream transfer to send the last packet */
421 keyboard_report_sent = *report;
424 static void send_mouse(report_mouse_t *report)
427 uint8_t timeout = 255;
429 if (USB_DeviceState != DEVICE_STATE_Configured)
432 /* Select the Mouse Report Endpoint */
433 Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
435 /* Check if write ready for a polling interval around 10ms */
436 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
437 if (!Endpoint_IsReadWriteAllowed()) return;
439 /* Write Mouse Report Data */
440 Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
442 /* Finalize the stream transfer to send the last packet */
447 static void send_system(uint16_t data)
449 uint8_t timeout = 255;
451 if (USB_DeviceState != DEVICE_STATE_Configured)
455 .report_id = REPORT_ID_SYSTEM,
458 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
460 /* Check if write ready for a polling interval around 10ms */
461 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
462 if (!Endpoint_IsReadWriteAllowed()) return;
464 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
468 static void send_consumer(uint16_t data)
470 uint8_t timeout = 255;
472 if (USB_DeviceState != DEVICE_STATE_Configured)
476 .report_id = REPORT_ID_CONSUMER,
479 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
481 /* Check if write ready for a polling interval around 10ms */
482 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
483 if (!Endpoint_IsReadWriteAllowed()) return;
485 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
490 /*******************************************************************************
492 ******************************************************************************/
493 #ifdef CONSOLE_ENABLE
494 #define SEND_TIMEOUT 5
495 int8_t sendchar(uint8_t c)
497 // Not wait once timeouted.
498 // Because sendchar() is called so many times, waiting each call causes big lag.
499 static bool timeouted = false;
501 // prevents Console_Task() from running during sendchar() runs.
502 // or char will be lost. These two function is mutually exclusive.
503 CONSOLE_FLUSH_SET(false);
505 if (USB_DeviceState != DEVICE_STATE_Configured)
508 uint8_t ep = Endpoint_GetCurrentEndpoint();
509 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
510 if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
514 if (timeouted && !Endpoint_IsReadWriteAllowed()) {
520 uint8_t timeout = SEND_TIMEOUT;
521 while (!Endpoint_IsReadWriteAllowed()) {
522 if (USB_DeviceState != DEVICE_STATE_Configured) {
525 if (Endpoint_IsStalled()) {
537 // send when bank is full
538 if (!Endpoint_IsReadWriteAllowed()) {
539 while (!(Endpoint_IsINReady()));
542 CONSOLE_FLUSH_SET(true);
545 Endpoint_SelectEndpoint(ep);
548 Endpoint_SelectEndpoint(ep);
552 int8_t sendchar(uint8_t c)
559 /*******************************************************************************
561 ******************************************************************************/
562 static void setup_mcu(void)
564 /* Disable watchdog if enabled by bootloader/fuses */
565 MCUSR &= ~(1 << WDRF);
568 /* Disable clock division */
569 clock_prescale_set(clock_div_1);
572 static void setup_usb(void)
574 // Leonardo needs. Without this USB device is not recognized.
580 USB_Device_EnableSOFEvents();
581 print_set_sendchar(sendchar);
584 int main(void) __attribute__ ((weak));
593 /* wait for USB startup & debug output */
594 while (USB_DeviceState != DEVICE_STATE_Configured) {
595 #if defined(INTERRUPT_CONTROL_ENDPOINT)
601 print("USB configured.\n");
605 host_set_driver(&lufa_driver);
606 #ifdef SLEEP_LED_ENABLE
610 print("Keyboard start.\n");
613 while (USB_DeviceState == DEVICE_STATE_Suspended) {
615 hook_usb_suspend_loop();
620 #if !defined(INTERRUPT_CONTROL_ENDPOINT)
628 __attribute__((weak))
629 void hook_early_init(void) {}
631 __attribute__((weak))
632 void hook_late_init(void) {}
634 __attribute__((weak))
635 void hook_usb_suspend_entry(void)
637 #ifdef SLEEP_LED_ENABLE
642 __attribute__((weak))
643 void hook_usb_suspend_loop(void)
645 suspend_power_down();
646 if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) {
647 USB_Device_SendRemoteWakeup();
651 __attribute__((weak))
652 void hook_usb_wakeup(void)
654 suspend_wakeup_init();
655 #ifdef SLEEP_LED_ENABLE
657 // NOTE: converters may not accept this
658 led_set(host_keyboard_leds());