blob: f19f1ba810cfad752cb72ae070f6ef4df73ed1e8 [file] [log] [blame]
Austin Schuh41baf202022-01-01 14:33:40 -08001/*
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 (TUSB_OPT_HOST_ENABLED && CFG_TUH_HID)
30
31#include "host/usbh.h"
32#include "host/usbh_classdriver.h"
33
34#include "hid_host.h"
35
36//--------------------------------------------------------------------+
37// MACRO CONSTANT TYPEDEF
38//--------------------------------------------------------------------+
39
40typedef struct
41{
42 uint8_t itf_num;
43 uint8_t ep_in;
44 uint8_t ep_out;
45
46 uint8_t itf_protocol; // None, Keyboard, Mouse
47 uint8_t protocol_mode; // Boot (0) or Report protocol (1)
48
49 uint8_t report_desc_type;
50 uint16_t report_desc_len;
51
52 uint16_t epin_size;
53 uint16_t epout_size;
54
55 uint8_t epin_buf[CFG_TUH_HID_EPIN_BUFSIZE];
56 uint8_t epout_buf[CFG_TUH_HID_EPOUT_BUFSIZE];
57} hidh_interface_t;
58
59typedef struct
60{
61 uint8_t inst_count;
62 hidh_interface_t instances[CFG_TUH_HID];
63} hidh_device_t;
64
65static hidh_device_t _hidh_dev[CFG_TUH_DEVICE_MAX];
66
67//------------- Internal prototypes -------------//
68
69// Get HID device & interface
70TU_ATTR_ALWAYS_INLINE static inline hidh_device_t* get_dev(uint8_t dev_addr);
71TU_ATTR_ALWAYS_INLINE static inline hidh_interface_t* get_instance(uint8_t dev_addr, uint8_t instance);
72static uint8_t get_instance_id_by_itfnum(uint8_t dev_addr, uint8_t itf);
73static uint8_t get_instance_id_by_epaddr(uint8_t dev_addr, uint8_t ep_addr);
74
75//--------------------------------------------------------------------+
76// Interface API
77//--------------------------------------------------------------------+
78
79uint8_t tuh_hid_instance_count(uint8_t dev_addr)
80{
81 return get_dev(dev_addr)->inst_count;
82}
83
84bool tuh_hid_mounted(uint8_t dev_addr, uint8_t instance)
85{
86 hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
87 return (hid_itf->ep_in != 0) || (hid_itf->ep_out != 0);
88}
89
90uint8_t tuh_hid_interface_protocol(uint8_t dev_addr, uint8_t instance)
91{
92 hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
93 return hid_itf->itf_protocol;
94}
95
96//--------------------------------------------------------------------+
97// Control Endpoint API
98//--------------------------------------------------------------------+
99
100uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance)
101{
102 hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
103 return hid_itf->protocol_mode;
104}
105
106static bool set_protocol_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
107{
108 uint8_t const itf_num = (uint8_t) request->wIndex;
109 uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num);
110 hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
111
112 if (XFER_RESULT_SUCCESS == result) hid_itf->protocol_mode = (uint8_t) request->wValue;
113
114 if (tuh_hid_set_protocol_complete_cb)
115 {
116 tuh_hid_set_protocol_complete_cb(dev_addr, instance, hid_itf->protocol_mode);
117 }
118
119 return true;
120}
121
122bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t instance, uint8_t protocol)
123{
124 hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
125 TU_VERIFY(hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE);
126
127 TU_LOG2("HID Set Protocol = %d\r\n", protocol);
128
129 tusb_control_request_t const request =
130 {
131 .bmRequestType_bit =
132 {
133 .recipient = TUSB_REQ_RCPT_INTERFACE,
134 .type = TUSB_REQ_TYPE_CLASS,
135 .direction = TUSB_DIR_OUT
136 },
137 .bRequest = HID_REQ_CONTROL_SET_PROTOCOL,
138 .wValue = protocol,
139 .wIndex = hid_itf->itf_num,
140 .wLength = 0
141 };
142
143 TU_ASSERT( tuh_control_xfer(dev_addr, &request, NULL, set_protocol_complete) );
144 return true;
145}
146
147static bool set_report_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
148{
149 TU_LOG2("HID Set Report complete\r\n");
150
151 if (tuh_hid_set_report_complete_cb)
152 {
153 uint8_t const itf_num = (uint8_t) request->wIndex;
154 uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num);
155
156 uint8_t const report_type = tu_u16_high(request->wValue);
157 uint8_t const report_id = tu_u16_low(request->wValue);
158
159 tuh_hid_set_report_complete_cb(dev_addr, instance, report_id, report_type, (result == XFER_RESULT_SUCCESS) ? request->wLength : 0);
160 }
161
162 return true;
163}
164
165bool tuh_hid_set_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, void* report, uint16_t len)
166{
167 hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
168 TU_LOG2("HID Set Report: id = %u, type = %u, len = %u\r\n", report_id, report_type, len);
169
170 tusb_control_request_t const request =
171 {
172 .bmRequestType_bit =
173 {
174 .recipient = TUSB_REQ_RCPT_INTERFACE,
175 .type = TUSB_REQ_TYPE_CLASS,
176 .direction = TUSB_DIR_OUT
177 },
178 .bRequest = HID_REQ_CONTROL_SET_REPORT,
179 .wValue = tu_u16(report_type, report_id),
180 .wIndex = hid_itf->itf_num,
181 .wLength = len
182 };
183
184 TU_ASSERT( tuh_control_xfer(dev_addr, &request, report, set_report_complete) );
185 return true;
186}
187
188//--------------------------------------------------------------------+
189// Interrupt Endpoint API
190//--------------------------------------------------------------------+
191
192bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t instance)
193{
194 hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
195
196 // claim endpoint
197 TU_VERIFY( usbh_edpt_claim(dev_addr, hid_itf->ep_in) );
198
199 return usbh_edpt_xfer(dev_addr, hid_itf->ep_in, hid_itf->epin_buf, hid_itf->epin_size);
200}
201
202//bool tuh_n_hid_n_ready(uint8_t dev_addr, uint8_t instance)
203//{
204// TU_VERIFY(tuh_n_hid_n_mounted(dev_addr, instance));
205//
206// hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
207// return !usbh_edpt_busy(dev_addr, hid_itf->ep_in);
208//}
209
210//void tuh_hid_send_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t const* report, uint16_t len);
211
212//--------------------------------------------------------------------+
213// USBH API
214//--------------------------------------------------------------------+
215void hidh_init(void)
216{
217 tu_memclr(_hidh_dev, sizeof(_hidh_dev));
218}
219
220bool hidh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
221{
222 (void) result;
223
224 uint8_t const dir = tu_edpt_dir(ep_addr);
225 uint8_t const instance = get_instance_id_by_epaddr(dev_addr, ep_addr);
226 hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
227
228 if ( dir == TUSB_DIR_IN )
229 {
230 TU_LOG2(" Get Report callback (%u, %u)\r\n", dev_addr, instance);
231 TU_LOG3_MEM(hid_itf->epin_buf, xferred_bytes, 2);
232 tuh_hid_report_received_cb(dev_addr, instance, hid_itf->epin_buf, xferred_bytes);
233 }else
234 {
235 if (tuh_hid_report_sent_cb) tuh_hid_report_sent_cb(dev_addr, instance, hid_itf->epout_buf, xferred_bytes);
236 }
237
238 return true;
239}
240
241void hidh_close(uint8_t dev_addr)
242{
243 TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, );
244
245 hidh_device_t* hid_dev = get_dev(dev_addr);
246
247 if (tuh_hid_umount_cb)
248 {
249 for (uint8_t inst = 0; inst < hid_dev->inst_count; inst++ ) tuh_hid_umount_cb(dev_addr, inst);
250 }
251
252 tu_memclr(hid_dev, sizeof(hidh_device_t));
253}
254
255//--------------------------------------------------------------------+
256// Enumeration
257//--------------------------------------------------------------------+
258
259static bool config_set_protocol (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
260static bool config_get_report_desc (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
261static bool config_get_report_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
262
263static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len);
264
265bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
266{
267 (void) max_len;
268
269 TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass);
270
271 TU_LOG2("HID opening Interface %u (addr = %u)\r\n", desc_itf->bInterfaceNumber, dev_addr);
272
273 // len = interface + hid + n*endpoints
274 uint16_t const drv_len = sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t);
275 TU_ASSERT(max_len >= drv_len);
276
277 uint8_t const *p_desc = (uint8_t const *) desc_itf;
278
279 //------------- HID descriptor -------------//
280 p_desc = tu_desc_next(p_desc);
281 tusb_hid_descriptor_hid_t const *desc_hid = (tusb_hid_descriptor_hid_t const *) p_desc;
282 TU_ASSERT(HID_DESC_TYPE_HID == desc_hid->bDescriptorType);
283
284 // not enough interface, try to increase CFG_TUH_HID
285 // TODO multiple devices
286 hidh_device_t* hid_dev = get_dev(dev_addr);
287 TU_ASSERT(hid_dev->inst_count < CFG_TUH_HID, 0);
288
289 //------------- Endpoint Descriptor -------------//
290 p_desc = tu_desc_next(p_desc);
291 tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc;
292 TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType);
293
294 // first endpoint may be OUT, skip to IN endpoint
295 // TODO also open endpoint OUT
296 if(tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_OUT)
297 {
298 p_desc = tu_desc_next(p_desc);
299 desc_ep = (tusb_desc_endpoint_t const *) p_desc;
300 TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType);
301 }
302
303 TU_ASSERT( usbh_edpt_open(rhport, dev_addr, desc_ep) );
304
305 hidh_interface_t* hid_itf = get_instance(dev_addr, hid_dev->inst_count);
306 hid_dev->inst_count++;
307
308 hid_itf->itf_num = desc_itf->bInterfaceNumber;
309 hid_itf->ep_in = desc_ep->bEndpointAddress;
310 hid_itf->epin_size = tu_edpt_packet_size(desc_ep);
311
312 // Assume bNumDescriptors = 1
313 hid_itf->report_desc_type = desc_hid->bReportType;
314 hid_itf->report_desc_len = tu_unaligned_read16(&desc_hid->wReportLength);
315
316 // Per HID Specs: default is Report protocol, though we will force Boot protocol when set_config
317 hid_itf->protocol_mode = HID_PROTOCOL_BOOT;
318 if ( HID_SUBCLASS_BOOT == desc_itf->bInterfaceSubClass ) hid_itf->itf_protocol = desc_itf->bInterfaceProtocol;
319
320 return true;
321}
322
323bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num)
324{
325 uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num);
326 hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
327
328 // Idle rate = 0 mean only report when there is changes
329 uint16_t const idle_rate = 0;
330
331 // SET IDLE request, device can stall if not support this request
332 TU_LOG2("HID Set Idle \r\n");
333 tusb_control_request_t const request =
334 {
335 .bmRequestType_bit =
336 {
337 .recipient = TUSB_REQ_RCPT_INTERFACE,
338 .type = TUSB_REQ_TYPE_CLASS,
339 .direction = TUSB_DIR_OUT
340 },
341 .bRequest = HID_REQ_CONTROL_SET_IDLE,
342 .wValue = idle_rate,
343 .wIndex = itf_num,
344 .wLength = 0
345 };
346
347 TU_ASSERT( tuh_control_xfer(dev_addr, &request, NULL, (hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE) ? config_set_protocol : config_get_report_desc) );
348
349 return true;
350}
351
352// Force device to work in BOOT protocol
353static bool config_set_protocol(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
354{
355 // Stall is a valid response for SET_IDLE, therefore we could ignore its result
356 (void) result;
357
358 uint8_t const itf_num = (uint8_t) request->wIndex;
359 uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num);
360 hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
361
362 TU_LOG2("HID Set Protocol to Boot Mode\r\n");
363 hid_itf->protocol_mode = HID_PROTOCOL_BOOT;
364 tusb_control_request_t const new_request =
365 {
366 .bmRequestType_bit =
367 {
368 .recipient = TUSB_REQ_RCPT_INTERFACE,
369 .type = TUSB_REQ_TYPE_CLASS,
370 .direction = TUSB_DIR_OUT
371 },
372 .bRequest = HID_REQ_CONTROL_SET_PROTOCOL,
373 .wValue = HID_PROTOCOL_BOOT,
374 .wIndex = hid_itf->itf_num,
375 .wLength = 0
376 };
377
378 TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, NULL, config_get_report_desc) );
379 return true;
380}
381
382static bool config_get_report_desc(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
383{
384 // We can be here after SET_IDLE or SET_PROTOCOL (boot device)
385 // Trigger assert if result is not successful with set protocol
386 if ( request->bRequest != HID_REQ_CONTROL_SET_IDLE )
387 {
388 TU_ASSERT(result == XFER_RESULT_SUCCESS);
389 }
390
391 uint8_t const itf_num = (uint8_t) request->wIndex;
392 uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num);
393 hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
394
395 // Get Report Descriptor if possible
396 // using usbh enumeration buffer since report descriptor can be very long
397 if( hid_itf->report_desc_len > CFG_TUH_ENUMERATION_BUFSIZE )
398 {
399 TU_LOG2("HID Skip Report Descriptor since it is too large %u bytes\r\n", hid_itf->report_desc_len);
400
401 // Driver is mounted without report descriptor
402 config_driver_mount_complete(dev_addr, instance, NULL, 0);
403 }else
404 {
405 TU_LOG2("HID Get Report Descriptor\r\n");
406 tusb_control_request_t const new_request =
407 {
408 .bmRequestType_bit =
409 {
410 .recipient = TUSB_REQ_RCPT_INTERFACE,
411 .type = TUSB_REQ_TYPE_STANDARD,
412 .direction = TUSB_DIR_IN
413 },
414 .bRequest = TUSB_REQ_GET_DESCRIPTOR,
415 .wValue = tu_u16(hid_itf->report_desc_type, 0),
416 .wIndex = itf_num,
417 .wLength = hid_itf->report_desc_len
418 };
419
420 TU_ASSERT(tuh_control_xfer(dev_addr, &new_request, usbh_get_enum_buf(), config_get_report_desc_complete));
421 }
422
423 return true;
424}
425
426static bool config_get_report_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
427{
428 TU_ASSERT(XFER_RESULT_SUCCESS == result);
429
430 uint8_t const itf_num = (uint8_t) request->wIndex;
431 uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num);
432
433 uint8_t const* desc_report = usbh_get_enum_buf();
434 uint16_t const desc_len = request->wLength;
435
436 config_driver_mount_complete(dev_addr, instance, desc_report, desc_len);
437
438 return true;
439}
440
441static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len)
442{
443 hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
444
445 // enumeration is complete
446 tuh_hid_mount_cb(dev_addr, instance, desc_report, desc_len);
447
448 // notify usbh that driver enumeration is complete
449 usbh_driver_set_config_complete(dev_addr, hid_itf->itf_num);
450}
451
452//--------------------------------------------------------------------+
453// Report Descriptor Parser
454//--------------------------------------------------------------------+
455
456uint8_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)
457{
458 // Report Item 6.2.2.2 USB HID 1.11
459 union TU_ATTR_PACKED
460 {
461 uint8_t byte;
462 struct TU_ATTR_PACKED
463 {
464 uint8_t size : 2;
465 uint8_t type : 2;
466 uint8_t tag : 4;
467 };
468 } header;
469
470 tu_memclr(report_info_arr, arr_count*sizeof(tuh_hid_report_info_t));
471
472 uint8_t report_num = 0;
473 tuh_hid_report_info_t* info = report_info_arr;
474
475 // current parsed report count & size from descriptor
476// uint8_t ri_report_count = 0;
477// uint8_t ri_report_size = 0;
478
479 uint8_t ri_collection_depth = 0;
480
481 while(desc_len && report_num < arr_count)
482 {
483 header.byte = *desc_report++;
484 desc_len--;
485
486 uint8_t const tag = header.tag;
487 uint8_t const type = header.type;
488 uint8_t const size = header.size;
489
490 uint8_t const data8 = desc_report[0];
491
492 TU_LOG(3, "tag = %d, type = %d, size = %d, data = ", tag, type, size);
493 for(uint32_t i=0; i<size; i++) TU_LOG(3, "%02X ", desc_report[i]);
494 TU_LOG(3, "\r\n");
495
496 switch(type)
497 {
498 case RI_TYPE_MAIN:
499 switch (tag)
500 {
501 case RI_MAIN_INPUT: break;
502 case RI_MAIN_OUTPUT: break;
503 case RI_MAIN_FEATURE: break;
504
505 case RI_MAIN_COLLECTION:
506 ri_collection_depth++;
507 break;
508
509 case RI_MAIN_COLLECTION_END:
510 ri_collection_depth--;
511 if (ri_collection_depth == 0)
512 {
513 info++;
514 report_num++;
515 }
516 break;
517
518 default: break;
519 }
520 break;
521
522 case RI_TYPE_GLOBAL:
523 switch(tag)
524 {
525 case RI_GLOBAL_USAGE_PAGE:
526 // only take in account the "usage page" before REPORT ID
527 if ( ri_collection_depth == 0 ) memcpy(&info->usage_page, desc_report, size);
528 break;
529
530 case RI_GLOBAL_LOGICAL_MIN : break;
531 case RI_GLOBAL_LOGICAL_MAX : break;
532 case RI_GLOBAL_PHYSICAL_MIN : break;
533 case RI_GLOBAL_PHYSICAL_MAX : break;
534
535 case RI_GLOBAL_REPORT_ID:
536 info->report_id = data8;
537 break;
538
539 case RI_GLOBAL_REPORT_SIZE:
540// ri_report_size = data8;
541 break;
542
543 case RI_GLOBAL_REPORT_COUNT:
544// ri_report_count = data8;
545 break;
546
547 case RI_GLOBAL_UNIT_EXPONENT : break;
548 case RI_GLOBAL_UNIT : break;
549 case RI_GLOBAL_PUSH : break;
550 case RI_GLOBAL_POP : break;
551
552 default: break;
553 }
554 break;
555
556 case RI_TYPE_LOCAL:
557 switch(tag)
558 {
559 case RI_LOCAL_USAGE:
560 // only take in account the "usage" before starting REPORT ID
561 if ( ri_collection_depth == 0 ) info->usage = data8;
562 break;
563
564 case RI_LOCAL_USAGE_MIN : break;
565 case RI_LOCAL_USAGE_MAX : break;
566 case RI_LOCAL_DESIGNATOR_INDEX : break;
567 case RI_LOCAL_DESIGNATOR_MIN : break;
568 case RI_LOCAL_DESIGNATOR_MAX : break;
569 case RI_LOCAL_STRING_INDEX : break;
570 case RI_LOCAL_STRING_MIN : break;
571 case RI_LOCAL_STRING_MAX : break;
572 case RI_LOCAL_DELIMITER : break;
573 default: break;
574 }
575 break;
576
577 // error
578 default: break;
579 }
580
581 desc_report += size;
582 desc_len -= size;
583 }
584
585 for ( uint8_t i = 0; i < report_num; i++ )
586 {
587 info = report_info_arr+i;
588 TU_LOG2("%u: id = %u, usage_page = %u, usage = %u\r\n", i, info->report_id, info->usage_page, info->usage);
589 }
590
591 return report_num;
592}
593
594//--------------------------------------------------------------------+
595// Helper
596//--------------------------------------------------------------------+
597
598// Get Device by address
599TU_ATTR_ALWAYS_INLINE static inline hidh_device_t* get_dev(uint8_t dev_addr)
600{
601 return &_hidh_dev[dev_addr-1];
602}
603
604// Get Interface by instance number
605TU_ATTR_ALWAYS_INLINE static inline hidh_interface_t* get_instance(uint8_t dev_addr, uint8_t instance)
606{
607 return &_hidh_dev[dev_addr-1].instances[instance];
608}
609
610// Get instance ID by interface number
611static uint8_t get_instance_id_by_itfnum(uint8_t dev_addr, uint8_t itf)
612{
613 for ( uint8_t inst = 0; inst < CFG_TUH_HID; inst++ )
614 {
615 hidh_interface_t *hid = get_instance(dev_addr, inst);
616
617 if ( (hid->itf_num == itf) && (hid->ep_in || hid->ep_out) ) return inst;
618 }
619
620 return 0xff;
621}
622
623// Get instance ID by endpoint address
624static uint8_t get_instance_id_by_epaddr(uint8_t dev_addr, uint8_t ep_addr)
625{
626 for ( uint8_t inst = 0; inst < CFG_TUH_HID; inst++ )
627 {
628 hidh_interface_t *hid = get_instance(dev_addr, inst);
629
630 if ( (ep_addr == hid->ep_in) || ( ep_addr == hid->ep_out) ) return inst;
631 }
632
633 return 0xff;
634}
635
636#endif