diff options
Diffstat (limited to 'firmware/usbstack/usb_hid.c')
-rw-r--r-- | firmware/usbstack/usb_hid.c | 424 |
1 files changed, 346 insertions, 78 deletions
diff --git a/firmware/usbstack/usb_hid.c b/firmware/usbstack/usb_hid.c index 31554eed48..e1ae75c0f9 100644 --- a/firmware/usbstack/usb_hid.c +++ b/firmware/usbstack/usb_hid.c | |||
@@ -37,17 +37,28 @@ | |||
37 | 37 | ||
38 | #define HID_VER 0x0110 /* 1.1 */ | 38 | #define HID_VER 0x0110 /* 1.1 */ |
39 | /* Subclass Codes (HID1_11.pdf, page 18) */ | 39 | /* Subclass Codes (HID1_11.pdf, page 18) */ |
40 | #define SUBCLASS_NONE 0 | ||
40 | #define SUBCLASS_BOOT_INTERFACE 1 | 41 | #define SUBCLASS_BOOT_INTERFACE 1 |
41 | /* Protocol Codes (HID1_11.pdf, page 19) */ | 42 | /* Protocol Codes (HID1_11.pdf, page 19) */ |
43 | #define PROTOCOL_CODE_NONE 0 | ||
44 | #define PROTOCOL_CODE_KEYBOARD 1 | ||
42 | #define PROTOCOL_CODE_MOUSE 2 | 45 | #define PROTOCOL_CODE_MOUSE 2 |
43 | /* HID main items (HID1_11.pdf, page 38) */ | 46 | /* HID main items (HID1_11.pdf, page 38) */ |
44 | #define INPUT 0x80 | 47 | #define INPUT 0x80 |
45 | #define COLLECTION 0xa0 | 48 | #define OUTPUT 0x90 |
49 | #define COLLECTION 0xA0 | ||
46 | #define COLLECTION_APPLICATION 0x01 | 50 | #define COLLECTION_APPLICATION 0x01 |
47 | #define END_COLLECTION 0xc0 | 51 | #define END_COLLECTION 0xC0 |
48 | /* Parts (HID1_11.pdf, page 40) */ | 52 | /* Parts (HID1_11.pdf, page 40) */ |
49 | #define PREFERERD (1 << 5) | 53 | #define MAIN_ITEM_CONSTANT BIT_N(0) /* 0x01 */ |
50 | #define NULL_STATE (1 << 6) | 54 | #define MAIN_ITEM_VARIABLE BIT_N(1) /* 0x02 */ |
55 | #define MAIN_ITEM_RELATIVE BIT_N(2) /* 0x04 */ | ||
56 | #define MAIN_ITEM_WRAP BIT_N(3) /* 0x08 */ | ||
57 | #define MAIN_ITEM_NONLINEAR BIT_N(4) /* 0x10 */ | ||
58 | #define MAIN_ITEM_NO_PREFERRED BIT_N(5) /* 0x20 */ | ||
59 | #define MAIN_ITEM_NULL_STATE BIT_N(6) /* 0x40 */ | ||
60 | #define MAIN_ITEM_VOLATILE BIT_N(7) /* 0x80 */ | ||
61 | #define MAIN_ITEM_BUFFERED_BYTES BIT_N(8) /* 0x0100 */ | ||
51 | /* HID global items (HID1_11.pdf, page 45) */ | 62 | /* HID global items (HID1_11.pdf, page 45) */ |
52 | #define USAGE_PAGE 0x04 | 63 | #define USAGE_PAGE 0x04 |
53 | #define LOGICAL_MINIMUM 0x14 | 64 | #define LOGICAL_MINIMUM 0x14 |
@@ -62,26 +73,44 @@ | |||
62 | #define USB_DT_HID 0x21 | 73 | #define USB_DT_HID 0x21 |
63 | #define USB_DT_REPORT 0x22 | 74 | #define USB_DT_REPORT 0x22 |
64 | 75 | ||
65 | /* (Hut1_12.pdf, Table 1, page 14) */ | ||
66 | #define USAGE_PAGE_CONSUMER 0x0c | ||
67 | |||
68 | #define CONSUMER_USAGE 0x09 | 76 | #define CONSUMER_USAGE 0x09 |
69 | 77 | ||
70 | /* HID-only class specific requests */ | 78 | /* HID-only class specific requests (HID1_11.pdf, page 61) */ |
71 | #define USB_HID_GET_REPORT 0x01 | 79 | #define USB_HID_GET_REPORT 0x01 |
72 | #define USB_HID_GET_IDLE 0x02 | 80 | #define USB_HID_GET_IDLE 0x02 |
73 | #define USB_HID_GET_PROTOCOL 0x03 | 81 | #define USB_HID_GET_PROTOCOL 0x03 |
74 | #define USB_HID_SET_REPORT 0x09 | 82 | #define USB_HID_SET_REPORT 0x09 |
75 | #define USB_HID_SET_IDLE 0x0a | 83 | #define USB_HID_SET_IDLE 0x0A |
76 | #define USB_HID_SET_PROTOCOL 0x0b | 84 | #define USB_HID_SET_PROTOCOL 0x0B |
85 | |||
86 | /* Get_Report and Set_Report Report Type field (HID1_11.pdf, page 61) */ | ||
87 | #define REPORT_TYPE_INPUT 0x01 | ||
88 | #define REPORT_TYPE_OUTPUT 0x02 | ||
89 | #define REPORT_TYPE_FEATURE 0x03 | ||
77 | 90 | ||
78 | #define HID_BUF_SIZE_MSG 16 | 91 | #define HID_BUF_SIZE_MSG 16 |
79 | #define HID_BUF_SIZE_CMD 5 | 92 | #define HID_BUF_SIZE_CMD 16 |
80 | #define HID_BUG_SIZE_REPORT 32 | 93 | #define HID_BUF_SIZE_REPORT 96 |
81 | #define HID_NUM_BUFFERS 5 | 94 | #define HID_NUM_BUFFERS 5 |
95 | #define SET_REPORT_BUF_LEN 2 | ||
96 | |||
97 | #ifdef LOGF_ENABLE | ||
98 | #define BUF_DUMP_BUF_LEN HID_BUF_SIZE_REPORT | ||
99 | #define BUF_DUMP_PREFIX_SIZE 5 | ||
100 | #define BUF_DUMP_LINE_SIZE (MAX_LOGF_ENTRY - BUF_DUMP_PREFIX_SIZE) | ||
101 | #define BUF_DUMP_ITEMS_IN_LINE (BUF_DUMP_LINE_SIZE / 3) | ||
102 | #define BUF_DUMP_NUM_LINES (BUF_DUMP_BUF_LEN / (BUF_DUMP_LINE_SIZE / 3)) | ||
103 | #endif | ||
82 | 104 | ||
83 | #define HID_BUF_INC(i) do { (i) = ((i) + 1) % HID_NUM_BUFFERS; } while (0) | 105 | #define HID_BUF_INC(i) do { (i) = ((i) + 1) % HID_NUM_BUFFERS; } while (0) |
84 | 106 | ||
107 | typedef enum | ||
108 | { | ||
109 | REPORT_ID_KEYBOARD = 1, | ||
110 | REPORT_ID_CONSUMER, | ||
111 | REPORT_ID_COUNT, | ||
112 | } report_id_t; | ||
113 | |||
85 | /* hid interface */ | 114 | /* hid interface */ |
86 | static struct usb_interface_descriptor __attribute__((aligned(2))) | 115 | static struct usb_interface_descriptor __attribute__((aligned(2))) |
87 | interface_descriptor = | 116 | interface_descriptor = |
@@ -93,7 +122,7 @@ static struct usb_interface_descriptor __attribute__((aligned(2))) | |||
93 | .bNumEndpoints = 1, | 122 | .bNumEndpoints = 1, |
94 | .bInterfaceClass = USB_CLASS_HID, | 123 | .bInterfaceClass = USB_CLASS_HID, |
95 | .bInterfaceSubClass = SUBCLASS_BOOT_INTERFACE, | 124 | .bInterfaceSubClass = SUBCLASS_BOOT_INTERFACE, |
96 | .bInterfaceProtocol = PROTOCOL_CODE_MOUSE, | 125 | .bInterfaceProtocol = PROTOCOL_CODE_KEYBOARD, |
97 | .iInterface = 0 | 126 | .iInterface = 0 |
98 | }; | 127 | }; |
99 | 128 | ||
@@ -129,7 +158,17 @@ static struct usb_endpoint_descriptor __attribute__((aligned(2))) | |||
129 | .bInterval = 0 | 158 | .bInterval = 0 |
130 | }; | 159 | }; |
131 | 160 | ||
132 | static unsigned char report_descriptor[HID_BUG_SIZE_REPORT] | 161 | typedef struct |
162 | { | ||
163 | uint8_t usage_page; | ||
164 | /* Write the id into the buffer in the appropriate location, and returns the | ||
165 | * buffer length */ | ||
166 | uint8_t (*buf_set)(unsigned char *buf, int id); | ||
167 | } usb_hid_report_t; | ||
168 | |||
169 | usb_hid_report_t usb_hid_reports[REPORT_ID_COUNT]; | ||
170 | |||
171 | static unsigned char report_descriptor[HID_BUF_SIZE_REPORT] | ||
133 | USB_DEVBSS_ATTR __attribute__((aligned(32))); | 172 | USB_DEVBSS_ATTR __attribute__((aligned(32))); |
134 | 173 | ||
135 | static unsigned char send_buffer[HID_NUM_BUFFERS][HID_BUF_SIZE_MSG] | 174 | static unsigned char send_buffer[HID_NUM_BUFFERS][HID_BUF_SIZE_MSG] |
@@ -138,16 +177,14 @@ size_t send_buffer_len[HID_NUM_BUFFERS]; | |||
138 | static int cur_buf_prepare; | 177 | static int cur_buf_prepare; |
139 | static int cur_buf_send; | 178 | static int cur_buf_send; |
140 | 179 | ||
141 | static uint16_t report_descriptor_len; | ||
142 | static bool active = false; | 180 | static bool active = false; |
143 | static int ep_in; | 181 | static int ep_in; |
144 | static int usb_interface; | 182 | static int usb_interface; |
145 | static uint32_t report_id; | ||
146 | 183 | ||
147 | static void usb_hid_try_send_drv(void); | 184 | static void usb_hid_try_send_drv(void); |
148 | 185 | ||
149 | static void pack_parameter(unsigned char **dest, uint8_t parameter, | 186 | static void pack_parameter(unsigned char **dest, bool is_signed, |
150 | uint32_t value) | 187 | uint8_t parameter, uint32_t value) |
151 | { | 188 | { |
152 | uint8_t size_value = 1; /* # of bytes */ | 189 | uint8_t size_value = 1; /* # of bytes */ |
153 | uint32_t v = value; | 190 | uint32_t v = value; |
@@ -155,6 +192,30 @@ static void pack_parameter(unsigned char **dest, uint8_t parameter, | |||
155 | while (v >>= 8) | 192 | while (v >>= 8) |
156 | size_value++; | 193 | size_value++; |
157 | 194 | ||
195 | if (is_signed) | ||
196 | { | ||
197 | bool is_negative = 0; | ||
198 | |||
199 | switch (size_value) | ||
200 | { | ||
201 | case 1: | ||
202 | is_negative = (int8_t)value < 0; | ||
203 | break; | ||
204 | case 2: | ||
205 | is_negative = (int16_t)value < 0; | ||
206 | break; | ||
207 | case 3: | ||
208 | case 4: | ||
209 | is_negative = (int32_t)value < 0; | ||
210 | break; | ||
211 | default: | ||
212 | break; | ||
213 | } | ||
214 | |||
215 | if (is_negative) | ||
216 | size_value++; | ||
217 | } | ||
218 | |||
158 | **dest = parameter | size_value; | 219 | **dest = parameter | size_value; |
159 | (*dest)++; | 220 | (*dest)++; |
160 | 221 | ||
@@ -182,48 +243,157 @@ int usb_hid_set_first_interface(int interface) | |||
182 | return interface + 1; | 243 | return interface + 1; |
183 | } | 244 | } |
184 | 245 | ||
185 | int usb_hid_get_config_descriptor(unsigned char *dest,int max_packet_size) | 246 | #ifdef LOGF_ENABLE |
247 | static unsigned char | ||
248 | buf_dump_ar[BUF_DUMP_NUM_LINES][BUF_DUMP_LINE_SIZE + 1] | ||
249 | USB_DEVBSS_ATTR __attribute__((aligned(32))); | ||
250 | |||
251 | void buf_dump(unsigned char *buf, size_t size) | ||
252 | { | ||
253 | size_t i; | ||
254 | int line; | ||
255 | static const char v[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', | ||
256 | 'A', 'B', 'C', 'D', 'E', 'F' }; | ||
257 | |||
258 | for (i = 0, line = 0; i < size; line++) | ||
259 | { | ||
260 | int j, i0 = i; | ||
261 | char *b = buf_dump_ar[line]; | ||
262 | |||
263 | for (j = 0; j < BUF_DUMP_ITEMS_IN_LINE && i < size; j++, i++) | ||
264 | { | ||
265 | *b++ = v[buf[i] >> 4]; | ||
266 | *b++ = v[buf[i] & 0xF]; | ||
267 | *b++ = ' '; | ||
268 | } | ||
269 | *b = 0; | ||
270 | |||
271 | /* Prefix must be of len BUF_DUMP_PREFIX_SIZE */ | ||
272 | logf("%03d: %s", i0, buf_dump_ar[line]); | ||
273 | } | ||
274 | } | ||
275 | #else | ||
276 | #undef buf_dump | ||
277 | #define buf_dump(...) | ||
278 | #endif | ||
279 | |||
280 | uint8_t buf_set_keyboard(unsigned char *buf, int id) | ||
281 | { | ||
282 | memset(buf, 0, 7); | ||
283 | |||
284 | if (HID_KEYBOARD_LEFT_CONTROL <= id && id <= HID_KEYBOARD_RIGHT_GUI) | ||
285 | buf[0] = (1 << (id - HID_KEYBOARD_LEFT_CONTROL)); | ||
286 | else | ||
287 | buf[1] = (uint8_t)id; | ||
288 | |||
289 | return 7; | ||
290 | } | ||
291 | |||
292 | uint8_t buf_set_consumer(unsigned char *buf, int id) | ||
293 | { | ||
294 | memset(buf, 0, 4); | ||
295 | buf[0] = (uint8_t)id; | ||
296 | |||
297 | return 4; | ||
298 | } | ||
299 | |||
300 | static size_t descriptor_report_get(unsigned char *dest) | ||
301 | { | ||
302 | unsigned char *report = dest; | ||
303 | usb_hid_report_t *usb_hid_report; | ||
304 | |||
305 | /* Keyboard control */ | ||
306 | usb_hid_report = &usb_hid_reports[REPORT_ID_KEYBOARD]; | ||
307 | usb_hid_report->usage_page = HID_USAGE_PAGE_KEYBOARD_KEYPAD; | ||
308 | usb_hid_report->buf_set = buf_set_keyboard; | ||
309 | |||
310 | pack_parameter(&report, 0, USAGE_PAGE, | ||
311 | HID_USAGE_PAGE_GENERIC_DESKTOP_CONTROLS); | ||
312 | PACK_VAL2(report, CONCAT(CONSUMER_USAGE, HID_GENERIC_DESKTOP_KEYBOARD)); | ||
313 | pack_parameter(&report, 0, COLLECTION, COLLECTION_APPLICATION); | ||
314 | pack_parameter(&report, 0, REPORT_ID, REPORT_ID_KEYBOARD); | ||
315 | pack_parameter(&report, 0, USAGE_PAGE, HID_GENERIC_DESKTOP_KEYPAD); | ||
316 | pack_parameter(&report, 0, USAGE_MINIMUM, HID_KEYBOARD_LEFT_CONTROL); | ||
317 | pack_parameter(&report, 0, USAGE_MAXIMUM, HID_KEYBOARD_RIGHT_GUI); | ||
318 | pack_parameter(&report, 1, LOGICAL_MINIMUM, 0); | ||
319 | pack_parameter(&report, 1, LOGICAL_MAXIMUM, 1); | ||
320 | pack_parameter(&report, 0, REPORT_SIZE, 1); | ||
321 | pack_parameter(&report, 0, REPORT_COUNT, 8); | ||
322 | pack_parameter(&report, 0, INPUT, MAIN_ITEM_VARIABLE); | ||
323 | pack_parameter(&report, 0, REPORT_SIZE, 1); | ||
324 | pack_parameter(&report, 0, REPORT_COUNT, 5); | ||
325 | pack_parameter(&report, 0, USAGE_PAGE, HID_USAGE_PAGE_LEDS); | ||
326 | pack_parameter(&report, 0, USAGE_MINIMUM, HID_LED_NUM_LOCK); | ||
327 | pack_parameter(&report, 0, USAGE_MAXIMUM, HID_LED_KANA); | ||
328 | pack_parameter(&report, 0, OUTPUT, MAIN_ITEM_VARIABLE); | ||
329 | pack_parameter(&report, 0, REPORT_SIZE, 3); | ||
330 | pack_parameter(&report, 0, REPORT_COUNT, 1); | ||
331 | pack_parameter(&report, 0, OUTPUT, MAIN_ITEM_CONSTANT); | ||
332 | pack_parameter(&report, 0, REPORT_SIZE, 8); | ||
333 | pack_parameter(&report, 0, REPORT_COUNT, 6); | ||
334 | pack_parameter(&report, 1, LOGICAL_MINIMUM, 0); | ||
335 | pack_parameter(&report, 1, LOGICAL_MAXIMUM, HID_KEYBOARD_EX_SEL); | ||
336 | pack_parameter(&report, 0, USAGE_PAGE, HID_USAGE_PAGE_KEYBOARD_KEYPAD); | ||
337 | pack_parameter(&report, 0, USAGE_MINIMUM, 0); | ||
338 | pack_parameter(&report, 0, USAGE_MAXIMUM, HID_KEYBOARD_EX_SEL); | ||
339 | pack_parameter(&report, 0, INPUT, 0); | ||
340 | PACK_VAL1(report, END_COLLECTION); | ||
341 | |||
342 | /* Consumer usage controls - play/pause, stop, etc. */ | ||
343 | usb_hid_report = &usb_hid_reports[REPORT_ID_CONSUMER]; | ||
344 | usb_hid_report->usage_page = HID_USAGE_PAGE_CONSUMER; | ||
345 | usb_hid_report->buf_set = buf_set_consumer; | ||
346 | |||
347 | pack_parameter(&report, 0, USAGE_PAGE, HID_USAGE_PAGE_CONSUMER); | ||
348 | PACK_VAL2(report, CONCAT(CONSUMER_USAGE, | ||
349 | HID_CONSUMER_USAGE_CONSUMER_CONTROL)); | ||
350 | pack_parameter(&report, 0, COLLECTION, COLLECTION_APPLICATION); | ||
351 | pack_parameter(&report, 0, REPORT_ID, REPORT_ID_CONSUMER); | ||
352 | pack_parameter(&report, 0, REPORT_SIZE, 16); | ||
353 | pack_parameter(&report, 0, REPORT_COUNT, 2); | ||
354 | pack_parameter(&report, 1, LOGICAL_MINIMUM, 1); | ||
355 | pack_parameter(&report, 1, LOGICAL_MAXIMUM, 652); | ||
356 | pack_parameter(&report, 0, USAGE_MINIMUM, | ||
357 | HID_CONSUMER_USAGE_CONSUMER_CONTROL); | ||
358 | pack_parameter(&report, 0, USAGE_MAXIMUM, HID_CONSUMER_USAGE_AC_SEND); | ||
359 | pack_parameter(&report, 0, INPUT, MAIN_ITEM_NO_PREFERRED | | ||
360 | MAIN_ITEM_NULL_STATE); | ||
361 | PACK_VAL1(report, END_COLLECTION); | ||
362 | |||
363 | return (size_t)((uint32_t)report - (uint32_t)dest); | ||
364 | } | ||
365 | |||
366 | static void descriptor_hid_get(unsigned char **dest) | ||
367 | { | ||
368 | hid_descriptor.wDescriptorLength0 = | ||
369 | (uint16_t)descriptor_report_get(report_descriptor); | ||
370 | |||
371 | PACK_DATA(*dest, hid_descriptor); | ||
372 | } | ||
373 | |||
374 | int usb_hid_get_config_descriptor(unsigned char *dest, int max_packet_size) | ||
186 | { | 375 | { |
187 | unsigned char *report, *orig_dest = dest; | 376 | unsigned char *orig_dest = dest; |
188 | 377 | ||
189 | logf("hid: config desc."); | 378 | logf("hid: config desc."); |
190 | 379 | ||
191 | /* Ignore given max_packet_size */ | 380 | /* Ignore given max_packet_size */ |
192 | (void)max_packet_size; | 381 | (void)max_packet_size; |
193 | 382 | ||
194 | /* TODO: Increment report_id for each report, and send command with | 383 | /* Interface descriptor */ |
195 | * appropriate report id */ | ||
196 | report_id = 2; | ||
197 | |||
198 | /* Initialize report descriptor */ | ||
199 | report = report_descriptor; | ||
200 | pack_parameter(&report, USAGE_PAGE, USAGE_PAGE_CONSUMER); | ||
201 | PACK_VAL2(report, CONCAT(CONSUMER_USAGE, CONSUMER_CONTROL)); | ||
202 | pack_parameter(&report, COLLECTION, COLLECTION_APPLICATION); | ||
203 | pack_parameter(&report, REPORT_ID, report_id); | ||
204 | pack_parameter(&report, REPORT_SIZE, 16); | ||
205 | pack_parameter(&report, REPORT_COUNT, 2); | ||
206 | pack_parameter(&report, LOGICAL_MINIMUM, 1); | ||
207 | pack_parameter(&report, LOGICAL_MAXIMUM, 652); | ||
208 | pack_parameter(&report, USAGE_MINIMUM, CONSUMER_CONTROL); | ||
209 | pack_parameter(&report, USAGE_MAXIMUM, AC_SEND); | ||
210 | pack_parameter(&report, INPUT, PREFERERD | NULL_STATE); | ||
211 | PACK_VAL1(report, END_COLLECTION); | ||
212 | report_descriptor_len = (uint16_t)((uint32_t)report - | ||
213 | (uint32_t)report_descriptor); | ||
214 | |||
215 | interface_descriptor.bInterfaceNumber = usb_interface; | 384 | interface_descriptor.bInterfaceNumber = usb_interface; |
216 | PACK_DATA(dest, interface_descriptor); | 385 | PACK_DATA(dest, interface_descriptor); |
217 | hid_descriptor.wDescriptorLength0 = report_descriptor_len; | ||
218 | PACK_DATA(dest, hid_descriptor); | ||
219 | 386 | ||
387 | /* HID descriptor */ | ||
388 | descriptor_hid_get(&dest); | ||
389 | |||
390 | /* Endpoint descriptor */ | ||
220 | endpoint_descriptor.wMaxPacketSize = 8; | 391 | endpoint_descriptor.wMaxPacketSize = 8; |
221 | endpoint_descriptor.bInterval = 8; | 392 | endpoint_descriptor.bInterval = 8; |
222 | |||
223 | endpoint_descriptor.bEndpointAddress = ep_in; | 393 | endpoint_descriptor.bEndpointAddress = ep_in; |
224 | PACK_DATA(dest, endpoint_descriptor); | 394 | PACK_DATA(dest, endpoint_descriptor); |
225 | 395 | ||
226 | return (dest - orig_dest); | 396 | return (int)(dest - orig_dest); |
227 | } | 397 | } |
228 | 398 | ||
229 | void usb_hid_init_connection(void) | 399 | void usb_hid_init_connection(void) |
@@ -263,10 +433,12 @@ void usb_hid_transfer_complete(int ep, int dir, int status, int length) | |||
263 | (void)status; | 433 | (void)status; |
264 | (void)length; | 434 | (void)length; |
265 | 435 | ||
266 | switch (dir) { | 436 | switch (dir) |
437 | { | ||
267 | case USB_DIR_OUT: | 438 | case USB_DIR_OUT: |
268 | break; | 439 | break; |
269 | case USB_DIR_IN: { | 440 | case USB_DIR_IN: |
441 | { | ||
270 | if (status) | 442 | if (status) |
271 | break; | 443 | break; |
272 | 444 | ||
@@ -278,26 +450,95 @@ void usb_hid_transfer_complete(int ep, int dir, int status, int length) | |||
278 | } | 450 | } |
279 | } | 451 | } |
280 | 452 | ||
453 | /* The DAP is registered as a keyboard with several LEDs, therefore the OS sends | ||
454 | * LED report to notify the DAP whether Num Lock / Caps Lock etc. are enabled. | ||
455 | * In order to allow sending info to the DAP, the Set Report mechanism can be | ||
456 | * used by defining vendor specific output reports and send them from the host | ||
457 | * to the DAP using the host's custom driver */ | ||
458 | static int usb_hid_set_report(struct usb_ctrlrequest *req) | ||
459 | { | ||
460 | static unsigned char buf[SET_REPORT_BUF_LEN] | ||
461 | USB_DEVBSS_ATTR __attribute__((aligned(32))); | ||
462 | int length; | ||
463 | int rc = 0; | ||
464 | |||
465 | if ((req->wValue >> 8) != REPORT_TYPE_OUTPUT) | ||
466 | { | ||
467 | logf("Unsopported report type"); | ||
468 | rc = 1; | ||
469 | goto Exit; | ||
470 | } | ||
471 | if ((req->wValue & 0xff) != REPORT_ID_KEYBOARD) | ||
472 | { | ||
473 | logf("Wrong report id"); | ||
474 | rc = 2; | ||
475 | goto Exit; | ||
476 | } | ||
477 | if (req->wIndex != (uint16_t)usb_interface) | ||
478 | { | ||
479 | logf("Wrong interface"); | ||
480 | rc = 3; | ||
481 | goto Exit; | ||
482 | } | ||
483 | length = req->wLength; | ||
484 | if (length != SET_REPORT_BUF_LEN) | ||
485 | { | ||
486 | logf("Wrong length"); | ||
487 | rc = 4; | ||
488 | goto Exit; | ||
489 | } | ||
490 | |||
491 | memset(buf, 0, length); | ||
492 | usb_drv_recv(EP_CONTROL, buf, length); | ||
493 | |||
494 | #ifdef LOGF_ENABLE | ||
495 | if (buf[1] & 0x01) | ||
496 | logf("Num Lock enabled"); | ||
497 | if (buf[1] & 0x02) | ||
498 | logf("Caps Lock enabled"); | ||
499 | if (buf[1] & 0x04) | ||
500 | logf("Scroll Lock enabled"); | ||
501 | if (buf[1] & 0x08) | ||
502 | logf("Compose enabled"); | ||
503 | if (buf[1] & 0x10) | ||
504 | logf("Kana enabled"); | ||
505 | #endif | ||
506 | |||
507 | /* Defining other LEDs and setting them from the USB host (OS) can be used | ||
508 | * to send messages to the DAP */ | ||
509 | |||
510 | Exit: | ||
511 | return rc; | ||
512 | } | ||
513 | |||
281 | /* called by usb_core_control_request() */ | 514 | /* called by usb_core_control_request() */ |
282 | bool usb_hid_control_request(struct usb_ctrlrequest* req, unsigned char* dest) | 515 | bool usb_hid_control_request(struct usb_ctrlrequest *req, unsigned char *dest) |
283 | { | 516 | { |
284 | bool handled = false; | 517 | bool handled = false; |
285 | 518 | ||
286 | switch(req->bRequestType & USB_TYPE_MASK) { | 519 | switch (req->bRequestType & USB_TYPE_MASK) |
287 | case USB_TYPE_STANDARD: { | 520 | { |
521 | case USB_TYPE_STANDARD: | ||
522 | { | ||
288 | unsigned char *orig_dest = dest; | 523 | unsigned char *orig_dest = dest; |
289 | 524 | ||
290 | switch(req->wValue>>8) { /* type */ | 525 | switch (req->wValue>>8) /* type */ |
291 | case USB_DT_HID: { | 526 | { |
527 | case USB_DT_HID: | ||
528 | { | ||
292 | logf("hid: type hid"); | 529 | logf("hid: type hid"); |
293 | hid_descriptor.wDescriptorLength0 = report_descriptor_len; | 530 | descriptor_hid_get(&dest); |
294 | PACK_DATA(dest, hid_descriptor); | ||
295 | break; | 531 | break; |
296 | } | 532 | } |
297 | case USB_DT_REPORT: { | 533 | case USB_DT_REPORT: |
534 | { | ||
535 | int len; | ||
536 | |||
298 | logf("hid: type report"); | 537 | logf("hid: type report"); |
299 | memcpy(dest, &report_descriptor, report_descriptor_len); | 538 | |
300 | dest += report_descriptor_len; | 539 | len = descriptor_report_get(report_descriptor); |
540 | memcpy(dest, &report_descriptor, len); | ||
541 | dest += len; | ||
301 | break; | 542 | break; |
302 | } | 543 | } |
303 | default: | 544 | default: |
@@ -305,26 +546,37 @@ bool usb_hid_control_request(struct usb_ctrlrequest* req, unsigned char* dest) | |||
305 | break; | 546 | break; |
306 | } | 547 | } |
307 | if (dest != orig_dest && | 548 | if (dest != orig_dest && |
308 | !usb_drv_send(EP_CONTROL, orig_dest, dest - orig_dest)) { | 549 | !usb_drv_send(EP_CONTROL, orig_dest, dest - orig_dest)) |
550 | { | ||
309 | usb_core_ack_control(req); | 551 | usb_core_ack_control(req); |
310 | handled = true; | 552 | handled = true; |
311 | } | 553 | } |
312 | break; | 554 | break; |
313 | } | 555 | } |
314 | 556 | ||
315 | case USB_TYPE_CLASS: { | 557 | case USB_TYPE_CLASS: |
316 | switch (req->bRequest) { | 558 | { |
317 | case USB_HID_SET_IDLE: | 559 | switch (req->bRequest) |
318 | logf("hid: set idle"); | 560 | { |
561 | case USB_HID_SET_IDLE: | ||
562 | logf("hid: set idle"); | ||
563 | usb_core_ack_control(req); | ||
564 | handled = true; | ||
565 | break; | ||
566 | case USB_HID_SET_REPORT: | ||
567 | logf("hid: set report"); | ||
568 | if (!usb_hid_set_report(req)) | ||
569 | { | ||
319 | usb_core_ack_control(req); | 570 | usb_core_ack_control(req); |
320 | handled = true; | 571 | handled = true; |
321 | break; | 572 | } |
322 | default: | 573 | break; |
323 | logf("%d: unsup. cls. req", req->bRequest); | 574 | default: |
324 | break; | 575 | logf("%d: unsup. cls. req", req->bRequest); |
325 | } | 576 | break; |
326 | break; | ||
327 | } | 577 | } |
578 | break; | ||
579 | } | ||
328 | 580 | ||
329 | case USB_TYPE_VENDOR: | 581 | case USB_TYPE_VENDOR: |
330 | logf("hid: unsup. ven. req"); | 582 | logf("hid: unsup. ven. req"); |
@@ -367,26 +619,42 @@ static void usb_hid_queue(unsigned char *data, int length) | |||
367 | HID_BUF_INC(cur_buf_prepare); | 619 | HID_BUF_INC(cur_buf_prepare); |
368 | } | 620 | } |
369 | 621 | ||
370 | void usb_hid_send_consumer_usage(consumer_usage_page_t id) | 622 | void usb_hid_send(usage_page_t usage_page, int id) |
371 | { | 623 | { |
624 | uint8_t report_id, length; | ||
372 | static unsigned char buf[HID_BUF_SIZE_CMD] USB_DEVBSS_ATTR | 625 | static unsigned char buf[HID_BUF_SIZE_CMD] USB_DEVBSS_ATTR |
373 | __attribute__((aligned(32))); | 626 | __attribute__((aligned(32))); |
374 | unsigned char *dest = buf; | 627 | usb_hid_report_t *report = NULL; |
375 | |||
376 | memset(buf, 0, sizeof(buf)); | ||
377 | 628 | ||
378 | logf("HID: Sending 0x%x", id); | 629 | for (report_id = 1; report_id < REPORT_ID_COUNT; report_id++) |
630 | { | ||
631 | if (usb_hid_reports[report_id].usage_page == usage_page) | ||
632 | { | ||
633 | report = &usb_hid_reports[report_id]; | ||
634 | break; | ||
635 | } | ||
636 | } | ||
637 | if (!report) | ||
638 | { | ||
639 | logf("Unsupported usage_page"); | ||
640 | return; | ||
641 | } | ||
379 | 642 | ||
380 | pack_parameter(&dest, 0, id); | 643 | logf("Sending cmd 0x%x", id); |
381 | buf[0] = report_id; | 644 | buf[0] = report_id; |
645 | length = report->buf_set(&buf[1], id) + 1; | ||
646 | logf("length %u", length); | ||
382 | 647 | ||
383 | /* Key pressed */ | 648 | /* Key pressed */ |
384 | usb_hid_queue(buf, HID_BUF_SIZE_CMD); | 649 | buf_dump(buf, length); |
650 | usb_hid_queue(buf, length); | ||
385 | 651 | ||
386 | /* Key released */ | 652 | /* Key released */ |
387 | memset(buf, 0, sizeof(buf)); | 653 | memset(buf, 0, length); |
388 | buf[0] = report_id; | 654 | buf[0] = report_id; |
389 | usb_hid_queue(buf, HID_BUF_SIZE_CMD); | 655 | |
656 | buf_dump(buf, length); | ||
657 | usb_hid_queue(buf, length); | ||
390 | 658 | ||
391 | usb_hid_try_send_drv(); | 659 | usb_hid_try_send_drv(); |
392 | } | 660 | } |