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"
52 #include "descriptor.h"
55 uint8_t keyboard_idle = 0;
56 uint8_t keyboard_protocol = 1;
57 static uint8_t keyboard_led_stats = 0;
59 static report_keyboard_t keyboard_report_sent;
63 static uint8_t keyboard_leds(void);
64 static void send_keyboard(report_keyboard_t *report);
65 static void send_mouse(report_mouse_t *report);
66 static void send_system(uint16_t data);
67 static void send_consumer(uint16_t data);
68 host_driver_t lufa_driver = {
77 /*******************************************************************************
79 ******************************************************************************/
81 static void Console_Task(void)
83 /* Device must be connected and configured for the task to run */
84 if (USB_DeviceState != DEVICE_STATE_Configured)
87 uint8_t ep = Endpoint_GetCurrentEndpoint();
90 // TODO: impl receivechar()/recvchar()
91 Endpoint_SelectEndpoint(CONSOLE_OUT_EPNUM);
93 /* Check to see if a packet has been sent from the host */
94 if (Endpoint_IsOUTReceived())
96 /* Check to see if the packet contains data */
97 if (Endpoint_IsReadWriteAllowed())
99 /* Create a temporary buffer to hold the read in report from the host */
100 uint8_t ConsoleData[CONSOLE_EPSIZE];
102 /* Read Console Report Data */
103 Endpoint_Read_Stream_LE(&ConsoleData, sizeof(ConsoleData), NULL);
105 /* Process Console Report Data */
106 //ProcessConsoleHIDReport(ConsoleData);
109 /* Finalize the stream transfer to send the last packet */
115 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
116 if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
117 Endpoint_SelectEndpoint(ep);
122 while (Endpoint_IsReadWriteAllowed())
125 // flash senchar packet
126 if (Endpoint_IsINReady()) {
130 Endpoint_SelectEndpoint(ep);
133 static void Console_Task(void)
139 /*******************************************************************************
141 ******************************************************************************/
143 * Event Order of Plug in:
144 * 0) EVENT_USB_Device_Connect
145 * 1) EVENT_USB_Device_Suspend
146 * 2) EVENT_USB_Device_Reset
147 * 3) EVENT_USB_Device_Wake
149 void EVENT_USB_Device_Connect(void)
151 /* For battery powered device */
152 if (!USB_IsInitialized) {
154 USB_Device_EnableSOFEvents();
158 void EVENT_USB_Device_Disconnect(void)
160 /* For battery powered device */
161 /* TODO: This doesn't work. After several plug in/outs can not be enumerated.
162 if (USB_IsInitialized) {
163 USB_Disable(); // Disable all interrupts
164 USB_Controller_Enable();
165 USB_INT_Enable(USB_INT_VBUSTI);
170 void EVENT_USB_Device_Reset(void)
174 void EVENT_USB_Device_Suspend()
176 #ifdef SLEEP_LED_ENABLE
181 void EVENT_USB_Device_WakeUp()
183 suspend_wakeup_init();
185 #ifdef SLEEP_LED_ENABLE
187 // NOTE: converters may not accept this
188 led_set(host_keyboard_leds());
192 void EVENT_USB_Device_StartOfFrame(void)
197 /** Event handler for the USB_ConfigurationChanged event.
198 * This is fired when the host sets the current configuration of the USB device after enumeration.
200 void EVENT_USB_Device_ConfigurationChanged(void)
202 bool ConfigSuccess = true;
204 /* Setup Keyboard HID Report Endpoints */
205 ConfigSuccess &= ENDPOINT_CONFIG(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
206 KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
209 /* Setup Mouse HID Report Endpoint */
210 ConfigSuccess &= ENDPOINT_CONFIG(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
211 MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE);
214 #ifdef EXTRAKEY_ENABLE
215 /* Setup Extra HID Report Endpoint */
216 ConfigSuccess &= ENDPOINT_CONFIG(EXTRAKEY_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
217 EXTRAKEY_EPSIZE, ENDPOINT_BANK_SINGLE);
220 #ifdef CONSOLE_ENABLE
221 /* Setup Console HID Report Endpoints */
222 ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
223 CONSOLE_EPSIZE, ENDPOINT_BANK_DOUBLE);
225 ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
226 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
231 /* Setup NKRO HID Report Endpoints */
232 ConfigSuccess &= ENDPOINT_CONFIG(NKRO_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
233 NKRO_EPSIZE, ENDPOINT_BANK_SINGLE);
238 Appendix G: HID Request Support Requirements
240 The following table enumerates the requests that need to be supported by various types of HID class devices.
242 Device type GetReport SetReport GetIdle SetIdle GetProtocol SetProtocol
243 ------------------------------------------------------------------------------------------
244 Boot Mouse Required Optional Optional Optional Required Required
245 Non-Boot Mouse Required Optional Optional Optional Optional Optional
246 Boot Keyboard Required Optional Required Required Required Required
247 Non-Boot Keybrd Required Optional Required Required Optional Optional
248 Other Device Required Optional Optional Optional Optional Optional
250 /** Event handler for the USB_ControlRequest event.
251 * This is fired before passing along unhandled control requests to the library for processing internally.
253 void EVENT_USB_Device_ControlRequest(void)
255 uint8_t* ReportData = NULL;
256 uint8_t ReportSize = 0;
258 /* Handle HID Class specific requests */
259 switch (USB_ControlRequest.bRequest)
261 case HID_REQ_GetReport:
262 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
264 Endpoint_ClearSETUP();
267 switch (USB_ControlRequest.wIndex) {
268 case KEYBOARD_INTERFACE:
270 ReportData = (uint8_t*)&keyboard_report_sent;
271 ReportSize = sizeof(keyboard_report_sent);
275 /* Write the report data to the control endpoint */
276 Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
281 case HID_REQ_SetReport:
282 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
286 switch (USB_ControlRequest.wIndex) {
287 case KEYBOARD_INTERFACE:
291 Endpoint_ClearSETUP();
293 while (!(Endpoint_IsOUTReceived())) {
294 if (USB_DeviceState == DEVICE_STATE_Unattached)
297 keyboard_led_stats = Endpoint_Read_8();
300 Endpoint_ClearStatusStage();
308 case HID_REQ_GetProtocol:
309 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
311 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
312 Endpoint_ClearSETUP();
313 while (!(Endpoint_IsINReady()));
314 Endpoint_Write_8(keyboard_protocol);
316 Endpoint_ClearStatusStage();
321 case HID_REQ_SetProtocol:
322 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
324 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
325 Endpoint_ClearSETUP();
326 Endpoint_ClearStatusStage();
328 keyboard_protocol = ((USB_ControlRequest.wValue & 0xFF) != 0x00);
330 keyboard_nkro = !!keyboard_protocol;
337 case HID_REQ_SetIdle:
338 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
340 Endpoint_ClearSETUP();
341 Endpoint_ClearStatusStage();
343 keyboard_idle = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
347 case HID_REQ_GetIdle:
348 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
350 Endpoint_ClearSETUP();
351 while (!(Endpoint_IsINReady()));
352 Endpoint_Write_8(keyboard_idle);
354 Endpoint_ClearStatusStage();
361 /*******************************************************************************
363 ******************************************************************************/
364 static uint8_t keyboard_leds(void)
366 return keyboard_led_stats;
369 static void send_keyboard(report_keyboard_t *report)
371 uint8_t timeout = 255;
373 if (USB_DeviceState != DEVICE_STATE_Configured)
376 /* Select the Keyboard Report Endpoint */
379 /* Report protocol - NKRO */
380 Endpoint_SelectEndpoint(NKRO_IN_EPNUM);
382 /* Check if write ready for a polling interval around 1ms */
383 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(4);
384 if (!Endpoint_IsReadWriteAllowed()) return;
386 /* Write Keyboard Report Data */
387 Endpoint_Write_Stream_LE(report, NKRO_EPSIZE, NULL);
393 Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
395 /* Check if write ready for a polling interval around 10ms */
396 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
397 if (!Endpoint_IsReadWriteAllowed()) return;
399 /* Write Keyboard Report Data */
400 Endpoint_Write_Stream_LE(report, KEYBOARD_EPSIZE, NULL);
403 /* Finalize the stream transfer to send the last packet */
406 keyboard_report_sent = *report;
409 static void send_mouse(report_mouse_t *report)
412 uint8_t timeout = 255;
414 if (USB_DeviceState != DEVICE_STATE_Configured)
417 /* Select the Mouse Report Endpoint */
418 Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
420 /* Check if write ready for a polling interval around 10ms */
421 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
422 if (!Endpoint_IsReadWriteAllowed()) return;
424 /* Write Mouse Report Data */
425 Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
427 /* Finalize the stream transfer to send the last packet */
432 static void send_system(uint16_t data)
434 uint8_t timeout = 255;
436 if (USB_DeviceState != DEVICE_STATE_Configured)
440 .report_id = REPORT_ID_SYSTEM,
443 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
445 /* Check if write ready for a polling interval around 10ms */
446 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
447 if (!Endpoint_IsReadWriteAllowed()) return;
449 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
453 static void send_consumer(uint16_t data)
455 uint8_t timeout = 255;
457 if (USB_DeviceState != DEVICE_STATE_Configured)
461 .report_id = REPORT_ID_CONSUMER,
464 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
466 /* Check if write ready for a polling interval around 10ms */
467 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
468 if (!Endpoint_IsReadWriteAllowed()) return;
470 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
475 /*******************************************************************************
477 ******************************************************************************/
478 #ifdef CONSOLE_ENABLE
479 #define SEND_TIMEOUT 5
480 int8_t sendchar(uint8_t c)
482 // Not wait once timeouted.
483 // Because sendchar() is called so many times, waiting each call causes big lag.
484 static bool timeouted = false;
486 if (USB_DeviceState != DEVICE_STATE_Configured)
489 uint8_t ep = Endpoint_GetCurrentEndpoint();
490 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
491 if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
492 Endpoint_SelectEndpoint(ep);
496 if (timeouted && !Endpoint_IsReadWriteAllowed()) {
497 Endpoint_SelectEndpoint(ep);
503 uint8_t timeout = SEND_TIMEOUT;
504 uint16_t prevFN = USB_Device_GetFrameNumber();
505 while (!Endpoint_IsReadWriteAllowed()) {
506 switch (USB_DeviceState) {
507 case DEVICE_STATE_Unattached:
508 case DEVICE_STATE_Suspended:
511 if (Endpoint_IsStalled()) {
512 Endpoint_SelectEndpoint(ep);
515 if (prevFN != USB_Device_GetFrameNumber()) {
518 Endpoint_SelectEndpoint(ep);
521 prevFN = USB_Device_GetFrameNumber();
527 // send when bank is full
528 if (!Endpoint_IsReadWriteAllowed())
531 Endpoint_SelectEndpoint(ep);
535 int8_t sendchar(uint8_t c)
542 /*******************************************************************************
544 ******************************************************************************/
545 static void SetupHardware(void)
547 /* Disable watchdog if enabled by bootloader/fuses */
548 MCUSR &= ~(1 << WDRF);
551 /* Disable clock division */
552 clock_prescale_set(clock_div_1);
554 // Leonardo needs. Without this USB device is not recognized.
560 USB_Device_EnableSOFEvents();
561 print_set_sendchar(sendchar);
564 int main(void) __attribute__ ((weak));
570 /* wait for USB startup & debug output */
571 while (USB_DeviceState != DEVICE_STATE_Configured) {
572 #if defined(INTERRUPT_CONTROL_ENDPOINT)
578 print("USB configured.\n");
582 host_set_driver(&lufa_driver);
583 #ifdef SLEEP_LED_ENABLE
587 print("Keyboard start.\n");
589 while (USB_DeviceState == DEVICE_STATE_Suspended) {
590 suspend_power_down(WDTO_120MS);
591 if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) {
592 USB_Device_SendRemoteWakeup();
598 #if !defined(INTERRUPT_CONTROL_ENDPOINT)