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
);
110 if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
111 Endpoint_SelectEndpoint(ep
);
116 while (Endpoint_IsReadWriteAllowed())
119 // flash senchar packet
120 if (Endpoint_IsINReady()) {
124 Endpoint_SelectEndpoint(ep
);
127 static void Console_Task(void)
133 /*******************************************************************************
135 ******************************************************************************/
137 void EVENT_USB_Device_Connect(void)
141 void EVENT_USB_Device_Disconnect(void)
145 void EVENT_USB_Device_Reset(void)
149 void EVENT_USB_Device_Suspend()
151 led_set(1<<USB_LED_CAPS_LOCK
);
154 void EVENT_USB_Device_WakeUp()
159 void EVENT_USB_Device_StartOfFrame(void)
164 /** Event handler for the USB_ConfigurationChanged event.
165 * This is fired when the host sets the current configuration of the USB device after enumeration.
167 #if LUFA_VERSION_INTEGER < 0x120730
169 #define ENDPOINT_CONFIG(epnum, eptype, epdir, epsize, epbank) Endpoint_ConfigureEndpoint(epnum, eptype, epdir, epsize, epbank)
171 /* new API >= 120730 */
172 #define ENDPOINT_BANK_SINGLE 1
173 #define ENDPOINT_BANK_DOUBLE 2
174 #define ENDPOINT_CONFIG(epnum, eptype, epdir, epsize, epbank) Endpoint_ConfigureEndpoint((epdir) | (epnum) , eptype, epsize, epbank)
176 void EVENT_USB_Device_ConfigurationChanged(void)
178 bool ConfigSuccess
= true;
180 /* Setup Keyboard HID Report Endpoints */
181 ConfigSuccess
&= ENDPOINT_CONFIG(KEYBOARD_IN_EPNUM
, EP_TYPE_INTERRUPT
, ENDPOINT_DIR_IN
,
182 KEYBOARD_EPSIZE
, ENDPOINT_BANK_SINGLE
);
185 /* Setup Mouse HID Report Endpoint */
186 ConfigSuccess
&= ENDPOINT_CONFIG(MOUSE_IN_EPNUM
, EP_TYPE_INTERRUPT
, ENDPOINT_DIR_IN
,
187 MOUSE_EPSIZE
, ENDPOINT_BANK_SINGLE
);
190 #ifdef EXTRAKEY_ENABLE
191 /* Setup Extra HID Report Endpoint */
192 ConfigSuccess
&= ENDPOINT_CONFIG(EXTRAKEY_IN_EPNUM
, EP_TYPE_INTERRUPT
, ENDPOINT_DIR_IN
,
193 EXTRAKEY_EPSIZE
, ENDPOINT_BANK_SINGLE
);
196 #ifdef CONSOLE_ENABLE
197 /* Setup Console HID Report Endpoints */
198 ConfigSuccess
&= ENDPOINT_CONFIG(CONSOLE_IN_EPNUM
, EP_TYPE_INTERRUPT
, ENDPOINT_DIR_IN
,
199 CONSOLE_EPSIZE
, ENDPOINT_BANK_DOUBLE
);
200 ConfigSuccess
&= ENDPOINT_CONFIG(CONSOLE_OUT_EPNUM
, EP_TYPE_INTERRUPT
, ENDPOINT_DIR_OUT
,
201 CONSOLE_EPSIZE
, ENDPOINT_BANK_SINGLE
);
206 Appendix G: HID Request Support Requirements
208 The following table enumerates the requests that need to be supported by various types of HID class devices.
210 Device type GetReport SetReport GetIdle SetIdle GetProtocol SetProtocol
211 ------------------------------------------------------------------------------------------
212 Boot Mouse Required Optional Optional Optional Required Required
213 Non-Boot Mouse Required Optional Optional Optional Optional Optional
214 Boot Keyboard Required Optional Required Required Required Required
215 Non-Boot Keybrd Required Optional Required Required Optional Optional
216 Other Device Required Optional Optional Optional Optional Optional
218 /** Event handler for the USB_ControlRequest event.
219 * This is fired before passing along unhandled control requests to the library for processing internally.
221 void EVENT_USB_Device_ControlRequest(void)
223 uint8_t* ReportData
= NULL
;
224 uint8_t ReportSize
= 0;
226 /* Handle HID Class specific requests */
227 switch (USB_ControlRequest
.bRequest
)
229 case HID_REQ_GetReport
:
230 if (USB_ControlRequest
.bmRequestType
== (REQDIR_DEVICETOHOST
| REQTYPE_CLASS
| REQREC_INTERFACE
))
232 Endpoint_ClearSETUP();
235 switch (USB_ControlRequest
.wIndex
) {
236 case KEYBOARD_INTERFACE
:
238 ReportData
= (uint8_t*)&keyboard_report_sent
;
239 ReportSize
= sizeof(keyboard_report_sent
);
243 /* Write the report data to the control endpoint */
244 Endpoint_Write_Control_Stream_LE(ReportData
, ReportSize
);
249 case HID_REQ_SetReport
:
250 if (USB_ControlRequest
.bmRequestType
== (REQDIR_HOSTTODEVICE
| REQTYPE_CLASS
| REQREC_INTERFACE
))
254 switch (USB_ControlRequest
.wIndex
) {
255 case KEYBOARD_INTERFACE
:
256 Endpoint_ClearSETUP();
258 while (!(Endpoint_IsOUTReceived())) {
259 if (USB_DeviceState
== DEVICE_STATE_Unattached
)
262 keyboard_led_stats
= Endpoint_Read_8();
265 Endpoint_ClearStatusStage();
273 case HID_REQ_GetProtocol
:
274 if (USB_ControlRequest
.bmRequestType
== (REQDIR_DEVICETOHOST
| REQTYPE_CLASS
| REQREC_INTERFACE
))
276 Endpoint_ClearSETUP();
277 while (!(Endpoint_IsINReady()));
278 Endpoint_Write_8(protocol_report
);
280 Endpoint_ClearStatusStage();
284 case HID_REQ_SetProtocol
:
285 if (USB_ControlRequest
.bmRequestType
== (REQDIR_HOSTTODEVICE
| REQTYPE_CLASS
| REQREC_INTERFACE
))
287 Endpoint_ClearSETUP();
288 Endpoint_ClearStatusStage();
290 protocol_report
= ((USB_ControlRequest
.wValue
& 0xFF) != 0x00);
294 case HID_REQ_SetIdle
:
295 if (USB_ControlRequest
.bmRequestType
== (REQDIR_HOSTTODEVICE
| REQTYPE_CLASS
| REQREC_INTERFACE
))
297 Endpoint_ClearSETUP();
298 Endpoint_ClearStatusStage();
300 idle_duration
= ((USB_ControlRequest
.wValue
& 0xFF00) >> 8);
304 case HID_REQ_GetIdle
:
305 if (USB_ControlRequest
.bmRequestType
== (REQDIR_DEVICETOHOST
| REQTYPE_CLASS
| REQREC_INTERFACE
))
307 Endpoint_ClearSETUP();
308 while (!(Endpoint_IsINReady()));
309 Endpoint_Write_8(idle_duration
);
311 Endpoint_ClearStatusStage();
318 /*******************************************************************************
320 ******************************************************************************/
321 static uint8_t keyboard_leds(void)
323 return keyboard_led_stats
;
326 static void send_keyboard(report_keyboard_t
*report
)
330 // TODO: handle NKRO report
331 /* Select the Keyboard Report Endpoint */
332 Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM
);
334 /* Check if Keyboard Endpoint Ready for Read/Write */
335 while (--timeout
&& !Endpoint_IsReadWriteAllowed()) ;
337 /* Write Keyboard Report Data */
338 Endpoint_Write_Stream_LE(report
, sizeof(report_keyboard_t
), NULL
);
340 /* Finalize the stream transfer to send the last packet */
343 keyboard_report_sent
= *report
;
346 static void send_mouse(report_mouse_t
*report
)
351 /* Select the Mouse Report Endpoint */
352 Endpoint_SelectEndpoint(MOUSE_IN_EPNUM
);
354 /* Check if Mouse Endpoint Ready for Read/Write */
355 while (--timeout
&& !Endpoint_IsReadWriteAllowed()) ;
357 /* Write Mouse Report Data */
358 Endpoint_Write_Stream_LE(report
, sizeof(report_mouse_t
), NULL
);
360 /* Finalize the stream transfer to send the last packet */
365 static void send_system(uint16_t data
)
370 .report_id
= REPORT_ID_SYSTEM
,
373 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM
);
374 while (--timeout
&& !Endpoint_IsReadWriteAllowed()) ;
375 Endpoint_Write_Stream_LE(&r
, sizeof(report_extra_t
), NULL
);
379 static void send_consumer(uint16_t data
)
384 .report_id
= REPORT_ID_CONSUMER
,
387 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM
);
388 while (--timeout
&& !Endpoint_IsReadWriteAllowed()) ;
389 Endpoint_Write_Stream_LE(&r
, sizeof(report_extra_t
), NULL
);
394 /*******************************************************************************
396 ******************************************************************************/
397 #ifdef CONSOLE_ENABLE
398 #define SEND_TIMEOUT 5
399 int8_t sendchar(uint8_t c
)
401 // Not wait once timeouted.
402 // Because sendchar() is called so many times, waiting each call causes big lag.
403 static bool timeouted
= false;
405 if (USB_DeviceState
!= DEVICE_STATE_Configured
)
408 uint8_t ep
= Endpoint_GetCurrentEndpoint();
409 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM
);
410 if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
411 Endpoint_SelectEndpoint(ep
);
415 if (timeouted
&& !Endpoint_IsReadWriteAllowed()) {
416 Endpoint_SelectEndpoint(ep
);
422 uint8_t timeout
= SEND_TIMEOUT
;
423 uint16_t prevFN
= USB_Device_GetFrameNumber();
424 while (!Endpoint_IsReadWriteAllowed()) {
425 switch (USB_DeviceState
) {
426 case DEVICE_STATE_Unattached
:
427 case DEVICE_STATE_Suspended
:
430 if (Endpoint_IsStalled()) {
431 Endpoint_SelectEndpoint(ep
);
434 if (prevFN
!= USB_Device_GetFrameNumber()) {
437 Endpoint_SelectEndpoint(ep
);
440 prevFN
= USB_Device_GetFrameNumber();
446 // send when bank is full
447 if (!Endpoint_IsReadWriteAllowed())
450 Endpoint_SelectEndpoint(ep
);
454 int8_t sendchar(uint8_t c
)
461 /*******************************************************************************
463 ******************************************************************************/
464 static void SetupHardware(void)
466 /* Disable watchdog if enabled by bootloader/fuses */
467 MCUSR
&= ~(1 << WDRF
);
470 /* Disable clock division */
471 clock_prescale_set(clock_div_1
);
473 // Leonardo needs. Without this USB device is not recognized.
479 USB_Device_EnableSOFEvents();
484 static bool wakeup_condition(void)
487 for (uint8_t r
= 0; r
< MATRIX_ROWS
; r
++) {
488 if (matrix_get_row(r
)) return true;
493 int main(void) __attribute__ ((weak
));
498 host_set_driver(&lufa_driver
);
502 while (USB_DeviceState
== DEVICE_STATE_Suspended
) {
503 // TODO: power saving
505 if (USB_Device_RemoteWakeupEnabled
) {
506 if (wakeup_condition()) {
507 USB_Device_SendRemoteWakeup();
514 #if !defined(INTERRUPT_CONTROL_ENDPOINT)