Add converter/usb_usb/README
[tmk_keyboard.git] / protocol / lufa / lufa.c
CommitLineData
dd93d291 1/*
2 * Copyright 2012 Jun Wako <wakojun@gmail.com>
3969ec09 3 * This file is based on:
4 * LUFA-120219/Demos/Device/Lowlevel/KeyboardMouse
5 * LUFA-120219/Demos/Device/Lowlevel/GenericHID
dd93d291 6 */
7
8/*
9 LUFA Library
10 Copyright (C) Dean Camera, 2012.
11
12 dean [at] fourwalledcubicle [dot] com
13 www.lufa-lib.org
14*/
15
16/*
17 Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
18 Copyright 2010 Denver Gingerich (denver [at] ossguy [dot] com)
19
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.
28
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
36 this software.
37*/
38
39#include "report.h"
40#include "host.h"
41#include "host_driver.h"
42#include "keyboard.h"
3969ec09 43#include "sendchar.h"
44#include "debug.h"
effa5914 45
46#include "descriptor.h"
dd93d291 47#include "lufa.h"
48
a112f361 49static uint8_t idle_duration = 0;
50static uint8_t protocol_report = 1;
dd93d291 51static uint8_t keyboard_led_stats = 0;
effa5914 52
effa5914 53static report_keyboard_t keyboard_report_sent;
a112f361 54
dd93d291 55
56/* Host driver */
57static uint8_t keyboard_leds(void);
58static void send_keyboard(report_keyboard_t *report);
59static void send_mouse(report_mouse_t *report);
60static void send_system(uint16_t data);
61static void send_consumer(uint16_t data);
c5060ea8 62host_driver_t lufa_driver = {
dd93d291 63 keyboard_leds,
64 send_keyboard,
65 send_mouse,
66 send_system,
67 send_consumer
68};
69
70
c5060ea8 71/*******************************************************************************
72 * Console
73 ******************************************************************************/
e075361b 74#ifdef CONSOLE_ENABLE
89470299 75static void Console_Task(void)
effa5914 76{
89470299 77 /* Device must be connected and configured for the task to run */
78 if (USB_DeviceState != DEVICE_STATE_Configured)
79 return;
80
81 uint8_t ep = Endpoint_GetCurrentEndpoint();
82
83#if 0
84 // TODO: impl receivechar()/recvchar()
85 Endpoint_SelectEndpoint(CONSOLE_OUT_EPNUM);
86
87 /* Check to see if a packet has been sent from the host */
88 if (Endpoint_IsOUTReceived())
89 {
90 /* Check to see if the packet contains data */
91 if (Endpoint_IsReadWriteAllowed())
92 {
93 /* Create a temporary buffer to hold the read in report from the host */
94 uint8_t ConsoleData[CONSOLE_EPSIZE];
95
96 /* Read Console Report Data */
97 Endpoint_Read_Stream_LE(&ConsoleData, sizeof(ConsoleData), NULL);
98
99 /* Process Console Report Data */
100 //ProcessConsoleHIDReport(ConsoleData);
101 }
102
103 /* Finalize the stream transfer to send the last packet */
104 Endpoint_ClearOUT();
105 }
106#endif
107
108 /* IN packet */
109 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
e075361b 110
111 // fill empty bank
112 while (Endpoint_IsReadWriteAllowed())
113 Endpoint_Write_8(0);
114
89470299 115 // flash senchar packet
116 if (Endpoint_IsINReady()) {
117 Endpoint_ClearIN();
118 }
119
120 Endpoint_SelectEndpoint(ep);
effa5914 121}
e075361b 122#else
123static void Console_Task(void)
124{
125}
126#endif
effa5914 127
128
129/*******************************************************************************
130 * USB Events
131 ******************************************************************************/
dd93d291 132/** Event handler for the USB_Connect event. */
133void EVENT_USB_Device_Connect(void)
134{
135}
136
137/** Event handler for the USB_Disconnect event. */
138void EVENT_USB_Device_Disconnect(void)
139{
140}
141
89470299 142void EVENT_USB_Device_StartOfFrame(void)
143{
e075361b 144 Console_Task();
89470299 145}
146
dd93d291 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.
149 */
150void EVENT_USB_Device_ConfigurationChanged(void)
151{
152 bool ConfigSuccess = true;
153
154 /* Setup Keyboard HID Report Endpoints */
155 ConfigSuccess &= Endpoint_ConfigureEndpoint(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
3d81d522 156 KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
dd93d291 157
f2ebac10 158#ifdef MOUSE_ENABLE
dd93d291 159 /* Setup Mouse HID Report Endpoint */
160 ConfigSuccess &= Endpoint_ConfigureEndpoint(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
3d81d522 161 MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE);
f2ebac10 162#endif
163
164#ifdef EXTRAKEY_ENABLE
165 /* Setup Extra HID Report Endpoint */
e075361b 166 ConfigSuccess &= Endpoint_ConfigureEndpoint(EXTRAKEY_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
167 EXTRAKEY_EPSIZE, ENDPOINT_BANK_SINGLE);
f2ebac10 168#endif
3969ec09 169
e075361b 170#ifdef CONSOLE_ENABLE
a9a3610d 171 /* Setup Console HID Report Endpoints */
3d81d522 172 ConfigSuccess &= Endpoint_ConfigureEndpoint(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
89470299 173 CONSOLE_EPSIZE, ENDPOINT_BANK_DOUBLE);
3d81d522 174 ConfigSuccess &= Endpoint_ConfigureEndpoint(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
175 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
e075361b 176#endif
dd93d291 177}
178
a9a3610d 179/*
180Appendix G: HID Request Support Requirements
181
182The following table enumerates the requests that need to be supported by various types of HID class devices.
183
184Device type GetReport SetReport GetIdle SetIdle GetProtocol SetProtocol
185------------------------------------------------------------------------------------------
186Boot Mouse Required Optional Optional Optional Required Required
187Non-Boot Mouse Required Optional Optional Optional Optional Optional
188Boot Keyboard Required Optional Required Required Required Required
189Non-Boot Keybrd Required Optional Required Required Optional Optional
190Other Device Required Optional Optional Optional Optional Optional
191*/
dd93d291 192/** Event handler for the USB_ControlRequest event.
193 * This is fired before passing along unhandled control requests to the library for processing internally.
194 */
195void EVENT_USB_Device_ControlRequest(void)
196{
3969ec09 197 uint8_t* ReportData = NULL;
198 uint8_t ReportSize = 0;
dd93d291 199
200 /* Handle HID Class specific requests */
201 switch (USB_ControlRequest.bRequest)
202 {
203 case HID_REQ_GetReport:
204 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
205 {
206 Endpoint_ClearSETUP();
207
3969ec09 208 // Interface
209 switch (USB_ControlRequest.wIndex) {
effa5914 210 case KEYBOARD_INTERFACE:
211 // TODO: test/check
dd93d291 212 ReportData = (uint8_t*)&keyboard_report_sent;
213 ReportSize = sizeof(keyboard_report_sent);
3969ec09 214 break;
dd93d291 215 }
216
217 /* Write the report data to the control endpoint */
218 Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
219 Endpoint_ClearOUT();
220 }
221
222 break;
223 case HID_REQ_SetReport:
224 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
225 {
dd93d291 226
3969ec09 227 // Interface
228 switch (USB_ControlRequest.wIndex) {
effa5914 229 case KEYBOARD_INTERFACE:
a112f361 230 Endpoint_ClearSETUP();
231
232 while (!(Endpoint_IsOUTReceived())) {
233 if (USB_DeviceState == DEVICE_STATE_Unattached)
234 return;
235 }
3969ec09 236 keyboard_led_stats = Endpoint_Read_8();
a112f361 237
238 Endpoint_ClearOUT();
239 Endpoint_ClearStatusStage();
f2ebac10 240 break;
3969ec09 241 }
dd93d291 242
a112f361 243 }
244
245 break;
246
247 case HID_REQ_GetProtocol:
248 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
249 {
250 Endpoint_ClearSETUP();
251 while (!(Endpoint_IsINReady()));
252 Endpoint_Write_8(protocol_report);
253 Endpoint_ClearIN();
254 Endpoint_ClearStatusStage();
255 }
256
257 break;
258 case HID_REQ_SetProtocol:
259 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
260 {
261 Endpoint_ClearSETUP();
262 Endpoint_ClearStatusStage();
263
264 protocol_report = ((USB_ControlRequest.wValue & 0xFF) != 0x00);
265 }
266
267 break;
268 case HID_REQ_SetIdle:
269 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
270 {
271 Endpoint_ClearSETUP();
272 Endpoint_ClearStatusStage();
273
274 idle_duration = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
275 }
276
277 break;
278 case HID_REQ_GetIdle:
279 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
280 {
281 Endpoint_ClearSETUP();
282 while (!(Endpoint_IsINReady()));
283 Endpoint_Write_8(idle_duration);
284 Endpoint_ClearIN();
dd93d291 285 Endpoint_ClearStatusStage();
286 }
287
288 break;
289 }
290}
291
dd93d291 292/*******************************************************************************
293 * Host driver
294 ******************************************************************************/
295static uint8_t keyboard_leds(void)
296{
297 return keyboard_led_stats;
298}
299
300static void send_keyboard(report_keyboard_t *report)
301{
302 // TODO: handle NKRO report
303 /* Select the Keyboard Report Endpoint */
304 Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
305
306 /* Check if Keyboard Endpoint Ready for Read/Write */
7350b7c6 307 while (!Endpoint_IsReadWriteAllowed()) ;
308
309 /* Write Keyboard Report Data */
310 Endpoint_Write_Stream_LE(report, sizeof(report_keyboard_t), NULL);
311
312 /* Finalize the stream transfer to send the last packet */
313 Endpoint_ClearIN();
dd93d291 314
dd93d291 315 keyboard_report_sent = *report;
316}
317
318static void send_mouse(report_mouse_t *report)
319{
f2ebac10 320#ifdef MOUSE_ENABLE
dd93d291 321 /* Select the Mouse Report Endpoint */
322 Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
323
324 /* Check if Mouse Endpoint Ready for Read/Write */
7350b7c6 325 while (!Endpoint_IsReadWriteAllowed()) ;
dd93d291 326
7350b7c6 327 /* Write Mouse Report Data */
328 Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
329
330 /* Finalize the stream transfer to send the last packet */
331 Endpoint_ClearIN();
f2ebac10 332#endif
dd93d291 333}
334
335static void send_system(uint16_t data)
336{
a112f361 337 report_extra_t r = {
338 .report_id = REPORT_ID_SYSTEM,
339 .usage = data
340 };
e075361b 341 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
7350b7c6 342 while (!Endpoint_IsReadWriteAllowed()) ;
343 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
344 Endpoint_ClearIN();
dd93d291 345}
346
347static void send_consumer(uint16_t data)
348{
a112f361 349 report_extra_t r = {
350 .report_id = REPORT_ID_CONSUMER,
351 .usage = data
352 };
e075361b 353 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
7350b7c6 354 while (!Endpoint_IsReadWriteAllowed()) ;
355 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
356 Endpoint_ClearIN();
dd93d291 357}
3969ec09 358
359
360/*******************************************************************************
361 * sendchar
362 ******************************************************************************/
e075361b 363#ifdef CONSOLE_ENABLE
364#define SEND_TIMEOUT 5
3969ec09 365int8_t sendchar(uint8_t c)
366{
367 if (USB_DeviceState != DEVICE_STATE_Configured)
368 return -1;
369
e075361b 370 uint8_t ep = Endpoint_GetCurrentEndpoint();
3d81d522 371 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
3969ec09 372
89470299 373 uint8_t timeout = SEND_TIMEOUT;
3969ec09 374 uint16_t prevFN = USB_Device_GetFrameNumber();
89470299 375 while (!Endpoint_IsReadWriteAllowed()) {
3969ec09 376 switch (USB_DeviceState) {
377 case DEVICE_STATE_Unattached:
378 case DEVICE_STATE_Suspended:
379 return -1;
380 }
e075361b 381 if (Endpoint_IsStalled()) {
382 Endpoint_SelectEndpoint(ep);
3969ec09 383 return -1;
e075361b 384 }
3969ec09 385 if (prevFN != USB_Device_GetFrameNumber()) {
e075361b 386 if (!(timeout--)) {
387 Endpoint_SelectEndpoint(ep);
3969ec09 388 return -1;
e075361b 389 }
3969ec09 390 prevFN = USB_Device_GetFrameNumber();
391 }
392 }
393
394 Endpoint_Write_8(c);
395
89470299 396 // send when bank is full
3969ec09 397 if (!Endpoint_IsReadWriteAllowed())
398 Endpoint_ClearIN();
399
e075361b 400 Endpoint_SelectEndpoint(ep);
401 return 0;
402}
403#else
404int8_t sendchar(uint8_t c)
405{
3969ec09 406 return 0;
407}
e075361b 408#endif
c5060ea8 409
410
411/*******************************************************************************
412 * main
413 ******************************************************************************/
414static void SetupHardware(void)
415{
416 /* Disable watchdog if enabled by bootloader/fuses */
417 MCUSR &= ~(1 << WDRF);
418 wdt_disable();
419
420 /* Disable clock division */
421 clock_prescale_set(clock_div_1);
422
423 // Leonardo needs. Without this USB device is not recognized.
424 USB_Disable();
425
426 USB_Init();
427
428 // for Console_Task
429 USB_Device_EnableSOFEvents();
430}
431
432int main(void) __attribute__ ((weak));
433int main(void)
434{
435 SetupHardware();
436 sei();
437
438 print_enable = true;
439 debug_enable = true;
440 debug_matrix = true;
441 debug_keyboard = true;
442 debug_mouse = true;
443
444 // TODO: can't print here
445 debug("LUFA init\n");
446
447 keyboard_init();
448 host_set_driver(&lufa_driver);
449 while (1) {
450 keyboard_proc();
451
452#if !defined(INTERRUPT_CONTROL_ENDPOINT)
453 USB_USBTask();
454#endif
455 }
456}
Imprint / Impressum