]> git.donarmstrong.com Git - tmk_firmware.git/blob - protocol/lufa/lufa.c
Add supsend and wakeup to pjrc stack
[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 "action.h"
44 #include "led.h"
45 #include "sendchar.h"
46 #include "debug.h"
47 #ifdef SLEEP_LED_ENABLE
48 #include "sleep_led.h"
49 #endif
50 #include "suspend.h"
51
52 #include "descriptor.h"
53 #include "lufa.h"
54
55 static uint8_t idle_duration = 0;
56 static uint8_t protocol_report = 1;
57 static uint8_t keyboard_led_stats = 0;
58
59 static report_keyboard_t keyboard_report_sent;
60
61
62 /* Host driver */
63 static uint8_t keyboard_leds(void);
64 static void send_keyboard(report_keyboard_t *report);
65 static void send_mouse(report_mouse_t *report);
66 static void send_system(uint16_t data);
67 static void send_consumer(uint16_t data);
68 host_driver_t lufa_driver = {
69     keyboard_leds,
70     send_keyboard,
71     send_mouse,
72     send_system,
73     send_consumer
74 };
75
76
77 /*******************************************************************************
78  * Console
79  ******************************************************************************/
80 #ifdef CONSOLE_ENABLE
81 static void Console_Task(void)
82 {
83     /* Device must be connected and configured for the task to run */
84     if (USB_DeviceState != DEVICE_STATE_Configured)
85         return;
86
87     uint8_t ep = Endpoint_GetCurrentEndpoint();
88
89 #if 0
90     // TODO: impl receivechar()/recvchar()
91     Endpoint_SelectEndpoint(CONSOLE_OUT_EPNUM);
92
93     /* Check to see if a packet has been sent from the host */
94     if (Endpoint_IsOUTReceived())
95     {
96         /* Check to see if the packet contains data */
97         if (Endpoint_IsReadWriteAllowed())
98         {
99             /* Create a temporary buffer to hold the read in report from the host */
100             uint8_t ConsoleData[CONSOLE_EPSIZE];
101  
102             /* Read Console Report Data */
103             Endpoint_Read_Stream_LE(&ConsoleData, sizeof(ConsoleData), NULL);
104  
105             /* Process Console Report Data */
106             //ProcessConsoleHIDReport(ConsoleData);
107         }
108
109         /* Finalize the stream transfer to send the last packet */
110         Endpoint_ClearOUT();
111     }
112 #endif
113
114     /* IN packet */
115     Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
116     if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
117         Endpoint_SelectEndpoint(ep);
118         return;
119     }
120
121     // fill empty bank
122     while (Endpoint_IsReadWriteAllowed())
123         Endpoint_Write_8(0);
124
125     // flash senchar packet
126     if (Endpoint_IsINReady()) {
127         Endpoint_ClearIN();
128     }
129
130     Endpoint_SelectEndpoint(ep);
131 }
132 #else
133 static void Console_Task(void)
134 {
135 }
136 #endif
137
138
139 /*******************************************************************************
140  * USB Events
141  ******************************************************************************/
142 /*
143  * Event Order of Plug in:
144  * 0) EVENT_USB_Device_Connect
145  * 1) EVENT_USB_Device_Suspend
146  * 2) EVENT_USB_Device_Reset
147  * 3) EVENT_USB_Device_Wake
148 */
149 void EVENT_USB_Device_Connect(void)
150 {
151     led_set(0x1f);  // all on
152 }
153
154 void EVENT_USB_Device_Disconnect(void)
155 {
156 }
157
158 void EVENT_USB_Device_Reset(void)
159 {
160 }
161
162 void EVENT_USB_Device_Suspend()
163 {
164 #ifdef SLEEP_LED_ENABLE
165     sleep_led_enable();
166 #endif
167 }
168
169 void EVENT_USB_Device_WakeUp()
170 {
171     suspend_wakeup_init();
172
173 #ifdef SLEEP_LED_ENABLE
174     sleep_led_disable();
175 #endif
176     led_set(host_keyboard_leds());
177 }
178
179 void EVENT_USB_Device_StartOfFrame(void)
180 {
181     Console_Task();
182 }
183
184 /** Event handler for the USB_ConfigurationChanged event.
185  * This is fired when the host sets the current configuration of the USB device after enumeration.
186  */
187 #if LUFA_VERSION_INTEGER < 0x120730
188     /* old API 120219 */
189     #define ENDPOINT_CONFIG(epnum, eptype, epdir, epsize, epbank)    Endpoint_ConfigureEndpoint(epnum, eptype, epdir, epsize, epbank)
190 #else
191     /* new API >= 120730 */
192     #define ENDPOINT_BANK_SINGLE 1
193     #define ENDPOINT_BANK_DOUBLE 2
194     #define ENDPOINT_CONFIG(epnum, eptype, epdir, epsize, epbank)    Endpoint_ConfigureEndpoint((epdir) | (epnum) , eptype, epsize, epbank)
195 #endif
196 void EVENT_USB_Device_ConfigurationChanged(void)
197 {
198     bool ConfigSuccess = true;
199
200     /* Setup Keyboard HID Report Endpoints */
201     ConfigSuccess &= ENDPOINT_CONFIG(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
202                                      KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
203
204 #ifdef MOUSE_ENABLE
205     /* Setup Mouse HID Report Endpoint */
206     ConfigSuccess &= ENDPOINT_CONFIG(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
207                                      MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE);
208 #endif
209
210 #ifdef EXTRAKEY_ENABLE
211     /* Setup Extra HID Report Endpoint */
212     ConfigSuccess &= ENDPOINT_CONFIG(EXTRAKEY_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
213                                      EXTRAKEY_EPSIZE, ENDPOINT_BANK_SINGLE);
214 #endif
215
216 #ifdef CONSOLE_ENABLE
217     /* Setup Console HID Report Endpoints */
218     ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
219                                      CONSOLE_EPSIZE, ENDPOINT_BANK_DOUBLE);
220     ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
221                                      CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
222 #endif
223 }
224
225 /*
226 Appendix G: HID Request Support Requirements
227
228 The following table enumerates the requests that need to be supported by various types of HID class devices.
229
230 Device type     GetReport   SetReport   GetIdle     SetIdle     GetProtocol SetProtocol
231 ------------------------------------------------------------------------------------------
232 Boot Mouse      Required    Optional    Optional    Optional    Required    Required
233 Non-Boot Mouse  Required    Optional    Optional    Optional    Optional    Optional
234 Boot Keyboard   Required    Optional    Required    Required    Required    Required
235 Non-Boot Keybrd Required    Optional    Required    Required    Optional    Optional
236 Other Device    Required    Optional    Optional    Optional    Optional    Optional
237 */
238 /** Event handler for the USB_ControlRequest event.
239  *  This is fired before passing along unhandled control requests to the library for processing internally.
240  */
241 void EVENT_USB_Device_ControlRequest(void)
242 {
243     uint8_t* ReportData = NULL;
244     uint8_t  ReportSize = 0;
245
246     /* Handle HID Class specific requests */
247     switch (USB_ControlRequest.bRequest)
248     {
249         case HID_REQ_GetReport:
250             if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
251             {
252                 Endpoint_ClearSETUP();
253
254                 // Interface
255                 switch (USB_ControlRequest.wIndex) {
256                 case KEYBOARD_INTERFACE:
257                     // TODO: test/check
258                     ReportData = (uint8_t*)&keyboard_report_sent;
259                     ReportSize = sizeof(keyboard_report_sent);
260                     break;
261                 }
262
263                 /* Write the report data to the control endpoint */
264                 Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
265                 Endpoint_ClearOUT();
266             }
267
268             break;
269         case HID_REQ_SetReport:
270             if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
271             {
272
273                 // Interface
274                 switch (USB_ControlRequest.wIndex) {
275                 case KEYBOARD_INTERFACE:
276                     Endpoint_ClearSETUP();
277
278                     while (!(Endpoint_IsOUTReceived())) {
279                         if (USB_DeviceState == DEVICE_STATE_Unattached)
280                           return;
281                     }
282                     keyboard_led_stats = Endpoint_Read_8();
283
284                     Endpoint_ClearOUT();
285                     Endpoint_ClearStatusStage();
286                     break;
287                 }
288
289             }
290
291             break;
292
293         case HID_REQ_GetProtocol:
294             if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
295             {
296                 Endpoint_ClearSETUP();
297                 while (!(Endpoint_IsINReady()));
298                 Endpoint_Write_8(protocol_report);
299                 Endpoint_ClearIN();
300                 Endpoint_ClearStatusStage();
301             }
302
303             break;
304         case HID_REQ_SetProtocol:
305             if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
306             {
307                 Endpoint_ClearSETUP();
308                 Endpoint_ClearStatusStage();
309
310                 protocol_report = ((USB_ControlRequest.wValue & 0xFF) != 0x00);
311             }
312
313             break;
314         case HID_REQ_SetIdle:
315             if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
316             {
317                 Endpoint_ClearSETUP();
318                 Endpoint_ClearStatusStage();
319
320                 idle_duration = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
321             }
322
323             break;
324         case HID_REQ_GetIdle:
325             if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
326             {
327                 Endpoint_ClearSETUP();
328                 while (!(Endpoint_IsINReady()));
329                 Endpoint_Write_8(idle_duration);
330                 Endpoint_ClearIN();
331                 Endpoint_ClearStatusStage();
332             }
333
334             break;
335     }
336 }
337
338 /*******************************************************************************
339  * Host driver 
340  ******************************************************************************/
341 static uint8_t keyboard_leds(void)
342 {
343     return keyboard_led_stats;
344 }
345
346 static void send_keyboard(report_keyboard_t *report)
347 {
348     uint8_t timeout = 0;
349
350     // TODO: handle NKRO report
351     /* Select the Keyboard Report Endpoint */
352     Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
353
354     /* Check if Keyboard Endpoint Ready for Read/Write */
355     while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
356
357     /* Write Keyboard Report Data */
358     Endpoint_Write_Stream_LE(report, sizeof(report_keyboard_t), NULL);
359
360     /* Finalize the stream transfer to send the last packet */
361     Endpoint_ClearIN();
362
363     keyboard_report_sent = *report;
364 }
365
366 static void send_mouse(report_mouse_t *report)
367 {
368 #ifdef MOUSE_ENABLE
369     uint8_t timeout = 0;
370
371     /* Select the Mouse Report Endpoint */
372     Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
373
374     /* Check if Mouse Endpoint Ready for Read/Write */
375     while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
376
377     /* Write Mouse Report Data */
378     Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
379
380     /* Finalize the stream transfer to send the last packet */
381     Endpoint_ClearIN();
382 #endif
383 }
384
385 static void send_system(uint16_t data)
386 {
387     uint8_t timeout = 0;
388
389     report_extra_t r = {
390         .report_id = REPORT_ID_SYSTEM,
391         .usage = data
392     };
393     Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
394     while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
395     Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
396     Endpoint_ClearIN();
397 }
398
399 static void send_consumer(uint16_t data)
400 {
401     uint8_t timeout = 0;
402
403     report_extra_t r = {
404         .report_id = REPORT_ID_CONSUMER,
405         .usage = data
406     };
407     Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
408     while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
409     Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
410     Endpoint_ClearIN();
411 }
412
413
414 /*******************************************************************************
415  * sendchar
416  ******************************************************************************/
417 #ifdef CONSOLE_ENABLE
418 #define SEND_TIMEOUT 5
419 int8_t sendchar(uint8_t c)
420 {
421     // Not wait once timeouted.
422     // Because sendchar() is called so many times, waiting each call causes big lag.
423     static bool timeouted = false;
424
425     if (USB_DeviceState != DEVICE_STATE_Configured)
426         return -1;
427
428     uint8_t ep = Endpoint_GetCurrentEndpoint();
429     Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
430     if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
431         Endpoint_SelectEndpoint(ep);
432         return -1;
433     }
434
435     if (timeouted && !Endpoint_IsReadWriteAllowed()) {
436         Endpoint_SelectEndpoint(ep);
437         return - 1;
438     }
439
440     timeouted = false;
441
442     uint8_t timeout = SEND_TIMEOUT;
443     uint16_t prevFN = USB_Device_GetFrameNumber();
444     while (!Endpoint_IsReadWriteAllowed()) {
445         switch (USB_DeviceState) {
446         case DEVICE_STATE_Unattached:
447         case DEVICE_STATE_Suspended:
448             return -1;
449         }
450         if (Endpoint_IsStalled()) {
451             Endpoint_SelectEndpoint(ep);
452             return -1;
453         }
454         if (prevFN != USB_Device_GetFrameNumber()) {
455             if (!(timeout--)) {
456                 timeouted = true;
457                 Endpoint_SelectEndpoint(ep);
458                 return -1;
459             }
460             prevFN = USB_Device_GetFrameNumber();
461         }
462     }
463
464     Endpoint_Write_8(c);
465
466     // send when bank is full
467     if (!Endpoint_IsReadWriteAllowed())
468         Endpoint_ClearIN();
469
470     Endpoint_SelectEndpoint(ep);
471     return 0;
472 }
473 #else
474 int8_t sendchar(uint8_t c)
475 {
476     return 0;
477 }
478 #endif
479
480
481 /*******************************************************************************
482  * main
483  ******************************************************************************/
484 static void SetupHardware(void)
485 {
486     /* Disable watchdog if enabled by bootloader/fuses */
487     MCUSR &= ~(1 << WDRF);
488     wdt_disable();
489
490     /* Disable clock division */
491     clock_prescale_set(clock_div_1);
492
493     // Leonardo needs. Without this USB device is not recognized.
494     USB_Disable();
495
496     USB_Init();
497
498     // for Console_Task
499     USB_Device_EnableSOFEvents();
500 }
501
502 int main(void)  __attribute__ ((weak));
503 int main(void)
504 {
505     SetupHardware();
506     keyboard_init();
507     host_set_driver(&lufa_driver);
508 #ifdef SLEEP_LED_ENABLE
509     sleep_led_init();
510 #endif
511     sei();
512
513     while (1) {
514         while (USB_DeviceState == DEVICE_STATE_Suspended) {
515             suspend_power_down();
516             if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) {
517                     USB_Device_SendRemoteWakeup();
518             }
519         }
520
521         keyboard_task();
522
523 #if !defined(INTERRUPT_CONTROL_ENDPOINT)
524         USB_USBTask();
525 #endif
526     }
527 }