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