diff options
| author | HiFiPhile <[email protected]> | 2024-05-09 13:45:44 +0200 |
|---|---|---|
| committer | HiFiPhile <[email protected]> | 2024-05-09 13:45:44 +0200 |
| commit | fd1cde9b894e5312e6c6f9da63cfea5aa05d83d2 (patch) | |
| tree | 5f43ffeecb05d80788cbe0bbc43913202a922a2a /src/class/hid | |
| parent | d0bff6fd3ec9fc133032dea84732451d93d202b4 (diff) | |
| parent | 74e57499baac36c4cccf76549259905162031e41 (diff) | |
Merge branch 'master' into pr/2181
Diffstat (limited to 'src/class/hid')
| -rw-r--r-- | src/class/hid/hid.h | 13 | ||||
| -rw-r--r-- | src/class/hid/hid_device.c | 359 | ||||
| -rw-r--r-- | src/class/hid/hid_device.h | 63 | ||||
| -rw-r--r-- | src/class/hid/hid_host.c | 599 | ||||
| -rw-r--r-- | src/class/hid/hid_host.h | 41 |
5 files changed, 566 insertions, 509 deletions
diff --git a/src/class/hid/hid.h b/src/class/hid/hid.h index fbd3eef38..fcaab7a50 100644 --- a/src/class/hid/hid.h +++ b/src/class/hid/hid.h @@ -300,6 +300,19 @@ typedef struct TU_ATTR_PACKED int8_t pan; // using AC Pan } hid_mouse_report_t; + +// Absolute Mouse: same as the Standard (relative) Mouse Report but +// with int16_t instead of int8_t for X and Y coordinates. +typedef struct TU_ATTR_PACKED +{ + uint8_t buttons; /**< buttons mask for currently pressed buttons in the mouse. */ + int16_t x; /**< Current x position of the mouse. */ + int16_t y; /**< Current y position of the mouse. */ + int8_t wheel; /**< Current delta wheel movement on the mouse. */ + int8_t pan; // using AC Pan +} hid_abs_mouse_report_t; + + /// Standard Mouse Buttons Bitmap typedef enum { diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c index 5637ea6b4..ada01582e 100644 --- a/src/class/hid/hid_device.c +++ b/src/class/hid/hid_device.c @@ -39,23 +39,23 @@ //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ -typedef struct -{ +typedef struct { uint8_t itf_num; uint8_t ep_in; - uint8_t ep_out; // optional Out endpoint - uint8_t itf_protocol; // Boot mouse or keyboard + uint8_t ep_out; // optional Out endpoint + uint8_t itf_protocol; // Boot mouse or keyboard - uint8_t protocol_mode; // Boot (0) or Report protocol (1) - uint8_t idle_rate; // up to application to handle idle rate uint16_t report_desc_len; + CFG_TUSB_MEM_ALIGN uint8_t protocol_mode; // Boot (0) or Report protocol (1) + CFG_TUSB_MEM_ALIGN uint8_t idle_rate; // up to application to handle idle rate CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_HID_EP_BUFSIZE]; CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_HID_EP_BUFSIZE]; + CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf[CFG_TUD_HID_EP_BUFSIZE]; // TODO save hid descriptor since host can specifically request this after enumeration // Note: HID descriptor may be not available from application after enumeration - tusb_hid_descriptor_hid_t const * hid_descriptor; + tusb_hid_descriptor_hid_t const *hid_descriptor; } hidd_interface_t; CFG_TUD_MEM_SECTION tu_static hidd_interface_t _hidd_itf[CFG_TUD_HID]; @@ -63,12 +63,12 @@ CFG_TUD_MEM_SECTION tu_static hidd_interface_t _hidd_itf[CFG_TUD_HID]; /*------------- Helpers -------------*/ static inline uint8_t get_index_by_itfnum(uint8_t itf_num) { - for (uint8_t i=0; i < CFG_TUD_HID; i++ ) - { - if ( itf_num == _hidd_itf[i].itf_num ) return i; - } + for (uint8_t i = 0; i < CFG_TUD_HID; i++) { + if (itf_num == _hidd_itf[i].itf_num) + return i; + } - return 0xFF; + return 0xFF; } //--------------------------------------------------------------------+ @@ -81,37 +81,29 @@ bool tud_hid_n_ready(uint8_t instance) return tud_ready() && (ep_in != 0) && !usbd_edpt_busy(rhport, ep_in); } -bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, uint16_t len) +bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const *report, uint16_t len) { uint8_t const rhport = 0; - hidd_interface_t * p_hid = &_hidd_itf[instance]; + hidd_interface_t *p_hid = &_hidd_itf[instance]; // claim endpoint - TU_VERIFY( usbd_edpt_claim(rhport, p_hid->ep_in) ); + TU_VERIFY(usbd_edpt_claim(rhport, p_hid->ep_in)); // prepare data - if (report_id) - { + if (report_id) { p_hid->epin_buf[0] = report_id; - TU_VERIFY(0 == tu_memcpy_s(p_hid->epin_buf+1, CFG_TUD_HID_EP_BUFSIZE-1, report, len)); + TU_VERIFY(0 == tu_memcpy_s(p_hid->epin_buf + 1, CFG_TUD_HID_EP_BUFSIZE - 1, report, len)); len++; - }else - { + } else { TU_VERIFY(0 == tu_memcpy_s(p_hid->epin_buf, CFG_TUD_HID_EP_BUFSIZE, report, len)); } return usbd_edpt_xfer(rhport, p_hid->ep_in, p_hid->epin_buf, len); } -uint8_t tud_hid_n_interface_protocol(uint8_t instance) -{ - return _hidd_itf[instance].itf_protocol; -} +uint8_t tud_hid_n_interface_protocol(uint8_t instance) { return _hidd_itf[instance].itf_protocol; } -uint8_t tud_hid_n_get_protocol(uint8_t instance) -{ - return _hidd_itf[instance].protocol_mode; -} +uint8_t tud_hid_n_get_protocol(uint8_t instance) { return _hidd_itf[instance].protocol_mode; } bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modifier, uint8_t keycode[6]) { @@ -120,44 +112,51 @@ bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modi report.modifier = modifier; report.reserved = 0; - if ( keycode ) - { + if (keycode) { memcpy(report.keycode, keycode, sizeof(report.keycode)); - }else - { + } else { tu_memclr(report.keycode, 6); } return tud_hid_n_report(instance, report_id, &report, sizeof(report)); } -bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, - uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal) +bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal) { - hid_mouse_report_t report = - { + hid_mouse_report_t report = { .buttons = buttons, - .x = x, - .y = y, - .wheel = vertical, - .pan = horizontal + .x = x, + .y = y, + .wheel = vertical, + .pan = horizontal }; return tud_hid_n_report(instance, report_id, &report, sizeof(report)); } -bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, - int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) { - hid_gamepad_report_t report = - { - .x = x, - .y = y, - .z = z, - .rz = rz, - .rx = rx, - .ry = ry, - .hat = hat, +bool tud_hid_n_abs_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal) +{ + hid_abs_mouse_report_t report = { .buttons = buttons, + .x = x, + .y = y, + .wheel = vertical, + .pan = horizontal + }; + return tud_hid_n_report(instance, report_id, &report, sizeof(report)); +} + +bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) +{ + hid_gamepad_report_t report = { + .x = x, + .y = y, + .z = z, + .rz = rz, + .rx = rx, + .ry = ry, + .hat = hat, + .buttons = buttons, }; return tud_hid_n_report(instance, report_id, &report, sizeof(report)); @@ -171,59 +170,59 @@ void hidd_init(void) hidd_reset(0); } +bool hidd_deinit(void) +{ + return true; +} + void hidd_reset(uint8_t rhport) { - (void) rhport; + (void)rhport; tu_memclr(_hidd_itf, sizeof(_hidd_itf)); } -uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t max_len) - { +uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const *desc_itf, uint16_t max_len) +{ TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass, 0); // len = interface + hid + n*endpoints - uint16_t const drv_len = - (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + - desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); + uint16_t const drv_len = (uint16_t)(sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); TU_ASSERT(max_len >= drv_len, 0); // Find available interface - hidd_interface_t * p_hid = NULL; + hidd_interface_t *p_hid = NULL; uint8_t hid_id; - for(hid_id=0; hid_id<CFG_TUD_HID; hid_id++) - { - if ( _hidd_itf[hid_id].ep_in == 0 ) - { + for (hid_id = 0; hid_id < CFG_TUD_HID; hid_id++) { + if (_hidd_itf[hid_id].ep_in == 0) { p_hid = &_hidd_itf[hid_id]; break; } } TU_ASSERT(p_hid, 0); - uint8_t const *p_desc = (uint8_t const *) desc_itf; + uint8_t const *p_desc = (uint8_t const *)desc_itf; //------------- HID descriptor -------------// p_desc = tu_desc_next(p_desc); TU_ASSERT(HID_DESC_TYPE_HID == tu_desc_type(p_desc), 0); - p_hid->hid_descriptor = (tusb_hid_descriptor_hid_t const *) p_desc; + p_hid->hid_descriptor = (tusb_hid_descriptor_hid_t const *)p_desc; //------------- Endpoint Descriptor -------------// p_desc = tu_desc_next(p_desc); TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, desc_itf->bNumEndpoints, TUSB_XFER_INTERRUPT, &p_hid->ep_out, &p_hid->ep_in), 0); - if ( desc_itf->bInterfaceSubClass == HID_SUBCLASS_BOOT ) p_hid->itf_protocol = desc_itf->bInterfaceProtocol; + if (desc_itf->bInterfaceSubClass == HID_SUBCLASS_BOOT) + p_hid->itf_protocol = desc_itf->bInterfaceProtocol; p_hid->protocol_mode = HID_PROTOCOL_REPORT; // Per Specs: default is report mode - p_hid->itf_num = desc_itf->bInterfaceNumber; + p_hid->itf_num = desc_itf->bInterfaceNumber; // Use offsetof to avoid pointer to the odd/misaligned address - p_hid->report_desc_len = tu_unaligned_read16((uint8_t const*) p_hid->hid_descriptor + offsetof(tusb_hid_descriptor_hid_t, wReportLength)); + p_hid->report_desc_len = tu_unaligned_read16((uint8_t const *)p_hid->hid_descriptor + offsetof(tusb_hid_descriptor_hid_t, wReportLength)); // Prepare for output endpoint - if (p_hid->ep_out) - { - if ( !usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf)) ) - { + if (p_hid->ep_out) { + if (!usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf))) { TU_LOG_FAILED(); TU_BREAKPOINT(); } @@ -235,144 +234,120 @@ uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint1 // Invoked when a control transfer occurred on an interface of this class // Driver response accordingly to the request and the transfer stage (setup/data/ack) // return false to stall control endpoint (e.g unsupported request) -bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +bool hidd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE); - uint8_t const hid_itf = get_index_by_itfnum((uint8_t) request->wIndex); + uint8_t const hid_itf = get_index_by_itfnum((uint8_t)request->wIndex); TU_VERIFY(hid_itf < CFG_TUD_HID); - hidd_interface_t* p_hid = &_hidd_itf[hid_itf]; + hidd_interface_t *p_hid = &_hidd_itf[hid_itf]; - if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) - { + if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) { //------------- STD Request -------------// - if ( stage == CONTROL_STAGE_SETUP ) - { - uint8_t const desc_type = tu_u16_high(request->wValue); - //uint8_t const desc_index = tu_u16_low (request->wValue); + if (stage == CONTROL_STAGE_SETUP) { + uint8_t const desc_type = tu_u16_high(request->wValue); + // uint8_t const desc_index = tu_u16_low (request->wValue); - if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_HID) - { + if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_HID) { TU_VERIFY(p_hid->hid_descriptor); - TU_VERIFY(tud_control_xfer(rhport, request, (void*)(uintptr_t) p_hid->hid_descriptor, p_hid->hid_descriptor->bLength)); - } - else if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_REPORT) - { - uint8_t const * desc_report = tud_hid_descriptor_report_cb(hid_itf); - tud_control_xfer(rhport, request, (void*)(uintptr_t) desc_report, p_hid->report_desc_len); - } - else - { + TU_VERIFY(tud_control_xfer(rhport, request, (void *)(uintptr_t)p_hid->hid_descriptor, p_hid->hid_descriptor->bLength)); + } else if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_REPORT) { + uint8_t const *desc_report = tud_hid_descriptor_report_cb(hid_itf); + tud_control_xfer(rhport, request, (void *)(uintptr_t)desc_report, p_hid->report_desc_len); + } else { return false; // stall unsupported request } } - } - else if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS) - { + } else if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS) { //------------- Class Specific Request -------------// - switch( request->bRequest ) - { - case HID_REQ_CONTROL_GET_REPORT: - if ( stage == CONTROL_STAGE_SETUP ) - { - uint8_t const report_type = tu_u16_high(request->wValue); - uint8_t const report_id = tu_u16_low(request->wValue); + switch (request->bRequest) { + case HID_REQ_CONTROL_GET_REPORT: + if (stage == CONTROL_STAGE_SETUP) { + uint8_t const report_type = tu_u16_high(request->wValue); + uint8_t const report_id = tu_u16_low(request->wValue); - uint8_t* report_buf = p_hid->epin_buf; - uint16_t req_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE); + uint8_t *report_buf = p_hid->ctrl_buf; + uint16_t req_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE); - uint16_t xferlen = 0; + uint16_t xferlen = 0; - // If host request a specific Report ID, add ID to as 1 byte of response - if ( (report_id != HID_REPORT_TYPE_INVALID) && (req_len > 1) ) - { - *report_buf++ = report_id; - req_len--; + // If host request a specific Report ID, add ID to as 1 byte of response + if ((report_id != HID_REPORT_TYPE_INVALID) && (req_len > 1)) { + *report_buf++ = report_id; + req_len--; - xferlen++; - } + xferlen++; + } - xferlen += tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, req_len); - TU_ASSERT( xferlen > 0 ); + xferlen += tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t)report_type, report_buf, req_len); + TU_ASSERT(xferlen > 0); - tud_control_xfer(rhport, request, p_hid->epin_buf, xferlen); - } + tud_control_xfer(rhport, request, p_hid->ctrl_buf, xferlen); + } break; - case HID_REQ_CONTROL_SET_REPORT: - if ( stage == CONTROL_STAGE_SETUP ) - { - TU_VERIFY(request->wLength <= sizeof(p_hid->epout_buf)); - tud_control_xfer(rhport, request, p_hid->epout_buf, request->wLength); - } - else if ( stage == CONTROL_STAGE_ACK ) - { - uint8_t const report_type = tu_u16_high(request->wValue); - uint8_t const report_id = tu_u16_low(request->wValue); - - uint8_t const* report_buf = p_hid->epout_buf; - uint16_t report_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE); + case HID_REQ_CONTROL_SET_REPORT: + if (stage == CONTROL_STAGE_SETUP) { + TU_VERIFY(request->wLength <= sizeof(p_hid->ctrl_buf)); + tud_control_xfer(rhport, request, p_hid->ctrl_buf, request->wLength); + } else if (stage == CONTROL_STAGE_ACK) { + uint8_t const report_type = tu_u16_high(request->wValue); + uint8_t const report_id = tu_u16_low(request->wValue); - // If host request a specific Report ID, extract report ID in buffer before invoking callback - if ( (report_id != HID_REPORT_TYPE_INVALID) && (report_len > 1) && (report_id == report_buf[0]) ) - { - report_buf++; - report_len--; - } + uint8_t const *report_buf = p_hid->ctrl_buf; + uint16_t report_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE); - tud_hid_set_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, report_len); + // If host request a specific Report ID, extract report ID in buffer before invoking callback + if ((report_id != HID_REPORT_TYPE_INVALID) && (report_len > 1) && (report_id == report_buf[0])) { + report_buf++; + report_len--; } - break; - case HID_REQ_CONTROL_SET_IDLE: - if ( stage == CONTROL_STAGE_SETUP ) - { - p_hid->idle_rate = tu_u16_high(request->wValue); - if ( tud_hid_set_idle_cb ) - { - // stall request if callback return false - TU_VERIFY( tud_hid_set_idle_cb( hid_itf, p_hid->idle_rate) ); - } + tud_hid_set_report_cb(hid_itf, report_id, (hid_report_type_t)report_type, report_buf, report_len); + } + break; - tud_control_status(rhport, request); + case HID_REQ_CONTROL_SET_IDLE: + if (stage == CONTROL_STAGE_SETUP) { + p_hid->idle_rate = tu_u16_high(request->wValue); + if (tud_hid_set_idle_cb) { + // stall request if callback return false + TU_VERIFY(tud_hid_set_idle_cb(hid_itf, p_hid->idle_rate)); } + + tud_control_status(rhport, request); + } break; - case HID_REQ_CONTROL_GET_IDLE: - if ( stage == CONTROL_STAGE_SETUP ) - { - // TODO idle rate of report - tud_control_xfer(rhport, request, &p_hid->idle_rate, 1); - } + case HID_REQ_CONTROL_GET_IDLE: + if (stage == CONTROL_STAGE_SETUP) { + // TODO idle rate of report + tud_control_xfer(rhport, request, &p_hid->idle_rate, 1); + } break; - case HID_REQ_CONTROL_GET_PROTOCOL: - if ( stage == CONTROL_STAGE_SETUP ) - { - tud_control_xfer(rhport, request, &p_hid->protocol_mode, 1); - } + case HID_REQ_CONTROL_GET_PROTOCOL: + if (stage == CONTROL_STAGE_SETUP) { + tud_control_xfer(rhport, request, &p_hid->protocol_mode, 1); + } break; - case HID_REQ_CONTROL_SET_PROTOCOL: - if ( stage == CONTROL_STAGE_SETUP ) - { - tud_control_status(rhport, request); - } - else if ( stage == CONTROL_STAGE_ACK ) - { - p_hid->protocol_mode = (uint8_t) request->wValue; - if (tud_hid_set_protocol_cb) - { - tud_hid_set_protocol_cb(hid_itf, p_hid->protocol_mode); - } + case HID_REQ_CONTROL_SET_PROTOCOL: + if (stage == CONTROL_STAGE_SETUP) { + tud_control_status(rhport, request); + } else if (stage == CONTROL_STAGE_ACK) { + p_hid->protocol_mode = (uint8_t)request->wValue; + if (tud_hid_set_protocol_cb) { + tud_hid_set_protocol_cb(hid_itf, p_hid->protocol_mode); } + } break; - default: return false; // stall unsupported request + default: + return false; // stall unsupported request } - }else - { + } else { return false; // stall unsupported request } @@ -381,31 +356,43 @@ bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { - (void) result; + (void)result; uint8_t instance = 0; - hidd_interface_t * p_hid = _hidd_itf; + hidd_interface_t *p_hid = _hidd_itf; // Identify which interface to use - for (instance = 0; instance < CFG_TUD_HID; instance++) - { + for (instance = 0; instance < CFG_TUD_HID; instance++) { p_hid = &_hidd_itf[instance]; - if ( (ep_addr == p_hid->ep_out) || (ep_addr == p_hid->ep_in) ) break; + if ((ep_addr == p_hid->ep_out) || (ep_addr == p_hid->ep_in)) + break; } TU_ASSERT(instance < CFG_TUD_HID); + // Check if there was a problem + if (XFER_RESULT_SUCCESS != result) { // Inform application about the issue + if (tud_hid_report_fail_cb) { + tud_hid_report_fail_cb(instance, ep_addr, (uint16_t)xferred_bytes); + } + + // Allow a new transfer to be received if issue happened on an OUT endpoint + if (ep_addr == p_hid->ep_out) { + // Prepare the OUT endpoint to be able to receive a new transfer + TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf))); + } + + return true; + } + // Sent report successfully - if (ep_addr == p_hid->ep_in) - { - if (tud_hid_report_complete_cb) - { - tud_hid_report_complete_cb(instance, p_hid->epin_buf, (uint16_t) xferred_bytes); + if (ep_addr == p_hid->ep_in) { + if (tud_hid_report_complete_cb) { + tud_hid_report_complete_cb(instance, p_hid->epin_buf, (uint16_t)xferred_bytes); } } - // Received report - else if (ep_addr == p_hid->ep_out) - { - tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_INVALID, p_hid->epout_buf, (uint16_t) xferred_bytes); + // Received report successfully + else if (ep_addr == p_hid->ep_out) { + tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_OUTPUT, p_hid->epout_buf, (uint16_t)xferred_bytes); TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf))); } diff --git a/src/class/hid/hid_device.h b/src/class/hid/hid_device.h index 17b24def1..7bdd53636 100644 --- a/src/class/hid/hid_device.h +++ b/src/class/hid/hid_device.h @@ -72,6 +72,16 @@ bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modi // use template layout report as defined by hid_mouse_report_t bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal); +// ABSOLUTE MOUSE: convenient helper to send absolute mouse report if application +// use template layout report as defined by hid_abs_mouse_report_t +bool tud_hid_n_abs_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal); + + +static inline bool tud_hid_abs_mouse_report(uint8_t report_id, uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal) +{ + return tud_hid_n_abs_mouse_report(0, report_id, buttons, x, y, vertical, horizontal); +} + // Gamepad: convenient helper to send gamepad report if application // use template layout report TUD_HID_REPORT_DESC_GAMEPAD bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons); @@ -118,6 +128,8 @@ TU_ATTR_WEAK bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate); // Note: For composite reports, report[0] is report ID TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len); +// Invoked when a transfer wasn't successful +TU_ATTR_WEAK void tud_hid_report_fail_cb(uint8_t instance, uint8_t ep_addr, uint16_t len); //--------------------------------------------------------------------+ // Inline Functions @@ -266,6 +278,55 @@ static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y HID_COLLECTION_END , \ HID_COLLECTION_END \ +// Absolute Mouse Report Descriptor Template +#define TUD_HID_REPORT_DESC_ABSMOUSE(...) \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_MOUSE ) ,\ + HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ + /* Report ID if any */\ + __VA_ARGS__ \ + HID_USAGE ( HID_USAGE_DESKTOP_POINTER ) ,\ + HID_COLLECTION ( HID_COLLECTION_PHYSICAL ) ,\ + HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\ + HID_USAGE_MIN ( 1 ) ,\ + HID_USAGE_MAX ( 5 ) ,\ + HID_LOGICAL_MIN ( 0 ) ,\ + HID_LOGICAL_MAX ( 1 ) ,\ + /* Left, Right, Middle, Backward, Forward buttons */ \ + HID_REPORT_COUNT( 5 ) ,\ + HID_REPORT_SIZE ( 1 ) ,\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ + /* 3 bit padding */ \ + HID_REPORT_COUNT( 1 ) ,\ + HID_REPORT_SIZE ( 3 ) ,\ + HID_INPUT ( HID_CONSTANT ) ,\ + HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ + /* X, Y absolute position [0, 32767] */ \ + HID_USAGE ( HID_USAGE_DESKTOP_X ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_Y ) ,\ + HID_LOGICAL_MIN ( 0x00 ) ,\ + HID_LOGICAL_MAX_N( 0x7FFF, 2 ) ,\ + HID_REPORT_SIZE ( 16 ) ,\ + HID_REPORT_COUNT ( 2 ) ,\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ + /* Vertical wheel scroll [-127, 127] */ \ + HID_USAGE ( HID_USAGE_DESKTOP_WHEEL ) ,\ + HID_LOGICAL_MIN ( 0x81 ) ,\ + HID_LOGICAL_MAX ( 0x7f ) ,\ + HID_REPORT_COUNT( 1 ) ,\ + HID_REPORT_SIZE ( 8 ) ,\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ) ,\ + HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ), \ + /* Horizontal wheel scroll [-127, 127] */ \ + HID_USAGE_N ( HID_USAGE_CONSUMER_AC_PAN, 2 ), \ + HID_LOGICAL_MIN ( 0x81 ), \ + HID_LOGICAL_MAX ( 0x7f ), \ + HID_REPORT_COUNT( 1 ), \ + HID_REPORT_SIZE ( 8 ), \ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ), \ + HID_COLLECTION_END , \ + HID_COLLECTION_END \ + // Consumer Control Report Descriptor Template #define TUD_HID_REPORT_DESC_CONSUMER(...) \ HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ) ,\ @@ -406,11 +467,13 @@ static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y // Internal Class Driver API //--------------------------------------------------------------------+ void hidd_init (void); +bool hidd_deinit (void); void hidd_reset (uint8_t rhport); uint16_t hidd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); bool hidd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); + #ifdef __cplusplus } #endif diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 6abe298e5..115a8a4df 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -29,30 +29,32 @@ #if (CFG_TUH_ENABLED && CFG_TUH_HID) #include "host/usbh.h" -#include "host/usbh_classdriver.h" +#include "host/usbh_pvt.h" #include "hid_host.h" -// Debug level, TUSB_CFG_DEBUG must be at least this level for debug message -#define HIDH_DEBUG 2 -#define TU_LOG_DRV(...) TU_LOG(HIDH_DEBUG, __VA_ARGS__) +// Level where CFG_TUSB_DEBUG must be at least for this driver is logged +#ifndef CFG_TUH_HID_LOG_LEVEL + #define CFG_TUH_HID_LOG_LEVEL CFG_TUH_LOG_LEVEL +#endif + +#define TU_LOG_DRV(...) TU_LOG(CFG_TUH_HID_LOG_LEVEL, __VA_ARGS__) //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ - -typedef struct -{ +typedef struct { uint8_t daddr; uint8_t itf_num; uint8_t ep_in; uint8_t ep_out; + bool mounted; // Enumeration is complete uint8_t itf_protocol; // None, Keyboard, Mouse uint8_t protocol_mode; // Boot (0) or Report protocol (1) - uint8_t report_desc_type; + uint8_t report_desc_type; uint16_t report_desc_len; uint16_t epin_size; @@ -65,81 +67,62 @@ typedef struct CFG_TUH_MEM_SECTION tu_static hidh_interface_t _hidh_itf[CFG_TUH_HID]; +tu_static uint8_t _hidh_default_protocol = HID_PROTOCOL_BOOT; + //--------------------------------------------------------------------+ // Helper //--------------------------------------------------------------------+ - -TU_ATTR_ALWAYS_INLINE static inline -hidh_interface_t* get_hid_itf(uint8_t daddr, uint8_t idx) -{ +TU_ATTR_ALWAYS_INLINE static inline hidh_interface_t* get_hid_itf(uint8_t daddr, uint8_t idx) { TU_ASSERT(daddr > 0 && idx < CFG_TUH_HID, NULL); hidh_interface_t* p_hid = &_hidh_itf[idx]; return (p_hid->daddr == daddr) ? p_hid : NULL; } // Get instance ID by endpoint address -static uint8_t get_idx_by_epaddr(uint8_t daddr, uint8_t ep_addr) -{ - for ( uint8_t idx = 0; idx < CFG_TUH_HID; idx++ ) - { - hidh_interface_t const * p_hid = &_hidh_itf[idx]; - - if ( p_hid->daddr == daddr && - (p_hid->ep_in == ep_addr || p_hid->ep_out == ep_addr) ) - { +static uint8_t get_idx_by_epaddr(uint8_t daddr, uint8_t ep_addr) { + for (uint8_t idx = 0; idx < CFG_TUH_HID; idx++) { + hidh_interface_t const* p_hid = &_hidh_itf[idx]; + if (p_hid->daddr == daddr && + (p_hid->ep_in == ep_addr || p_hid->ep_out == ep_addr)) { return idx; } } - return TUSB_INDEX_INVALID_8; } -static hidh_interface_t* find_new_itf(void) -{ - for(uint8_t i=0; i<CFG_TUH_HID; i++) - { +static hidh_interface_t* find_new_itf(void) { + for (uint8_t i = 0; i < CFG_TUH_HID; i++) { if (_hidh_itf[i].daddr == 0) return &_hidh_itf[i]; } - return NULL; } //--------------------------------------------------------------------+ // Interface API //--------------------------------------------------------------------+ - -uint8_t tuh_hid_itf_get_count(uint8_t daddr) -{ +uint8_t tuh_hid_itf_get_count(uint8_t daddr) { uint8_t count = 0; - - for(uint8_t i=0; i<CFG_TUH_HID; i++) - { + for (uint8_t i = 0; i < CFG_TUH_HID; i++) { if (_hidh_itf[i].daddr == daddr) count++; } - return count; } -uint8_t tuh_hid_itf_get_total_count(void) -{ +uint8_t tuh_hid_itf_get_total_count(void) { uint8_t count = 0; - - for(uint8_t i=0; i<CFG_TUH_HID; i++) - { + for (uint8_t i = 0; i < CFG_TUH_HID; i++) { if (_hidh_itf[i].daddr != 0) count++; } - return count; } -bool tuh_hid_mounted(uint8_t daddr, uint8_t idx) -{ +bool tuh_hid_mounted(uint8_t daddr, uint8_t idx) { hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - return p_hid != NULL; + TU_VERIFY(p_hid); + return p_hid->mounted; } -bool tuh_hid_itf_get_info(uint8_t daddr, uint8_t idx, tuh_itf_info_t* info) -{ +bool tuh_hid_itf_get_info(uint8_t daddr, uint8_t idx, tuh_itf_info_t* info) { hidh_interface_t* p_hid = get_hid_itf(daddr, idx); TU_VERIFY(p_hid && info); @@ -147,34 +130,30 @@ bool tuh_hid_itf_get_info(uint8_t daddr, uint8_t idx, tuh_itf_info_t* info) // re-construct descriptor tusb_desc_interface_t* desc = &info->desc; - desc->bLength = sizeof(tusb_desc_interface_t); - desc->bDescriptorType = TUSB_DESC_INTERFACE; + desc->bLength = sizeof(tusb_desc_interface_t); + desc->bDescriptorType = TUSB_DESC_INTERFACE; - desc->bInterfaceNumber = p_hid->itf_num; - desc->bAlternateSetting = 0; - desc->bNumEndpoints = (uint8_t) ((p_hid->ep_in ? 1u : 0u) + (p_hid->ep_out ? 1u : 0u)); - desc->bInterfaceClass = TUSB_CLASS_HID; + desc->bInterfaceNumber = p_hid->itf_num; + desc->bAlternateSetting = 0; + desc->bNumEndpoints = (uint8_t) ((p_hid->ep_in ? 1u : 0u) + (p_hid->ep_out ? 1u : 0u)); + desc->bInterfaceClass = TUSB_CLASS_HID; desc->bInterfaceSubClass = (p_hid->itf_protocol ? HID_SUBCLASS_BOOT : HID_SUBCLASS_NONE); desc->bInterfaceProtocol = p_hid->itf_protocol; - desc->iInterface = 0; // not used yet + desc->iInterface = 0; // not used yet return true; } -uint8_t tuh_hid_itf_get_index(uint8_t daddr, uint8_t itf_num) -{ - for ( uint8_t idx = 0; idx < CFG_TUH_HID; idx++ ) - { - hidh_interface_t const * p_hid = &_hidh_itf[idx]; - - if ( p_hid->daddr == daddr && p_hid->itf_num == itf_num) return idx; +uint8_t tuh_hid_itf_get_index(uint8_t daddr, uint8_t itf_num) { + for (uint8_t idx = 0; idx < CFG_TUH_HID; idx++) { + hidh_interface_t const* p_hid = &_hidh_itf[idx]; + if (p_hid->daddr == daddr && p_hid->itf_num == itf_num) return idx; } return TUSB_INDEX_INVALID_8; } -uint8_t tuh_hid_interface_protocol(uint8_t daddr, uint8_t idx) -{ +uint8_t tuh_hid_interface_protocol(uint8_t daddr, uint8_t idx) { hidh_interface_t* p_hid = get_hid_itf(daddr, idx); return p_hid ? p_hid->itf_protocol : 0; } @@ -182,150 +161,179 @@ uint8_t tuh_hid_interface_protocol(uint8_t daddr, uint8_t idx) //--------------------------------------------------------------------+ // Control Endpoint API //--------------------------------------------------------------------+ - -uint8_t tuh_hid_get_protocol(uint8_t daddr, uint8_t idx) -{ +uint8_t tuh_hid_get_protocol(uint8_t daddr, uint8_t idx) { hidh_interface_t* p_hid = get_hid_itf(daddr, idx); return p_hid ? p_hid->protocol_mode : 0; } -static void set_protocol_complete(tuh_xfer_t* xfer) -{ +static void set_protocol_complete(tuh_xfer_t* xfer) { uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t const daddr = xfer->daddr; - uint8_t const idx = tuh_hid_itf_get_index(daddr, itf_num); + uint8_t const daddr = xfer->daddr; + uint8_t const idx = tuh_hid_itf_get_index(daddr, itf_num); hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - TU_VERIFY(p_hid, ); + TU_VERIFY(p_hid,); - if (XFER_RESULT_SUCCESS == xfer->result) - { + if (XFER_RESULT_SUCCESS == xfer->result) { p_hid->protocol_mode = (uint8_t) tu_le16toh(xfer->setup->wValue); } - if (tuh_hid_set_protocol_complete_cb) - { + if (tuh_hid_set_protocol_complete_cb) { tuh_hid_set_protocol_complete_cb(daddr, idx, p_hid->protocol_mode); } } -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) -{ +void tuh_hid_set_default_protocol(uint8_t protocol) { + _hidh_default_protocol = protocol; +} + +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) { TU_LOG_DRV("HID Set Protocol = %d\r\n", protocol); - tusb_control_request_t const request = - { - .bmRequestType_bit = - { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_OUT - }, - .bRequest = HID_REQ_CONTROL_SET_PROTOCOL, - .wValue = protocol, - .wIndex = itf_num, - .wLength = 0 + tusb_control_request_t const request = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = HID_REQ_CONTROL_SET_PROTOCOL, + .wValue = protocol, + .wIndex = itf_num, + .wLength = 0 }; - tuh_xfer_t xfer = - { - .daddr = daddr, - .ep_addr = 0, - .setup = &request, - .buffer = NULL, - .complete_cb = complete_cb, - .user_data = user_data + tuh_xfer_t xfer = { + .daddr = daddr, + .ep_addr = 0, + .setup = &request, + .buffer = NULL, + .complete_cb = complete_cb, + .user_data = user_data }; return tuh_control_xfer(&xfer); } -bool tuh_hid_set_protocol(uint8_t daddr, uint8_t idx, uint8_t protocol) -{ +bool tuh_hid_set_protocol(uint8_t daddr, uint8_t idx, uint8_t protocol) { hidh_interface_t* p_hid = get_hid_itf(daddr, idx); TU_VERIFY(p_hid && p_hid->itf_protocol != HID_ITF_PROTOCOL_NONE); return _hidh_set_protocol(daddr, p_hid->itf_num, protocol, set_protocol_complete, 0); } -static void set_report_complete(tuh_xfer_t* xfer) -{ +static void get_report_complete(tuh_xfer_t* xfer) { + TU_LOG_DRV("HID Get Report complete\r\n"); + + if (tuh_hid_get_report_complete_cb) { + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t const idx = tuh_hid_itf_get_index(xfer->daddr, itf_num); + + uint8_t const report_type = tu_u16_high(xfer->setup->wValue); + uint8_t const report_id = tu_u16_low(xfer->setup->wValue); + + tuh_hid_get_report_complete_cb(xfer->daddr, idx, report_id, report_type, + (xfer->result == XFER_RESULT_SUCCESS) ? xfer->setup->wLength : 0); + } +} + +bool tuh_hid_get_report(uint8_t daddr, uint8_t idx, uint8_t report_id, uint8_t report_type, void* report, uint16_t len) { + hidh_interface_t* p_hid = get_hid_itf(daddr, idx); + TU_VERIFY(p_hid); + TU_LOG_DRV("HID Get Report: id = %u, type = %u, len = %u\r\n", report_id, report_type, len); + + tusb_control_request_t const request = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_IN + }, + .bRequest = HID_REQ_CONTROL_GET_REPORT, + .wValue = tu_htole16(tu_u16(report_type, report_id)), + .wIndex = tu_htole16((uint16_t) p_hid->itf_num), + .wLength = len + }; + + tuh_xfer_t xfer = { + .daddr = daddr, + .ep_addr = 0, + .setup = &request, + .buffer = report, + .complete_cb = get_report_complete, + .user_data = 0 + }; + + return tuh_control_xfer(&xfer); +} + +static void set_report_complete(tuh_xfer_t* xfer) { TU_LOG_DRV("HID Set Report complete\r\n"); - if (tuh_hid_set_report_complete_cb) - { + if (tuh_hid_set_report_complete_cb) { uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t const idx = tuh_hid_itf_get_index(xfer->daddr, itf_num); + uint8_t const idx = tuh_hid_itf_get_index(xfer->daddr, itf_num); uint8_t const report_type = tu_u16_high(xfer->setup->wValue); - uint8_t const report_id = tu_u16_low(xfer->setup->wValue); + uint8_t const report_id = tu_u16_low(xfer->setup->wValue); tuh_hid_set_report_complete_cb(xfer->daddr, idx, report_id, report_type, (xfer->result == XFER_RESULT_SUCCESS) ? xfer->setup->wLength : 0); } } -bool tuh_hid_set_report(uint8_t daddr, uint8_t idx, uint8_t report_id, uint8_t report_type, void* report, uint16_t len) -{ +bool tuh_hid_set_report(uint8_t daddr, uint8_t idx, uint8_t report_id, uint8_t report_type, void* report, uint16_t len) { hidh_interface_t* p_hid = get_hid_itf(daddr, idx); TU_VERIFY(p_hid); - TU_LOG_DRV("HID Set Report: id = %u, type = %u, len = %u\r\n", report_id, report_type, len); - tusb_control_request_t const request = - { - .bmRequestType_bit = - { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_OUT - }, - .bRequest = HID_REQ_CONTROL_SET_REPORT, - .wValue = tu_htole16(tu_u16(report_type, report_id)), - .wIndex = tu_htole16((uint16_t)p_hid->itf_num), - .wLength = len + tusb_control_request_t const request = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = HID_REQ_CONTROL_SET_REPORT, + .wValue = tu_htole16(tu_u16(report_type, report_id)), + .wIndex = tu_htole16((uint16_t) p_hid->itf_num), + .wLength = len }; - tuh_xfer_t xfer = - { - .daddr = daddr, - .ep_addr = 0, - .setup = &request, - .buffer = report, - .complete_cb = set_report_complete, - .user_data = 0 + tuh_xfer_t xfer = { + .daddr = daddr, + .ep_addr = 0, + .setup = &request, + .buffer = report, + .complete_cb = set_report_complete, + .user_data = 0 }; return tuh_control_xfer(&xfer); } -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) -{ +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) { // SET IDLE request, device can stall if not support this request TU_LOG_DRV("HID Set Idle \r\n"); - tusb_control_request_t const request = - { - .bmRequestType_bit = - { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_OUT - }, - .bRequest = HID_REQ_CONTROL_SET_IDLE, - .wValue = tu_htole16(idle_rate), - .wIndex = tu_htole16((uint16_t)itf_num), - .wLength = 0 + tusb_control_request_t const request = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = HID_REQ_CONTROL_SET_IDLE, + .wValue = tu_htole16(idle_rate), + .wIndex = tu_htole16((uint16_t) itf_num), + .wLength = 0 }; - tuh_xfer_t xfer = - { - .daddr = daddr, - .ep_addr = 0, - .setup = &request, - .buffer = NULL, - .complete_cb = complete_cb, - .user_data = user_data + tuh_xfer_t xfer = { + .daddr = daddr, + .ep_addr = 0, + .setup = &request, + .buffer = NULL, + .complete_cb = complete_cb, + .user_data = user_data }; return tuh_control_xfer(&xfer); @@ -336,68 +344,60 @@ static bool _hidh_set_idle(uint8_t daddr, uint8_t itf_num, uint16_t idle_rate, t //--------------------------------------------------------------------+ // Check if HID interface is ready to receive report -bool tuh_hid_receive_ready(uint8_t dev_addr, uint8_t idx) -{ +bool tuh_hid_receive_ready(uint8_t dev_addr, uint8_t idx) { hidh_interface_t* p_hid = get_hid_itf(dev_addr, idx); TU_VERIFY(p_hid); - return !usbh_edpt_busy(dev_addr, p_hid->ep_in); } -bool tuh_hid_receive_report(uint8_t daddr, uint8_t idx) -{ +bool tuh_hid_receive_report(uint8_t daddr, uint8_t idx) { hidh_interface_t* p_hid = get_hid_itf(daddr, idx); TU_VERIFY(p_hid); // claim endpoint - TU_VERIFY( usbh_edpt_claim(daddr, p_hid->ep_in) ); + TU_VERIFY(usbh_edpt_claim(daddr, p_hid->ep_in)); - if ( !usbh_edpt_xfer(daddr, p_hid->ep_in, p_hid->epin_buf, p_hid->epin_size) ) - { + if (!usbh_edpt_xfer(daddr, p_hid->ep_in, p_hid->epin_buf, p_hid->epin_size)) { usbh_edpt_release(daddr, p_hid->ep_in); return false; } return true; } - -bool tuh_hid_send_ready(uint8_t dev_addr, uint8_t idx) -{ +bool tuh_hid_receive_abort(uint8_t dev_addr, uint8_t idx) { hidh_interface_t* p_hid = get_hid_itf(dev_addr, idx); TU_VERIFY(p_hid); + return tuh_edpt_abort_xfer(dev_addr, p_hid->ep_in); +} +bool tuh_hid_send_ready(uint8_t dev_addr, uint8_t idx) { + hidh_interface_t* p_hid = get_hid_itf(dev_addr, idx); + TU_VERIFY(p_hid); return !usbh_edpt_busy(dev_addr, p_hid->ep_out); } -bool tuh_hid_send_report(uint8_t daddr, uint8_t idx, uint8_t report_id, const void* report, uint16_t len) -{ +bool tuh_hid_send_report(uint8_t daddr, uint8_t idx, uint8_t report_id, const void* report, uint16_t len) { TU_LOG_DRV("HID Send Report %d\r\n", report_id); hidh_interface_t* p_hid = get_hid_itf(daddr, idx); TU_VERIFY(p_hid); - if (p_hid->ep_out == 0) - { + if (p_hid->ep_out == 0) { // This HID does not have an out endpoint (other than control) return false; - } - else if (len > CFG_TUH_HID_EPOUT_BUFSIZE || - (report_id != 0 && len > (CFG_TUH_HID_EPOUT_BUFSIZE - 1))) - { + } else if (len > CFG_TUH_HID_EPOUT_BUFSIZE || + (report_id != 0 && len > (CFG_TUH_HID_EPOUT_BUFSIZE - 1))) { // ep_out buffer is not large enough to hold contents return false; } // claim endpoint - TU_VERIFY( usbh_edpt_claim(daddr, p_hid->ep_out) ); + TU_VERIFY(usbh_edpt_claim(daddr, p_hid->ep_out)); - if (report_id == 0) - { + if (report_id == 0) { // No report ID in transmission memcpy(&p_hid->epout_buf[0], report, len); - } - else - { + } else { p_hid->epout_buf[0] = report_id; memcpy(&p_hid->epout_buf[1], report, len); ++len; // 1 more byte for report_id @@ -405,8 +405,7 @@ bool tuh_hid_send_report(uint8_t daddr, uint8_t idx, uint8_t report_id, const vo TU_LOG3_MEM(p_hid->epout_buf, len, 2); - if ( !usbh_edpt_xfer(daddr, p_hid->ep_out, p_hid->epout_buf, len) ) - { + if (!usbh_edpt_xfer(daddr, p_hid->ep_out, p_hid->epout_buf, len)) { usbh_edpt_release(daddr, p_hid->ep_out); return false; } @@ -417,13 +416,17 @@ bool tuh_hid_send_report(uint8_t daddr, uint8_t idx, uint8_t report_id, const vo //--------------------------------------------------------------------+ // USBH API //--------------------------------------------------------------------+ -void hidh_init(void) -{ +bool hidh_init(void) { + TU_LOG_DRV("sizeof(hidh_interface_t) = %u\r\n", sizeof(hidh_interface_t)); tu_memclr(_hidh_itf, sizeof(_hidh_itf)); + return true; } -bool hidh_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ +bool hidh_deinit(void) { + return true; +} + +bool hidh_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { (void) result; uint8_t const dir = tu_edpt_dir(ep_addr); @@ -432,29 +435,26 @@ bool hidh_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t hidh_interface_t* p_hid = get_hid_itf(daddr, idx); TU_VERIFY(p_hid); - if ( dir == TUSB_DIR_IN ) - { + if (dir == TUSB_DIR_IN) { TU_LOG_DRV(" Get Report callback (%u, %u)\r\n", daddr, idx); TU_LOG3_MEM(p_hid->epin_buf, xferred_bytes, 2); tuh_hid_report_received_cb(daddr, idx, p_hid->epin_buf, (uint16_t) xferred_bytes); - }else - { - if (tuh_hid_report_sent_cb) tuh_hid_report_sent_cb(daddr, idx, p_hid->epout_buf, (uint16_t) xferred_bytes); + } else { + if (tuh_hid_report_sent_cb) { + tuh_hid_report_sent_cb(daddr, idx, p_hid->epout_buf, (uint16_t) xferred_bytes); + } } return true; } -void hidh_close(uint8_t daddr) -{ - for(uint8_t i=0; i<CFG_TUH_HID; i++) - { +void hidh_close(uint8_t daddr) { + for (uint8_t i = 0; i < CFG_TUH_HID; i++) { hidh_interface_t* p_hid = &_hidh_itf[i]; - if (p_hid->daddr == daddr) - { + if (p_hid->daddr == daddr) { TU_LOG_DRV(" HIDh close addr = %u index = %u\r\n", daddr, i); - if(tuh_hid_umount_cb) tuh_hid_umount_cb(daddr, i); - p_hid->daddr = 0; + if (tuh_hid_umount_cb) tuh_hid_umount_cb(daddr, i); + tu_memclr(p_hid, sizeof(hidh_interface_t)); } } } @@ -463,25 +463,22 @@ void hidh_close(uint8_t daddr) // Enumeration //--------------------------------------------------------------------+ -bool hidh_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) -{ +bool hidh_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const* desc_itf, uint16_t max_len) { (void) rhport; (void) max_len; TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass); - TU_LOG_DRV("[%u] HID opening Interface %u\r\n", daddr, desc_itf->bInterfaceNumber); // len = interface + hid + n*endpoints uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); TU_ASSERT(max_len >= drv_len); - - uint8_t const *p_desc = (uint8_t const *) desc_itf; + uint8_t const* p_desc = (uint8_t const*) desc_itf; //------------- HID descriptor -------------// p_desc = tu_desc_next(p_desc); - tusb_hid_descriptor_hid_t const *desc_hid = (tusb_hid_descriptor_hid_t const *) p_desc; + tusb_hid_descriptor_hid_t const* desc_hid = (tusb_hid_descriptor_hid_t const*) p_desc; TU_ASSERT(HID_DESC_TYPE_HID == desc_hid->bDescriptorType); hidh_interface_t* p_hid = find_new_itf(); @@ -490,38 +487,33 @@ bool hidh_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *desc_ //------------- Endpoint Descriptors -------------// p_desc = tu_desc_next(p_desc); - tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; + tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) p_desc; - for(int i = 0; i < desc_itf->bNumEndpoints; i++) - { + for (int i = 0; i < desc_itf->bNumEndpoints; i++) { TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType); - TU_ASSERT( tuh_edpt_open(daddr, desc_ep) ); + TU_ASSERT(tuh_edpt_open(daddr, desc_ep)); - if(tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) - { - p_hid->ep_in = desc_ep->bEndpointAddress; + if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) { + p_hid->ep_in = desc_ep->bEndpointAddress; p_hid->epin_size = tu_edpt_packet_size(desc_ep); - } - else - { - p_hid->ep_out = desc_ep->bEndpointAddress; + } else { + p_hid->ep_out = desc_ep->bEndpointAddress; p_hid->epout_size = tu_edpt_packet_size(desc_ep); } p_desc = tu_desc_next(p_desc); - desc_ep = (tusb_desc_endpoint_t const *) p_desc; + desc_ep = (tusb_desc_endpoint_t const*) p_desc; } - p_hid->itf_num = desc_itf->bInterfaceNumber; + p_hid->itf_num = desc_itf->bInterfaceNumber; // Assume bNumDescriptors = 1 p_hid->report_desc_type = desc_hid->bReportType; - p_hid->report_desc_len = tu_unaligned_read16(&desc_hid->wReportLength); + p_hid->report_desc_len = tu_unaligned_read16(&desc_hid->wReportLength); // Per HID Specs: default is Report protocol, though we will force Boot protocol when set_config - p_hid->protocol_mode = HID_PROTOCOL_BOOT; - if ( HID_SUBCLASS_BOOT == desc_itf->bInterfaceSubClass ) - { + p_hid->protocol_mode = _hidh_default_protocol; + if (HID_SUBCLASS_BOOT == desc_itf->bInterfaceSubClass) { p_hid->itf_protocol = desc_itf->bInterfaceProtocol; } @@ -542,15 +534,14 @@ enum { static void config_driver_mount_complete(uint8_t daddr, uint8_t idx, uint8_t const* desc_report, uint16_t desc_len); static void process_set_config(tuh_xfer_t* xfer); -bool hidh_set_config(uint8_t daddr, uint8_t itf_num) -{ +bool hidh_set_config(uint8_t daddr, uint8_t itf_num) { tusb_control_request_t request; request.wIndex = tu_htole16((uint16_t) itf_num); tuh_xfer_t xfer; - xfer.daddr = daddr; - xfer.result = XFER_RESULT_SUCCESS; - xfer.setup = &request; + xfer.daddr = daddr; + xfer.result = XFER_RESULT_SUCCESS; + xfer.setup = &request; xfer.user_data = CONFG_SET_IDLE; // fake request to kick-off the set config process @@ -559,71 +550,68 @@ bool hidh_set_config(uint8_t daddr, uint8_t itf_num) return true; } -static void process_set_config(tuh_xfer_t* xfer) -{ +static void process_set_config(tuh_xfer_t* xfer) { // Stall is a valid response for SET_IDLE, sometime SET_PROTOCOL as well // therefore we could ignore its result - if ( !(xfer->setup->bRequest == HID_REQ_CONTROL_SET_IDLE || - xfer->setup->bRequest == HID_REQ_CONTROL_SET_PROTOCOL) ) - { - TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, ); + if (!(xfer->setup->bRequest == HID_REQ_CONTROL_SET_IDLE || + xfer->setup->bRequest == HID_REQ_CONTROL_SET_PROTOCOL)) { + TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS,); } uintptr_t const state = xfer->user_data; uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t const daddr = xfer->daddr; + uint8_t const daddr = xfer->daddr; - uint8_t const idx = tuh_hid_itf_get_index(daddr, itf_num); + uint8_t const idx = tuh_hid_itf_get_index(daddr, itf_num); hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - TU_VERIFY(p_hid, ); + TU_VERIFY(p_hid,); - switch(state) - { - case CONFG_SET_IDLE: - { + switch (state) { + case CONFG_SET_IDLE: { // Idle rate = 0 mean only report when there is changes const uint16_t idle_rate = 0; - const uintptr_t next_state = (p_hid->itf_protocol != HID_ITF_PROTOCOL_NONE) ? CONFIG_SET_PROTOCOL : CONFIG_GET_REPORT_DESC; + const uintptr_t next_state = (p_hid->itf_protocol != HID_ITF_PROTOCOL_NONE) + ? CONFIG_SET_PROTOCOL : CONFIG_GET_REPORT_DESC; _hidh_set_idle(daddr, itf_num, idle_rate, process_set_config, next_state); + break; } - break; case CONFIG_SET_PROTOCOL: - _hidh_set_protocol(daddr, p_hid->itf_num, HID_PROTOCOL_BOOT, process_set_config, CONFIG_GET_REPORT_DESC); - break; + _hidh_set_protocol(daddr, p_hid->itf_num, _hidh_default_protocol, process_set_config, CONFIG_GET_REPORT_DESC); + break; case CONFIG_GET_REPORT_DESC: // Get Report Descriptor if possible // using usbh enumeration buffer since report descriptor can be very long - if( p_hid->report_desc_len > CFG_TUH_ENUMERATION_BUFSIZE ) - { + if (p_hid->report_desc_len > CFG_TUH_ENUMERATION_BUFSIZE) { TU_LOG_DRV("HID Skip Report Descriptor since it is too large %u bytes\r\n", p_hid->report_desc_len); // Driver is mounted without report descriptor config_driver_mount_complete(daddr, idx, NULL, 0); - }else - { - tuh_descriptor_get_hid_report(daddr, itf_num, p_hid->report_desc_type, 0, usbh_get_enum_buf(), p_hid->report_desc_len, process_set_config, CONFIG_COMPLETE); + } else { + tuh_descriptor_get_hid_report(daddr, itf_num, p_hid->report_desc_type, 0, + usbh_get_enum_buf(), p_hid->report_desc_len, + process_set_config, CONFIG_COMPLETE); } break; - case CONFIG_COMPLETE: - { + case CONFIG_COMPLETE: { uint8_t const* desc_report = usbh_get_enum_buf(); - uint16_t const desc_len = tu_le16toh(xfer->setup->wLength); + uint16_t const desc_len = tu_le16toh(xfer->setup->wLength); config_driver_mount_complete(daddr, idx, desc_report, desc_len); + break; } - break; - default: break; + default: + break; } } -static void config_driver_mount_complete(uint8_t daddr, uint8_t idx, uint8_t const* desc_report, uint16_t desc_len) -{ +static void config_driver_mount_complete(uint8_t daddr, uint8_t idx, uint8_t const* desc_report, uint16_t desc_len) { hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - TU_VERIFY(p_hid, ); + TU_VERIFY(p_hid,); + p_hid->mounted = true; // enumeration is complete if (tuh_hid_mount_cb) tuh_hid_mount_cb(daddr, idx, desc_report, desc_len); @@ -636,21 +624,19 @@ static void config_driver_mount_complete(uint8_t daddr, uint8_t idx, uint8_t con // Report Descriptor Parser //--------------------------------------------------------------------+ -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) -{ +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) { // Report Item 6.2.2.2 USB HID 1.11 - union TU_ATTR_PACKED - { + union TU_ATTR_PACKED { uint8_t byte; - struct TU_ATTR_PACKED - { - uint8_t size : 2; - uint8_t type : 2; - uint8_t tag : 4; + struct TU_ATTR_PACKED { + uint8_t size : 2; + uint8_t type : 2; + uint8_t tag : 4; }; } header; - tu_memclr(report_info_arr, arr_count*sizeof(tuh_hid_report_info_t)); + tu_memclr(report_info_arr, arr_count * sizeof(tuh_hid_report_info_t)); uint8_t report_num = 0; tuh_hid_report_info_t* info = report_info_arr; @@ -660,114 +646,105 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, // uint8_t ri_report_size = 0; uint8_t ri_collection_depth = 0; - - while(desc_len && report_num < arr_count) - { + while (desc_len && report_num < arr_count) { header.byte = *desc_report++; desc_len--; - uint8_t const tag = header.tag; + uint8_t const tag = header.tag; uint8_t const type = header.type; uint8_t const size = header.size; uint8_t const data8 = desc_report[0]; TU_LOG(3, "tag = %d, type = %d, size = %d, data = ", tag, type, size); - for(uint32_t i=0; i<size; i++) TU_LOG(3, "%02X ", desc_report[i]); + for (uint32_t i = 0; i < size; i++) TU_LOG(3, "%02X ", desc_report[i]); TU_LOG(3, "\r\n"); - switch(type) - { + switch (type) { case RI_TYPE_MAIN: - switch (tag) - { + switch (tag) { case RI_MAIN_INPUT: break; case RI_MAIN_OUTPUT: break; case RI_MAIN_FEATURE: break; - case RI_MAIN_COLLECTION: ri_collection_depth++; - break; + break; case RI_MAIN_COLLECTION_END: ri_collection_depth--; - if (ri_collection_depth == 0) - { + if (ri_collection_depth == 0) { info++; report_num++; } - break; + break; - default: break; + default:break; } - break; + break; case RI_TYPE_GLOBAL: - switch(tag) - { + switch (tag) { case RI_GLOBAL_USAGE_PAGE: // only take in account the "usage page" before REPORT ID - if ( ri_collection_depth == 0 ) memcpy(&info->usage_page, desc_report, size); - break; + if (ri_collection_depth == 0) memcpy(&info->usage_page, desc_report, size); + break; - case RI_GLOBAL_LOGICAL_MIN : break; - case RI_GLOBAL_LOGICAL_MAX : break; - case RI_GLOBAL_PHYSICAL_MIN : break; - case RI_GLOBAL_PHYSICAL_MAX : break; + case RI_GLOBAL_LOGICAL_MIN: break; + case RI_GLOBAL_LOGICAL_MAX: break; + case RI_GLOBAL_PHYSICAL_MIN: break; + case RI_GLOBAL_PHYSICAL_MAX: break; case RI_GLOBAL_REPORT_ID: info->report_id = data8; - break; + break; case RI_GLOBAL_REPORT_SIZE: // ri_report_size = data8; - break; + break; case RI_GLOBAL_REPORT_COUNT: // ri_report_count = data8; - break; + break; - case RI_GLOBAL_UNIT_EXPONENT : break; - case RI_GLOBAL_UNIT : break; - case RI_GLOBAL_PUSH : break; - case RI_GLOBAL_POP : break; + case RI_GLOBAL_UNIT_EXPONENT: break; + case RI_GLOBAL_UNIT: break; + case RI_GLOBAL_PUSH: break; + case RI_GLOBAL_POP: break; default: break; } - break; + break; case RI_TYPE_LOCAL: - switch(tag) - { + switch (tag) { case RI_LOCAL_USAGE: // only take in account the "usage" before starting REPORT ID - if ( ri_collection_depth == 0 ) info->usage = data8; - break; + if (ri_collection_depth == 0) info->usage = data8; + break; - case RI_LOCAL_USAGE_MIN : break; - case RI_LOCAL_USAGE_MAX : break; - case RI_LOCAL_DESIGNATOR_INDEX : break; - case RI_LOCAL_DESIGNATOR_MIN : break; - case RI_LOCAL_DESIGNATOR_MAX : break; - case RI_LOCAL_STRING_INDEX : break; - case RI_LOCAL_STRING_MIN : break; - case RI_LOCAL_STRING_MAX : break; - case RI_LOCAL_DELIMITER : break; + case RI_LOCAL_USAGE_MIN: break; + case RI_LOCAL_USAGE_MAX: break; + case RI_LOCAL_DESIGNATOR_INDEX: break; + case RI_LOCAL_DESIGNATOR_MIN: break; + case RI_LOCAL_DESIGNATOR_MAX: break; + case RI_LOCAL_STRING_INDEX: break; + case RI_LOCAL_STRING_MIN: break; + case RI_LOCAL_STRING_MAX: break; + case RI_LOCAL_DELIMITER: break; default: break; } - break; + break; - // error + // error default: break; } desc_report += size; - desc_len -= size; + desc_len -= size; } - for ( uint8_t i = 0; i < report_num; i++ ) - { - info = report_info_arr+i; + for (uint8_t i = 0; i < report_num; i++) { + info = report_info_arr + i; TU_LOG_DRV("%u: id = %u, usage_page = %u, usage = %u\r\n", i, info->report_id, info->usage_page, info->usage); } diff --git a/src/class/hid/hid_host.h b/src/class/hid/hid_host.h index 08ad421d2..9681c704b 100644 --- a/src/class/hid/hid_host.h +++ b/src/class/hid/hid_host.h @@ -30,7 +30,7 @@ #include "hid.h" #ifdef __cplusplus - extern "C" { +extern "C" { #endif //--------------------------------------------------------------------+ @@ -47,10 +47,9 @@ #endif -typedef struct -{ - uint8_t report_id; - uint8_t usage; +typedef struct { + uint8_t report_id; + uint8_t usage; uint16_t usage_page; // TODO still use the endpoint size for now @@ -86,7 +85,8 @@ bool tuh_hid_mounted(uint8_t dev_addr, uint8_t idx); // Parse report descriptor into array of report_info struct and return number of reports. // For complicated report, application should write its own parser. -uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) TU_ATTR_UNUSED; +TU_ATTR_UNUSED uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr, uint8_t arr_count, + uint8_t const* desc_report, uint16_t desc_len); //--------------------------------------------------------------------+ // Control Endpoint API @@ -97,13 +97,22 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr, // Application can use set_protocol() to switch back to Report protocol. uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t idx); +// Device by default is enumerated in Boot protocol for simplicity. Application +// can use this to modify the default protocol for next enumeration. +void tuh_hid_set_default_protocol(uint8_t protocol); + // Set protocol to HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) // This function is only supported by Boot interface (tuh_n_hid_interface_protocol() != NONE) bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t idx, uint8_t protocol); +// Get Report using control endpoint +// report_type is either Input, Output or Feature, (value from hid_report_type_t) +bool tuh_hid_get_report(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, void* report, uint16_t len); + // Set Report using control endpoint // report_type is either Input, Output or Feature, (value from hid_report_type_t) -bool tuh_hid_set_report(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, void* report, uint16_t len); +bool tuh_hid_set_report(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, + void* report, uint16_t len); //--------------------------------------------------------------------+ // Interrupt Endpoint API @@ -117,6 +126,9 @@ bool tuh_hid_receive_ready(uint8_t dev_addr, uint8_t idx); // - false if failed to queue the transfer e.g endpoint is busy bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t idx); +// Abort receiving report on Interrupt Endpoint +bool tuh_hid_receive_abort(uint8_t dev_addr, uint8_t idx); + // Check if HID interface is ready to send report bool tuh_hid_send_ready(uint8_t dev_addr, uint8_t idx); @@ -145,6 +157,10 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* re // Invoked when sent report to device successfully via interrupt endpoint TU_ATTR_WEAK void tuh_hid_report_sent_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report, uint16_t len); +// Invoked when Get Report to device via either control endpoint +// len = 0 indicate there is error in the transfer e.g stalled response +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); + // Invoked when Sent Report to device via either control endpoint // len = 0 indicate there is error in the transfer e.g stalled response 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); @@ -155,11 +171,12 @@ TU_ATTR_WEAK void tuh_hid_set_protocol_complete_cb(uint8_t dev_addr, uint8_t idx //--------------------------------------------------------------------+ // Internal Class Driver API //--------------------------------------------------------------------+ -void hidh_init (void); -bool hidh_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len); -bool hidh_set_config (uint8_t dev_addr, uint8_t itf_num); -bool hidh_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); -void hidh_close (uint8_t dev_addr); +bool hidh_init(void); +bool hidh_deinit(void); +bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const* desc_itf, uint16_t max_len); +bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num); +bool hidh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); +void hidh_close(uint8_t dev_addr); #ifdef __cplusplus } |
