]> git.donarmstrong.com Git - tmk_firmware.git/blob - protocol/lufa/lufa.c
Add protocol/lufa. LUFA supported now.
[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 keyboard_led_stats = 0;
50
51 // TODO: impl Control Request GET_REPORT
52 static report_keyboard_t keyboard_report_sent;
53 static report_mouse_t mouse_report_sent;
54
55 /* Host driver */
56 static uint8_t keyboard_leds(void);
57 static void send_keyboard(report_keyboard_t *report);
58 static void send_mouse(report_mouse_t *report);
59 static void send_system(uint16_t data);
60 static void send_consumer(uint16_t data);
61 static host_driver_t lufa_driver = {
62     keyboard_leds,
63     send_keyboard,
64     send_mouse,
65     send_system,
66     send_consumer
67 };
68
69
70 static void SetupHardware(void);
71 static void Console_HID_Task(void);
72
73 int main(void)
74 {
75     SetupHardware();
76     sei();
77
78     print_enable = true;
79     debug_enable = true;
80     debug_matrix = true;
81     debug_keyboard = true;
82     debug_mouse = true;
83
84 /* TODO: can't print here
85     _delay_ms(5000);
86     USB_USBTask();
87     print("abcdefg\n");
88     USB_USBTask();
89 */
90
91     keyboard_init();
92     host_set_driver(&lufa_driver);
93     while (1) {
94         keyboard_proc();
95
96         Console_HID_Task();
97         USB_USBTask();
98     }
99 }
100
101 void SetupHardware(void)
102 {
103     /* Disable watchdog if enabled by bootloader/fuses */
104     MCUSR &= ~(1 << WDRF);
105     wdt_disable();
106
107     /* Disable clock division */
108     clock_prescale_set(clock_div_1);
109
110     USB_Init();
111 }
112
113 static void Console_HID_Task(void)
114 {
115         /* Device must be connected and configured for the task to run */
116         if (USB_DeviceState != DEVICE_STATE_Configured)
117           return;
118
119         // TODO: impl receivechar()/recvchar()
120         Endpoint_SelectEndpoint(CONSOLE_OUT_EPNUM);
121
122         /* Check to see if a packet has been sent from the host */
123         if (Endpoint_IsOUTReceived())
124         {
125                 /* Check to see if the packet contains data */
126                 if (Endpoint_IsReadWriteAllowed())
127                 {
128                         /* Create a temporary buffer to hold the read in report from the host */
129                         uint8_t ConsoleData[CONSOLE_EPSIZE];
130
131                         /* Read Console Report Data */
132                         Endpoint_Read_Stream_LE(&ConsoleData, sizeof(ConsoleData), NULL);
133
134                         /* Process Console Report Data */
135                         //ProcessConsoleHIDReport(ConsoleData);
136                 }
137
138                 /* Finalize the stream transfer to send the last packet */
139                 Endpoint_ClearOUT();
140         }
141
142         /* IN packet */
143         Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
144         // send IN packet
145         if (Endpoint_IsINReady())
146             Endpoint_ClearIN();
147 }
148
149
150 /*******************************************************************************
151  * USB Events
152  ******************************************************************************/
153 /** Event handler for the USB_Connect event. */
154 void EVENT_USB_Device_Connect(void)
155 {
156 }
157
158 /** Event handler for the USB_Disconnect event. */
159 void EVENT_USB_Device_Disconnect(void)
160 {
161 }
162
163 /** Event handler for the USB_ConfigurationChanged event.
164  * This is fired when the host sets the current configuration of the USB device after enumeration.
165  */
166 void EVENT_USB_Device_ConfigurationChanged(void)
167 {
168     bool ConfigSuccess = true;
169
170     /* Setup Keyboard HID Report Endpoints */
171     ConfigSuccess &= Endpoint_ConfigureEndpoint(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
172                                                 KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
173
174     /* Setup Mouse HID Report Endpoint */
175     ConfigSuccess &= Endpoint_ConfigureEndpoint(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
176                                                 MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE);
177
178     /* Setup Console HID Report Endpoints */
179     ConfigSuccess &= Endpoint_ConfigureEndpoint(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
180                                                 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
181     ConfigSuccess &= Endpoint_ConfigureEndpoint(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
182                                                 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
183
184     /* Setup Extra HID Report Endpoint */
185     ConfigSuccess &= Endpoint_ConfigureEndpoint(EXTRA_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
186                                                 EXTRA_EPSIZE, ENDPOINT_BANK_SINGLE);
187 }
188
189 /*
190 Appendix G: HID Request Support Requirements
191
192 The following table enumerates the requests that need to be supported by various types of HID class devices.
193
194 Device type     GetReport   SetReport   GetIdle     SetIdle     GetProtocol SetProtocol
195 ------------------------------------------------------------------------------------------
196 Boot Mouse      Required    Optional    Optional    Optional    Required    Required
197 Non-Boot Mouse  Required    Optional    Optional    Optional    Optional    Optional
198 Boot Keyboard   Required    Optional    Required    Required    Required    Required
199 Non-Boot Keybrd Required    Optional    Required    Required    Optional    Optional
200 Other Device    Required    Optional    Optional    Optional    Optional    Optional
201 */
202 /** Event handler for the USB_ControlRequest event.
203  *  This is fired before passing along unhandled control requests to the library for processing internally.
204  */
205 void EVENT_USB_Device_ControlRequest(void)
206 {
207     uint8_t* ReportData = NULL;
208     uint8_t  ReportSize = 0;
209
210     /* Handle HID Class specific requests */
211     switch (USB_ControlRequest.bRequest)
212     {
213         case HID_REQ_GetReport:
214             if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
215             {
216                 Endpoint_ClearSETUP();
217
218                 // Interface
219                 switch (USB_ControlRequest.wIndex) {
220                 case KEYBOARD_INTERFACE:
221                     // TODO: test/check
222                     ReportData = (uint8_t*)&keyboard_report_sent;
223                     ReportSize = sizeof(keyboard_report_sent);
224                     break;
225                 case MOUSE_INTERFACE:
226                     // TODO: test/check
227                     ReportData = (uint8_t*)&mouse_report_sent;
228                     ReportSize = sizeof(mouse_report_sent);
229                     break;
230                 case CONSOLE_INTERFACE:
231                     break;
232                 case EXTRA_INTERFACE:
233                     break;
234                 }
235
236                 /* Write the report data to the control endpoint */
237                 Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
238                 Endpoint_ClearOUT();
239             }
240
241             break;
242         case HID_REQ_SetReport:
243             if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
244             {
245                 Endpoint_ClearSETUP();
246
247                 /* Wait until the LED report has been sent by the host */
248                 while (!(Endpoint_IsOUTReceived()))
249                 {
250                     if (USB_DeviceState == DEVICE_STATE_Unattached)
251                       return;
252                 }
253
254                 // Interface
255                 switch (USB_ControlRequest.wIndex) {
256                 case KEYBOARD_INTERFACE:
257                     // TODO: test/check
258                     /* Read in the LED report from the host */
259                     keyboard_led_stats = Endpoint_Read_8();
260                     break;
261                 case MOUSE_INTERFACE:
262                     break;
263                 case CONSOLE_INTERFACE:
264                     break;
265                 case EXTRA_INTERFACE:
266                     break;
267                 }
268
269                 Endpoint_ClearOUT();
270                 Endpoint_ClearStatusStage();
271             }
272
273             break;
274     }
275 }
276
277 /*******************************************************************************
278  * Host driver 
279  ******************************************************************************/
280 static uint8_t keyboard_leds(void)
281 {
282     return keyboard_led_stats;
283 }
284
285 static void send_keyboard(report_keyboard_t *report)
286 {
287     // TODO: handle NKRO report
288     /* Select the Keyboard Report Endpoint */
289     Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
290
291     /* Check if Keyboard Endpoint Ready for Read/Write */
292     if (Endpoint_IsReadWriteAllowed())
293     {
294         /* Write Keyboard Report Data */
295         Endpoint_Write_Stream_LE(report, sizeof(report_keyboard_t), NULL);
296
297         /* Finalize the stream transfer to send the last packet */
298         Endpoint_ClearIN();
299     }
300     keyboard_report_sent = *report;
301 }
302
303 static void send_mouse(report_mouse_t *report)
304 {
305     /* Select the Mouse Report Endpoint */
306     Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
307
308     /* Check if Mouse Endpoint Ready for Read/Write */
309     if (Endpoint_IsReadWriteAllowed())
310     {
311         /* Write Mouse Report Data */
312         Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
313
314         /* Finalize the stream transfer to send the last packet */
315         Endpoint_ClearIN();
316     }
317     mouse_report_sent = *report;
318 }
319
320 typedef struct {
321     uint8_t  report_id;
322     uint16_t usage;
323 } __attribute__ ((packed)) report_extra_t;
324
325 static void send_system(uint16_t data)
326 {
327     Endpoint_SelectEndpoint(EXTRA_IN_EPNUM);
328     if (Endpoint_IsReadWriteAllowed()) {
329         report_extra_t r = {
330             .report_id = REPORT_ID_SYSTEM,
331             .usage = data
332         };
333         Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
334         Endpoint_ClearIN();
335     }
336 }
337
338 static void send_consumer(uint16_t data)
339 {
340     Endpoint_SelectEndpoint(EXTRA_IN_EPNUM);
341     if (Endpoint_IsReadWriteAllowed()) {
342         report_extra_t r = {
343             .report_id = REPORT_ID_CONSUMER,
344             .usage = data
345         };
346         Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
347         Endpoint_ClearIN();
348     }
349 }
350
351
352 /*******************************************************************************
353  * sendchar
354  ******************************************************************************/
355 int8_t sendchar(uint8_t c)
356 {
357     if (USB_DeviceState != DEVICE_STATE_Configured)
358       return -1;
359
360     Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
361
362     uint8_t timeout = 10;
363     uint16_t prevFN = USB_Device_GetFrameNumber();
364     while (!Endpoint_IsINReady()) {
365         switch (USB_DeviceState) {
366         case DEVICE_STATE_Unattached:
367         case DEVICE_STATE_Suspended:
368             return -1;
369         }
370         if (Endpoint_IsStalled())
371             return -1;
372         if (prevFN != USB_Device_GetFrameNumber()) {
373             if (!(timeout--))
374                 return -1;
375             prevFN = USB_Device_GetFrameNumber();
376         }
377     }
378
379     Endpoint_Write_8(c);
380
381     // send when packet is full
382     if (!Endpoint_IsReadWriteAllowed())
383         Endpoint_ClearIN();
384
385     return 0;
386 }