Add conditional compile for MOUSE_ENABLE and EXTRAKEY_ENABLE.
[tmk_keyboard.git] / protocol / lufa / lufa.c
CommitLineData
dd93d291 1/*
2 * Copyright 2012 Jun Wako <wakojun@gmail.com>
3969ec09 3 * This file is based on:
4 * LUFA-120219/Demos/Device/Lowlevel/KeyboardMouse
5 * LUFA-120219/Demos/Device/Lowlevel/GenericHID
dd93d291 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"
3969ec09 43#include "sendchar.h"
44#include "debug.h"
effa5914 45
46#include "descriptor.h"
dd93d291 47#include "lufa.h"
48
49static uint8_t keyboard_led_stats = 0;
effa5914 50
51// TODO: impl Control Request GET_REPORT
52static report_keyboard_t keyboard_report_sent;
f2ebac10 53#ifdef MOUSE_ENABLE
effa5914 54static report_mouse_t mouse_report_sent;
f2ebac10 55#endif
dd93d291 56
57/* Host driver */
58static uint8_t keyboard_leds(void);
59static void send_keyboard(report_keyboard_t *report);
60static void send_mouse(report_mouse_t *report);
61static void send_system(uint16_t data);
62static void send_consumer(uint16_t data);
63static host_driver_t lufa_driver = {
64 keyboard_leds,
65 send_keyboard,
66 send_mouse,
67 send_system,
68 send_consumer
69};
70
71
effa5914 72static void SetupHardware(void);
a9a3610d 73static void Console_HID_Task(void);
effa5914 74
dd93d291 75int main(void)
76{
77 SetupHardware();
78 sei();
79
3969ec09 80 print_enable = true;
81 debug_enable = true;
82 debug_matrix = true;
83 debug_keyboard = true;
84 debug_mouse = true;
85
effa5914 86/* TODO: can't print here
87 _delay_ms(5000);
88 USB_USBTask();
3969ec09 89 print("abcdefg\n");
effa5914 90 USB_USBTask();
91*/
3969ec09 92
dd93d291 93 keyboard_init();
94 host_set_driver(&lufa_driver);
95 while (1) {
96 keyboard_proc();
effa5914 97
a9a3610d 98 Console_HID_Task();
dd93d291 99 USB_USBTask();
100 }
101}
102
dd93d291 103void 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
a9a3610d 115static void Console_HID_Task(void)
effa5914 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()
3d81d522 122 Endpoint_SelectEndpoint(CONSOLE_OUT_EPNUM);
effa5914 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 */
3d81d522 131 uint8_t ConsoleData[CONSOLE_EPSIZE];
effa5914 132
a9a3610d 133 /* Read Console Report Data */
134 Endpoint_Read_Stream_LE(&ConsoleData, sizeof(ConsoleData), NULL);
effa5914 135
a9a3610d 136 /* Process Console Report Data */
137 //ProcessConsoleHIDReport(ConsoleData);
effa5914 138 }
139
140 /* Finalize the stream transfer to send the last packet */
141 Endpoint_ClearOUT();
142 }
143
144 /* IN packet */
3d81d522 145 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
effa5914 146 // send IN packet
147 if (Endpoint_IsINReady())
148 Endpoint_ClearIN();
149}
150
151
152/*******************************************************************************
153 * USB Events
154 ******************************************************************************/
dd93d291 155/** Event handler for the USB_Connect event. */
156void EVENT_USB_Device_Connect(void)
157{
158}
159
160/** Event handler for the USB_Disconnect event. */
161void 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 */
168void 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,
3d81d522 174 KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
dd93d291 175
f2ebac10 176#ifdef MOUSE_ENABLE
dd93d291 177 /* Setup Mouse HID Report Endpoint */
178 ConfigSuccess &= Endpoint_ConfigureEndpoint(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
3d81d522 179 MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE);
f2ebac10 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
3969ec09 187
a9a3610d 188 /* Setup Console HID Report Endpoints */
3d81d522 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);
dd93d291 193}
194
a9a3610d 195/*
196Appendix G: HID Request Support Requirements
197
198The following table enumerates the requests that need to be supported by various types of HID class devices.
199
200Device type GetReport SetReport GetIdle SetIdle GetProtocol SetProtocol
201------------------------------------------------------------------------------------------
202Boot Mouse Required Optional Optional Optional Required Required
203Non-Boot Mouse Required Optional Optional Optional Optional Optional
204Boot Keyboard Required Optional Required Required Required Required
205Non-Boot Keybrd Required Optional Required Required Optional Optional
206Other Device Required Optional Optional Optional Optional Optional
207*/
dd93d291 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 */
211void EVENT_USB_Device_ControlRequest(void)
212{
3969ec09 213 uint8_t* ReportData = NULL;
214 uint8_t ReportSize = 0;
dd93d291 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
3969ec09 224 // Interface
225 switch (USB_ControlRequest.wIndex) {
effa5914 226 case KEYBOARD_INTERFACE:
227 // TODO: test/check
dd93d291 228 ReportData = (uint8_t*)&keyboard_report_sent;
229 ReportSize = sizeof(keyboard_report_sent);
3969ec09 230 break;
f2ebac10 231#ifdef MOUSE_ENABLE
effa5914 232 case MOUSE_INTERFACE:
233 // TODO: test/check
dd93d291 234 ReportData = (uint8_t*)&mouse_report_sent;
235 ReportSize = sizeof(mouse_report_sent);
3969ec09 236 break;
f2ebac10 237#endif
238#ifdef EXTRAKEY_ENABLE
3d81d522 239 case EXTRA_INTERFACE:
3969ec09 240 break;
f2ebac10 241#endif
242 case CONSOLE_INTERFACE:
243 break;
dd93d291 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
3969ec09 264 // Interface
265 switch (USB_ControlRequest.wIndex) {
effa5914 266 case KEYBOARD_INTERFACE:
267 // TODO: test/check
3969ec09 268 /* Read in the LED report from the host */
269 keyboard_led_stats = Endpoint_Read_8();
270 break;
f2ebac10 271#ifdef MOUSE_ENABLE
effa5914 272 case MOUSE_INTERFACE:
3969ec09 273 break;
f2ebac10 274#endif
275#ifdef EXTRAKEY_ENABLE
3d81d522 276 case EXTRA_INTERFACE:
3969ec09 277 break;
f2ebac10 278#endif
279 case CONSOLE_INTERFACE:
280 break;
3969ec09 281 }
dd93d291 282
283 Endpoint_ClearOUT();
284 Endpoint_ClearStatusStage();
285 }
286
287 break;
288 }
289}
290
dd93d291 291/*******************************************************************************
292 * Host driver
293 ******************************************************************************/
294static uint8_t keyboard_leds(void)
295{
296 return keyboard_led_stats;
297}
298
299static 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
317static void send_mouse(report_mouse_t *report)
318{
f2ebac10 319#ifdef MOUSE_ENABLE
dd93d291 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 */
3d81d522 327 Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
dd93d291 328
329 /* Finalize the stream transfer to send the last packet */
330 Endpoint_ClearIN();
331 }
332 mouse_report_sent = *report;
f2ebac10 333#endif
dd93d291 334}
335
3d81d522 336typedef struct {
337 uint8_t report_id;
338 uint16_t usage;
339} __attribute__ ((packed)) report_extra_t;
340
dd93d291 341static void send_system(uint16_t data)
342{
3d81d522 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 }
dd93d291 352}
353
354static void send_consumer(uint16_t data)
355{
3d81d522 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 }
dd93d291 365}
3969ec09 366
367
368/*******************************************************************************
369 * sendchar
370 ******************************************************************************/
371int8_t sendchar(uint8_t c)
372{
373 if (USB_DeviceState != DEVICE_STATE_Configured)
374 return -1;
375
3d81d522 376 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
3969ec09 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;
3969ec09 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}
Imprint / Impressum