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 idle_duration = 0;
50 static uint8_t protocol_report = 1;
51 static uint8_t keyboard_led_stats = 0;
53 static report_keyboard_t keyboard_report_sent;
57 static uint8_t keyboard_leds(void);
58 static void send_keyboard(report_keyboard_t *report);
59 static void send_mouse(report_mouse_t *report);
60 static void send_system(uint16_t data);
61 static void send_consumer(uint16_t data);
62 host_driver_t lufa_driver = {
71 /*******************************************************************************
73 ******************************************************************************/
75 static void Console_Task(void)
77 /* Device must be connected and configured for the task to run */
78 if (USB_DeviceState != DEVICE_STATE_Configured)
81 uint8_t ep = Endpoint_GetCurrentEndpoint();
84 // TODO: impl receivechar()/recvchar()
85 Endpoint_SelectEndpoint(CONSOLE_OUT_EPNUM);
87 /* Check to see if a packet has been sent from the host */
88 if (Endpoint_IsOUTReceived())
90 /* Check to see if the packet contains data */
91 if (Endpoint_IsReadWriteAllowed())
93 /* Create a temporary buffer to hold the read in report from the host */
94 uint8_t ConsoleData[CONSOLE_EPSIZE];
96 /* Read Console Report Data */
97 Endpoint_Read_Stream_LE(&ConsoleData, sizeof(ConsoleData), NULL);
99 /* Process Console Report Data */
100 //ProcessConsoleHIDReport(ConsoleData);
103 /* Finalize the stream transfer to send the last packet */
109 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
112 while (Endpoint_IsReadWriteAllowed())
115 // flash senchar packet
116 if (Endpoint_IsINReady()) {
120 Endpoint_SelectEndpoint(ep);
123 static void Console_Task(void)
129 /*******************************************************************************
131 ******************************************************************************/
132 /** Event handler for the USB_Connect event. */
133 void EVENT_USB_Device_Connect(void)
137 /** Event handler for the USB_Disconnect event. */
138 void EVENT_USB_Device_Disconnect(void)
142 void EVENT_USB_Device_StartOfFrame(void)
147 /** Event handler for the USB_ConfigurationChanged event.
148 * This is fired when the host sets the current configuration of the USB device after enumeration.
150 void EVENT_USB_Device_ConfigurationChanged(void)
152 bool ConfigSuccess = true;
154 /* Setup Keyboard HID Report Endpoints */
155 ConfigSuccess &= Endpoint_ConfigureEndpoint(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
156 KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
159 /* Setup Mouse HID Report Endpoint */
160 ConfigSuccess &= Endpoint_ConfigureEndpoint(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
161 MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE);
164 #ifdef EXTRAKEY_ENABLE
165 /* Setup Extra HID Report Endpoint */
166 ConfigSuccess &= Endpoint_ConfigureEndpoint(EXTRAKEY_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
167 EXTRAKEY_EPSIZE, ENDPOINT_BANK_SINGLE);
170 #ifdef CONSOLE_ENABLE
171 /* Setup Console HID Report Endpoints */
172 ConfigSuccess &= Endpoint_ConfigureEndpoint(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
173 CONSOLE_EPSIZE, ENDPOINT_BANK_DOUBLE);
174 ConfigSuccess &= Endpoint_ConfigureEndpoint(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
175 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
180 Appendix G: HID Request Support Requirements
182 The following table enumerates the requests that need to be supported by various types of HID class devices.
184 Device type GetReport SetReport GetIdle SetIdle GetProtocol SetProtocol
185 ------------------------------------------------------------------------------------------
186 Boot Mouse Required Optional Optional Optional Required Required
187 Non-Boot Mouse Required Optional Optional Optional Optional Optional
188 Boot Keyboard Required Optional Required Required Required Required
189 Non-Boot Keybrd Required Optional Required Required Optional Optional
190 Other Device Required Optional Optional Optional Optional Optional
192 /** Event handler for the USB_ControlRequest event.
193 * This is fired before passing along unhandled control requests to the library for processing internally.
195 void EVENT_USB_Device_ControlRequest(void)
197 uint8_t* ReportData = NULL;
198 uint8_t ReportSize = 0;
200 /* Handle HID Class specific requests */
201 switch (USB_ControlRequest.bRequest)
203 case HID_REQ_GetReport:
204 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
206 Endpoint_ClearSETUP();
209 switch (USB_ControlRequest.wIndex) {
210 case KEYBOARD_INTERFACE:
212 ReportData = (uint8_t*)&keyboard_report_sent;
213 ReportSize = sizeof(keyboard_report_sent);
217 /* Write the report data to the control endpoint */
218 Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
223 case HID_REQ_SetReport:
224 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
228 switch (USB_ControlRequest.wIndex) {
229 case KEYBOARD_INTERFACE:
230 Endpoint_ClearSETUP();
232 while (!(Endpoint_IsOUTReceived())) {
233 if (USB_DeviceState == DEVICE_STATE_Unattached)
236 keyboard_led_stats = Endpoint_Read_8();
239 Endpoint_ClearStatusStage();
247 case HID_REQ_GetProtocol:
248 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
250 Endpoint_ClearSETUP();
251 while (!(Endpoint_IsINReady()));
252 Endpoint_Write_8(protocol_report);
254 Endpoint_ClearStatusStage();
258 case HID_REQ_SetProtocol:
259 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
261 Endpoint_ClearSETUP();
262 Endpoint_ClearStatusStage();
264 protocol_report = ((USB_ControlRequest.wValue & 0xFF) != 0x00);
268 case HID_REQ_SetIdle:
269 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
271 Endpoint_ClearSETUP();
272 Endpoint_ClearStatusStage();
274 idle_duration = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
278 case HID_REQ_GetIdle:
279 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
281 Endpoint_ClearSETUP();
282 while (!(Endpoint_IsINReady()));
283 Endpoint_Write_8(idle_duration);
285 Endpoint_ClearStatusStage();
292 /*******************************************************************************
294 ******************************************************************************/
295 static uint8_t keyboard_leds(void)
297 return keyboard_led_stats;
300 static void send_keyboard(report_keyboard_t *report)
302 // TODO: handle NKRO report
303 /* Select the Keyboard Report Endpoint */
304 Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
306 /* Check if Keyboard Endpoint Ready for Read/Write */
307 while (!Endpoint_IsReadWriteAllowed()) ;
309 /* Write Keyboard Report Data */
310 Endpoint_Write_Stream_LE(report, sizeof(report_keyboard_t), NULL);
312 /* Finalize the stream transfer to send the last packet */
315 keyboard_report_sent = *report;
318 static void send_mouse(report_mouse_t *report)
321 /* Select the Mouse Report Endpoint */
322 Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
324 /* Check if Mouse Endpoint Ready for Read/Write */
325 while (!Endpoint_IsReadWriteAllowed()) ;
327 /* Write Mouse Report Data */
328 Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
330 /* Finalize the stream transfer to send the last packet */
335 static void send_system(uint16_t data)
338 .report_id = REPORT_ID_SYSTEM,
341 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
342 while (!Endpoint_IsReadWriteAllowed()) ;
343 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
347 static void send_consumer(uint16_t data)
350 .report_id = REPORT_ID_CONSUMER,
353 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
354 while (!Endpoint_IsReadWriteAllowed()) ;
355 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
360 /*******************************************************************************
362 ******************************************************************************/
363 #ifdef CONSOLE_ENABLE
364 #define SEND_TIMEOUT 5
365 int8_t sendchar(uint8_t c)
367 if (USB_DeviceState != DEVICE_STATE_Configured)
370 uint8_t ep = Endpoint_GetCurrentEndpoint();
371 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
373 uint8_t timeout = SEND_TIMEOUT;
374 uint16_t prevFN = USB_Device_GetFrameNumber();
375 while (!Endpoint_IsReadWriteAllowed()) {
376 switch (USB_DeviceState) {
377 case DEVICE_STATE_Unattached:
378 case DEVICE_STATE_Suspended:
381 if (Endpoint_IsStalled()) {
382 Endpoint_SelectEndpoint(ep);
385 if (prevFN != USB_Device_GetFrameNumber()) {
387 Endpoint_SelectEndpoint(ep);
390 prevFN = USB_Device_GetFrameNumber();
396 // send when bank is full
397 if (!Endpoint_IsReadWriteAllowed())
400 Endpoint_SelectEndpoint(ep);
404 int8_t sendchar(uint8_t c)
411 /*******************************************************************************
413 ******************************************************************************/
414 static void SetupHardware(void)
416 /* Disable watchdog if enabled by bootloader/fuses */
417 MCUSR &= ~(1 << WDRF);
420 /* Disable clock division */
421 clock_prescale_set(clock_div_1);
423 // Leonardo needs. Without this USB device is not recognized.
429 USB_Device_EnableSOFEvents();
432 int main(void) __attribute__ ((weak));
441 debug_keyboard = true;
444 // TODO: can't print here
445 debug("LUFA init\n");
448 host_set_driver(&lufa_driver);
452 #if !defined(INTERRUPT_CONTROL_ENDPOINT)