]> git.gir.st - tmk_keyboard.git/blob - protocol/lufa/lufa.c
Add intial code of RemoteWakeUp
[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 if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
111 Endpoint_SelectEndpoint(ep);
112 return;
113 }
114
115 // fill empty bank
116 while (Endpoint_IsReadWriteAllowed())
117 Endpoint_Write_8(0);
118
119 // flash senchar packet
120 if (Endpoint_IsINReady()) {
121 Endpoint_ClearIN();
122 }
123
124 Endpoint_SelectEndpoint(ep);
125 }
126 #else
127 static void Console_Task(void)
128 {
129 }
130 #endif
131
132
133 /*******************************************************************************
134 * USB Events
135 ******************************************************************************/
136 #include "led.h"
137 void EVENT_USB_Device_Connect(void)
138 {
139 }
140
141 void EVENT_USB_Device_Disconnect(void)
142 {
143 }
144
145 void EVENT_USB_Device_Reset(void)
146 {
147 }
148
149 void EVENT_USB_Device_Suspend()
150 {
151 led_set(1<<USB_LED_CAPS_LOCK);
152 }
153
154 void EVENT_USB_Device_WakeUp()
155 {
156 led_set(0);
157 }
158
159 void EVENT_USB_Device_StartOfFrame(void)
160 {
161 Console_Task();
162 }
163
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.
166 */
167 #if LUFA_VERSION_INTEGER < 0x120730
168 /* old API 120219 */
169 #define ENDPOINT_CONFIG(epnum, eptype, epdir, epsize, epbank) Endpoint_ConfigureEndpoint(epnum, eptype, epdir, epsize, epbank)
170 #else
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)
175 #endif
176 void EVENT_USB_Device_ConfigurationChanged(void)
177 {
178 bool ConfigSuccess = true;
179
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);
183
184 #ifdef MOUSE_ENABLE
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);
188 #endif
189
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);
194 #endif
195
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);
202 #endif
203 }
204
205 /*
206 Appendix G: HID Request Support Requirements
207
208 The following table enumerates the requests that need to be supported by various types of HID class devices.
209
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
217 */
218 /** Event handler for the USB_ControlRequest event.
219 * This is fired before passing along unhandled control requests to the library for processing internally.
220 */
221 void EVENT_USB_Device_ControlRequest(void)
222 {
223 uint8_t* ReportData = NULL;
224 uint8_t ReportSize = 0;
225
226 /* Handle HID Class specific requests */
227 switch (USB_ControlRequest.bRequest)
228 {
229 case HID_REQ_GetReport:
230 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
231 {
232 Endpoint_ClearSETUP();
233
234 // Interface
235 switch (USB_ControlRequest.wIndex) {
236 case KEYBOARD_INTERFACE:
237 // TODO: test/check
238 ReportData = (uint8_t*)&keyboard_report_sent;
239 ReportSize = sizeof(keyboard_report_sent);
240 break;
241 }
242
243 /* Write the report data to the control endpoint */
244 Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
245 Endpoint_ClearOUT();
246 }
247
248 break;
249 case HID_REQ_SetReport:
250 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
251 {
252
253 // Interface
254 switch (USB_ControlRequest.wIndex) {
255 case KEYBOARD_INTERFACE:
256 Endpoint_ClearSETUP();
257
258 while (!(Endpoint_IsOUTReceived())) {
259 if (USB_DeviceState == DEVICE_STATE_Unattached)
260 return;
261 }
262 keyboard_led_stats = Endpoint_Read_8();
263
264 Endpoint_ClearOUT();
265 Endpoint_ClearStatusStage();
266 break;
267 }
268
269 }
270
271 break;
272
273 case HID_REQ_GetProtocol:
274 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
275 {
276 Endpoint_ClearSETUP();
277 while (!(Endpoint_IsINReady()));
278 Endpoint_Write_8(protocol_report);
279 Endpoint_ClearIN();
280 Endpoint_ClearStatusStage();
281 }
282
283 break;
284 case HID_REQ_SetProtocol:
285 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
286 {
287 Endpoint_ClearSETUP();
288 Endpoint_ClearStatusStage();
289
290 protocol_report = ((USB_ControlRequest.wValue & 0xFF) != 0x00);
291 }
292
293 break;
294 case HID_REQ_SetIdle:
295 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
296 {
297 Endpoint_ClearSETUP();
298 Endpoint_ClearStatusStage();
299
300 idle_duration = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
301 }
302
303 break;
304 case HID_REQ_GetIdle:
305 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
306 {
307 Endpoint_ClearSETUP();
308 while (!(Endpoint_IsINReady()));
309 Endpoint_Write_8(idle_duration);
310 Endpoint_ClearIN();
311 Endpoint_ClearStatusStage();
312 }
313
314 break;
315 }
316 }
317
318 /*******************************************************************************
319 * Host driver
320 ******************************************************************************/
321 static uint8_t keyboard_leds(void)
322 {
323 return keyboard_led_stats;
324 }
325
326 static void send_keyboard(report_keyboard_t *report)
327 {
328 uint8_t timeout = 0;
329
330 // TODO: handle NKRO report
331 /* Select the Keyboard Report Endpoint */
332 Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
333
334 /* Check if Keyboard Endpoint Ready for Read/Write */
335 while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
336
337 /* Write Keyboard Report Data */
338 Endpoint_Write_Stream_LE(report, sizeof(report_keyboard_t), NULL);
339
340 /* Finalize the stream transfer to send the last packet */
341 Endpoint_ClearIN();
342
343 keyboard_report_sent = *report;
344 }
345
346 static void send_mouse(report_mouse_t *report)
347 {
348 #ifdef MOUSE_ENABLE
349 uint8_t timeout = 0;
350
351 /* Select the Mouse Report Endpoint */
352 Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
353
354 /* Check if Mouse Endpoint Ready for Read/Write */
355 while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
356
357 /* Write Mouse Report Data */
358 Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
359
360 /* Finalize the stream transfer to send the last packet */
361 Endpoint_ClearIN();
362 #endif
363 }
364
365 static void send_system(uint16_t data)
366 {
367 uint8_t timeout = 0;
368
369 report_extra_t r = {
370 .report_id = REPORT_ID_SYSTEM,
371 .usage = data
372 };
373 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
374 while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
375 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
376 Endpoint_ClearIN();
377 }
378
379 static void send_consumer(uint16_t data)
380 {
381 uint8_t timeout = 0;
382
383 report_extra_t r = {
384 .report_id = REPORT_ID_CONSUMER,
385 .usage = data
386 };
387 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
388 while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
389 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
390 Endpoint_ClearIN();
391 }
392
393
394 /*******************************************************************************
395 * sendchar
396 ******************************************************************************/
397 #ifdef CONSOLE_ENABLE
398 #define SEND_TIMEOUT 5
399 int8_t sendchar(uint8_t c)
400 {
401 // Not wait once timeouted.
402 // Because sendchar() is called so many times, waiting each call causes big lag.
403 static bool timeouted = false;
404
405 if (USB_DeviceState != DEVICE_STATE_Configured)
406 return -1;
407
408 uint8_t ep = Endpoint_GetCurrentEndpoint();
409 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
410 if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
411 Endpoint_SelectEndpoint(ep);
412 return -1;
413 }
414
415 if (timeouted && !Endpoint_IsReadWriteAllowed()) {
416 Endpoint_SelectEndpoint(ep);
417 return - 1;
418 }
419
420 timeouted = false;
421
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:
428 return -1;
429 }
430 if (Endpoint_IsStalled()) {
431 Endpoint_SelectEndpoint(ep);
432 return -1;
433 }
434 if (prevFN != USB_Device_GetFrameNumber()) {
435 if (!(timeout--)) {
436 timeouted = true;
437 Endpoint_SelectEndpoint(ep);
438 return -1;
439 }
440 prevFN = USB_Device_GetFrameNumber();
441 }
442 }
443
444 Endpoint_Write_8(c);
445
446 // send when bank is full
447 if (!Endpoint_IsReadWriteAllowed())
448 Endpoint_ClearIN();
449
450 Endpoint_SelectEndpoint(ep);
451 return 0;
452 }
453 #else
454 int8_t sendchar(uint8_t c)
455 {
456 return 0;
457 }
458 #endif
459
460
461 /*******************************************************************************
462 * main
463 ******************************************************************************/
464 static void SetupHardware(void)
465 {
466 /* Disable watchdog if enabled by bootloader/fuses */
467 MCUSR &= ~(1 << WDRF);
468 wdt_disable();
469
470 /* Disable clock division */
471 clock_prescale_set(clock_div_1);
472
473 // Leonardo needs. Without this USB device is not recognized.
474 USB_Disable();
475
476 USB_Init();
477
478 // for Console_Task
479 USB_Device_EnableSOFEvents();
480 }
481
482
483 #include "matrix.h"
484 static bool wakeup_condition(void)
485 {
486 matrix_scan();
487 for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
488 if (matrix_get_row(r)) return true;
489 }
490 return false;
491 }
492
493 int main(void) __attribute__ ((weak));
494 int main(void)
495 {
496 SetupHardware();
497 keyboard_init();
498 host_set_driver(&lufa_driver);
499 sei();
500
501 while (1) {
502 while (USB_DeviceState == DEVICE_STATE_Suspended) {
503 // TODO: power saving
504
505 if (USB_Device_RemoteWakeupEnabled) {
506 if (wakeup_condition()) {
507 USB_Device_SendRemoteWakeup();
508 }
509 }
510 }
511
512 keyboard_task();
513
514 #if !defined(INTERRUPT_CONTROL_ENDPOINT)
515 USB_USBTask();
516 #endif
517 }
518 }
Imprint / Impressum