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"
46 #include "descriptor.h"
49 static uint8_t keyboard_led_stats = 0;
51 // TODO: impl Control Request GET_REPORT
52 static report_keyboard_t keyboard_report_sent;
54 static report_mouse_t mouse_report_sent;
58 static uint8_t keyboard_leds(void);
59 static void send_keyboard(report_keyboard_t *report);
60 static void send_mouse(report_mouse_t *report);
61 static void send_system(uint16_t data);
62 static void send_consumer(uint16_t data);
63 static host_driver_t lufa_driver = {
72 static void SetupHardware(void);
73 static void Console_HID_Task(void);
83 debug_keyboard = true;
86 /* TODO: can't print here
94 host_set_driver(&lufa_driver);
103 void SetupHardware(void)
105 /* Disable watchdog if enabled by bootloader/fuses */
106 MCUSR &= ~(1 << WDRF);
109 /* Disable clock division */
110 clock_prescale_set(clock_div_1);
115 static void Console_HID_Task(void)
117 /* Device must be connected and configured for the task to run */
118 if (USB_DeviceState != DEVICE_STATE_Configured)
121 // TODO: impl receivechar()/recvchar()
122 Endpoint_SelectEndpoint(CONSOLE_OUT_EPNUM);
124 /* Check to see if a packet has been sent from the host */
125 if (Endpoint_IsOUTReceived())
127 /* Check to see if the packet contains data */
128 if (Endpoint_IsReadWriteAllowed())
130 /* Create a temporary buffer to hold the read in report from the host */
131 uint8_t ConsoleData[CONSOLE_EPSIZE];
133 /* Read Console Report Data */
134 Endpoint_Read_Stream_LE(&ConsoleData, sizeof(ConsoleData), NULL);
136 /* Process Console Report Data */
137 //ProcessConsoleHIDReport(ConsoleData);
140 /* Finalize the stream transfer to send the last packet */
145 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
147 if (Endpoint_IsINReady())
152 /*******************************************************************************
154 ******************************************************************************/
155 /** Event handler for the USB_Connect event. */
156 void EVENT_USB_Device_Connect(void)
160 /** Event handler for the USB_Disconnect event. */
161 void EVENT_USB_Device_Disconnect(void)
165 /** Event handler for the USB_ConfigurationChanged event.
166 * This is fired when the host sets the current configuration of the USB device after enumeration.
168 void EVENT_USB_Device_ConfigurationChanged(void)
170 bool ConfigSuccess = true;
172 /* Setup Keyboard HID Report Endpoints */
173 ConfigSuccess &= Endpoint_ConfigureEndpoint(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
174 KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
177 /* Setup Mouse HID Report Endpoint */
178 ConfigSuccess &= Endpoint_ConfigureEndpoint(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
179 MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE);
182 #ifdef EXTRAKEY_ENABLE
183 /* Setup Extra HID Report Endpoint */
184 ConfigSuccess &= Endpoint_ConfigureEndpoint(EXTRA_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
185 EXTRA_EPSIZE, ENDPOINT_BANK_SINGLE);
188 /* Setup Console HID Report Endpoints */
189 ConfigSuccess &= Endpoint_ConfigureEndpoint(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
190 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
191 ConfigSuccess &= Endpoint_ConfigureEndpoint(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
192 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
196 Appendix G: HID Request Support Requirements
198 The following table enumerates the requests that need to be supported by various types of HID class devices.
200 Device type GetReport SetReport GetIdle SetIdle GetProtocol SetProtocol
201 ------------------------------------------------------------------------------------------
202 Boot Mouse Required Optional Optional Optional Required Required
203 Non-Boot Mouse Required Optional Optional Optional Optional Optional
204 Boot Keyboard Required Optional Required Required Required Required
205 Non-Boot Keybrd Required Optional Required Required Optional Optional
206 Other Device Required Optional Optional Optional Optional Optional
208 /** Event handler for the USB_ControlRequest event.
209 * This is fired before passing along unhandled control requests to the library for processing internally.
211 void EVENT_USB_Device_ControlRequest(void)
213 uint8_t* ReportData = NULL;
214 uint8_t ReportSize = 0;
216 /* Handle HID Class specific requests */
217 switch (USB_ControlRequest.bRequest)
219 case HID_REQ_GetReport:
220 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
222 Endpoint_ClearSETUP();
225 switch (USB_ControlRequest.wIndex) {
226 case KEYBOARD_INTERFACE:
228 ReportData = (uint8_t*)&keyboard_report_sent;
229 ReportSize = sizeof(keyboard_report_sent);
232 case MOUSE_INTERFACE:
234 ReportData = (uint8_t*)&mouse_report_sent;
235 ReportSize = sizeof(mouse_report_sent);
238 #ifdef EXTRAKEY_ENABLE
239 case EXTRA_INTERFACE:
242 case CONSOLE_INTERFACE:
246 /* Write the report data to the control endpoint */
247 Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
252 case HID_REQ_SetReport:
253 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
255 Endpoint_ClearSETUP();
257 /* Wait until the LED report has been sent by the host */
258 while (!(Endpoint_IsOUTReceived()))
260 if (USB_DeviceState == DEVICE_STATE_Unattached)
265 switch (USB_ControlRequest.wIndex) {
266 case KEYBOARD_INTERFACE:
268 /* Read in the LED report from the host */
269 keyboard_led_stats = Endpoint_Read_8();
272 case MOUSE_INTERFACE:
275 #ifdef EXTRAKEY_ENABLE
276 case EXTRA_INTERFACE:
279 case CONSOLE_INTERFACE:
284 Endpoint_ClearStatusStage();
291 /*******************************************************************************
293 ******************************************************************************/
294 static uint8_t keyboard_leds(void)
296 return keyboard_led_stats;
299 static void send_keyboard(report_keyboard_t *report)
301 // TODO: handle NKRO report
302 /* Select the Keyboard Report Endpoint */
303 Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
305 /* Check if Keyboard Endpoint Ready for Read/Write */
306 if (Endpoint_IsReadWriteAllowed())
308 /* Write Keyboard Report Data */
309 Endpoint_Write_Stream_LE(report, sizeof(report_keyboard_t), NULL);
311 /* Finalize the stream transfer to send the last packet */
314 keyboard_report_sent = *report;
317 static void send_mouse(report_mouse_t *report)
320 /* Select the Mouse Report Endpoint */
321 Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
323 /* Check if Mouse Endpoint Ready for Read/Write */
324 if (Endpoint_IsReadWriteAllowed())
326 /* Write Mouse Report Data */
327 Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
329 /* Finalize the stream transfer to send the last packet */
332 mouse_report_sent = *report;
339 } __attribute__ ((packed)) report_extra_t;
341 static void send_system(uint16_t data)
343 Endpoint_SelectEndpoint(EXTRA_IN_EPNUM);
344 if (Endpoint_IsReadWriteAllowed()) {
346 .report_id = REPORT_ID_SYSTEM,
349 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
354 static void send_consumer(uint16_t data)
356 Endpoint_SelectEndpoint(EXTRA_IN_EPNUM);
357 if (Endpoint_IsReadWriteAllowed()) {
359 .report_id = REPORT_ID_CONSUMER,
362 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
368 /*******************************************************************************
370 ******************************************************************************/
371 int8_t sendchar(uint8_t c)
373 if (USB_DeviceState != DEVICE_STATE_Configured)
376 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
378 uint8_t timeout = 10;
379 uint16_t prevFN = USB_Device_GetFrameNumber();
380 while (!Endpoint_IsINReady()) {
381 switch (USB_DeviceState) {
382 case DEVICE_STATE_Unattached:
383 case DEVICE_STATE_Suspended:
386 if (Endpoint_IsStalled())
388 if (prevFN != USB_Device_GetFrameNumber()) {
391 prevFN = USB_Device_GetFrameNumber();
397 // send when packet is full
398 if (!Endpoint_IsReadWriteAllowed())