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