M480 BSP V3.05.006
The Board Support Package for M480 Series
hid_core.c
Go to the documentation of this file.
1/**************************************************************************/
10#include <stdio.h>
11#include <string.h>
12#include <stdlib.h>
13
14#include "NuMicro.h"
15
16#include "usb.h"
17#include "usbh_lib.h"
18#include "usbh_hid.h"
19
20
22
23HID_MOUSE_FUNC *_mouse_callback = NULL;
24HID_KEYBOARD_FUNC *_keyboard_callback = NULL;
25
26#include "hid_parser.c"
27
28#define USB_CTRL_TIMEOUT_MS 100
29
30
31static int get_free_utr_slot(HID_DEV_T *hdev)
32{
33 int i;
34
35 for (i = 0; i < CONFIG_HID_DEV_MAX_PIPE; i++)
36 {
37 if (hdev->utr_list[i] == NULL)
38 return i;
39 }
40 return -1;
41}
42
43
45
46
56int32_t usbh_hid_get_report_descriptor(HID_DEV_T *hdev, uint8_t *desc_buf, int buf_max_len)
57{
58 IFACE_T *iface;
59 uint32_t xfer_len;
60 int ret;
61
62 if (buf_max_len < 9)
64
65 if (!hdev || !hdev->iface)
66 return USBH_ERR_NOT_FOUND;
67
68 iface = (IFACE_T *)hdev->iface;
69
70 ret = usbh_ctrl_xfer(iface->udev,
71 REQ_TYPE_IN | REQ_TYPE_STD_DEV | REQ_TYPE_TO_IFACE, /* bmRequestType */
72 USB_REQ_GET_DESCRIPTOR, /* bRequest */
73 (USB_DT_REPORT << 8) + 0, /* wValue */
74 iface->if_num, /* wIndex */
75 buf_max_len, /* wLength */
76 desc_buf, &xfer_len, USB_CTRL_TIMEOUT_MS);
77
78 if ((ret < 0) || (xfer_len == 0))
79 {
80 HID_DBGMSG("failed to get HID descriptor.\n");
81 return HID_RET_IO_ERR;
82 }
83 return (int)xfer_len;
84}
85
86
102int32_t usbh_hid_get_report(HID_DEV_T *hdev, int rtp_typ, int rtp_id,
103 uint8_t *data, int len)
104{
105 IFACE_T *iface;
106 uint32_t xfer_len;
107 int ret;
108
109 if (!hdev || !hdev->iface)
110 return USBH_ERR_NOT_FOUND;
111
112 iface = (IFACE_T *)hdev->iface;
113
114 ret = usbh_ctrl_xfer(iface->udev,
115 REQ_TYPE_IN | REQ_TYPE_CLASS_DEV | REQ_TYPE_TO_IFACE, /* bmRequestType */
116 HID_REPORT_GET, /* bRequest */
117 rtp_id + (rtp_typ << 8), /* wValue */
118 iface->if_num, /* wIndex */
119 len, /* wLength */
120 data, &xfer_len, USB_CTRL_TIMEOUT_MS);
121 if (ret < 0)
122 {
123 HID_DBGMSG("failed to get report!\n");
124 return HID_RET_IO_ERR;
125 }
126 return (int)xfer_len;
127}
128
129
147int32_t usbh_hid_set_report(HID_DEV_T *hdev, int rtp_typ, int rtp_id,
148 uint8_t *data, int len)
149{
150 IFACE_T *iface;
151 uint32_t xfer_len;
152 int ret;
153
154 if (!hdev || !hdev->iface)
155 return USBH_ERR_NOT_FOUND;
156
157 iface = (IFACE_T *)hdev->iface;
158
159 ret = usbh_ctrl_xfer(iface->udev,
160 REQ_TYPE_OUT | REQ_TYPE_CLASS_DEV | REQ_TYPE_TO_IFACE, /* bmRequestType */
161 HID_REPORT_SET, /* bRequest */
162 rtp_id + (rtp_typ << 8), /* wValue */
163 iface->if_num, /* wIndex */
164 len, /* wLength */
165 data, &xfer_len, USB_CTRL_TIMEOUT_MS);
166 if (ret < 0)
167 {
168 HID_DBGMSG("failed to set report!\n");
169 return HID_RET_IO_ERR;
170 }
171 return (int)xfer_len;
172}
173
174
176
177static void led_ctrl_irq(UTR_T *utr)
178{
179 // HID_DBGMSG("Set LED control xfer done.\n");
180 utr->bIsTransferDone = 1;
181}
182
183int32_t usbh_hid_set_report_non_blocking(HID_DEV_T *hdev, int rtp_typ, int rtp_id,
184 uint8_t *data, int len)
185{
186 IFACE_T *iface;
187 UTR_T *utr;
188 int status;
189
190 if (!hdev || !hdev->iface)
191 return USBH_ERR_NOT_FOUND;
192
193 iface = (IFACE_T *)hdev->iface;
194
195 utr = hdev->rpd.utr_led;
196 if (utr == NULL)
197 {
198 utr = alloc_utr(iface->udev);
199 if (utr == NULL)
200 return USBH_ERR_MEMORY_OUT;
201 hdev->rpd.utr_led = utr;
202 }
203 else
204 {
205 if (utr->bIsTransferDone == 0)
206 return HID_RET_IO_ERR; /* unlikely! the last LED control trnasfer is not completed */
207 }
208
209 utr->setup.bmRequestType = REQ_TYPE_OUT | REQ_TYPE_CLASS_DEV | REQ_TYPE_TO_IFACE;
210 utr->setup.bRequest = HID_REPORT_SET;
211 utr->setup.wValue = rtp_id + (rtp_typ << 8);
212 utr->setup.wIndex = iface->if_num;
213 utr->setup.wLength = len;
214
215 utr->buff = data;
216 utr->data_len = len;
217 utr->func = led_ctrl_irq;
218 utr->bIsTransferDone = 0;
219
220 status = iface->udev->hc_driver->ctrl_xfer(utr);
221 if (status < 0)
222 {
223 iface->udev->ep0.hw_pipe = NULL;
224 return status;
225 }
226 return 0;
227}
228
230
231
243int32_t usbh_hid_get_idle(HID_DEV_T *hdev, int rtp_id, uint8_t *idle_rate)
244{
245 IFACE_T *iface;
246 uint32_t xfer_len;
247 int ret;
248
249 if (!hdev || !hdev->iface)
250 return USBH_ERR_NOT_FOUND;
251
252 iface = (IFACE_T *)hdev->iface;
253
254 ret = usbh_ctrl_xfer(iface->udev,
255 REQ_TYPE_IN | REQ_TYPE_CLASS_DEV | REQ_TYPE_TO_IFACE, /* bmRequestType */
256 HID_GET_IDLE, /* bRequest */
257 rtp_id, /* wValue */
258 iface->if_num, /* wIndex */
259 1, /* wLength */
260 idle_rate, &xfer_len, USB_CTRL_TIMEOUT_MS);
261
262 if ((ret < 0) || (xfer_len != 1))
263 {
264 HID_DBGMSG("failed to get idle rate! %d\n", ret);
265 return HID_RET_IO_ERR;
266 }
267 return HID_RET_OK;
268}
269
270
283int32_t usbh_hid_set_idle(HID_DEV_T *hdev, int rtp_id, uint8_t idle_rate)
284{
285 IFACE_T *iface;
286 uint32_t xfer_len;
287 uint16_t wValue = idle_rate;
288 int ret;
289
290 if (!hdev || !hdev->iface)
291 return USBH_ERR_NOT_FOUND;
292
293 iface = (IFACE_T *)hdev->iface;
294
295 ret = usbh_ctrl_xfer(iface->udev,
296 REQ_TYPE_OUT | REQ_TYPE_CLASS_DEV | REQ_TYPE_TO_IFACE, /* bmRequestType */
297 HID_SET_IDLE, /* bRequest */
298 rtp_id + (wValue << 8), /* wValue */
299 iface->if_num, /* wIndex */
300 0, /* wLength */
301 NULL, &xfer_len, USB_CTRL_TIMEOUT_MS);
302
303 if (ret < 0)
304 {
305 HID_DBGMSG("failed to set idle rate! %d\n", ret);
306 return HID_RET_IO_ERR;
307 }
308 return HID_RET_OK;
309}
310
311
323int32_t usbh_hid_get_protocol(HID_DEV_T *hdev, uint8_t *protocol)
324{
325 IFACE_T *iface;
326 uint32_t xfer_len;
327 int ret;
328
329 if (!hdev || !hdev->iface)
330 return USBH_ERR_NOT_FOUND;
331
332 iface = (IFACE_T *)hdev->iface;
333
334 ret = usbh_ctrl_xfer(iface->udev,
335 REQ_TYPE_IN | REQ_TYPE_CLASS_DEV | REQ_TYPE_TO_IFACE, /* bmRequestType */
336 HID_GET_PROTOCOL, /* bRequest */
337 0, /* wValue */
338 iface->if_num, /* wIndex */
339 1, /* wLength */
340 protocol, &xfer_len, USB_CTRL_TIMEOUT_MS);
341
342 if ((ret < 0) || (xfer_len != 1))
343 {
344 HID_DBGMSG("failed to get idle rate! %d\n", ret);
345 return HID_RET_IO_ERR;
346 }
347 return HID_RET_OK;
348}
349
350
362int32_t usbh_hid_set_protocol(HID_DEV_T *hdev, uint8_t protocol)
363{
364 IFACE_T *iface;
365 uint32_t xfer_len;
366 int ret;
367
368 if (!hdev || !hdev->iface)
369 return USBH_ERR_NOT_FOUND;
370
371 iface = (IFACE_T *)hdev->iface;
372
373 ret = usbh_ctrl_xfer(iface->udev,
374 REQ_TYPE_OUT | REQ_TYPE_CLASS_DEV | REQ_TYPE_TO_IFACE, /* bmRequestType */
375 HID_SET_PROTOCOL, /* bRequest */
376 protocol, /* wValue */
377 iface->if_num, /* wIndex */
378 0, /* wLength */
379 NULL, &xfer_len, USB_CTRL_TIMEOUT_MS);
380
381 if (ret < 0)
382 {
383 HID_DBGMSG("failed to set idle rate! %d\n", ret);
384 return HID_RET_IO_ERR;
385 }
386 return HID_RET_OK;
387}
388
389
391
392
393/*
394 * HID int-in complete function
395 */
396static void hid_read_irq(UTR_T *utr)
397{
398 HID_DEV_T *hdev;
399 int ret;
400
401 //HID_DBGMSG("hid_read_irq. %d\n", utr->xfer_len);
402
403 hdev = (HID_DEV_T *)utr->context;
404
405 if (utr->status != 0)
406 {
407 HID_DBGMSG("hid_read_irq - has error: 0x%x\n", utr->status);
408 if (hdev->read_func)
409 hdev->read_func(hdev, utr->ep->bEndpointAddress, utr->status, utr->buff, 0);
410 return;
411 }
412
413 if (hdev->bSubClassCode == HID_SUBCLASS_BOOT_DEVICE)
414 {
415 if (hdev->bProtocolCode == HID_PROTOCOL_MOUSE)
416 hid_parse_mouse_reports(hdev, utr->buff, utr->xfer_len);
417
418 if (hdev->bProtocolCode == HID_PROTOCOL_KEYBOARD)
419 hid_parse_keyboard_reports(hdev, utr->buff, utr->xfer_len);
420 }
421
422 if (hdev->read_func && utr->xfer_len)
423 hdev->read_func(hdev, utr->ep->bEndpointAddress, utr->status, utr->buff, utr->xfer_len);
424
425 utr->xfer_len = 0;
426 ret = usbh_int_xfer(utr);
427 if (ret)
428 {
429 HID_DBGMSG("hid_read_irq - failed to submit interrupt-in request (%d)", ret);
430 if (hdev->read_func)
431 hdev->read_func(hdev, utr->ep->bEndpointAddress, ret, utr->buff, 0);
432 usbh_free_mem(utr->buff, utr->data_len);
433 free_utr(utr);
434 }
435}
436
437/*
438 * HID int-out complete function
439 */
440static void hid_write_irq(UTR_T *utr)
441{
442 HID_DEV_T *hdev;
443 int ret;
444
445 //HID_DBGMSG("hid_write_irq. %d\n", urb->actual_length);
446
447 hdev = (HID_DEV_T *)utr->context;
448
449 if (utr->status)
450 {
451 HID_DBGMSG("hid_write_irq - has error: 0x%x\n", utr->status);
452 hdev->write_func(hdev, utr->ep->bEndpointAddress, utr->status, utr->buff, &(utr->data_len));
453 return;
454 }
455
456 if (hdev->write_func)
457 {
458 utr->data_len = utr->ep->wMaxPacketSize;
459 hdev->write_func(hdev, utr->ep->bEndpointAddress, utr->status, utr->buff, &(utr->data_len));
460 }
461
462 utr->xfer_len = 0;
463 ret = usbh_int_xfer(utr);
464 if (ret)
465 {
466 HID_DBGMSG("hid_write_irq - failed to submit interrupt-out request (%d)", ret);
467 hdev->write_func(hdev, utr->ep->bEndpointAddress, ret, utr->buff, &(utr->data_len));
468 free_utr(utr);
469 }
470}
471
472
474
485int32_t usbh_hid_start_int_read(HID_DEV_T *hdev, uint8_t ep_addr, HID_IR_FUNC *func)
486{
487 IFACE_T *iface = (IFACE_T *)hdev->iface;
488 UTR_T *utr;
489 EP_INFO_T *ep;
490 int i, ret;
491
492 if ((!iface) || (!iface->udev))
494
495 if (!func)
497
498 if (ep_addr == 0)
499 ep = usbh_iface_find_ep(iface, 0, EP_ADDR_DIR_IN | EP_ATTR_TT_INT);
500 else
501 ep = usbh_iface_find_ep(iface, ep_addr, 0);
502
503 if (ep == NULL)
505
506 utr = alloc_utr(iface->udev);
507 if (!utr)
508 return USBH_ERR_MEMORY_OUT;
509
510 utr->buff = usbh_alloc_mem(ep->wMaxPacketSize);
511 if (utr->buff == NULL)
512 {
513 free_utr(utr);
514 return USBH_ERR_MEMORY_OUT;
515 }
516
517 hdev->read_func = func;
518 utr->context = hdev;
519 utr->ep = ep;
520 utr->data_len = ep->wMaxPacketSize;
521 utr->xfer_len = 0;
522 utr->func = hid_read_irq;
523
524 ret = usbh_int_xfer(utr);
525 if (ret < 0)
526 {
527 HID_DBGMSG("Error - failed to submit interrupt read request (%d)", ret);
528 usbh_free_mem(utr->buff, utr->data_len);
529 free_utr(utr);
530 return HID_RET_IO_ERR;
531 }
532
533 i = get_free_utr_slot(hdev);
534 if (i < 0)
535 {
536 HID_DBGMSG("Error - No free HID slot!\n");
537 usbh_quit_utr(utr);
538 usbh_free_mem(utr->buff, utr->data_len);
539 free_utr(utr);
540 return USBH_ERR_MEMORY_OUT; /* no free UTR slot. */
541 }
542 else
543 {
544 hdev->utr_list[i] = utr;
545 }
546
547 return HID_RET_OK;
548}
549
559int32_t usbh_hid_stop_int_read(HID_DEV_T *hdev, uint8_t ep_addr)
560{
561 IFACE_T *iface = (IFACE_T *)hdev->iface;
562 UTR_T *utr;
563 int i, ret;
564
565 if ((!iface) || (!iface->udev))
567
568 for (i = 0; i < CONFIG_HID_DEV_MAX_PIPE; i++)
569 {
570 utr = hdev->utr_list[i];
571 if (ep_addr == 0)
572 {
573 /* Find any running UTR whose endpoint direction is IN */
574 if ((utr != NULL) && (utr->ep != NULL) &&
575 ((utr->ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_IN))
576 {
577 break;
578 }
579 }
580 else
581 {
582 /* Find any running UTR whose endpoint address is matched with ep_addr */
583 if ((utr != NULL) && (utr->ep != NULL) && (utr->ep->bEndpointAddress == ep_addr))
584 {
585 break; /* UTR found */
586 }
587 }
588 utr = NULL;
589 }
590
591 if (utr == NULL)
593
594 hdev->utr_list[i] = NULL; /* remove it from HID UTR list */
595
596 ret = usbh_quit_utr(utr); /* force to stop the transfer */
597
598 usbh_free_mem(utr->buff, utr->ep->wMaxPacketSize);
599 free_utr(utr);
600
601 return ret;
602}
603
614int32_t usbh_hid_start_int_write(HID_DEV_T *hdev, uint8_t ep_addr, HID_IW_FUNC *func)
615{
616 IFACE_T *iface = (IFACE_T *)hdev->iface;
617 UTR_T *utr;
618 EP_INFO_T *ep;
619 int i, ret;
620
621 if ((!iface) || (!iface->udev))
623
624 if (!func)
626
627 if (ep_addr == 0)
628 ep = usbh_iface_find_ep(iface, 0, EP_ADDR_DIR_OUT | EP_ATTR_TT_INT);
629 else
630 ep = usbh_iface_find_ep(iface, ep_addr, 0);
631
632 if (ep == NULL)
634
635 utr = alloc_utr(iface->udev);
636 if (!utr)
637 return USBH_ERR_MEMORY_OUT;
638
639 utr->buff = usbh_alloc_mem(ep->wMaxPacketSize);
640 if (utr->buff == NULL)
641 {
642 free_utr(utr);
643 return USBH_ERR_MEMORY_OUT;
644 }
645
646 hdev->write_func = func;
647
648 utr->context = hdev;
649 utr->ep = ep;
650 utr->data_len = ep->wMaxPacketSize;
651 utr->xfer_len = 0;
652 utr->func = hid_write_irq;
653
654 /* first time interrupt write call-back to get first data packet */
655 func(hdev, ep->bEndpointAddress, 0, utr->buff, &(utr->data_len));
656
657 ret = usbh_int_xfer(utr);
658 if (ret < 0)
659 {
660 HID_DBGMSG("Error - failed to submit interrupt read request (%d)", ret);
661 free_utr(utr);
662 return HID_RET_IO_ERR;
663 }
664
665 i = get_free_utr_slot(hdev);
666 if (i < 0)
667 {
668 HID_DBGMSG("Error - No free HID slot!\n");
669 usbh_quit_utr(utr);
670 usbh_free_mem(utr->buff, utr->data_len);
671 free_utr(utr);
672 return USBH_ERR_MEMORY_OUT; /* no free UTR slot. */
673 }
674 else
675 {
676 hdev->utr_list[i] = utr;
677 }
678
679 return HID_RET_OK;
680}
681
691int32_t usbh_hid_stop_int_write(HID_DEV_T *hdev, uint8_t ep_addr)
692{
693 IFACE_T *iface = (IFACE_T *)hdev->iface;
694 UTR_T *utr;
695 int i, ret;
696
697 if ((!iface) || (!iface->udev))
699
700 for (i = 0; i < CONFIG_HID_DEV_MAX_PIPE; i++)
701 {
702 utr = hdev->utr_list[i];
703 if (ep_addr == 0)
704 {
705 /* Find any running UTR whose endpoint direction is OUT */
706 if ((utr != NULL) && (utr->ep != NULL) &&
707 ((utr->ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_OUT))
708 {
709 break;
710 }
711 }
712 else
713 {
714 /* Find any running UTR whose endpoint address is matched with ep_addr */
715 if ((utr != NULL) && (utr->ep != NULL) && (utr->ep->bEndpointAddress == ep_addr))
716 {
717 break; /* UTR found */
718 }
719 }
720 utr = NULL;
721 }
722
723 if (utr == NULL)
725
726 hdev->utr_list[i] = NULL; /* remove it from HID UTR list */
727
728 ret = usbh_quit_utr(utr);
729
730 usbh_free_mem(utr->buff, utr->ep->wMaxPacketSize);
731 free_utr(utr);
732
733 return ret;
734}
735
744{
745 _mouse_callback = func;
746}
747
756{
757 _keyboard_callback = func;
758}
759
760
NuMicro peripheral access layer header file.
#define NULL
NULL pointer.
Definition: M480.h:605
#define USBH_ERR_EP_NOT_FOUND
Definition: usbh_lib.h:40
#define HID_REPORT_GET
Definition: usbh_hid.h:156
#define HID_RET_IO_ERR
Definition: usbh_lib.h:87
#define HID_RET_DEV_NOT_FOUND
Definition: usbh_lib.h:86
#define HID_GET_IDLE
Definition: usbh_hid.h:157
#define HID_RET_INVALID_PARAMETER
Definition: usbh_lib.h:88
#define HID_REPORT_SET
Definition: usbh_hid.h:159
#define HID_RET_OK
Definition: usbh_lib.h:85
#define HID_GET_PROTOCOL
Definition: usbh_hid.h:158
#define HID_SET_PROTOCOL
Definition: usbh_hid.h:161
#define USBH_ERR_NOT_FOUND
Definition: usbh_lib.h:39
#define CONFIG_HID_DEV_MAX_PIPE
Definition: usbh_hid.h:53
#define USBH_ERR_MEMORY_OUT
Definition: usbh_lib.h:32
#define HID_SET_IDLE
Definition: usbh_hid.h:160
void usbh_hid_regitser_mouse_callback(HID_MOUSE_FUNC *func)
Register the mouse event callback function to HID class driver. Any mouse reports will be sent to use...
Definition: hid_core.c:743
void usbh_hid_regitser_keyboard_callback(HID_KEYBOARD_FUNC *func)
Register the keyboard event callback function to HID class driver. Any keyboard reports will be sent ...
Definition: hid_core.c:755
void() HID_KEYBOARD_FUNC(struct usbhid_dev *hdev, KEYBOARD_EVENT_T *kbd)
Definition: usbh_hid.h:320
void() HID_MOUSE_FUNC(struct usbhid_dev *hdev, MOUSE_EVENT_T *mouse)
Definition: usbh_hid.h:319
HIDDEN_SYMBOLS struct usbhid_dev HID_DEV_T
void() HID_IR_FUNC(struct usbhid_dev *hdev, uint16_t ep_addr, int status, uint8_t *rdata, uint32_t data_len)
Definition: usbh_lib.h:123
void() HID_IW_FUNC(struct usbhid_dev *hdev, uint16_t ep_addr, int status, uint8_t *wbuff, uint32_t *data_len)
Definition: usbh_lib.h:124
int32_t usbh_hid_stop_int_write(HID_DEV_T *hdev, uint8_t ep_addr)
stop purge the USB interrupt out transfer.
Definition: hid_core.c:691
int32_t usbh_hid_set_protocol(HID_DEV_T *hdev, uint8_t protocol)
Issue a HID class SET_PROTOCOL request. The SET_PROTOCOL switches between the boot protocol and the r...
Definition: hid_core.c:362
int32_t usbh_hid_stop_int_read(HID_DEV_T *hdev, uint8_t ep_addr)
Stop purge the USB interrupt in transfer.
Definition: hid_core.c:559
int32_t usbh_hid_set_report(HID_DEV_T *hdev, int rtp_typ, int rtp_id, uint8_t *data, int len)
Issue a HID class SET_REPORT request. The Set_Report request allows the host to send a report to the ...
Definition: hid_core.c:147
int32_t usbh_hid_get_report(HID_DEV_T *hdev, int rtp_typ, int rtp_id, uint8_t *data, int len)
Issue a HID class GET_REPORT request.
Definition: hid_core.c:102
HIDDEN_SYMBOLS int32_t usbh_hid_start_int_read(HID_DEV_T *hdev, uint8_t ep_addr, HID_IR_FUNC *func)
Start purge the USB interrupt in transfer.
Definition: hid_core.c:485
int32_t usbh_hid_get_report_descriptor(HID_DEV_T *hdev, uint8_t *desc_buf, int buf_max_len)
Read report descriptor from HID device.
Definition: hid_core.c:56
int32_t usbh_hid_set_idle(HID_DEV_T *hdev, int rtp_id, uint8_t idle_rate)
Issue a HID class SET_IDLE request. The SET_IDLE request silences a particular report on the Interrup...
Definition: hid_core.c:283
int32_t usbh_hid_get_protocol(HID_DEV_T *hdev, uint8_t *protocol)
Issue a HID class GET_PROTOCOL request. The GET_PROTOCOL request reads which protocol is currently ac...
Definition: hid_core.c:323
HIDDEN_SYMBOLS int32_t usbh_hid_get_idle(HID_DEV_T *hdev, int rtp_id, uint8_t *idle_rate)
Issue a HID class GET_IDLE request. The GET_IDLE request reads the current idle rate for a particular...
Definition: hid_core.c:243
int32_t usbh_hid_start_int_write(HID_DEV_T *hdev, uint8_t ep_addr, HID_IW_FUNC *func)
Start purge the USB interrupt out transfer.
Definition: hid_core.c:614
M480 MCU USB Host HID report descriptor parser.
USB Host library header file.
USB Host HID class driver header file.
USB Host library exported header file.