Open FFBoard
Open source force feedback firmware
hid_host.c
Go to the documentation of this file.
1/*
2 * The MIT License (MIT)
3 *
4 * Copyright (c) 2019 Ha Thach (tinyusb.org)
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 *
24 * This file is part of the TinyUSB stack.
25 */
26
27#include "tusb_option.h"
28
29#if (CFG_TUH_ENABLED && CFG_TUH_HID)
30
31#include "host/usbh.h"
32#include "host/usbh_pvt.h"
33
34#include "hid_host.h"
35
36// Level where CFG_TUSB_DEBUG must be at least for this driver is logged
37#ifndef CFG_TUH_HID_LOG_LEVEL
38 #define CFG_TUH_HID_LOG_LEVEL CFG_TUH_LOG_LEVEL
39#endif
40
41#define TU_LOG_DRV(...) TU_LOG(CFG_TUH_HID_LOG_LEVEL, __VA_ARGS__)
42
43//--------------------------------------------------------------------+
44// MACRO CONSTANT TYPEDEF
45//--------------------------------------------------------------------+
46typedef struct {
47 uint8_t daddr;
48
49 uint8_t itf_num;
50 uint8_t ep_in;
51 uint8_t ep_out;
52 bool mounted; // Enumeration is complete
53
54 uint8_t itf_protocol; // None, Keyboard, Mouse
55 uint8_t protocol_mode; // Boot (0) or Report protocol (1)
56
59
60 uint16_t epin_size;
61 uint16_t epout_size;
62
63 CFG_TUH_MEM_ALIGN uint8_t epin_buf[CFG_TUH_HID_EPIN_BUFSIZE];
64 CFG_TUH_MEM_ALIGN uint8_t epout_buf[CFG_TUH_HID_EPOUT_BUFSIZE];
66
67CFG_TUH_MEM_SECTION
68tu_static hidh_interface_t _hidh_itf[CFG_TUH_HID];
69
71
72//--------------------------------------------------------------------+
73// Helper
74//--------------------------------------------------------------------+
75TU_ATTR_ALWAYS_INLINE static inline hidh_interface_t* get_hid_itf(uint8_t daddr, uint8_t idx) {
76 TU_ASSERT(daddr > 0 && idx < CFG_TUH_HID, NULL);
77 hidh_interface_t* p_hid = &_hidh_itf[idx];
78 return (p_hid->daddr == daddr) ? p_hid : NULL;
79}
80
81// Get instance ID by endpoint address
82static uint8_t get_idx_by_epaddr(uint8_t daddr, uint8_t ep_addr) {
83 for (uint8_t idx = 0; idx < CFG_TUH_HID; idx++) {
84 hidh_interface_t const* p_hid = &_hidh_itf[idx];
85 if (p_hid->daddr == daddr &&
86 (p_hid->ep_in == ep_addr || p_hid->ep_out == ep_addr)) {
87 return idx;
88 }
89 }
91}
92
94 for (uint8_t i = 0; i < CFG_TUH_HID; i++) {
95 if (_hidh_itf[i].daddr == 0) return &_hidh_itf[i];
96 }
97 return NULL;
98}
99
100//--------------------------------------------------------------------+
101// Interface API
102//--------------------------------------------------------------------+
103uint8_t tuh_hid_itf_get_count(uint8_t daddr) {
104 uint8_t count = 0;
105 for (uint8_t i = 0; i < CFG_TUH_HID; i++) {
106 if (_hidh_itf[i].daddr == daddr) count++;
107 }
108 return count;
109}
110
112 uint8_t count = 0;
113 for (uint8_t i = 0; i < CFG_TUH_HID; i++) {
114 if (_hidh_itf[i].daddr != 0) count++;
115 }
116 return count;
117}
118
119bool tuh_hid_mounted(uint8_t daddr, uint8_t idx) {
120 hidh_interface_t* p_hid = get_hid_itf(daddr, idx);
121 TU_VERIFY(p_hid);
122 return p_hid->mounted;
123}
124
125bool tuh_hid_itf_get_info(uint8_t daddr, uint8_t idx, tuh_itf_info_t* info) {
126 hidh_interface_t* p_hid = get_hid_itf(daddr, idx);
127 TU_VERIFY(p_hid && info);
128
129 info->daddr = daddr;
130
131 // re-construct descriptor
133 desc->bLength = sizeof(tusb_desc_interface_t);
134 desc->bDescriptorType = TUSB_DESC_INTERFACE;
135
136 desc->bInterfaceNumber = p_hid->itf_num;
137 desc->bAlternateSetting = 0;
138 desc->bNumEndpoints = (uint8_t) ((p_hid->ep_in ? 1u : 0u) + (p_hid->ep_out ? 1u : 0u));
139 desc->bInterfaceClass = TUSB_CLASS_HID;
140 desc->bInterfaceSubClass = (p_hid->itf_protocol ? HID_SUBCLASS_BOOT : HID_SUBCLASS_NONE);
141 desc->bInterfaceProtocol = p_hid->itf_protocol;
142 desc->iInterface = 0; // not used yet
143
144 return true;
145}
146
147uint8_t tuh_hid_itf_get_index(uint8_t daddr, uint8_t itf_num) {
148 for (uint8_t idx = 0; idx < CFG_TUH_HID; idx++) {
149 hidh_interface_t const* p_hid = &_hidh_itf[idx];
150 if (p_hid->daddr == daddr && p_hid->itf_num == itf_num) return idx;
151 }
152
154}
155
156uint8_t tuh_hid_interface_protocol(uint8_t daddr, uint8_t idx) {
157 hidh_interface_t* p_hid = get_hid_itf(daddr, idx);
158 return p_hid ? p_hid->itf_protocol : 0;
159}
160
161//--------------------------------------------------------------------+
162// Control Endpoint API
163//--------------------------------------------------------------------+
164uint8_t tuh_hid_get_protocol(uint8_t daddr, uint8_t idx) {
165 hidh_interface_t* p_hid = get_hid_itf(daddr, idx);
166 return p_hid ? p_hid->protocol_mode : 0;
167}
168
170 uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
171 uint8_t const daddr = xfer->daddr;
172 uint8_t const idx = tuh_hid_itf_get_index(daddr, itf_num);
173
174 hidh_interface_t* p_hid = get_hid_itf(daddr, idx);
175 TU_VERIFY(p_hid,);
176
177 if (XFER_RESULT_SUCCESS == xfer->result) {
178 p_hid->protocol_mode = (uint8_t) tu_le16toh(xfer->setup->wValue);
179 }
180
183 }
184}
185
186void tuh_hid_set_default_protocol(uint8_t protocol) {
187 _hidh_default_protocol = protocol;
188}
189
190static bool _hidh_set_protocol(uint8_t daddr, uint8_t itf_num, uint8_t protocol,
192 TU_LOG_DRV("HID Set Protocol = %d\r\n", protocol);
193
196 .recipient = TUSB_REQ_RCPT_INTERFACE,
197 .type = TUSB_REQ_TYPE_CLASS,
198 .direction = TUSB_DIR_OUT
199 },
201 .wValue = protocol,
202 .wIndex = itf_num,
203 .wLength = 0
204 };
205
206 tuh_xfer_t xfer = {
207 .daddr = daddr,
208 .ep_addr = 0,
209 .setup = &request,
210 .buffer = NULL,
211 .complete_cb = complete_cb,
212 .user_data = user_data
213 };
214
215 return tuh_control_xfer(&xfer);
216}
217
218bool tuh_hid_set_protocol(uint8_t daddr, uint8_t idx, uint8_t protocol) {
219 hidh_interface_t* p_hid = get_hid_itf(daddr, idx);
220 TU_VERIFY(p_hid && p_hid->itf_protocol != HID_ITF_PROTOCOL_NONE);
221
222 return _hidh_set_protocol(daddr, p_hid->itf_num, protocol, set_protocol_complete, 0);
223}
224
226 TU_LOG_DRV("HID Get Report complete\r\n");
227
229 uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
230 uint8_t const idx = tuh_hid_itf_get_index(xfer->daddr, itf_num);
231
232 uint8_t const report_type = tu_u16_high(xfer->setup->wValue);
233 uint8_t const report_id = tu_u16_low(xfer->setup->wValue);
234
235 tuh_hid_get_report_complete_cb(xfer->daddr, idx, report_id, report_type,
236 (xfer->result == XFER_RESULT_SUCCESS) ? xfer->setup->wLength : 0);
237 }
238}
239
240bool tuh_hid_get_report(uint8_t daddr, uint8_t idx, uint8_t report_id, uint8_t report_type, void* report, uint16_t len) {
241 hidh_interface_t* p_hid = get_hid_itf(daddr, idx);
242 TU_VERIFY(p_hid);
243 TU_LOG_DRV("HID Get Report: id = %u, type = %u, len = %u\r\n", report_id, report_type, len);
244
247 .recipient = TUSB_REQ_RCPT_INTERFACE,
248 .type = TUSB_REQ_TYPE_CLASS,
249 .direction = TUSB_DIR_IN
250 },
251 .bRequest = HID_REQ_CONTROL_GET_REPORT,
252 .wValue = tu_htole16(tu_u16(report_type, report_id)),
253 .wIndex = tu_htole16((uint16_t) p_hid->itf_num),
254 .wLength = len
255 };
256
257 tuh_xfer_t xfer = {
258 .daddr = daddr,
259 .ep_addr = 0,
260 .setup = &request,
261 .buffer = report,
262 .complete_cb = get_report_complete,
263 .user_data = 0
264 };
265
266 return tuh_control_xfer(&xfer);
267}
268
270 TU_LOG_DRV("HID Set Report complete\r\n");
271
273 uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
274 uint8_t const idx = tuh_hid_itf_get_index(xfer->daddr, itf_num);
275
276 uint8_t const report_type = tu_u16_high(xfer->setup->wValue);
277 uint8_t const report_id = tu_u16_low(xfer->setup->wValue);
278
279 tuh_hid_set_report_complete_cb(xfer->daddr, idx, report_id, report_type,
280 (xfer->result == XFER_RESULT_SUCCESS) ? xfer->setup->wLength : 0);
281 }
282}
283
284bool tuh_hid_set_report(uint8_t daddr, uint8_t idx, uint8_t report_id, uint8_t report_type, void* report, uint16_t len) {
285 hidh_interface_t* p_hid = get_hid_itf(daddr, idx);
286 TU_VERIFY(p_hid);
287 TU_LOG_DRV("HID Set Report: id = %u, type = %u, len = %u\r\n", report_id, report_type, len);
288
291 .recipient = TUSB_REQ_RCPT_INTERFACE,
292 .type = TUSB_REQ_TYPE_CLASS,
293 .direction = TUSB_DIR_OUT
294 },
295 .bRequest = HID_REQ_CONTROL_SET_REPORT,
296 .wValue = tu_htole16(tu_u16(report_type, report_id)),
297 .wIndex = tu_htole16((uint16_t) p_hid->itf_num),
298 .wLength = len
299 };
300
301 tuh_xfer_t xfer = {
302 .daddr = daddr,
303 .ep_addr = 0,
304 .setup = &request,
305 .buffer = report,
306 .complete_cb = set_report_complete,
307 .user_data = 0
308 };
309
310 return tuh_control_xfer(&xfer);
311}
312
313static bool _hidh_set_idle(uint8_t daddr, uint8_t itf_num, uint16_t idle_rate,
315 // SET IDLE request, device can stall if not support this request
316 TU_LOG_DRV("HID Set Idle \r\n");
317
320 .recipient = TUSB_REQ_RCPT_INTERFACE,
321 .type = TUSB_REQ_TYPE_CLASS,
322 .direction = TUSB_DIR_OUT
323 },
324 .bRequest = HID_REQ_CONTROL_SET_IDLE,
325 .wValue = tu_htole16(idle_rate),
326 .wIndex = tu_htole16((uint16_t) itf_num),
327 .wLength = 0
328 };
329
330 tuh_xfer_t xfer = {
331 .daddr = daddr,
332 .ep_addr = 0,
333 .setup = &request,
334 .buffer = NULL,
335 .complete_cb = complete_cb,
336 .user_data = user_data
337 };
338
339 return tuh_control_xfer(&xfer);
340}
341
342//--------------------------------------------------------------------+
343// Interrupt Endpoint API
344//--------------------------------------------------------------------+
345
346// Check if HID interface is ready to receive report
347bool tuh_hid_receive_ready(uint8_t dev_addr, uint8_t idx) {
349 TU_VERIFY(p_hid);
350 return !usbh_edpt_busy(dev_addr, p_hid->ep_in);
351}
352
353bool tuh_hid_receive_report(uint8_t daddr, uint8_t idx) {
354 hidh_interface_t* p_hid = get_hid_itf(daddr, idx);
355 TU_VERIFY(p_hid);
356
357 // claim endpoint
358 TU_VERIFY(usbh_edpt_claim(daddr, p_hid->ep_in));
359
360 if (!usbh_edpt_xfer(daddr, p_hid->ep_in, p_hid->epin_buf, p_hid->epin_size)) {
362 return false;
363 }
364
365 return true;
366}
367bool tuh_hid_receive_abort(uint8_t dev_addr, uint8_t idx) {
369 TU_VERIFY(p_hid);
370 return tuh_edpt_abort_xfer(dev_addr, p_hid->ep_in);
371}
372
373bool tuh_hid_send_ready(uint8_t dev_addr, uint8_t idx) {
375 TU_VERIFY(p_hid);
376 return !usbh_edpt_busy(dev_addr, p_hid->ep_out);
377}
378
379bool tuh_hid_send_report(uint8_t daddr, uint8_t idx, uint8_t report_id, const void* report, uint16_t len) {
380 TU_LOG_DRV("HID Send Report %d\r\n", report_id);
381
382 hidh_interface_t* p_hid = get_hid_itf(daddr, idx);
383 TU_VERIFY(p_hid);
384
385 if (p_hid->ep_out == 0) {
386 // This HID does not have an out endpoint (other than control)
387 return false;
388 } else if (len > CFG_TUH_HID_EPOUT_BUFSIZE ||
389 (report_id != 0 && len > (CFG_TUH_HID_EPOUT_BUFSIZE - 1))) {
390 // ep_out buffer is not large enough to hold contents
391 return false;
392 }
393
394 // claim endpoint
395 TU_VERIFY(usbh_edpt_claim(daddr, p_hid->ep_out));
396
397 if (report_id == 0) {
398 // No report ID in transmission
399 memcpy(&p_hid->epout_buf[0], report, len);
400 } else {
401 p_hid->epout_buf[0] = report_id;
402 memcpy(&p_hid->epout_buf[1], report, len);
403 ++len; // 1 more byte for report_id
404 }
405
406 TU_LOG3_MEM(p_hid->epout_buf, len, 2);
407
408 if (!usbh_edpt_xfer(daddr, p_hid->ep_out, p_hid->epout_buf, len)) {
410 return false;
411 }
412
413 return true;
414}
415
416//--------------------------------------------------------------------+
417// USBH API
418//--------------------------------------------------------------------+
419bool hidh_init(void) {
420 TU_LOG_DRV("sizeof(hidh_interface_t) = %u\r\n", sizeof(hidh_interface_t));
421 tu_memclr(_hidh_itf, sizeof(_hidh_itf));
422 return true;
423}
424
425bool hidh_deinit(void) {
426 return true;
427}
428
429bool hidh_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
430 (void) result;
431
432 uint8_t const dir = tu_edpt_dir(ep_addr);
433 uint8_t const idx = get_idx_by_epaddr(daddr, ep_addr);
434
435 hidh_interface_t* p_hid = get_hid_itf(daddr, idx);
436 TU_VERIFY(p_hid);
437
438 if (dir == TUSB_DIR_IN) {
439 TU_LOG_DRV(" Get Report callback (%u, %u)\r\n", daddr, idx);
440 TU_LOG3_MEM(p_hid->epin_buf, xferred_bytes, 2);
441 tuh_hid_report_received_cb(daddr, idx, p_hid->epin_buf, (uint16_t) xferred_bytes);
442 } else {
444 tuh_hid_report_sent_cb(daddr, idx, p_hid->epout_buf, (uint16_t) xferred_bytes);
445 }
446 }
447
448 return true;
449}
450
451void hidh_close(uint8_t daddr) {
452 for (uint8_t i = 0; i < CFG_TUH_HID; i++) {
453 hidh_interface_t* p_hid = &_hidh_itf[i];
454 if (p_hid->daddr == daddr) {
455 TU_LOG_DRV(" HIDh close addr = %u index = %u\r\n", daddr, i);
457 tu_memclr(p_hid, sizeof(hidh_interface_t));
458 }
459 }
460}
461
462//--------------------------------------------------------------------+
463// Enumeration
464//--------------------------------------------------------------------+
465
466bool hidh_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const* desc_itf, uint16_t max_len) {
467 (void) rhport;
468 (void) max_len;
469
470 TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass);
471 TU_LOG_DRV("[%u] HID opening Interface %u\r\n", daddr, desc_itf->bInterfaceNumber);
472
473 // len = interface + hid + n*endpoints
474 uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) +
475 desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t));
476 TU_ASSERT(max_len >= drv_len);
477 uint8_t const* p_desc = (uint8_t const*) desc_itf;
478
479 //------------- HID descriptor -------------//
480 p_desc = tu_desc_next(p_desc);
481 tusb_hid_descriptor_hid_t const* desc_hid = (tusb_hid_descriptor_hid_t const*) p_desc;
482 TU_ASSERT(HID_DESC_TYPE_HID == desc_hid->bDescriptorType);
483
485 TU_ASSERT(p_hid); // not enough interface, try to increase CFG_TUH_HID
486 p_hid->daddr = daddr;
487
488 //------------- Endpoint Descriptors -------------//
489 p_desc = tu_desc_next(p_desc);
490 tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) p_desc;
491
492 for (int i = 0; i < desc_itf->bNumEndpoints; i++) {
493 TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType);
494 TU_ASSERT(tuh_edpt_open(daddr, desc_ep));
495
496 if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) {
497 p_hid->ep_in = desc_ep->bEndpointAddress;
498 p_hid->epin_size = tu_edpt_packet_size(desc_ep);
499 } else {
500 p_hid->ep_out = desc_ep->bEndpointAddress;
501 p_hid->epout_size = tu_edpt_packet_size(desc_ep);
502 }
503
504 p_desc = tu_desc_next(p_desc);
505 desc_ep = (tusb_desc_endpoint_t const*) p_desc;
506 }
507
508 p_hid->itf_num = desc_itf->bInterfaceNumber;
509
510 // Assume bNumDescriptors = 1
511 p_hid->report_desc_type = desc_hid->bReportType;
512 p_hid->report_desc_len = tu_unaligned_read16(&desc_hid->wReportLength);
513
514 // Per HID Specs: default is Report protocol, though we will force Boot protocol when set_config
516 if (HID_SUBCLASS_BOOT == desc_itf->bInterfaceSubClass) {
517 p_hid->itf_protocol = desc_itf->bInterfaceProtocol;
518 }
519
520 return true;
521}
522
523//--------------------------------------------------------------------+
524// Set Configure
525//--------------------------------------------------------------------+
526
527enum {
533
534static void config_driver_mount_complete(uint8_t daddr, uint8_t idx, uint8_t const* desc_report, uint16_t desc_len);
536
537bool hidh_set_config(uint8_t daddr, uint8_t itf_num) {
539 request.wIndex = tu_htole16((uint16_t) itf_num);
540
542 xfer.daddr = daddr;
543 xfer.result = XFER_RESULT_SUCCESS;
544 xfer.setup = &request;
545 xfer.user_data = CONFG_SET_IDLE;
546
547 // fake request to kick-off the set config process
549
550 return true;
551}
552
554 // Stall is a valid response for SET_IDLE, sometime SET_PROTOCOL as well
555 // therefore we could ignore its result
556 if (!(xfer->setup->bRequest == HID_REQ_CONTROL_SET_IDLE ||
557 xfer->setup->bRequest == HID_REQ_CONTROL_SET_PROTOCOL)) {
558 TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS,);
559 }
560
561 uintptr_t const state = xfer->user_data;
562 uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
563 uint8_t const daddr = xfer->daddr;
564
565 uint8_t const idx = tuh_hid_itf_get_index(daddr, itf_num);
566 hidh_interface_t* p_hid = get_hid_itf(daddr, idx);
567 TU_VERIFY(p_hid,);
568
569 switch (state) {
570 case CONFG_SET_IDLE: {
571 // Idle rate = 0 mean only report when there is changes
572 const uint16_t idle_rate = 0;
573 const uintptr_t next_state = (p_hid->itf_protocol != HID_ITF_PROTOCOL_NONE)
575 _hidh_set_idle(daddr, itf_num, idle_rate, process_set_config, next_state);
576 break;
577 }
578
581 break;
582
584 // Get Report Descriptor if possible
585 // using usbh enumeration buffer since report descriptor can be very long
586 if (p_hid->report_desc_len > CFG_TUH_ENUMERATION_BUFSIZE) {
587 TU_LOG_DRV("HID Skip Report Descriptor since it is too large %u bytes\r\n", p_hid->report_desc_len);
588
589 // Driver is mounted without report descriptor
590 config_driver_mount_complete(daddr, idx, NULL, 0);
591 } else {
595 }
596 break;
597
598 case CONFIG_COMPLETE: {
599 uint8_t const* desc_report = usbh_get_enum_buf();
600 uint16_t const desc_len = tu_le16toh(xfer->setup->wLength);
601
602 config_driver_mount_complete(daddr, idx, desc_report, desc_len);
603 break;
604 }
605
606 default:
607 break;
608 }
609}
610
611static void config_driver_mount_complete(uint8_t daddr, uint8_t idx, uint8_t const* desc_report, uint16_t desc_len) {
612 hidh_interface_t* p_hid = get_hid_itf(daddr, idx);
613 TU_VERIFY(p_hid,);
614 p_hid->mounted = true;
615
616 // enumeration is complete
617 if (tuh_hid_mount_cb) tuh_hid_mount_cb(daddr, idx, desc_report, desc_len);
618
619 // notify usbh that driver enumeration is complete
621}
622
623//--------------------------------------------------------------------+
624// Report Descriptor Parser
625//--------------------------------------------------------------------+
626
627uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, uint8_t arr_count,
628 uint8_t const* desc_report, uint16_t desc_len) {
629 // Report Item 6.2.2.2 USB HID 1.11
630 union TU_ATTR_PACKED {
631 uint8_t byte;
632 struct TU_ATTR_PACKED {
633 uint8_t size : 2;
634 uint8_t type : 2;
635 uint8_t tag : 4;
636 };
637 } header;
638
639 tu_memclr(report_info_arr, arr_count * sizeof(tuh_hid_report_info_t));
640
641 uint8_t report_num = 0;
642 tuh_hid_report_info_t* info = report_info_arr;
643
644 // current parsed report count & size from descriptor
645// uint8_t ri_report_count = 0;
646// uint8_t ri_report_size = 0;
647
648 uint8_t ri_collection_depth = 0;
649 while (desc_len && report_num < arr_count) {
650 header.byte = *desc_report++;
651 desc_len--;
652
653 uint8_t const tag = header.tag;
654 uint8_t const type = header.type;
655 uint8_t const size = header.size;
656
657 uint8_t const data8 = desc_report[0];
658
659 TU_LOG(3, "tag = %d, type = %d, size = %d, data = ", tag, type, size);
660 for (uint32_t i = 0; i < size; i++) {
661 TU_LOG(3, "%02X ", desc_report[i]);
662 }
663 TU_LOG(3, "\r\n");
664
665 switch (type) {
666 case RI_TYPE_MAIN:
667 switch (tag) {
668 case RI_MAIN_INPUT: break;
669 case RI_MAIN_OUTPUT: break;
670 case RI_MAIN_FEATURE: break;
672 ri_collection_depth++;
673 break;
674
676 ri_collection_depth--;
677 if (ri_collection_depth == 0) {
678 info++;
679 report_num++;
680 }
681 break;
682
683 default:break;
684 }
685 break;
686
687 case RI_TYPE_GLOBAL:
688 switch (tag) {
690 // only take in account the "usage page" before REPORT ID
691 if (ri_collection_depth == 0) memcpy(&info->usage_page, desc_report, size);
692 break;
693
694 case RI_GLOBAL_LOGICAL_MIN: break;
695 case RI_GLOBAL_LOGICAL_MAX: break;
696 case RI_GLOBAL_PHYSICAL_MIN: break;
697 case RI_GLOBAL_PHYSICAL_MAX: break;
698
700 info->report_id = data8;
701 break;
702
704// ri_report_size = data8;
705 break;
706
708// ri_report_count = data8;
709 break;
710
711 case RI_GLOBAL_UNIT_EXPONENT: break;
712 case RI_GLOBAL_UNIT: break;
713 case RI_GLOBAL_PUSH: break;
714 case RI_GLOBAL_POP: break;
715
716 default: break;
717 }
718 break;
719
720 case RI_TYPE_LOCAL:
721 switch (tag) {
722 case RI_LOCAL_USAGE:
723 // only take in account the "usage" before starting REPORT ID
724 if (ri_collection_depth == 0) info->usage = data8;
725 break;
726
727 case RI_LOCAL_USAGE_MIN: break;
728 case RI_LOCAL_USAGE_MAX: break;
729 case RI_LOCAL_DESIGNATOR_INDEX: break;
730 case RI_LOCAL_DESIGNATOR_MIN: break;
731 case RI_LOCAL_DESIGNATOR_MAX: break;
732 case RI_LOCAL_STRING_INDEX: break;
733 case RI_LOCAL_STRING_MIN: break;
734 case RI_LOCAL_STRING_MAX: break;
735 case RI_LOCAL_DELIMITER: break;
736 default: break;
737 }
738 break;
739
740 // error
741 default: break;
742 }
743
744 desc_report += size;
745 desc_len -= size;
746 }
747
748 for (uint8_t i = 0; i < report_num; i++) {
749 info = report_info_arr + i;
750 TU_LOG_DRV("%u: id = %u, usage_page = %u, usage = %u\r\n", i, info->report_id, info->usage_page, info->usage);
751 }
752
753 return report_num;
754}
755
756#endif
uint8_t header
xfer_td_t xfer[EP_CBI_COUNT+1][2]
Definition: dcd_nrf5x.c:119
uint8_t dev_addr
Definition: dcd_pic32mz.c:81
static usb_descriptor_buffers_t desc
Definition: dcd_pio_usb.c:46
@ HID_REQ_CONTROL_SET_REPORT
Set Report.
Definition: hid.h:98
@ HID_REQ_CONTROL_GET_REPORT
Get Report.
Definition: hid.h:95
@ HID_REQ_CONTROL_SET_PROTOCOL
Set Protocol.
Definition: hid.h:100
@ HID_REQ_CONTROL_SET_IDLE
Set Idle.
Definition: hid.h:99
@ HID_SUBCLASS_BOOT
Boot Interface Subclass.
Definition: hid.h:64
@ HID_SUBCLASS_NONE
No Subclass.
Definition: hid.h:63
@ HID_ITF_PROTOCOL_NONE
None.
Definition: hid.h:70
@ HID_DESC_TYPE_HID
HID Descriptor.
Definition: hid.h:78
@ HID_PROTOCOL_BOOT
Definition: hid.h:147
@ RI_TYPE_LOCAL
Definition: hid.h:606
@ RI_TYPE_MAIN
Definition: hid.h:604
@ RI_TYPE_GLOBAL
Definition: hid.h:605
@ RI_LOCAL_STRING_INDEX
Definition: hid.h:726
@ RI_LOCAL_STRING_MAX
Definition: hid.h:728
@ RI_LOCAL_STRING_MIN
Definition: hid.h:727
@ RI_LOCAL_USAGE_MAX
Definition: hid.h:721
@ RI_LOCAL_DELIMITER
Definition: hid.h:729
@ RI_LOCAL_USAGE
Definition: hid.h:719
@ RI_LOCAL_DESIGNATOR_MIN
Definition: hid.h:723
@ RI_LOCAL_DESIGNATOR_MAX
Definition: hid.h:724
@ RI_LOCAL_USAGE_MIN
Definition: hid.h:720
@ RI_LOCAL_DESIGNATOR_INDEX
Definition: hid.h:722
@ RI_MAIN_COLLECTION_END
Definition: hid.h:617
@ RI_MAIN_COLLECTION
Definition: hid.h:615
@ RI_MAIN_OUTPUT
Definition: hid.h:614
@ RI_MAIN_INPUT
Definition: hid.h:613
@ RI_MAIN_FEATURE
Definition: hid.h:616
@ RI_GLOBAL_PUSH
Definition: hid.h:679
@ RI_GLOBAL_UNIT
Definition: hid.h:675
@ RI_GLOBAL_PHYSICAL_MIN
Definition: hid.h:672
@ RI_GLOBAL_USAGE_PAGE
Definition: hid.h:669
@ RI_GLOBAL_LOGICAL_MIN
Definition: hid.h:670
@ RI_GLOBAL_POP
Definition: hid.h:680
@ RI_GLOBAL_PHYSICAL_MAX
Definition: hid.h:673
@ RI_GLOBAL_UNIT_EXPONENT
Definition: hid.h:674
@ RI_GLOBAL_REPORT_ID
Definition: hid.h:677
@ RI_GLOBAL_REPORT_SIZE
Definition: hid.h:676
@ RI_GLOBAL_LOGICAL_MAX
Definition: hid.h:671
@ RI_GLOBAL_REPORT_COUNT
Definition: hid.h:678
uint8_t tuh_hid_itf_get_index(uint8_t daddr, uint8_t itf_num)
Definition: hid_host.c:147
void hidh_close(uint8_t daddr)
Definition: hid_host.c:451
bool tuh_hid_mounted(uint8_t daddr, uint8_t idx)
Definition: hid_host.c:119
static hidh_interface_t * find_new_itf(void)
Definition: hid_host.c:93
bool tuh_hid_send_ready(uint8_t dev_addr, uint8_t idx)
Definition: hid_host.c:373
uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t *report_info_arr, uint8_t arr_count, uint8_t const *desc_report, uint16_t desc_len)
Definition: hid_host.c:627
static TU_ATTR_ALWAYS_INLINE hidh_interface_t * get_hid_itf(uint8_t daddr, uint8_t idx)
Definition: hid_host.c:75
static void config_driver_mount_complete(uint8_t daddr, uint8_t idx, uint8_t const *desc_report, uint16_t desc_len)
Definition: hid_host.c:611
static void process_set_config(tuh_xfer_t *xfer)
Definition: hid_host.c:553
static bool _hidh_set_idle(uint8_t daddr, uint8_t itf_num, uint16_t idle_rate, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: hid_host.c:313
bool tuh_hid_receive_ready(uint8_t dev_addr, uint8_t idx)
Definition: hid_host.c:347
bool tuh_hid_set_protocol(uint8_t daddr, uint8_t idx, uint8_t protocol)
Definition: hid_host.c:218
static void set_protocol_complete(tuh_xfer_t *xfer)
Definition: hid_host.c:169
static uint8_t get_idx_by_epaddr(uint8_t daddr, uint8_t ep_addr)
Definition: hid_host.c:82
bool hidh_init(void)
Definition: hid_host.c:419
static void get_report_complete(tuh_xfer_t *xfer)
Definition: hid_host.c:225
uint8_t tuh_hid_interface_protocol(uint8_t daddr, uint8_t idx)
Definition: hid_host.c:156
bool hidh_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
Definition: hid_host.c:466
bool tuh_hid_receive_abort(uint8_t dev_addr, uint8_t idx)
Definition: hid_host.c:367
static void set_report_complete(tuh_xfer_t *xfer)
Definition: hid_host.c:269
bool hidh_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
Definition: hid_host.c:429
void tuh_hid_set_default_protocol(uint8_t protocol)
Definition: hid_host.c:186
bool hidh_set_config(uint8_t daddr, uint8_t itf_num)
Definition: hid_host.c:537
@ CONFG_SET_IDLE
Definition: hid_host.c:528
@ CONFIG_GET_REPORT_DESC
Definition: hid_host.c:530
@ CONFIG_SET_PROTOCOL
Definition: hid_host.c:529
@ CONFIG_COMPLETE
Definition: hid_host.c:531
tu_static uint8_t _hidh_default_protocol
Definition: hid_host.c:70
bool tuh_hid_itf_get_info(uint8_t daddr, uint8_t idx, tuh_itf_info_t *info)
Definition: hid_host.c:125
uint8_t tuh_hid_itf_get_total_count(void)
Definition: hid_host.c:111
bool tuh_hid_receive_report(uint8_t daddr, uint8_t idx)
Definition: hid_host.c:353
bool hidh_deinit(void)
Definition: hid_host.c:425
static bool _hidh_set_protocol(uint8_t daddr, uint8_t itf_num, uint8_t protocol, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: hid_host.c:190
uint8_t tuh_hid_get_protocol(uint8_t daddr, uint8_t idx)
Definition: hid_host.c:164
bool tuh_hid_get_report(uint8_t daddr, uint8_t idx, uint8_t report_id, uint8_t report_type, void *report, uint16_t len)
Definition: hid_host.c:240
bool tuh_hid_send_report(uint8_t daddr, uint8_t idx, uint8_t report_id, const void *report, uint16_t len)
Definition: hid_host.c:379
bool tuh_hid_set_report(uint8_t daddr, uint8_t idx, uint8_t report_id, uint8_t report_type, void *report, uint16_t len)
Definition: hid_host.c:284
CFG_TUH_MEM_SECTION tu_static hidh_interface_t _hidh_itf[CFG_TUH_HID]
Definition: hid_host.c:68
uint8_t tuh_hid_itf_get_count(uint8_t daddr)
Definition: hid_host.c:103
TU_ATTR_WEAK void tuh_hid_set_report_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, uint16_t len)
TU_ATTR_WEAK void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t idx, uint8_t const *report_desc, uint16_t desc_len)
TU_ATTR_WEAK void tuh_hid_report_sent_cb(uint8_t dev_addr, uint8_t idx, uint8_t const *report, uint16_t len)
TU_ATTR_WEAK void tuh_hid_get_report_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, uint16_t len)
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t idx, uint8_t const *report, uint16_t len)
TU_ATTR_WEAK void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t idx)
TU_ATTR_WEAK void tuh_hid_set_protocol_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t protocol)
static void * memcpy(void *dst, const void *src, size_t n)
Definition: ringbuffer.c:8
AUDIO Channel Cluster Descriptor (4.1)
Definition: audio.h:647
uint32_t tag
Tag sent by the host. The device shall echo the contents of this field back to the host in the dCSWTa...
Definition: msc.h:85
uint8_t type
Request type tusb_request_type_t.
Definition: audio.h:824
struct TU_ATTR_PACKED::@16::TU_ATTR_PACKED bmRequestType_bit
uint8_t * buffer
Definition: video_device.c:111
uint16_t wIndex
Definition: audio.h:943
uint8_t bDescriptorType
Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
Definition: audio.h:657
uint8_t bInterfaceClass
Class code (assigned by the USB-IF).
Definition: tusb_types.h:349
uint8_t bEndpointAddress
Definition: video.h:306
uint8_t bInterfaceSubClass
Subclass code (assigned by the USB-IF). These codes are qualified by the value of the bInterfaceCla...
Definition: tusb_types.h:350
uint8_t bNumEndpoints
Number of endpoints used by this interface (excluding endpoint zero). If this value is zero,...
Definition: tusb_types.h:348
uint8_t bInterfaceProtocol
Protocol code (assigned by the USB). These codes are qualified by the value of the bInterfaceClass ...
Definition: tusb_types.h:351
uint8_t bInterfaceNumber
Number of this interface. Zero-based value identifying the index in the array of concurrent interface...
Definition: tusb_types.h:346
uint8_t ep_in
Definition: hid_host.c:50
uint8_t daddr
Definition: hid_host.c:47
uint8_t itf_protocol
Definition: hid_host.c:54
CFG_TUH_MEM_ALIGN uint8_t epout_buf[CFG_TUH_HID_EPOUT_BUFSIZE]
Definition: hid_host.c:64
uint8_t protocol_mode
Definition: hid_host.c:55
uint16_t epout_size
Definition: hid_host.c:61
uint8_t report_desc_type
Definition: hid_host.c:57
uint16_t epin_size
Definition: hid_host.c:60
CFG_TUH_MEM_ALIGN uint8_t epin_buf[CFG_TUH_HID_EPIN_BUFSIZE]
Definition: hid_host.c:63
uint16_t report_desc_len
Definition: hid_host.c:58
uint8_t itf_num
Definition: hid_host.c:49
uint8_t ep_out
Definition: hid_host.c:51
static TU_ATTR_ALWAYS_INLINE uint8_t tu_u16_low(uint16_t ui16)
Definition: tusb_common.h:146
static TU_ATTR_ALWAYS_INLINE uint8_t tu_u16_high(uint16_t ui16)
Definition: tusb_common.h:145
static TU_ATTR_ALWAYS_INLINE uint16_t tu_unaligned_read16(const void *mem)
Definition: tusb_common.h:219
static TU_ATTR_ALWAYS_INLINE uint16_t tu_u16(uint8_t high, uint8_t low)
Definition: tusb_common.h:133
@ TUSB_DIR_IN
Definition: tusb_types.h:67
@ TUSB_DIR_OUT
Definition: tusb_types.h:66
@ TUSB_CLASS_HID
Definition: tusb_types.h:162
xfer_result_t
Definition: tusb_types.h:236
@ XFER_RESULT_SUCCESS
Definition: tusb_types.h:237
@ TUSB_REQ_RCPT_INTERFACE
Definition: tusb_types.h:152
static TU_ATTR_ALWAYS_INLINE uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const *desc_ep)
Definition: tusb_types.h:515
TU_ATTR_PACKED_END TU_ATTR_BIT_FIELD_ORDER_END static TU_ATTR_ALWAYS_INLINE tusb_dir_t tu_edpt_dir(uint8_t addr)
Definition: tusb_types.h:502
@ TUSB_REQ_TYPE_CLASS
Definition: tusb_types.h:145
struct TU_ATTR_PACKED tusb_desc_interface_t
USB Interface Descriptor.
static TU_ATTR_ALWAYS_INLINE uint8_t const * tu_desc_next(void const *desc)
Definition: tusb_types.h:531
@ TUSB_DESC_ENDPOINT
Definition: tusb_types.h:97
@ TUSB_DESC_INTERFACE
Definition: tusb_types.h:96
@ TUSB_INDEX_INVALID_8
Definition: tusb_types.h:274
void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num)
Definition: usbh.c:1717
CFG_TUH_MEM_ALIGN tusb_control_request_t request
Definition: usbh.c:259
bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr)
Definition: usbh.c:861
uint8_t daddr
Definition: usbh.c:264
uintptr_t user_data
Definition: usbh.c:262
uint8_t * usbh_get_enum_buf(void)
Definition: usbh.c:819
bool tuh_control_xfer(tuh_xfer_t *xfer)
Definition: usbh.c:602
bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr)
Definition: usbh.c:846
tuh_xfer_cb_t complete_cb
Definition: usbh.c:261
bool tuh_edpt_open(uint8_t dev_addr, tusb_desc_endpoint_t const *desc_ep)
Definition: usbh.c:930
bool usbh_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
Definition: usbh.c:935
bool tuh_descriptor_get_hid_report(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, uint8_t index, void *buffer, uint16_t len, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: usbh.c:1064
bool tuh_edpt_abort_xfer(uint8_t daddr, uint8_t ep_addr)
Definition: usbh.c:781
void(* tuh_xfer_cb_t)(tuh_xfer_t *xfer)
Definition: usbh.h:44
static TU_ATTR_ALWAYS_INLINE bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
Definition: usbh_pvt.h:87