]> git.gir.st - tmk_keyboard.git/blob - protocol/lufa/lufa.c
Add converter/usb_usb/README
[tmk_keyboard.git] / protocol / lufa / lufa.c
1 /*
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
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"
43 #include "sendchar.h"
44 #include "debug.h"
45
46 #include "descriptor.h"
47 #include "lufa.h"
48
49 static uint8_t idle_duration = 0;
50 static uint8_t protocol_report = 1;
51 static uint8_t keyboard_led_stats = 0;
52
53 static report_keyboard_t keyboard_report_sent;
54
55
56 /* Host driver */
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 = {
63 keyboard_leds,
64 send_keyboard,
65 send_mouse,
66 send_system,
67 send_consumer
68 };
69
70
71 /*******************************************************************************
72 * Console
73 ******************************************************************************/
74 #ifdef CONSOLE_ENABLE
75 static void Console_Task(void)
76 {
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);
110
111 // fill empty bank
112 while (Endpoint_IsReadWriteAllowed())
113 Endpoint_Write_8(0);
114
115 // flash senchar packet
116 if (Endpoint_IsINReady()) {
117 Endpoint_ClearIN();
118 }
119
120 Endpoint_SelectEndpoint(ep);
121 }
122 #else
123 static void Console_Task(void)
124 {
125 }
126 #endif
127
128
129 /*******************************************************************************
130 * USB Events
131 ******************************************************************************/
132 /** Event handler for the USB_Connect event. */
133 void EVENT_USB_Device_Connect(void)
134 {
135 }
136
137 /** Event handler for the USB_Disconnect event. */
138 void EVENT_USB_Device_Disconnect(void)
139 {
140 }
141
142 void EVENT_USB_Device_StartOfFrame(void)
143 {
144 Console_Task();
145 }
146
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 */
150 void 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,
156 KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
157
158 #ifdef MOUSE_ENABLE
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);
162 #endif
163
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);
168 #endif
169
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);
176 #endif
177 }
178
179 /*
180 Appendix G: HID Request Support Requirements
181
182 The following table enumerates the requests that need to be supported by various types of HID class devices.
183
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
191 */
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 */
195 void EVENT_USB_Device_ControlRequest(void)
196 {
197 uint8_t* ReportData = NULL;
198 uint8_t ReportSize = 0;
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
208 // Interface
209 switch (USB_ControlRequest.wIndex) {
210 case KEYBOARD_INTERFACE:
211 // TODO: test/check
212 ReportData = (uint8_t*)&keyboard_report_sent;
213 ReportSize = sizeof(keyboard_report_sent);
214 break;
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 {
226
227 // Interface
228 switch (USB_ControlRequest.wIndex) {
229 case KEYBOARD_INTERFACE:
230 Endpoint_ClearSETUP();
231
232 while (!(Endpoint_IsOUTReceived())) {
233 if (USB_DeviceState == DEVICE_STATE_Unattached)
234 return;
235 }
236 keyboard_led_stats = Endpoint_Read_8();
237
238 Endpoint_ClearOUT();
239 Endpoint_ClearStatusStage();
240 break;
241 }
242
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();
285 Endpoint_ClearStatusStage();
286 }
287
288 break;
289 }
290 }
291
292 /*******************************************************************************
293 * Host driver
294 ******************************************************************************/
295 static uint8_t keyboard_leds(void)
296 {
297 return keyboard_led_stats;
298 }
299
300 static 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 */
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();
314
315 keyboard_report_sent = *report;
316 }
317
318 static void send_mouse(report_mouse_t *report)
319 {
320 #ifdef MOUSE_ENABLE
321 /* Select the Mouse Report Endpoint */
322 Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
323
324 /* Check if Mouse Endpoint Ready for Read/Write */
325 while (!Endpoint_IsReadWriteAllowed()) ;
326
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();
332 #endif
333 }
334
335 static void send_system(uint16_t data)
336 {
337 report_extra_t r = {
338 .report_id = REPORT_ID_SYSTEM,
339 .usage = data
340 };
341 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
342 while (!Endpoint_IsReadWriteAllowed()) ;
343 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
344 Endpoint_ClearIN();
345 }
346
347 static void send_consumer(uint16_t data)
348 {
349 report_extra_t r = {
350 .report_id = REPORT_ID_CONSUMER,
351 .usage = data
352 };
353 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
354 while (!Endpoint_IsReadWriteAllowed()) ;
355 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
356 Endpoint_ClearIN();
357 }
358
359
360 /*******************************************************************************
361 * sendchar
362 ******************************************************************************/
363 #ifdef CONSOLE_ENABLE
364 #define SEND_TIMEOUT 5
365 int8_t sendchar(uint8_t c)
366 {
367 if (USB_DeviceState != DEVICE_STATE_Configured)
368 return -1;
369
370 uint8_t ep = Endpoint_GetCurrentEndpoint();
371 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
372
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:
379 return -1;
380 }
381 if (Endpoint_IsStalled()) {
382 Endpoint_SelectEndpoint(ep);
383 return -1;
384 }
385 if (prevFN != USB_Device_GetFrameNumber()) {
386 if (!(timeout--)) {
387 Endpoint_SelectEndpoint(ep);
388 return -1;
389 }
390 prevFN = USB_Device_GetFrameNumber();
391 }
392 }
393
394 Endpoint_Write_8(c);
395
396 // send when bank is full
397 if (!Endpoint_IsReadWriteAllowed())
398 Endpoint_ClearIN();
399
400 Endpoint_SelectEndpoint(ep);
401 return 0;
402 }
403 #else
404 int8_t sendchar(uint8_t c)
405 {
406 return 0;
407 }
408 #endif
409
410
411 /*******************************************************************************
412 * main
413 ******************************************************************************/
414 static 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
432 int main(void) __attribute__ ((weak));
433 int 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