]>
Commit | Line | Data |
---|---|---|
28203e90 | 1 | /* |
2 | * (c) 2015 flabberast <s3+flabbergast@sdfeu.org> | |
3 | * | |
4 | * Based on the following work: | |
5 | * - Guillaume Duc's raw hid example (MIT License) | |
6 | * https://github.com/guiduc/usb-hid-chibios-example | |
7 | * - PJRC Teensy examples (MIT License) | |
8 | * https://www.pjrc.com/teensy/usb_keyboard.html | |
9 | * - hasu's TMK keyboard code (GPL v2 and some code Modified BSD) | |
10 | * https://github.com/tmk/tmk_keyboard/ | |
11 | * - ChibiOS demo code (Apache 2.0 License) | |
12 | * http://www.chibios.org | |
13 | * | |
14 | * Since some GPL'd code is used, this work is licensed under | |
15 | * GPL v2 or later. | |
16 | */ | |
17 | ||
18 | #include "ch.h" | |
19 | #include "hal.h" | |
20 | ||
21 | #include "usb_main.h" | |
22 | ||
23 | #include "host.h" | |
24 | #include "debug.h" | |
25 | #include "suspend.h" | |
26 | #ifdef SLEEP_LED_ENABLE | |
27 | #include "sleep_led.h" | |
28 | #include "led.h" | |
29 | #endif | |
71381457 | 30 | #include "hook.h" |
31 | ||
32 | /* TMK hooks */ | |
33 | __attribute__((weak)) | |
34 | void hook_usb_wakeup(void) { | |
35 | #ifdef SLEEP_LED_ENABLE | |
36 | sleep_led_disable(); | |
37 | // NOTE: converters may not accept this | |
38 | led_set(host_keyboard_leds()); | |
39 | #endif /* SLEEP_LED_ENABLE */ | |
40 | } | |
41 | ||
42 | __attribute__((weak)) | |
43 | void hook_usb_suspend_entry(void) { | |
44 | #ifdef SLEEP_LED_ENABLE | |
45 | sleep_led_enable(); | |
46 | #endif /* SLEEP_LED_ENABLE */ | |
47 | } | |
48 | ||
28203e90 | 49 | |
50 | /* --------------------------------------------------------- | |
51 | * Global interface variables and declarations | |
52 | * --------------------------------------------------------- | |
53 | */ | |
54 | ||
71381457 | 55 | uint8_t keyboard_idle __attribute__((aligned(2))) = 0; |
56 | uint8_t keyboard_protocol __attribute__((aligned(2))) = 1; | |
57 | uint16_t keyboard_led_stats __attribute__((aligned(2))) = 0; | |
28203e90 | 58 | volatile uint16_t keyboard_idle_count = 0; |
59 | static virtual_timer_t keyboard_idle_timer; | |
60 | static void keyboard_idle_timer_cb(void *arg); | |
61 | #ifdef NKRO_ENABLE | |
62 | extern bool keyboard_nkro; | |
63 | #endif /* NKRO_ENABLE */ | |
64 | ||
65 | report_keyboard_t keyboard_report_sent = {{0}}; | |
66 | #ifdef MOUSE_ENABLE | |
67 | report_mouse_t mouse_report_blank = {0}; | |
68 | #endif /* MOUSE_ENABLE */ | |
69 | #ifdef EXTRAKEY_ENABLE | |
70 | uint8_t extra_report_blank[3] = {0}; | |
71 | #endif /* EXTRAKEY_ENABLE */ | |
72 | ||
73 | #ifdef CONSOLE_ENABLE | |
74 | /* The emission buffers queue */ | |
75 | output_buffers_queue_t console_buf_queue; | |
76 | static uint8_t console_queue_buffer[BQ_BUFFER_SIZE(CONSOLE_QUEUE_CAPACITY, CONSOLE_EPSIZE)]; | |
77 | ||
78 | static virtual_timer_t console_flush_timer; | |
79 | void console_queue_onotify(io_buffers_queue_t *bqp); | |
80 | static void console_flush_cb(void *arg); | |
81 | #endif /* CONSOLE_ENABLE */ | |
82 | ||
83 | /* --------------------------------------------------------- | |
84 | * Descriptors and USB driver objects | |
85 | * --------------------------------------------------------- | |
86 | */ | |
87 | ||
88 | /* HID specific constants */ | |
89 | #define USB_DESCRIPTOR_HID 0x21 | |
90 | #define USB_DESCRIPTOR_HID_REPORT 0x22 | |
91 | #define HID_GET_REPORT 0x01 | |
92 | #define HID_GET_IDLE 0x02 | |
93 | #define HID_GET_PROTOCOL 0x03 | |
94 | #define HID_SET_REPORT 0x09 | |
95 | #define HID_SET_IDLE 0x0A | |
96 | #define HID_SET_PROTOCOL 0x0B | |
97 | ||
98 | /* USB Device Descriptor */ | |
99 | static const uint8_t usb_device_descriptor_data[] = { | |
100 | USB_DESC_DEVICE(0x0200, // bcdUSB (1.1) | |
101 | 0, // bDeviceClass (defined in later in interface) | |
102 | 0, // bDeviceSubClass | |
103 | 0, // bDeviceProtocol | |
104 | 64, // bMaxPacketSize (64 bytes) (the driver didn't work with 32) | |
105 | VENDOR_ID, // idVendor | |
106 | PRODUCT_ID, // idProduct | |
107 | DEVICE_VER, // bcdDevice | |
108 | 1, // iManufacturer | |
109 | 2, // iProduct | |
110 | 3, // iSerialNumber | |
111 | 1) // bNumConfigurations | |
112 | }; | |
113 | ||
114 | /* Device Descriptor wrapper */ | |
115 | static const USBDescriptor usb_device_descriptor = { | |
116 | sizeof usb_device_descriptor_data, | |
117 | usb_device_descriptor_data | |
118 | }; | |
119 | ||
120 | /* | |
121 | * HID Report Descriptor | |
122 | * | |
123 | * See "Device Class Definition for Human Interface Devices (HID)" | |
124 | * (http://www.usb.org/developers/hidpage/HID1_11.pdf) for the | |
125 | * detailed descrition of all the fields | |
126 | */ | |
127 | ||
128 | /* Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60 */ | |
129 | static const uint8_t keyboard_hid_report_desc_data[] = { | |
130 | 0x05, 0x01, // Usage Page (Generic Desktop), | |
131 | 0x09, 0x06, // Usage (Keyboard), | |
132 | 0xA1, 0x01, // Collection (Application), | |
133 | 0x75, 0x01, // Report Size (1), | |
134 | 0x95, 0x08, // Report Count (8), | |
135 | 0x05, 0x07, // Usage Page (Key Codes), | |
136 | 0x19, 0xE0, // Usage Minimum (224), | |
137 | 0x29, 0xE7, // Usage Maximum (231), | |
138 | 0x15, 0x00, // Logical Minimum (0), | |
139 | 0x25, 0x01, // Logical Maximum (1), | |
140 | 0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte | |
141 | 0x95, 0x01, // Report Count (1), | |
142 | 0x75, 0x08, // Report Size (8), | |
143 | 0x81, 0x03, // Input (Constant), ;Reserved byte | |
144 | 0x95, 0x05, // Report Count (5), | |
145 | 0x75, 0x01, // Report Size (1), | |
146 | 0x05, 0x08, // Usage Page (LEDs), | |
147 | 0x19, 0x01, // Usage Minimum (1), | |
148 | 0x29, 0x05, // Usage Maximum (5), | |
149 | 0x91, 0x02, // Output (Data, Variable, Absolute), ;LED report | |
150 | 0x95, 0x01, // Report Count (1), | |
151 | 0x75, 0x03, // Report Size (3), | |
152 | 0x91, 0x03, // Output (Constant), ;LED report padding | |
153 | 0x95, KBD_REPORT_KEYS, // Report Count (), | |
154 | 0x75, 0x08, // Report Size (8), | |
155 | 0x15, 0x00, // Logical Minimum (0), | |
7ce326de | 156 | 0x26, 0xFF, 0x00, // Logical Maximum(255), |
28203e90 | 157 | 0x05, 0x07, // Usage Page (Key Codes), |
158 | 0x19, 0x00, // Usage Minimum (0), | |
159 | 0x29, 0xFF, // Usage Maximum (255), | |
160 | 0x81, 0x00, // Input (Data, Array), | |
161 | 0xc0 // End Collection | |
162 | }; | |
163 | /* wrapper */ | |
164 | static const USBDescriptor keyboard_hid_report_descriptor = { | |
165 | sizeof keyboard_hid_report_desc_data, | |
166 | keyboard_hid_report_desc_data | |
167 | }; | |
168 | ||
169 | #ifdef NKRO_ENABLE | |
170 | static const uint8_t nkro_hid_report_desc_data[] = { | |
171 | 0x05, 0x01, // Usage Page (Generic Desktop), | |
172 | 0x09, 0x06, // Usage (Keyboard), | |
173 | 0xA1, 0x01, // Collection (Application), | |
174 | // bitmap of modifiers | |
175 | 0x75, 0x01, // Report Size (1), | |
176 | 0x95, 0x08, // Report Count (8), | |
177 | 0x05, 0x07, // Usage Page (Key Codes), | |
178 | 0x19, 0xE0, // Usage Minimum (224), | |
179 | 0x29, 0xE7, // Usage Maximum (231), | |
180 | 0x15, 0x00, // Logical Minimum (0), | |
181 | 0x25, 0x01, // Logical Maximum (1), | |
182 | 0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte | |
183 | // LED output report | |
184 | 0x95, 0x05, // Report Count (5), | |
185 | 0x75, 0x01, // Report Size (1), | |
186 | 0x05, 0x08, // Usage Page (LEDs), | |
187 | 0x19, 0x01, // Usage Minimum (1), | |
188 | 0x29, 0x05, // Usage Maximum (5), | |
189 | 0x91, 0x02, // Output (Data, Variable, Absolute), | |
190 | 0x95, 0x01, // Report Count (1), | |
191 | 0x75, 0x03, // Report Size (3), | |
192 | 0x91, 0x03, // Output (Constant), | |
193 | // bitmap of keys | |
194 | 0x95, NKRO_REPORT_KEYS * 8, // Report Count (), | |
195 | 0x75, 0x01, // Report Size (1), | |
196 | 0x15, 0x00, // Logical Minimum (0), | |
197 | 0x25, 0x01, // Logical Maximum(1), | |
198 | 0x05, 0x07, // Usage Page (Key Codes), | |
199 | 0x19, 0x00, // Usage Minimum (0), | |
200 | 0x29, NKRO_REPORT_KEYS * 8 - 1, // Usage Maximum (), | |
201 | 0x81, 0x02, // Input (Data, Variable, Absolute), | |
202 | 0xc0 // End Collection | |
203 | }; | |
204 | /* wrapper */ | |
205 | static const USBDescriptor nkro_hid_report_descriptor = { | |
206 | sizeof nkro_hid_report_desc_data, | |
207 | nkro_hid_report_desc_data | |
208 | }; | |
209 | #endif /* NKRO_ENABLE */ | |
210 | ||
211 | #ifdef MOUSE_ENABLE | |
212 | /* Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension | |
213 | * http://www.microchip.com/forums/tm.aspx?high=&m=391435&mpage=1#391521 | |
214 | * http://www.keil.com/forum/15671/ | |
215 | * http://www.microsoft.com/whdc/device/input/wheel.mspx */ | |
216 | static const uint8_t mouse_hid_report_desc_data[] = { | |
217 | /* mouse */ | |
218 | 0x05, 0x01, // USAGE_PAGE (Generic Desktop) | |
219 | 0x09, 0x02, // USAGE (Mouse) | |
220 | 0xa1, 0x01, // COLLECTION (Application) | |
221 | //0x85, REPORT_ID_MOUSE, // REPORT_ID (1) | |
222 | 0x09, 0x01, // USAGE (Pointer) | |
223 | 0xa1, 0x00, // COLLECTION (Physical) | |
224 | // ---------------------------- Buttons | |
225 | 0x05, 0x09, // USAGE_PAGE (Button) | |
226 | 0x19, 0x01, // USAGE_MINIMUM (Button 1) | |
227 | 0x29, 0x05, // USAGE_MAXIMUM (Button 5) | |
228 | 0x15, 0x00, // LOGICAL_MINIMUM (0) | |
229 | 0x25, 0x01, // LOGICAL_MAXIMUM (1) | |
230 | 0x75, 0x01, // REPORT_SIZE (1) | |
231 | 0x95, 0x05, // REPORT_COUNT (5) | |
232 | 0x81, 0x02, // INPUT (Data,Var,Abs) | |
233 | 0x75, 0x03, // REPORT_SIZE (3) | |
234 | 0x95, 0x01, // REPORT_COUNT (1) | |
235 | 0x81, 0x03, // INPUT (Cnst,Var,Abs) | |
236 | // ---------------------------- X,Y position | |
237 | 0x05, 0x01, // USAGE_PAGE (Generic Desktop) | |
238 | 0x09, 0x30, // USAGE (X) | |
239 | 0x09, 0x31, // USAGE (Y) | |
240 | 0x15, 0x81, // LOGICAL_MINIMUM (-127) | |
241 | 0x25, 0x7f, // LOGICAL_MAXIMUM (127) | |
242 | 0x75, 0x08, // REPORT_SIZE (8) | |
243 | 0x95, 0x02, // REPORT_COUNT (2) | |
244 | 0x81, 0x06, // INPUT (Data,Var,Rel) | |
245 | // ---------------------------- Vertical wheel | |
246 | 0x09, 0x38, // USAGE (Wheel) | |
247 | 0x15, 0x81, // LOGICAL_MINIMUM (-127) | |
248 | 0x25, 0x7f, // LOGICAL_MAXIMUM (127) | |
249 | 0x35, 0x00, // PHYSICAL_MINIMUM (0) - reset physical | |
250 | 0x45, 0x00, // PHYSICAL_MAXIMUM (0) | |
251 | 0x75, 0x08, // REPORT_SIZE (8) | |
252 | 0x95, 0x01, // REPORT_COUNT (1) | |
253 | 0x81, 0x06, // INPUT (Data,Var,Rel) | |
254 | // ---------------------------- Horizontal wheel | |
255 | 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) | |
256 | 0x0a, 0x38, 0x02, // USAGE (AC Pan) | |
257 | 0x15, 0x81, // LOGICAL_MINIMUM (-127) | |
258 | 0x25, 0x7f, // LOGICAL_MAXIMUM (127) | |
259 | 0x75, 0x08, // REPORT_SIZE (8) | |
260 | 0x95, 0x01, // REPORT_COUNT (1) | |
261 | 0x81, 0x06, // INPUT (Data,Var,Rel) | |
262 | 0xc0, // END_COLLECTION | |
263 | 0xc0, // END_COLLECTION | |
264 | }; | |
265 | /* wrapper */ | |
266 | static const USBDescriptor mouse_hid_report_descriptor = { | |
267 | sizeof mouse_hid_report_desc_data, | |
268 | mouse_hid_report_desc_data | |
269 | }; | |
270 | #endif /* MOUSE_ENABLE */ | |
271 | ||
272 | #ifdef CONSOLE_ENABLE | |
273 | static const uint8_t console_hid_report_desc_data[] = { | |
274 | 0x06, 0x31, 0xFF, // Usage Page 0xFF31 (vendor defined) | |
275 | 0x09, 0x74, // Usage 0x74 | |
276 | 0xA1, 0x53, // Collection 0x53 | |
277 | 0x75, 0x08, // report size = 8 bits | |
278 | 0x15, 0x00, // logical minimum = 0 | |
279 | 0x26, 0xFF, 0x00, // logical maximum = 255 | |
280 | 0x95, CONSOLE_EPSIZE, // report count | |
281 | 0x09, 0x75, // usage | |
282 | 0x81, 0x02, // Input (array) | |
283 | 0xC0 // end collection | |
284 | }; | |
285 | /* wrapper */ | |
286 | static const USBDescriptor console_hid_report_descriptor = { | |
287 | sizeof console_hid_report_desc_data, | |
288 | console_hid_report_desc_data | |
289 | }; | |
290 | #endif /* CONSOLE_ENABLE */ | |
291 | ||
292 | #ifdef EXTRAKEY_ENABLE | |
293 | /* audio controls & system controls | |
294 | * http://www.microsoft.com/whdc/archive/w2kbd.mspx */ | |
295 | static const uint8_t extra_hid_report_desc_data[] = { | |
296 | /* system control */ | |
297 | 0x05, 0x01, // USAGE_PAGE (Generic Desktop) | |
298 | 0x09, 0x80, // USAGE (System Control) | |
299 | 0xa1, 0x01, // COLLECTION (Application) | |
300 | 0x85, REPORT_ID_SYSTEM, // REPORT_ID (2) | |
301 | 0x15, 0x01, // LOGICAL_MINIMUM (0x1) | |
7ce326de | 302 | 0x26, 0xb7, 0x00, // LOGICAL_MAXIMUM (0xb7) |
28203e90 | 303 | 0x19, 0x01, // USAGE_MINIMUM (0x1) |
304 | 0x29, 0xb7, // USAGE_MAXIMUM (0xb7) | |
305 | 0x75, 0x10, // REPORT_SIZE (16) | |
306 | 0x95, 0x01, // REPORT_COUNT (1) | |
307 | 0x81, 0x00, // INPUT (Data,Array,Abs) | |
308 | 0xc0, // END_COLLECTION | |
309 | /* consumer */ | |
310 | 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) | |
311 | 0x09, 0x01, // USAGE (Consumer Control) | |
312 | 0xa1, 0x01, // COLLECTION (Application) | |
313 | 0x85, REPORT_ID_CONSUMER, // REPORT_ID (3) | |
314 | 0x15, 0x01, // LOGICAL_MINIMUM (0x1) | |
315 | 0x26, 0x9c, 0x02, // LOGICAL_MAXIMUM (0x29c) | |
316 | 0x19, 0x01, // USAGE_MINIMUM (0x1) | |
317 | 0x2a, 0x9c, 0x02, // USAGE_MAXIMUM (0x29c) | |
318 | 0x75, 0x10, // REPORT_SIZE (16) | |
319 | 0x95, 0x01, // REPORT_COUNT (1) | |
320 | 0x81, 0x00, // INPUT (Data,Array,Abs) | |
321 | 0xc0, // END_COLLECTION | |
322 | }; | |
323 | /* wrapper */ | |
324 | static const USBDescriptor extra_hid_report_descriptor = { | |
325 | sizeof extra_hid_report_desc_data, | |
326 | extra_hid_report_desc_data | |
327 | }; | |
328 | #endif /* EXTRAKEY_ENABLE */ | |
329 | ||
330 | ||
331 | /* | |
332 | * Configuration Descriptor tree for a HID device | |
333 | * | |
334 | * The HID Specifications version 1.11 require the following order: | |
335 | * - Configuration Descriptor | |
336 | * - Interface Descriptor | |
337 | * - HID Descriptor | |
338 | * - Endpoints Descriptors | |
339 | */ | |
340 | #define KBD_HID_DESC_NUM 0 | |
341 | #define KBD_HID_DESC_OFFSET (9 + (9 + 9 + 7) * KBD_HID_DESC_NUM + 9) | |
342 | ||
343 | #ifdef MOUSE_ENABLE | |
344 | # define MOUSE_HID_DESC_NUM (KBD_HID_DESC_NUM + 1) | |
345 | # define MOUSE_HID_DESC_OFFSET (9 + (9 + 9 + 7) * MOUSE_HID_DESC_NUM + 9) | |
346 | #else /* MOUSE_ENABLE */ | |
347 | # define MOUSE_HID_DESC_NUM (KBD_HID_DESC_NUM + 0) | |
348 | #endif /* MOUSE_ENABLE */ | |
349 | ||
350 | #ifdef CONSOLE_ENABLE | |
351 | #define CONSOLE_HID_DESC_NUM (MOUSE_HID_DESC_NUM + 1) | |
352 | #define CONSOLE_HID_DESC_OFFSET (9 + (9 + 9 + 7) * CONSOLE_HID_DESC_NUM + 9) | |
353 | #else /* CONSOLE_ENABLE */ | |
354 | # define CONSOLE_HID_DESC_NUM (MOUSE_HID_DESC_NUM + 0) | |
355 | #endif /* CONSOLE_ENABLE */ | |
356 | ||
357 | #ifdef EXTRAKEY_ENABLE | |
358 | # define EXTRA_HID_DESC_NUM (CONSOLE_HID_DESC_NUM + 1) | |
359 | # define EXTRA_HID_DESC_OFFSET (9 + (9 + 9 + 7) * EXTRA_HID_DESC_NUM + 9) | |
360 | #else /* EXTRAKEY_ENABLE */ | |
361 | # define EXTRA_HID_DESC_NUM (CONSOLE_HID_DESC_NUM + 0) | |
362 | #endif /* EXTRAKEY_ENABLE */ | |
363 | ||
364 | #ifdef NKRO_ENABLE | |
365 | # define NKRO_HID_DESC_NUM (EXTRA_HID_DESC_NUM + 1) | |
366 | # define NKRO_HID_DESC_OFFSET (9 + (9 + 9 + 7) * EXTRA_HID_DESC_NUM + 9) | |
367 | #else /* NKRO_ENABLE */ | |
368 | # define NKRO_HID_DESC_NUM (EXTRA_HID_DESC_NUM + 0) | |
369 | #endif /* NKRO_ENABLE */ | |
370 | ||
371 | #define NUM_INTERFACES (NKRO_HID_DESC_NUM + 1) | |
372 | #define CONFIG1_DESC_SIZE (9 + (9 + 9 + 7) * NUM_INTERFACES) | |
373 | ||
374 | static const uint8_t hid_configuration_descriptor_data[] = { | |
375 | /* Configuration Descriptor (9 bytes) USB spec 9.6.3, page 264-266, Table 9-10 */ | |
376 | USB_DESC_CONFIGURATION(CONFIG1_DESC_SIZE, // wTotalLength | |
377 | NUM_INTERFACES, // bNumInterfaces | |
378 | 1, // bConfigurationValue | |
379 | 0, // iConfiguration | |
380 | 0xA0, // bmAttributes (RESERVED|REMOTEWAKEUP) | |
381 | 50), // bMaxPower (50mA) | |
382 | ||
383 | /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */ | |
384 | USB_DESC_INTERFACE(KBD_INTERFACE, // bInterfaceNumber | |
385 | 0, // bAlternateSetting | |
386 | 1, // bNumEndpoints | |
387 | 0x03, // bInterfaceClass: HID | |
388 | 0x01, // bInterfaceSubClass: Boot | |
389 | 0x01, // bInterfaceProtocol: Keyboard | |
390 | 0), // iInterface | |
391 | ||
392 | /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */ | |
393 | USB_DESC_BYTE(9), // bLength | |
394 | USB_DESC_BYTE(0x21), // bDescriptorType (HID class) | |
395 | USB_DESC_BCD(0x0111), // bcdHID: HID version 1.11 | |
396 | USB_DESC_BYTE(0), // bCountryCode | |
397 | USB_DESC_BYTE(1), // bNumDescriptors | |
398 | USB_DESC_BYTE(0x22), // bDescriptorType (report desc) | |
399 | USB_DESC_WORD(sizeof(keyboard_hid_report_desc_data)), // wDescriptorLength | |
400 | ||
401 | /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */ | |
402 | USB_DESC_ENDPOINT(KBD_ENDPOINT | 0x80, // bEndpointAddress | |
403 | 0x03, // bmAttributes (Interrupt) | |
404 | KBD_EPSIZE,// wMaxPacketSize | |
405 | 10), // bInterval | |
406 | ||
407 | #ifdef MOUSE_ENABLE | |
408 | /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */ | |
409 | USB_DESC_INTERFACE(MOUSE_INTERFACE, // bInterfaceNumber | |
410 | 0, // bAlternateSetting | |
411 | 1, // bNumEndpoints | |
412 | 0x03, // bInterfaceClass (0x03 = HID) | |
413 | // ThinkPad T23 BIOS doesn't work with boot mouse. | |
414 | 0x00, // bInterfaceSubClass (0x01 = Boot) | |
415 | 0x00, // bInterfaceProtocol (0x02 = Mouse) | |
416 | /* | |
417 | 0x01, // bInterfaceSubClass (0x01 = Boot) | |
418 | 0x02, // bInterfaceProtocol (0x02 = Mouse) | |
419 | */ | |
420 | 0), // iInterface | |
421 | ||
422 | /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */ | |
423 | USB_DESC_BYTE(9), // bLength | |
424 | USB_DESC_BYTE(0x21), // bDescriptorType (HID class) | |
425 | USB_DESC_BCD(0x0111), // bcdHID: HID version 1.11 | |
426 | USB_DESC_BYTE(0), // bCountryCode | |
427 | USB_DESC_BYTE(1), // bNumDescriptors | |
428 | USB_DESC_BYTE(0x22), // bDescriptorType (report desc) | |
429 | USB_DESC_WORD(sizeof(mouse_hid_report_desc_data)), // wDescriptorLength | |
430 | ||
431 | /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */ | |
432 | USB_DESC_ENDPOINT(MOUSE_ENDPOINT | 0x80, // bEndpointAddress | |
433 | 0x03, // bmAttributes (Interrupt) | |
434 | MOUSE_EPSIZE, // wMaxPacketSize | |
435 | 1), // bInterval | |
436 | #endif /* MOUSE_ENABLE */ | |
437 | ||
438 | #ifdef CONSOLE_ENABLE | |
439 | /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */ | |
440 | USB_DESC_INTERFACE(CONSOLE_INTERFACE, // bInterfaceNumber | |
441 | 0, // bAlternateSetting | |
442 | 1, // bNumEndpoints | |
443 | 0x03, // bInterfaceClass: HID | |
444 | 0x00, // bInterfaceSubClass: None | |
445 | 0x00, // bInterfaceProtocol: None | |
446 | 0), // iInterface | |
447 | ||
448 | /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */ | |
449 | USB_DESC_BYTE(9), // bLength | |
450 | USB_DESC_BYTE(0x21), // bDescriptorType (HID class) | |
451 | USB_DESC_BCD(0x0111), // bcdHID: HID version 1.11 | |
452 | USB_DESC_BYTE(0), // bCountryCode | |
453 | USB_DESC_BYTE(1), // bNumDescriptors | |
454 | USB_DESC_BYTE(0x22), // bDescriptorType (report desc) | |
455 | USB_DESC_WORD(sizeof(console_hid_report_desc_data)), // wDescriptorLength | |
456 | ||
457 | /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */ | |
458 | USB_DESC_ENDPOINT(CONSOLE_ENDPOINT | 0x80, // bEndpointAddress | |
459 | 0x03, // bmAttributes (Interrupt) | |
460 | CONSOLE_EPSIZE, // wMaxPacketSize | |
461 | 1), // bInterval | |
462 | #endif /* CONSOLE_ENABLE */ | |
463 | ||
464 | #ifdef EXTRAKEY_ENABLE | |
465 | /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */ | |
466 | USB_DESC_INTERFACE(EXTRA_INTERFACE, // bInterfaceNumber | |
467 | 0, // bAlternateSetting | |
468 | 1, // bNumEndpoints | |
469 | 0x03, // bInterfaceClass: HID | |
470 | 0x00, // bInterfaceSubClass: None | |
471 | 0x00, // bInterfaceProtocol: None | |
472 | 0), // iInterface | |
473 | ||
474 | /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */ | |
475 | USB_DESC_BYTE(9), // bLength | |
476 | USB_DESC_BYTE(0x21), // bDescriptorType (HID class) | |
477 | USB_DESC_BCD(0x0111), // bcdHID: HID version 1.11 | |
478 | USB_DESC_BYTE(0), // bCountryCode | |
479 | USB_DESC_BYTE(1), // bNumDescriptors | |
480 | USB_DESC_BYTE(0x22), // bDescriptorType (report desc) | |
481 | USB_DESC_WORD(sizeof(extra_hid_report_desc_data)), // wDescriptorLength | |
482 | ||
483 | /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */ | |
484 | USB_DESC_ENDPOINT(EXTRA_ENDPOINT | 0x80, // bEndpointAddress | |
485 | 0x03, // bmAttributes (Interrupt) | |
486 | EXTRA_EPSIZE, // wMaxPacketSize | |
487 | 10), // bInterval | |
488 | #endif /* EXTRAKEY_ENABLE */ | |
489 | ||
490 | #ifdef NKRO_ENABLE | |
491 | /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */ | |
492 | USB_DESC_INTERFACE(NKRO_INTERFACE, // bInterfaceNumber | |
493 | 0, // bAlternateSetting | |
494 | 1, // bNumEndpoints | |
495 | 0x03, // bInterfaceClass: HID | |
496 | 0x00, // bInterfaceSubClass: None | |
497 | 0x00, // bInterfaceProtocol: None | |
498 | 0), // iInterface | |
499 | ||
500 | /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */ | |
501 | USB_DESC_BYTE(9), // bLength | |
502 | USB_DESC_BYTE(0x21), // bDescriptorType (HID class) | |
503 | USB_DESC_BCD(0x0111), // bcdHID: HID version 1.11 | |
504 | USB_DESC_BYTE(0), // bCountryCode | |
505 | USB_DESC_BYTE(1), // bNumDescriptors | |
506 | USB_DESC_BYTE(0x22), // bDescriptorType (report desc) | |
507 | USB_DESC_WORD(sizeof(nkro_hid_report_desc_data)), // wDescriptorLength | |
508 | ||
509 | /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */ | |
510 | USB_DESC_ENDPOINT(NKRO_ENDPOINT | 0x80, // bEndpointAddress | |
511 | 0x03, // bmAttributes (Interrupt) | |
512 | NKRO_EPSIZE, // wMaxPacketSize | |
513 | 1), // bInterval | |
514 | #endif /* NKRO_ENABLE */ | |
515 | }; | |
516 | ||
517 | /* Configuration Descriptor wrapper */ | |
518 | static const USBDescriptor hid_configuration_descriptor = { | |
519 | sizeof hid_configuration_descriptor_data, | |
520 | hid_configuration_descriptor_data | |
521 | }; | |
522 | ||
523 | /* wrappers */ | |
524 | #define HID_DESCRIPTOR_SIZE 9 | |
525 | static const USBDescriptor keyboard_hid_descriptor = { | |
526 | HID_DESCRIPTOR_SIZE, | |
527 | &hid_configuration_descriptor_data[KBD_HID_DESC_OFFSET] | |
528 | }; | |
529 | #ifdef MOUSE_ENABLE | |
530 | static const USBDescriptor mouse_hid_descriptor = { | |
531 | HID_DESCRIPTOR_SIZE, | |
532 | &hid_configuration_descriptor_data[MOUSE_HID_DESC_OFFSET] | |
533 | }; | |
534 | #endif /* MOUSE_ENABLE */ | |
535 | #ifdef CONSOLE_ENABLE | |
536 | static const USBDescriptor console_hid_descriptor = { | |
537 | HID_DESCRIPTOR_SIZE, | |
538 | &hid_configuration_descriptor_data[CONSOLE_HID_DESC_OFFSET] | |
539 | }; | |
540 | #endif /* CONSOLE_ENABLE */ | |
541 | #ifdef EXTRAKEY_ENABLE | |
542 | static const USBDescriptor extra_hid_descriptor = { | |
543 | HID_DESCRIPTOR_SIZE, | |
544 | &hid_configuration_descriptor_data[EXTRA_HID_DESC_OFFSET] | |
545 | }; | |
546 | #endif /* EXTRAKEY_ENABLE */ | |
547 | #ifdef NKRO_ENABLE | |
548 | static const USBDescriptor nkro_hid_descriptor = { | |
549 | HID_DESCRIPTOR_SIZE, | |
550 | &hid_configuration_descriptor_data[NKRO_HID_DESC_OFFSET] | |
551 | }; | |
552 | #endif /* NKRO_ENABLE */ | |
553 | ||
554 | ||
555 | /* U.S. English language identifier */ | |
556 | static const uint8_t usb_string_langid[] = { | |
557 | USB_DESC_BYTE(4), // bLength | |
558 | USB_DESC_BYTE(USB_DESCRIPTOR_STRING), // bDescriptorType | |
559 | USB_DESC_WORD(0x0409) // wLANGID (U.S. English) | |
560 | }; | |
561 | ||
562 | /* ugly ugly hack */ | |
563 | #define PP_NARG(...) \ | |
564 | PP_NARG_(__VA_ARGS__,PP_RSEQ_N()) | |
565 | #define PP_NARG_(...) \ | |
566 | PP_ARG_N(__VA_ARGS__) | |
567 | #define PP_ARG_N( \ | |
568 | _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ | |
569 | _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \ | |
570 | _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \ | |
571 | _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \ | |
572 | _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \ | |
573 | _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \ | |
574 | _61,_62,_63,N,...) N | |
575 | #define PP_RSEQ_N() \ | |
576 | 63,62,61,60, \ | |
577 | 59,58,57,56,55,54,53,52,51,50, \ | |
578 | 49,48,47,46,45,44,43,42,41,40, \ | |
579 | 39,38,37,36,35,34,33,32,31,30, \ | |
580 | 29,28,27,26,25,24,23,22,21,20, \ | |
581 | 19,18,17,16,15,14,13,12,11,10, \ | |
582 | 9,8,7,6,5,4,3,2,1,0 | |
583 | ||
584 | /* Vendor string = manufacturer */ | |
585 | static const uint8_t usb_string_vendor[] = { | |
586 | USB_DESC_BYTE(PP_NARG(USBSTR_MANUFACTURER)+2), // bLength | |
587 | USB_DESC_BYTE(USB_DESCRIPTOR_STRING), // bDescriptorType | |
588 | USBSTR_MANUFACTURER | |
589 | }; | |
590 | ||
591 | /* Device Description string = product */ | |
592 | static const uint8_t usb_string_description[] = { | |
593 | USB_DESC_BYTE(PP_NARG(USBSTR_PRODUCT)+2), // bLength | |
594 | USB_DESC_BYTE(USB_DESCRIPTOR_STRING), // bDescriptorType | |
595 | USBSTR_PRODUCT | |
596 | }; | |
597 | ||
598 | /* Serial Number string (will be filled by the function init_usb_serial_string) */ | |
599 | static uint8_t usb_string_serial[] = { | |
600 | USB_DESC_BYTE(22), // bLength | |
601 | USB_DESC_BYTE(USB_DESCRIPTOR_STRING), // bDescriptorType | |
602 | '0', 0, 'x', 0, 'D', 0, 'E', 0, 'A', 0, 'D', 0, 'B', 0, 'E', 0, 'E', 0, 'F', 0 | |
603 | }; | |
604 | ||
605 | /* Strings wrappers array */ | |
606 | static const USBDescriptor usb_strings[] = { | |
607 | { sizeof usb_string_langid, usb_string_langid } | |
608 | , | |
609 | { sizeof usb_string_vendor, usb_string_vendor } | |
610 | , | |
611 | { sizeof usb_string_description, usb_string_description } | |
612 | , | |
613 | { sizeof usb_string_serial, usb_string_serial } | |
614 | }; | |
615 | ||
616 | /* | |
617 | * Handles the GET_DESCRIPTOR callback | |
618 | * | |
619 | * Returns the proper descriptor | |
620 | */ | |
621 | static const USBDescriptor *usb_get_descriptor_cb(USBDriver *usbp, uint8_t dtype, uint8_t dindex, uint16_t lang) { | |
622 | (void)usbp; | |
623 | (void)lang; | |
624 | switch(dtype) { | |
625 | /* Generic descriptors */ | |
626 | case USB_DESCRIPTOR_DEVICE: /* Device Descriptor */ | |
627 | return &usb_device_descriptor; | |
628 | ||
629 | case USB_DESCRIPTOR_CONFIGURATION: /* Configuration Descriptor */ | |
630 | return &hid_configuration_descriptor; | |
631 | ||
632 | case USB_DESCRIPTOR_STRING: /* Strings */ | |
633 | if(dindex < 4) | |
634 | return &usb_strings[dindex]; | |
635 | break; | |
636 | ||
637 | /* HID specific descriptors */ | |
638 | case USB_DESCRIPTOR_HID: /* HID Descriptors */ | |
639 | switch(lang) { /* yea, poor label, it's actually wIndex from the setup packet */ | |
640 | case KBD_INTERFACE: | |
641 | return &keyboard_hid_descriptor; | |
642 | ||
643 | #ifdef MOUSE_ENABLE | |
644 | case MOUSE_INTERFACE: | |
645 | return &mouse_hid_descriptor; | |
646 | #endif /* MOUSE_ENABLE */ | |
647 | #ifdef CONSOLE_ENABLE | |
648 | case CONSOLE_INTERFACE: | |
649 | return &console_hid_descriptor; | |
650 | #endif /* CONSOLE_ENABLE */ | |
651 | #ifdef EXTRAKEY_ENABLE | |
652 | case EXTRA_INTERFACE: | |
653 | return &extra_hid_descriptor; | |
654 | #endif /* EXTRAKEY_ENABLE */ | |
655 | #ifdef NKRO_ENABLE | |
656 | case NKRO_INTERFACE: | |
657 | return &nkro_hid_descriptor; | |
658 | #endif /* NKRO_ENABLE */ | |
659 | } | |
660 | ||
661 | case USB_DESCRIPTOR_HID_REPORT: /* HID Report Descriptor */ | |
662 | switch(lang) { | |
663 | case KBD_INTERFACE: | |
664 | return &keyboard_hid_report_descriptor; | |
665 | ||
666 | #ifdef MOUSE_ENABLE | |
667 | case MOUSE_INTERFACE: | |
668 | return &mouse_hid_report_descriptor; | |
669 | #endif /* MOUSE_ENABLE */ | |
670 | #ifdef CONSOLE_ENABLE | |
671 | case CONSOLE_INTERFACE: | |
672 | return &console_hid_report_descriptor; | |
673 | #endif /* CONSOLE_ENABLE */ | |
674 | #ifdef EXTRAKEY_ENABLE | |
675 | case EXTRA_INTERFACE: | |
676 | return &extra_hid_report_descriptor; | |
677 | #endif /* EXTRAKEY_ENABLE */ | |
678 | #ifdef NKRO_ENABLE | |
679 | case NKRO_INTERFACE: | |
680 | return &nkro_hid_report_descriptor; | |
681 | #endif /* NKRO_ENABLE */ | |
682 | } | |
683 | } | |
684 | return NULL; | |
685 | } | |
686 | ||
687 | /* keyboard endpoint state structure */ | |
688 | static USBInEndpointState kbd_ep_state; | |
689 | /* keyboard endpoint initialization structure (IN) */ | |
690 | static const USBEndpointConfig kbd_ep_config = { | |
691 | USB_EP_MODE_TYPE_INTR, /* Interrupt EP */ | |
692 | NULL, /* SETUP packet notification callback */ | |
693 | kbd_in_cb, /* IN notification callback */ | |
694 | NULL, /* OUT notification callback */ | |
695 | KBD_EPSIZE, /* IN maximum packet size */ | |
696 | 0, /* OUT maximum packet size */ | |
697 | &kbd_ep_state, /* IN Endpoint state */ | |
698 | NULL, /* OUT endpoint state */ | |
699 | 2, /* IN multiplier */ | |
700 | NULL /* SETUP buffer (not a SETUP endpoint) */ | |
701 | }; | |
702 | ||
703 | #ifdef MOUSE_ENABLE | |
704 | /* mouse endpoint state structure */ | |
705 | static USBInEndpointState mouse_ep_state; | |
706 | ||
707 | /* mouse endpoint initialization structure (IN) */ | |
708 | static const USBEndpointConfig mouse_ep_config = { | |
709 | USB_EP_MODE_TYPE_INTR, /* Interrupt EP */ | |
710 | NULL, /* SETUP packet notification callback */ | |
711 | mouse_in_cb, /* IN notification callback */ | |
712 | NULL, /* OUT notification callback */ | |
713 | MOUSE_EPSIZE, /* IN maximum packet size */ | |
714 | 0, /* OUT maximum packet size */ | |
715 | &mouse_ep_state, /* IN Endpoint state */ | |
716 | NULL, /* OUT endpoint state */ | |
717 | 2, /* IN multiplier */ | |
718 | NULL /* SETUP buffer (not a SETUP endpoint) */ | |
719 | }; | |
720 | #endif /* MOUSE_ENABLE */ | |
721 | ||
722 | #ifdef CONSOLE_ENABLE | |
723 | /* console endpoint state structure */ | |
724 | static USBInEndpointState console_ep_state; | |
725 | ||
726 | /* console endpoint initialization structure (IN) */ | |
727 | static const USBEndpointConfig console_ep_config = { | |
728 | USB_EP_MODE_TYPE_INTR, /* Interrupt EP */ | |
729 | NULL, /* SETUP packet notification callback */ | |
730 | console_in_cb, /* IN notification callback */ | |
731 | NULL, /* OUT notification callback */ | |
732 | CONSOLE_EPSIZE, /* IN maximum packet size */ | |
733 | 0, /* OUT maximum packet size */ | |
734 | &console_ep_state, /* IN Endpoint state */ | |
735 | NULL, /* OUT endpoint state */ | |
736 | 2, /* IN multiplier */ | |
737 | NULL /* SETUP buffer (not a SETUP endpoint) */ | |
738 | }; | |
739 | #endif /* CONSOLE_ENABLE */ | |
740 | ||
741 | #ifdef EXTRAKEY_ENABLE | |
742 | /* extrakey endpoint state structure */ | |
743 | static USBInEndpointState extra_ep_state; | |
744 | ||
745 | /* extrakey endpoint initialization structure (IN) */ | |
746 | static const USBEndpointConfig extra_ep_config = { | |
747 | USB_EP_MODE_TYPE_INTR, /* Interrupt EP */ | |
748 | NULL, /* SETUP packet notification callback */ | |
749 | extra_in_cb, /* IN notification callback */ | |
750 | NULL, /* OUT notification callback */ | |
751 | EXTRA_EPSIZE, /* IN maximum packet size */ | |
752 | 0, /* OUT maximum packet size */ | |
753 | &extra_ep_state, /* IN Endpoint state */ | |
754 | NULL, /* OUT endpoint state */ | |
755 | 2, /* IN multiplier */ | |
756 | NULL /* SETUP buffer (not a SETUP endpoint) */ | |
757 | }; | |
758 | #endif /* EXTRAKEY_ENABLE */ | |
759 | ||
760 | #ifdef NKRO_ENABLE | |
761 | /* nkro endpoint state structure */ | |
762 | static USBInEndpointState nkro_ep_state; | |
763 | ||
764 | /* nkro endpoint initialization structure (IN) */ | |
765 | static const USBEndpointConfig nkro_ep_config = { | |
766 | USB_EP_MODE_TYPE_INTR, /* Interrupt EP */ | |
767 | NULL, /* SETUP packet notification callback */ | |
768 | nkro_in_cb, /* IN notification callback */ | |
769 | NULL, /* OUT notification callback */ | |
770 | NKRO_EPSIZE, /* IN maximum packet size */ | |
771 | 0, /* OUT maximum packet size */ | |
772 | &nkro_ep_state, /* IN Endpoint state */ | |
773 | NULL, /* OUT endpoint state */ | |
774 | 2, /* IN multiplier */ | |
775 | NULL /* SETUP buffer (not a SETUP endpoint) */ | |
776 | }; | |
777 | #endif /* NKRO_ENABLE */ | |
778 | ||
779 | /* --------------------------------------------------------- | |
780 | * USB driver functions | |
781 | * --------------------------------------------------------- | |
782 | */ | |
783 | ||
784 | /* Handles the USB driver global events | |
785 | * TODO: maybe disable some things when connection is lost? */ | |
786 | static void usb_event_cb(USBDriver *usbp, usbevent_t event) { | |
787 | switch(event) { | |
788 | case USB_EVENT_RESET: | |
789 | //TODO: from ISR! print("[R]"); | |
790 | return; | |
791 | ||
792 | case USB_EVENT_ADDRESS: | |
793 | return; | |
794 | ||
795 | case USB_EVENT_CONFIGURED: | |
796 | osalSysLockFromISR(); | |
797 | /* Enable the endpoints specified into the configuration. */ | |
798 | usbInitEndpointI(usbp, KBD_ENDPOINT, &kbd_ep_config); | |
799 | #ifdef MOUSE_ENABLE | |
800 | usbInitEndpointI(usbp, MOUSE_ENDPOINT, &mouse_ep_config); | |
801 | #endif /* MOUSE_ENABLE */ | |
802 | #ifdef CONSOLE_ENABLE | |
803 | usbInitEndpointI(usbp, CONSOLE_ENDPOINT, &console_ep_config); | |
804 | /* don't need to start the flush timer, it starts from console_in_cb automatically */ | |
805 | #endif /* CONSOLE_ENABLE */ | |
806 | #ifdef EXTRAKEY_ENABLE | |
807 | usbInitEndpointI(usbp, EXTRA_ENDPOINT, &extra_ep_config); | |
808 | #endif /* EXTRAKEY_ENABLE */ | |
809 | #ifdef NKRO_ENABLE | |
810 | usbInitEndpointI(usbp, NKRO_ENDPOINT, &nkro_ep_config); | |
811 | #endif /* NKRO_ENABLE */ | |
812 | osalSysUnlockFromISR(); | |
813 | return; | |
814 | ||
815 | case USB_EVENT_SUSPEND: | |
816 | //TODO: from ISR! print("[S]"); | |
71381457 | 817 | hook_usb_suspend_entry(); |
28203e90 | 818 | return; |
819 | ||
820 | case USB_EVENT_WAKEUP: | |
821 | //TODO: from ISR! print("[W]"); | |
822 | suspend_wakeup_init(); | |
71381457 | 823 | hook_usb_wakeup(); |
28203e90 | 824 | return; |
825 | ||
826 | case USB_EVENT_STALLED: | |
827 | return; | |
828 | } | |
829 | } | |
830 | ||
831 | /* Function used locally in os/hal/src/usb.c for getting descriptors | |
832 | * need it here for HID descriptor */ | |
833 | static uint16_t get_hword(uint8_t *p) { | |
834 | uint16_t hw; | |
835 | ||
836 | hw = (uint16_t)*p++; | |
837 | hw |= (uint16_t)*p << 8U; | |
838 | return hw; | |
839 | } | |
840 | ||
841 | /* | |
842 | * Appendix G: HID Request Support Requirements | |
843 | * | |
844 | * The following table enumerates the requests that need to be supported by various types of HID class devices. | |
845 | * Device type GetReport SetReport GetIdle SetIdle GetProtocol SetProtocol | |
846 | * ------------------------------------------------------------------------------------------ | |
847 | * Boot Mouse Required Optional Optional Optional Required Required | |
848 | * Non-Boot Mouse Required Optional Optional Optional Optional Optional | |
849 | * Boot Keyboard Required Optional Required Required Required Required | |
850 | * Non-Boot Keybrd Required Optional Required Required Optional Optional | |
851 | * Other Device Required Optional Optional Optional Optional Optional | |
852 | */ | |
853 | ||
854 | /* Callback for SETUP request on the endpoint 0 (control) */ | |
855 | static bool usb_request_hook_cb(USBDriver *usbp) { | |
856 | const USBDescriptor *dp; | |
857 | ||
858 | /* usbp->setup fields: | |
859 | * 0: bmRequestType (bitmask) | |
860 | * 1: bRequest | |
861 | * 2,3: (LSB,MSB) wValue | |
862 | * 4,5: (LSB,MSB) wIndex | |
863 | * 6,7: (LSB,MSB) wLength (number of bytes to transfer if there is a data phase) */ | |
864 | ||
865 | /* Handle HID class specific requests */ | |
866 | if(((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) && | |
867 | ((usbp->setup[0] & USB_RTYPE_RECIPIENT_MASK) == USB_RTYPE_RECIPIENT_INTERFACE)) { | |
868 | switch(usbp->setup[0] & USB_RTYPE_DIR_MASK) { | |
869 | case USB_RTYPE_DIR_DEV2HOST: | |
870 | switch(usbp->setup[1]) { /* bRequest */ | |
871 | case HID_GET_REPORT: | |
872 | switch(usbp->setup[4]) { /* LSB(wIndex) (check MSB==0?) */ | |
873 | case KBD_INTERFACE: | |
874 | #ifdef NKRO_ENABLE | |
875 | case NKRO_INTERFACE: | |
876 | #endif /* NKRO_ENABLE */ | |
877 | usbSetupTransfer(usbp, (uint8_t *)&keyboard_report_sent, sizeof(keyboard_report_sent), NULL); | |
878 | return TRUE; | |
879 | break; | |
880 | ||
881 | #ifdef MOUSE_ENABLE | |
882 | case MOUSE_INTERFACE: | |
883 | usbSetupTransfer(usbp, (uint8_t *)&mouse_report_blank, sizeof(mouse_report_blank), NULL); | |
884 | return TRUE; | |
885 | break; | |
886 | #endif /* MOUSE_ENABLE */ | |
887 | ||
888 | #ifdef CONSOLE_ENABLE | |
889 | case CONSOLE_INTERFACE: | |
890 | usbSetupTransfer(usbp, console_queue_buffer, CONSOLE_EPSIZE, NULL); | |
891 | return TRUE; | |
892 | break; | |
893 | #endif /* CONSOLE_ENABLE */ | |
894 | ||
895 | #ifdef EXTRAKEY_ENABLE | |
896 | case EXTRA_INTERFACE: | |
897 | if(usbp->setup[3] == 1) { /* MSB(wValue) [Report Type] == 1 [Input Report] */ | |
898 | switch(usbp->setup[2]) { /* LSB(wValue) [Report ID] */ | |
899 | case REPORT_ID_SYSTEM: | |
900 | extra_report_blank[0] = REPORT_ID_SYSTEM; | |
901 | usbSetupTransfer(usbp, (uint8_t *)extra_report_blank, sizeof(extra_report_blank), NULL); | |
902 | return TRUE; | |
903 | break; | |
904 | case REPORT_ID_CONSUMER: | |
905 | extra_report_blank[0] = REPORT_ID_CONSUMER; | |
906 | usbSetupTransfer(usbp, (uint8_t *)extra_report_blank, sizeof(extra_report_blank), NULL); | |
907 | return TRUE; | |
908 | break; | |
909 | default: | |
910 | return FALSE; | |
911 | } | |
912 | } else { | |
913 | return FALSE; | |
914 | } | |
915 | break; | |
916 | #endif /* EXTRAKEY_ENABLE */ | |
917 | ||
918 | default: | |
919 | usbSetupTransfer(usbp, NULL, 0, NULL); | |
920 | return TRUE; | |
921 | break; | |
922 | } | |
923 | break; | |
924 | ||
925 | case HID_GET_PROTOCOL: | |
926 | if((usbp->setup[4] == KBD_INTERFACE) && (usbp->setup[5] == 0)) { /* wIndex */ | |
927 | usbSetupTransfer(usbp, &keyboard_protocol, 1, NULL); | |
928 | return TRUE; | |
929 | } | |
930 | break; | |
931 | ||
932 | case HID_GET_IDLE: | |
933 | usbSetupTransfer(usbp, &keyboard_idle, 1, NULL); | |
934 | return TRUE; | |
935 | break; | |
936 | } | |
937 | break; | |
938 | ||
939 | case USB_RTYPE_DIR_HOST2DEV: | |
940 | switch(usbp->setup[1]) { /* bRequest */ | |
941 | case HID_SET_REPORT: | |
942 | switch(usbp->setup[4]) { /* LSB(wIndex) (check MSB==0 and wLength==1?) */ | |
943 | case KBD_INTERFACE: | |
944 | #ifdef NKRO_ENABLE | |
945 | case NKRO_INTERFACE: | |
946 | #endif /* NKRO_ENABLE */ | |
947 | /* keyboard_led_stats = <read byte from next OUT report> | |
948 | * keyboard_led_stats needs be word (or dword), otherwise we get an exception on F0 */ | |
949 | usbSetupTransfer(usbp, (uint8_t *)&keyboard_led_stats, 1, NULL); | |
950 | return TRUE; | |
951 | break; | |
952 | } | |
953 | break; | |
954 | ||
955 | case HID_SET_PROTOCOL: | |
956 | if((usbp->setup[4] == KBD_INTERFACE) && (usbp->setup[5] == 0)) { /* wIndex */ | |
957 | keyboard_protocol = ((usbp->setup[2]) != 0x00); /* LSB(wValue) */ | |
958 | #ifdef NKRO_ENABLE | |
959 | keyboard_nkro = !!keyboard_protocol; | |
960 | if(!keyboard_nkro && keyboard_idle) { | |
961 | #else /* NKRO_ENABLE */ | |
962 | if(keyboard_idle) { | |
963 | #endif /* NKRO_ENABLE */ | |
964 | /* arm the idle timer if boot protocol & idle */ | |
965 | osalSysLockFromISR(); | |
966 | chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp); | |
967 | osalSysUnlockFromISR(); | |
968 | } | |
969 | } | |
970 | usbSetupTransfer(usbp, NULL, 0, NULL); | |
971 | return TRUE; | |
972 | break; | |
973 | ||
974 | case HID_SET_IDLE: | |
975 | keyboard_idle = usbp->setup[3]; /* MSB(wValue) */ | |
976 | /* arm the timer */ | |
977 | #ifdef NKRO_ENABLE | |
978 | if(!keyboard_nkro && keyboard_idle) { | |
979 | #else /* NKRO_ENABLE */ | |
980 | if(keyboard_idle) { | |
981 | #endif /* NKRO_ENABLE */ | |
982 | osalSysLockFromISR(); | |
983 | chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp); | |
984 | osalSysUnlockFromISR(); | |
985 | } | |
986 | usbSetupTransfer(usbp, NULL, 0, NULL); | |
987 | return TRUE; | |
988 | break; | |
989 | } | |
990 | break; | |
991 | } | |
992 | } | |
993 | ||
994 | /* Handle the Get_Descriptor Request for HID class (not handled by the default hook) */ | |
995 | if((usbp->setup[0] == 0x81) && (usbp->setup[1] == USB_REQ_GET_DESCRIPTOR)) { | |
996 | dp = usbp->config->get_descriptor_cb(usbp, usbp->setup[3], usbp->setup[2], get_hword(&usbp->setup[4])); | |
997 | if(dp == NULL) | |
998 | return FALSE; | |
999 | usbSetupTransfer(usbp, (uint8_t *)dp->ud_string, dp->ud_size, NULL); | |
1000 | return TRUE; | |
1001 | } | |
1002 | ||
1003 | return FALSE; | |
1004 | } | |
1005 | ||
1006 | /* Start-of-frame callback */ | |
1007 | static void usb_sof_cb(USBDriver *usbp) { | |
1008 | kbd_sof_cb(usbp); | |
1009 | } | |
1010 | ||
1011 | ||
1012 | /* USB driver configuration */ | |
1013 | static const USBConfig usbcfg = { | |
1014 | usb_event_cb, /* USB events callback */ | |
1015 | usb_get_descriptor_cb, /* Device GET_DESCRIPTOR request callback */ | |
1016 | usb_request_hook_cb, /* Requests hook callback */ | |
1017 | usb_sof_cb /* Start Of Frame callback */ | |
1018 | }; | |
1019 | ||
1020 | /* | |
1021 | * Initialize the USB driver | |
1022 | */ | |
1023 | void init_usb_driver(USBDriver *usbp) { | |
1024 | /* | |
1025 | * Activates the USB driver and then the USB bus pull-up on D+. | |
1026 | * Note, a delay is inserted in order to not have to disconnect the cable | |
1027 | * after a reset. | |
1028 | */ | |
1029 | usbDisconnectBus(usbp); | |
1030 | chThdSleepMilliseconds(1500); | |
1031 | usbStart(usbp, &usbcfg); | |
1032 | usbConnectBus(usbp); | |
1033 | ||
1034 | chVTObjectInit(&keyboard_idle_timer); | |
1035 | #ifdef CONSOLE_ENABLE | |
d5689296 | 1036 | obqObjectInit(&console_buf_queue, true, console_queue_buffer, CONSOLE_EPSIZE, CONSOLE_QUEUE_CAPACITY, console_queue_onotify, (void*)usbp); |
28203e90 | 1037 | chVTObjectInit(&console_flush_timer); |
1038 | #endif | |
1039 | } | |
1040 | ||
1041 | /* | |
1042 | * Send remote wakeup packet | |
1043 | * Note: should not be called from ISR | |
1044 | */ | |
1045 | void send_remote_wakeup(USBDriver *usbp) { | |
1046 | (void)usbp; | |
1047 | #if defined(K20x) || defined(KL2x) | |
1048 | #if KINETIS_USB_USE_USB0 | |
1049 | USB0->CTL |= USBx_CTL_RESUME; | |
1050 | chThdSleepMilliseconds(15); | |
1051 | USB0->CTL &= ~USBx_CTL_RESUME; | |
1052 | #endif /* KINETIS_USB_USE_USB0 */ | |
1053 | #elif defined(STM32F0XX) || defined(STM32F1XX) /* K20x || KL2x */ | |
1054 | STM32_USB->CNTR |= CNTR_RESUME; | |
1055 | chThdSleepMilliseconds(15); | |
1056 | STM32_USB->CNTR &= ~CNTR_RESUME; | |
1057 | #else /* STM32F0XX || STM32F1XX */ | |
1058 | #warning Sending remote wakeup packet not implemented for your platform. | |
1059 | #endif /* K20x || KL2x */ | |
1060 | } | |
1061 | ||
1062 | /* --------------------------------------------------------- | |
1063 | * Keyboard functions | |
1064 | * --------------------------------------------------------- | |
1065 | */ | |
1066 | ||
1067 | /* keyboard IN callback hander (a kbd report has made it IN) */ | |
1068 | void kbd_in_cb(USBDriver *usbp, usbep_t ep) { | |
1069 | /* STUB */ | |
1070 | (void)usbp; | |
1071 | (void)ep; | |
1072 | } | |
1073 | ||
1074 | #ifdef NKRO_ENABLE | |
1075 | /* nkro IN callback hander (a nkro report has made it IN) */ | |
1076 | void nkro_in_cb(USBDriver *usbp, usbep_t ep) { | |
1077 | /* STUB */ | |
1078 | (void)usbp; | |
1079 | (void)ep; | |
1080 | } | |
1081 | #endif /* NKRO_ENABLE */ | |
1082 | ||
1083 | /* start-of-frame handler | |
1084 | * TODO: i guess it would be better to re-implement using timers, | |
1085 | * so that this is not going to have to be checked every 1ms */ | |
1086 | void kbd_sof_cb(USBDriver *usbp) { | |
1087 | (void)usbp; | |
1088 | } | |
1089 | ||
1090 | /* Idle requests timer code | |
1091 | * callback (called from ISR, unlocked state) */ | |
1092 | static void keyboard_idle_timer_cb(void *arg) { | |
1093 | USBDriver *usbp = (USBDriver *)arg; | |
1094 | ||
1095 | osalSysLockFromISR(); | |
1096 | ||
1097 | /* check that the states of things are as they're supposed to */ | |
1098 | if(usbGetDriverStateI(usbp) != USB_ACTIVE) { | |
1099 | /* do not rearm the timer, should be enabled on IDLE request */ | |
1100 | osalSysUnlockFromISR(); | |
1101 | return; | |
1102 | } | |
1103 | ||
1104 | #ifdef NKRO_ENABLE | |
1105 | if(!keyboard_nkro && keyboard_idle) { | |
1106 | #else /* NKRO_ENABLE */ | |
1107 | if(keyboard_idle) { | |
1108 | #endif /* NKRO_ENABLE */ | |
1109 | /* TODO: are we sure we want the KBD_ENDPOINT? */ | |
1110 | if(!usbGetTransmitStatusI(usbp, KBD_ENDPOINT)) { | |
1111 | usbStartTransmitI(usbp, KBD_ENDPOINT, (uint8_t *)&keyboard_report_sent, KBD_EPSIZE); | |
1112 | } | |
1113 | /* rearm the timer */ | |
1114 | chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp); | |
1115 | } | |
1116 | ||
1117 | /* do not rearm the timer if the condition above fails | |
1118 | * it should be enabled again on either IDLE or SET_PROTOCOL requests */ | |
1119 | osalSysUnlockFromISR(); | |
1120 | } | |
1121 | ||
1122 | /* LED status */ | |
1123 | uint8_t keyboard_leds(void) { | |
1124 | return (uint8_t)(keyboard_led_stats & 0xFF); | |
1125 | } | |
1126 | ||
1127 | /* prepare and start sending a report IN | |
1128 | * not callable from ISR or locked state */ | |
1129 | void send_keyboard(report_keyboard_t *report) { | |
1130 | osalSysLock(); | |
1131 | if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) { | |
1132 | osalSysUnlock(); | |
1133 | return; | |
1134 | } | |
1135 | osalSysUnlock(); | |
1136 | ||
1137 | #ifdef NKRO_ENABLE | |
1138 | if(keyboard_nkro) { /* NKRO protocol */ | |
1139 | /* need to wait until the previous packet has made it through */ | |
1140 | /* can rewrite this using the synchronous API, then would wait | |
1141 | * until *after* the packet has been transmitted. I think | |
1142 | * this is more efficient */ | |
1143 | /* busy wait, should be short and not very common */ | |
1144 | osalSysLock(); | |
1145 | if(usbGetTransmitStatusI(&USB_DRIVER, NKRO_ENDPOINT)) { | |
1146 | /* Need to either suspend, or loop and call unlock/lock during | |
1147 | * every iteration - otherwise the system will remain locked, | |
1148 | * no interrupts served, so USB not going through as well. | |
1149 | * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */ | |
1150 | osalThreadSuspendS(&(&USB_DRIVER)->epc[NKRO_ENDPOINT]->in_state->thread); | |
1151 | } | |
1152 | usbStartTransmitI(&USB_DRIVER, NKRO_ENDPOINT, (uint8_t *)report, sizeof(report_keyboard_t)); | |
1153 | osalSysUnlock(); | |
1154 | } else | |
1155 | #endif /* NKRO_ENABLE */ | |
1156 | { /* boot protocol */ | |
1157 | /* need to wait until the previous packet has made it through */ | |
1158 | /* busy wait, should be short and not very common */ | |
1159 | osalSysLock(); | |
1160 | if(usbGetTransmitStatusI(&USB_DRIVER, KBD_ENDPOINT)) { | |
1161 | /* Need to either suspend, or loop and call unlock/lock during | |
1162 | * every iteration - otherwise the system will remain locked, | |
1163 | * no interrupts served, so USB not going through as well. | |
1164 | * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */ | |
1165 | osalThreadSuspendS(&(&USB_DRIVER)->epc[KBD_ENDPOINT]->in_state->thread); | |
1166 | } | |
1167 | usbStartTransmitI(&USB_DRIVER, KBD_ENDPOINT, (uint8_t *)report, KBD_EPSIZE); | |
1168 | osalSysUnlock(); | |
1169 | } | |
1170 | keyboard_report_sent = *report; | |
1171 | } | |
1172 | ||
1173 | /* --------------------------------------------------------- | |
1174 | * Mouse functions | |
1175 | * --------------------------------------------------------- | |
1176 | */ | |
1177 | ||
1178 | #ifdef MOUSE_ENABLE | |
1179 | ||
1180 | /* mouse IN callback hander (a mouse report has made it IN) */ | |
1181 | void mouse_in_cb(USBDriver *usbp, usbep_t ep) { | |
1182 | (void)usbp; | |
1183 | (void)ep; | |
1184 | } | |
1185 | ||
1186 | void send_mouse(report_mouse_t *report) { | |
1187 | osalSysLock(); | |
1188 | if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) { | |
1189 | osalSysUnlock(); | |
1190 | return; | |
1191 | } | |
1192 | osalSysUnlock(); | |
1193 | ||
1194 | /* TODO: LUFA manually waits for the endpoint to become ready | |
1195 | * for about 10ms for mouse, kbd, system; 1ms for nkro | |
1196 | * is this really needed? | |
1197 | */ | |
1198 | ||
1199 | osalSysLock(); | |
1200 | usbStartTransmitI(&USB_DRIVER, MOUSE_ENDPOINT, (uint8_t *)report, sizeof(report_mouse_t)); | |
1201 | osalSysUnlock(); | |
1202 | } | |
1203 | ||
1204 | #else /* MOUSE_ENABLE */ | |
1205 | void send_mouse(report_mouse_t *report) { | |
1206 | (void)report; | |
1207 | } | |
1208 | #endif /* MOUSE_ENABLE */ | |
1209 | ||
1210 | /* --------------------------------------------------------- | |
1211 | * Extrakey functions | |
1212 | * --------------------------------------------------------- | |
1213 | */ | |
1214 | ||
1215 | #ifdef EXTRAKEY_ENABLE | |
1216 | ||
1217 | /* extrakey IN callback hander */ | |
1218 | void extra_in_cb(USBDriver *usbp, usbep_t ep) { | |
1219 | /* STUB */ | |
1220 | (void)usbp; | |
1221 | (void)ep; | |
1222 | } | |
1223 | ||
1224 | static void send_extra_report(uint8_t report_id, uint16_t data) { | |
1225 | osalSysLock(); | |
1226 | if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) { | |
1227 | osalSysUnlock(); | |
1228 | return; | |
1229 | } | |
1230 | ||
1231 | report_extra_t report = { | |
1232 | .report_id = report_id, | |
1233 | .usage = data | |
1234 | }; | |
1235 | ||
1236 | usbStartTransmitI(&USB_DRIVER, EXTRA_ENDPOINT, (uint8_t *)&report, sizeof(report_extra_t)); | |
1237 | osalSysUnlock(); | |
1238 | } | |
1239 | ||
1240 | void send_system(uint16_t data) { | |
1241 | send_extra_report(REPORT_ID_SYSTEM, data); | |
1242 | } | |
1243 | ||
1244 | void send_consumer(uint16_t data) { | |
1245 | send_extra_report(REPORT_ID_CONSUMER, data); | |
1246 | } | |
1247 | ||
1248 | #else /* EXTRAKEY_ENABLE */ | |
1249 | void send_system(uint16_t data) { | |
1250 | (void)data; | |
1251 | } | |
1252 | void send_consumer(uint16_t data) { | |
1253 | (void)data; | |
1254 | } | |
1255 | #endif /* EXTRAKEY_ENABLE */ | |
1256 | ||
1257 | /* --------------------------------------------------------- | |
1258 | * Console functions | |
1259 | * --------------------------------------------------------- | |
1260 | */ | |
1261 | ||
1262 | #ifdef CONSOLE_ENABLE | |
1263 | ||
1264 | /* console IN callback hander */ | |
1265 | void console_in_cb(USBDriver *usbp, usbep_t ep) { | |
1266 | (void)ep; /* should have ep == CONSOLE_ENDPOINT, so use that to save time/space */ | |
1267 | uint8_t *buf; | |
1268 | size_t n; | |
1269 | ||
1270 | osalSysLockFromISR(); | |
1271 | ||
1272 | /* rearm the timer */ | |
1273 | chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, (void *)usbp); | |
1274 | ||
1275 | /* Freeing the buffer just transmitted, if it was not a zero size packet.*/ | |
1276 | if (usbp->epc[CONSOLE_ENDPOINT]->in_state->txsize > 0U) { | |
1277 | obqReleaseEmptyBufferI(&console_buf_queue); | |
1278 | } | |
1279 | ||
1280 | /* Checking if there is a buffer ready for transmission.*/ | |
1281 | buf = obqGetFullBufferI(&console_buf_queue, &n); | |
1282 | ||
1283 | if (buf != NULL) { | |
1284 | /* The endpoint cannot be busy, we are in the context of the callback, | |
1285 | so it is safe to transmit without a check.*/ | |
1286 | /* Should have n == CONSOLE_EPSIZE; check it? */ | |
1287 | usbStartTransmitI(usbp, CONSOLE_ENDPOINT, buf, CONSOLE_EPSIZE); | |
1288 | } else { | |
1289 | /* Nothing to transmit.*/ | |
1290 | } | |
1291 | ||
1292 | osalSysUnlockFromISR(); | |
1293 | } | |
1294 | ||
1295 | /* Callback when data is inserted into the output queue | |
1296 | * Called from a locked state */ | |
1297 | void console_queue_onotify(io_buffers_queue_t *bqp) { | |
1298 | size_t n; | |
1299 | USBDriver *usbp = bqGetLinkX(bqp); | |
1300 | ||
1301 | if(usbGetDriverStateI(usbp) != USB_ACTIVE) | |
1302 | return; | |
1303 | ||
1304 | /* Checking if there is already a transaction ongoing on the endpoint.*/ | |
1305 | if (!usbGetTransmitStatusI(usbp, CONSOLE_ENDPOINT)) { | |
1306 | /* Trying to get a full buffer.*/ | |
1307 | uint8_t *buf = obqGetFullBufferI(&console_buf_queue, &n); | |
1308 | if (buf != NULL) { | |
1309 | /* Buffer found, starting a new transaction.*/ | |
1310 | /* Should have n == CONSOLE_EPSIZE; check this? */ | |
1311 | usbStartTransmitI(usbp, CONSOLE_ENDPOINT, buf, CONSOLE_EPSIZE); | |
1312 | } | |
1313 | } | |
1314 | } | |
1315 | ||
1316 | /* Flush timer code | |
1317 | * callback (called from ISR, unlocked state) */ | |
1318 | static void console_flush_cb(void *arg) { | |
1319 | USBDriver *usbp = (USBDriver *)arg; | |
1320 | osalSysLockFromISR(); | |
1321 | ||
1322 | /* check that the states of things are as they're supposed to */ | |
1323 | if(usbGetDriverStateI(usbp) != USB_ACTIVE) { | |
1324 | /* rearm the timer */ | |
1325 | chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, (void *)usbp); | |
1326 | osalSysUnlockFromISR(); | |
1327 | return; | |
1328 | } | |
1329 | ||
1330 | /* If there is already a transaction ongoing then another one cannot be | |
1331 | started.*/ | |
1332 | if (usbGetTransmitStatusI(usbp, CONSOLE_ENDPOINT)) { | |
1333 | /* rearm the timer */ | |
1334 | chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, (void *)usbp); | |
1335 | osalSysUnlockFromISR(); | |
1336 | return; | |
1337 | } | |
1338 | ||
1339 | /* Checking if there only a buffer partially filled, if so then it is | |
1340 | enforced in the queue and transmitted.*/ | |
1341 | if(obqTryFlushI(&console_buf_queue)) { | |
1342 | size_t n,i; | |
1343 | uint8_t *buf = obqGetFullBufferI(&console_buf_queue, &n); | |
1344 | ||
1345 | osalDbgAssert(buf != NULL, "queue is empty"); | |
1346 | ||
1347 | /* zero the rest of the buffer (buf should point to allocated space) */ | |
1348 | for(i=n; i<CONSOLE_EPSIZE; i++) | |
1349 | buf[i]=0; | |
1350 | usbStartTransmitI(usbp, CONSOLE_ENDPOINT, buf, CONSOLE_EPSIZE); | |
1351 | } | |
1352 | ||
1353 | /* rearm the timer */ | |
1354 | chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, (void *)usbp); | |
1355 | osalSysUnlockFromISR(); | |
1356 | } | |
1357 | ||
1358 | ||
1359 | int8_t sendchar(uint8_t c) { | |
1360 | osalSysLock(); | |
1361 | if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) { | |
1362 | osalSysUnlock(); | |
1363 | return 0; | |
1364 | } | |
1365 | osalSysUnlock(); | |
71381457 | 1366 | /* Timeout after 100us if the queue is full. |
28203e90 | 1367 | * Increase this timeout if too much stuff is getting |
1368 | * dropped (i.e. the buffer is getting full too fast | |
1369 | * for USB/HIDRAW to dequeue). Another possibility | |
1370 | * for fixing this kind of thing is to increase | |
1371 | * CONSOLE_QUEUE_CAPACITY. */ | |
1372 | return(obqPutTimeout(&console_buf_queue, c, US2ST(100))); | |
1373 | } | |
1374 | ||
1375 | #else /* CONSOLE_ENABLE */ | |
1376 | int8_t sendchar(uint8_t c) { | |
1377 | (void)c; | |
1378 | return 0; | |
1379 | } | |
1380 | #endif /* CONSOLE_ENABLE */ | |
1381 | ||
1382 | void sendchar_pf(void *p, char c) { | |
1383 | (void)p; | |
1384 | sendchar((uint8_t)c); | |
1385 | } |