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"
54 #ifdef LUFA_DEBUG_SUART
55 #include "avr/suart.h"
59 #include "descriptor.h"
66 uint8_t keyboard_idle = 0;
67 /* 0: Boot Protocol, 1: Report Protocol(default) */
68 uint8_t keyboard_protocol = 1;
69 static uint8_t keyboard_led_stats = 0;
71 static report_keyboard_t keyboard_report_sent;
75 static uint8_t keyboard_leds(void);
76 static void send_keyboard(report_keyboard_t *report);
77 static void send_mouse(report_mouse_t *report);
78 static void send_system(uint16_t data);
79 static void send_consumer(uint16_t data);
80 host_driver_t lufa_driver = {
89 /*******************************************************************************
91 ******************************************************************************/
93 #define SENDBUF_SIZE 256
94 static uint8_t sbuf[SENDBUF_SIZE];
95 static ringbuf_t sendbuf = {
99 .size_mask = SENDBUF_SIZE - 1
102 static bool console_putc(uint8_t c)
104 // return immediately if called while interrupt
105 if (!(SREG & (1<<SREG_I)))
108 if (USB_DeviceState != DEVICE_STATE_Configured)
111 uint8_t ep = Endpoint_GetCurrentEndpoint();
113 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
114 if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
115 goto EXIT_RESTORE_EP;
118 // write from buffer to endpoint bank
119 while (!ringbuf_is_empty(&sendbuf) && Endpoint_IsReadWriteAllowed()) {
120 Endpoint_Write_8(ringbuf_get(&sendbuf));
122 // clear bank when it is full
123 if (!Endpoint_IsReadWriteAllowed() && Endpoint_IsINReady()) {
128 // write c to bank directly if there is no others in buffer
129 if (ringbuf_is_empty(&sendbuf) && Endpoint_IsReadWriteAllowed()) {
131 Endpoint_SelectEndpoint(ep);
136 Endpoint_SelectEndpoint(ep);
138 return ringbuf_put(&sendbuf, c);
141 static void console_flush(void)
143 if (USB_DeviceState != DEVICE_STATE_Configured)
146 uint8_t ep = Endpoint_GetCurrentEndpoint();
148 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
149 if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
150 Endpoint_SelectEndpoint(ep);
154 // write from buffer to endpoint bank
155 while (!ringbuf_is_empty(&sendbuf) && Endpoint_IsReadWriteAllowed()) {
156 Endpoint_Write_8(ringbuf_get(&sendbuf));
158 // clear bank when it is full
159 if (!Endpoint_IsReadWriteAllowed() && Endpoint_IsINReady()) {
164 // clear bank when there are chars in bank
165 if (Endpoint_BytesInEndpoint() && Endpoint_IsINReady()) {
166 // Windows needs to fill packet with 0
167 while (Endpoint_IsReadWriteAllowed()) {
173 Endpoint_SelectEndpoint(ep);
176 static void console_task(void)
178 static uint16_t fn = 0;
179 if (fn == USB_Device_GetFrameNumber()) {
182 fn = USB_Device_GetFrameNumber();
188 /*******************************************************************************
190 ******************************************************************************/
192 * Event Order of Plug in:
193 * 0) EVENT_USB_Device_Connect
194 * 1) EVENT_USB_Device_Suspend
195 * 2) EVENT_USB_Device_Reset
196 * 3) EVENT_USB_Device_Wake
198 void EVENT_USB_Device_Connect(void)
201 /* For battery powered device */
202 if (!USB_IsInitialized) {
205 USB_Device_EnableSOFEvents();
209 void EVENT_USB_Device_Disconnect(void)
212 /* For battery powered device */
213 USB_IsInitialized = false;
214 /* TODO: This doesn't work. After several plug in/outs can not be enumerated.
215 if (USB_IsInitialized) {
216 USB_Disable(); // Disable all interrupts
217 USB_Controller_Enable();
218 USB_INT_Enable(USB_INT_VBUSTI);
223 void EVENT_USB_Device_Reset(void)
230 void EVENT_USB_Device_Suspend()
235 hook_usb_suspend_entry();
238 void EVENT_USB_Device_WakeUp()
247 void EVENT_USB_Device_StartOfFrame(void)
251 /** Event handler for the USB_ConfigurationChanged event.
252 * This is fired when the host sets the current configuration of the USB device after enumeration.
254 * ATMega32u2 supports dual bank(ping-pong mode) only on endpoint 3 and 4,
255 * it is safe to use singl bank for all endpoints.
257 void EVENT_USB_Device_ConfigurationChanged(void)
262 bool ConfigSuccess = true;
264 /* Setup Keyboard HID Report Endpoints */
265 ConfigSuccess &= ENDPOINT_CONFIG(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
266 KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
269 /* Setup Mouse HID Report Endpoint */
270 ConfigSuccess &= ENDPOINT_CONFIG(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
271 MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE);
274 #ifdef EXTRAKEY_ENABLE
275 /* Setup Extra HID Report Endpoint */
276 ConfigSuccess &= ENDPOINT_CONFIG(EXTRAKEY_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
277 EXTRAKEY_EPSIZE, ENDPOINT_BANK_SINGLE);
280 #ifdef CONSOLE_ENABLE
281 /* Setup Console HID Report Endpoints */
282 ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
283 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
285 ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
286 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
291 /* Setup NKRO HID Report Endpoints */
292 ConfigSuccess &= ENDPOINT_CONFIG(NKRO_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
293 NKRO_EPSIZE, ENDPOINT_BANK_SINGLE);
298 Appendix G: HID Request Support Requirements
300 The following table enumerates the requests that need to be supported by various types of HID class devices.
302 Device type GetReport SetReport GetIdle SetIdle GetProtocol SetProtocol
303 ------------------------------------------------------------------------------------------
304 Boot Mouse Required Optional Optional Optional Required Required
305 Non-Boot Mouse Required Optional Optional Optional Optional Optional
306 Boot Keyboard Required Optional Required Required Required Required
307 Non-Boot Keybrd Required Optional Required Required Optional Optional
308 Other Device Required Optional Optional Optional Optional Optional
310 /** Event handler for the USB_ControlRequest event.
311 * This is fired before passing along unhandled control requests to the library for processing internally.
313 void EVENT_USB_Device_ControlRequest(void)
315 uint8_t* ReportData = NULL;
316 uint8_t ReportSize = 0;
318 /* Handle HID Class specific requests */
319 switch (USB_ControlRequest.bRequest)
321 case HID_REQ_GetReport:
322 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
324 Endpoint_ClearSETUP();
327 switch (USB_ControlRequest.wIndex) {
328 case KEYBOARD_INTERFACE:
330 ReportData = (uint8_t*)&keyboard_report_sent;
331 ReportSize = sizeof(keyboard_report_sent);
335 /* Write the report data to the control endpoint */
336 Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
339 xprintf("[r%d]", USB_ControlRequest.wIndex);
344 case HID_REQ_SetReport:
345 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
349 switch (USB_ControlRequest.wIndex) {
350 case KEYBOARD_INTERFACE:
354 Endpoint_ClearSETUP();
356 while (!(Endpoint_IsOUTReceived())) {
357 if (USB_DeviceState == DEVICE_STATE_Unattached)
360 keyboard_led_stats = Endpoint_Read_8();
363 Endpoint_ClearStatusStage();
365 xprintf("[L%d]", USB_ControlRequest.wIndex);
374 case HID_REQ_GetProtocol:
375 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
377 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
378 Endpoint_ClearSETUP();
379 while (!(Endpoint_IsINReady()));
380 Endpoint_Write_8(keyboard_protocol);
382 Endpoint_ClearStatusStage();
390 case HID_REQ_SetProtocol:
391 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
393 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
394 Endpoint_ClearSETUP();
395 Endpoint_ClearStatusStage();
397 keyboard_protocol = (USB_ControlRequest.wValue & 0xFF);
406 case HID_REQ_SetIdle:
407 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
409 Endpoint_ClearSETUP();
410 Endpoint_ClearStatusStage();
412 keyboard_idle = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
414 xprintf("[I%d]%d", USB_ControlRequest.wIndex, (USB_ControlRequest.wValue & 0xFF00) >> 8);
419 case HID_REQ_GetIdle:
420 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
422 Endpoint_ClearSETUP();
423 while (!(Endpoint_IsINReady()));
424 Endpoint_Write_8(keyboard_idle);
426 Endpoint_ClearStatusStage();
436 /*******************************************************************************
438 ******************************************************************************/
439 static uint8_t keyboard_leds(void)
441 return keyboard_led_stats;
444 static void send_keyboard(report_keyboard_t *report)
446 uint8_t timeout = 128;
448 if (USB_DeviceState != DEVICE_STATE_Configured)
451 /* Select the Keyboard Report Endpoint */
453 if (keyboard_protocol && keyboard_nkro) {
454 /* Report protocol - NKRO */
455 Endpoint_SelectEndpoint(NKRO_IN_EPNUM);
457 /* Check if write ready for a polling interval around 1ms */
458 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(8);
459 if (!Endpoint_IsReadWriteAllowed()) return;
461 /* Write Keyboard Report Data */
462 Endpoint_Write_Stream_LE(report, NKRO_EPSIZE, NULL);
468 Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
470 /* Check if write ready for a polling interval around 10ms */
471 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(80);
472 if (!Endpoint_IsReadWriteAllowed()) return;
474 /* Write Keyboard Report Data */
475 Endpoint_Write_Stream_LE(report, KEYBOARD_EPSIZE, NULL);
478 /* Finalize the stream transfer to send the last packet */
481 keyboard_report_sent = *report;
484 static void send_mouse(report_mouse_t *report)
487 uint8_t timeout = 255;
489 if (USB_DeviceState != DEVICE_STATE_Configured)
492 /* Select the Mouse Report Endpoint */
493 Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
495 /* Check if write ready for a polling interval around 10ms */
496 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
497 if (!Endpoint_IsReadWriteAllowed()) return;
499 /* Write Mouse Report Data */
500 Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
502 /* Finalize the stream transfer to send the last packet */
507 static void send_system(uint16_t data)
509 #ifdef EXTRAKEY_ENABLE
510 uint8_t timeout = 255;
512 if (USB_DeviceState != DEVICE_STATE_Configured)
516 .report_id = REPORT_ID_SYSTEM,
519 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
521 /* Check if write ready for a polling interval around 10ms */
522 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
523 if (!Endpoint_IsReadWriteAllowed()) return;
525 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
530 static void send_consumer(uint16_t data)
532 #ifdef EXTRAKEY_ENABLE
533 uint8_t timeout = 255;
535 if (USB_DeviceState != DEVICE_STATE_Configured)
539 .report_id = REPORT_ID_CONSUMER,
542 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
544 /* Check if write ready for a polling interval around 10ms */
545 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
546 if (!Endpoint_IsReadWriteAllowed()) return;
548 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
554 /*******************************************************************************
556 ******************************************************************************/
557 #ifdef CONSOLE_ENABLE
558 int8_t sendchar(uint8_t c)
560 #ifdef LUFA_DEBUG_SUART
564 bool r = console_putc(c);
568 int8_t sendchar(uint8_t c)
570 #ifdef LUFA_DEBUG_SUART
578 /*******************************************************************************
580 ******************************************************************************/
581 static void setup_mcu(void)
583 /* Disable watchdog if enabled by bootloader/fuses */
584 MCUSR &= ~(1 << WDRF);
587 /* Disable clock division */
588 clock_prescale_set(clock_div_1);
591 static void setup_usb(void)
593 // Leonardo needs. Without this USB device is not recognized.
598 USB_Device_EnableSOFEvents();
601 int main(void) __attribute__ ((weak));
606 #ifdef LUFA_DEBUG_SUART
607 SUART_OUT_DDR |= (1<<SUART_OUT_BIT);
608 SUART_OUT_PORT |= (1<<SUART_OUT_BIT);
611 // setup sendchar: DO NOT USE print functions before this line
612 print_set_sendchar(sendchar);
613 host_set_driver(&lufa_driver);
615 print("Keyboard init.\n");
619 #ifdef SLEEP_LED_ENABLE
625 /* wait for USB startup */
626 while (USB_DeviceState != DEVICE_STATE_Configured) {
627 #if defined(INTERRUPT_CONTROL_ENDPOINT)
636 /* wait for Console startup */
637 // TODO: 2000ms delay often works anyhoo but proper startup would be better
638 // 1000ms delay of hid_listen affects this probably
639 #ifdef CONSOLE_ENABLE
641 uint16_t delay = 2000;
643 #ifndef INTERRUPT_CONTROL_ENDPOINT
653 print("Keyboard start.\n");
655 while (USB_DeviceState == DEVICE_STATE_Suspended) {
659 hook_usb_suspend_loop();
664 #ifdef CONSOLE_ENABLE
668 #if !defined(INTERRUPT_CONTROL_ENDPOINT)
676 __attribute__((weak))
677 void hook_early_init(void) {}
679 __attribute__((weak))
680 void hook_late_init(void) {}
682 static uint8_t _led_stats = 0;
683 __attribute__((weak))
684 void hook_usb_suspend_entry(void)
686 // Turn LED off to save power
687 // Set 0 with putting aside status before suspend and restore
688 // it after wakeup, then LED is updated at keyboard_task() in main loop
689 _led_stats = keyboard_led_stats;
690 keyboard_led_stats = 0;
691 led_set(keyboard_led_stats);
695 #ifdef SLEEP_LED_ENABLE
700 __attribute__((weak))
701 void hook_usb_suspend_loop(void)
703 suspend_power_down();
704 if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) {
705 USB_Device_SendRemoteWakeup();
709 __attribute__((weak))
710 void hook_usb_wakeup(void)
712 suspend_wakeup_init();
713 #ifdef SLEEP_LED_ENABLE
717 // Restore LED status
718 // BIOS/grub won't recognize/enumerate if led_set() takes long(around 40ms?)
719 // Converters fall into the case and miss wakeup event(timeout to reply?) in the end.
720 //led_set(host_keyboard_leds());
721 // Instead, restore stats and update at keyboard_task() in main loop
722 keyboard_led_stats = _led_stats;