]> git.donarmstrong.com Git - tmk_firmware.git/blob - protocol/lufa/lufa.c
Add intial code of RemoteWakeUp
[tmk_firmware.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 }