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