]> git.donarmstrong.com Git - tmk_firmware.git/blob - protocol/lufa/lufa.c
Add support for LUFA-120730
[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 /** Event handler for the USB_Connect event. */
137 void EVENT_USB_Device_Connect(void)
138 {
139 }
140
141 /** Event handler for the USB_Disconnect event. */
142 void EVENT_USB_Device_Disconnect(void)
143 {
144 }
145
146 void EVENT_USB_Device_StartOfFrame(void)
147 {
148     Console_Task();
149 }
150
151 /** Event handler for the USB_ConfigurationChanged event.
152  * This is fired when the host sets the current configuration of the USB device after enumeration.
153  */
154 #if LUFA_VERSION_INTEGER < 0x120730
155     /* old API 120219 */
156     #define ENDPOINT_CONFIG(epnum, eptype, epdir, epsize, epbank)    Endpoint_ConfigureEndpoint(epnum, eptype, epdir, epsize, epbank)
157 #else
158     /* new API >= 120730 */
159     #define ENDPOINT_BANK_SINGLE 1
160     #define ENDPOINT_BANK_DOUBLE 2
161     #define ENDPOINT_CONFIG(epnum, eptype, epdir, epsize, epbank)    Endpoint_ConfigureEndpoint((epdir) | (epnum) , eptype, epsize, epbank)
162 #endif
163 void EVENT_USB_Device_ConfigurationChanged(void)
164 {
165     bool ConfigSuccess = true;
166
167     /* Setup Keyboard HID Report Endpoints */
168     ConfigSuccess &= ENDPOINT_CONFIG(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
169                                      KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
170
171 #ifdef MOUSE_ENABLE
172     /* Setup Mouse HID Report Endpoint */
173     ConfigSuccess &= ENDPOINT_CONFIG(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
174                                      MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE);
175 #endif
176
177 #ifdef EXTRAKEY_ENABLE
178     /* Setup Extra HID Report Endpoint */
179     ConfigSuccess &= ENDPOINT_CONFIG(EXTRAKEY_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
180                                      EXTRAKEY_EPSIZE, ENDPOINT_BANK_SINGLE);
181 #endif
182
183 #ifdef CONSOLE_ENABLE
184     /* Setup Console HID Report Endpoints */
185     ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
186                                      CONSOLE_EPSIZE, ENDPOINT_BANK_DOUBLE);
187     ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
188                                      CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
189 #endif
190 }
191
192 /*
193 Appendix G: HID Request Support Requirements
194
195 The following table enumerates the requests that need to be supported by various types of HID class devices.
196
197 Device type     GetReport   SetReport   GetIdle     SetIdle     GetProtocol SetProtocol
198 ------------------------------------------------------------------------------------------
199 Boot Mouse      Required    Optional    Optional    Optional    Required    Required
200 Non-Boot Mouse  Required    Optional    Optional    Optional    Optional    Optional
201 Boot Keyboard   Required    Optional    Required    Required    Required    Required
202 Non-Boot Keybrd Required    Optional    Required    Required    Optional    Optional
203 Other Device    Required    Optional    Optional    Optional    Optional    Optional
204 */
205 /** Event handler for the USB_ControlRequest event.
206  *  This is fired before passing along unhandled control requests to the library for processing internally.
207  */
208 void EVENT_USB_Device_ControlRequest(void)
209 {
210     uint8_t* ReportData = NULL;
211     uint8_t  ReportSize = 0;
212
213     /* Handle HID Class specific requests */
214     switch (USB_ControlRequest.bRequest)
215     {
216         case HID_REQ_GetReport:
217             if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
218             {
219                 Endpoint_ClearSETUP();
220
221                 // Interface
222                 switch (USB_ControlRequest.wIndex) {
223                 case KEYBOARD_INTERFACE:
224                     // TODO: test/check
225                     ReportData = (uint8_t*)&keyboard_report_sent;
226                     ReportSize = sizeof(keyboard_report_sent);
227                     break;
228                 }
229
230                 /* Write the report data to the control endpoint */
231                 Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
232                 Endpoint_ClearOUT();
233             }
234
235             break;
236         case HID_REQ_SetReport:
237             if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
238             {
239
240                 // Interface
241                 switch (USB_ControlRequest.wIndex) {
242                 case KEYBOARD_INTERFACE:
243                     Endpoint_ClearSETUP();
244
245                     while (!(Endpoint_IsOUTReceived())) {
246                         if (USB_DeviceState == DEVICE_STATE_Unattached)
247                           return;
248                     }
249                     keyboard_led_stats = Endpoint_Read_8();
250
251                     Endpoint_ClearOUT();
252                     Endpoint_ClearStatusStage();
253                     break;
254                 }
255
256             }
257
258             break;
259
260         case HID_REQ_GetProtocol:
261             if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
262             {
263                 Endpoint_ClearSETUP();
264                 while (!(Endpoint_IsINReady()));
265                 Endpoint_Write_8(protocol_report);
266                 Endpoint_ClearIN();
267                 Endpoint_ClearStatusStage();
268             }
269
270             break;
271         case HID_REQ_SetProtocol:
272             if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
273             {
274                 Endpoint_ClearSETUP();
275                 Endpoint_ClearStatusStage();
276
277                 protocol_report = ((USB_ControlRequest.wValue & 0xFF) != 0x00);
278             }
279
280             break;
281         case HID_REQ_SetIdle:
282             if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
283             {
284                 Endpoint_ClearSETUP();
285                 Endpoint_ClearStatusStage();
286
287                 idle_duration = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
288             }
289
290             break;
291         case HID_REQ_GetIdle:
292             if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
293             {
294                 Endpoint_ClearSETUP();
295                 while (!(Endpoint_IsINReady()));
296                 Endpoint_Write_8(idle_duration);
297                 Endpoint_ClearIN();
298                 Endpoint_ClearStatusStage();
299             }
300
301             break;
302     }
303 }
304
305 /*******************************************************************************
306  * Host driver 
307  ******************************************************************************/
308 static uint8_t keyboard_leds(void)
309 {
310     return keyboard_led_stats;
311 }
312
313 static void send_keyboard(report_keyboard_t *report)
314 {
315     uint8_t timeout = 0;
316
317     // TODO: handle NKRO report
318     /* Select the Keyboard Report Endpoint */
319     Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
320
321     /* Check if Keyboard Endpoint Ready for Read/Write */
322     while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
323
324     /* Write Keyboard Report Data */
325     Endpoint_Write_Stream_LE(report, sizeof(report_keyboard_t), NULL);
326
327     /* Finalize the stream transfer to send the last packet */
328     Endpoint_ClearIN();
329
330     keyboard_report_sent = *report;
331 }
332
333 static void send_mouse(report_mouse_t *report)
334 {
335 #ifdef MOUSE_ENABLE
336     uint8_t timeout = 0;
337
338     /* Select the Mouse Report Endpoint */
339     Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
340
341     /* Check if Mouse Endpoint Ready for Read/Write */
342     while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
343
344     /* Write Mouse Report Data */
345     Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
346
347     /* Finalize the stream transfer to send the last packet */
348     Endpoint_ClearIN();
349 #endif
350 }
351
352 static void send_system(uint16_t data)
353 {
354     uint8_t timeout = 0;
355
356     report_extra_t r = {
357         .report_id = REPORT_ID_SYSTEM,
358         .usage = data
359     };
360     Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
361     while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
362     Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
363     Endpoint_ClearIN();
364 }
365
366 static void send_consumer(uint16_t data)
367 {
368     uint8_t timeout = 0;
369
370     report_extra_t r = {
371         .report_id = REPORT_ID_CONSUMER,
372         .usage = data
373     };
374     Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
375     while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
376     Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
377     Endpoint_ClearIN();
378 }
379
380
381 /*******************************************************************************
382  * sendchar
383  ******************************************************************************/
384 #ifdef CONSOLE_ENABLE
385 #define SEND_TIMEOUT 5
386 int8_t sendchar(uint8_t c)
387 {
388     // Not wait once timeouted.
389     // Because sendchar() is called so many times, waiting each call causes big lag.
390     static bool timeouted = false;
391
392     if (USB_DeviceState != DEVICE_STATE_Configured)
393         return -1;
394
395     uint8_t ep = Endpoint_GetCurrentEndpoint();
396     Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
397     if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
398         Endpoint_SelectEndpoint(ep);
399         return -1;
400     }
401
402     if (timeouted && !Endpoint_IsReadWriteAllowed()) {
403         Endpoint_SelectEndpoint(ep);
404         return - 1;
405     }
406
407     timeouted = false;
408
409     uint8_t timeout = SEND_TIMEOUT;
410     uint16_t prevFN = USB_Device_GetFrameNumber();
411     while (!Endpoint_IsReadWriteAllowed()) {
412         switch (USB_DeviceState) {
413         case DEVICE_STATE_Unattached:
414         case DEVICE_STATE_Suspended:
415             return -1;
416         }
417         if (Endpoint_IsStalled()) {
418             Endpoint_SelectEndpoint(ep);
419             return -1;
420         }
421         if (prevFN != USB_Device_GetFrameNumber()) {
422             if (!(timeout--)) {
423                 timeouted = true;
424                 Endpoint_SelectEndpoint(ep);
425                 return -1;
426             }
427             prevFN = USB_Device_GetFrameNumber();
428         }
429     }
430
431     Endpoint_Write_8(c);
432
433     // send when bank is full
434     if (!Endpoint_IsReadWriteAllowed())
435         Endpoint_ClearIN();
436
437     Endpoint_SelectEndpoint(ep);
438     return 0;
439 }
440 #else
441 int8_t sendchar(uint8_t c)
442 {
443     return 0;
444 }
445 #endif
446
447
448 /*******************************************************************************
449  * main
450  ******************************************************************************/
451 static void SetupHardware(void)
452 {
453     /* Disable watchdog if enabled by bootloader/fuses */
454     MCUSR &= ~(1 << WDRF);
455     wdt_disable();
456
457     /* Disable clock division */
458     clock_prescale_set(clock_div_1);
459
460     // Leonardo needs. Without this USB device is not recognized.
461     USB_Disable();
462
463     USB_Init();
464
465     // for Console_Task
466     USB_Device_EnableSOFEvents();
467 }
468
469 int main(void)  __attribute__ ((weak));
470 int main(void)
471 {
472     SetupHardware();
473     keyboard_init();
474     host_set_driver(&lufa_driver);
475     sei();
476
477     // TODO: can't print here
478     debug("LUFA init\n");
479     while (1) {
480         keyboard_task();
481
482 #if !defined(INTERRUPT_CONTROL_ENDPOINT)
483         USB_USBTask();
484 #endif
485     }
486 }