diff options
author | Wei-Han Chen <stimim@google.com> | 2018-07-06 15:04:41 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-08-31 11:19:46 -0700 |
commit | 83ee439d07468b4e4a196b81da665c06f3c779a1 (patch) | |
tree | 74dc69b0ce2b8918d109d969b56f818fc4b63cf7 /chip/stm32/usb_hid.c | |
parent | b9841cfcdf7404c868ea9967217cf750820b9491 (diff) | |
download | chrome-ec-83ee439d07468b4e4a196b81da665c06f3c779a1.tar.gz |
stm32: usb_hid: refactor to support `Get_Report` request
`Get_Report` request is required by USB HID standard.
BRANCH=none
BUG=b:70482333
TEST=manual on device
Signed-off-by: Wei-Han Chen <stimim@chromium.org>
Change-Id: I1543f019676259beb161db3195364998987ea529
Reviewed-on: https://chromium-review.googlesource.com/1188171
Commit-Ready: Wei-Han Chen <stimim@chromium.org>
Tested-by: Wei-Han Chen <stimim@chromium.org>
Reviewed-by: Wei-Han Chen <stimim@chromium.org>
Reviewed-by: Nicolas Boichat <drinkcat@chromium.org>
Diffstat (limited to 'chip/stm32/usb_hid.c')
-rw-r--r-- | chip/stm32/usb_hid.c | 73 |
1 files changed, 55 insertions, 18 deletions
diff --git a/chip/stm32/usb_hid.c b/chip/stm32/usb_hid.c index 873d80009a..043c4f8082 100644 --- a/chip/stm32/usb_hid.c +++ b/chip/stm32/usb_hid.c @@ -64,10 +64,41 @@ void hid_reset(int ep, usb_uint *hid_ep_tx_buf, int tx_len, static int report_left; static const uint8_t *report_ptr; +/* + * Send report through ep0_buf_tx. + * + * If report size is greater than USB packet size (64 bytes), rest of the + * reports will be saved in `report_ptr` and `report_left`, so we can call this + * function again to send the remain parts. + * + * @return 0 if entire report is sent, 1 if there are remaining data. + */ +static int send_report(usb_uint *ep0_buf_tx, + const uint8_t *report, + int report_size) +{ + int packet_size = MIN(report_size, USB_MAX_PACKET_SIZE); + + memcpy_to_usbram((void *) usb_sram_addr(ep0_buf_tx), + report, packet_size); + btable_ep[0].tx_count = packet_size; + /* report_left != 0 if report doesn't fit in 1 packet. */ + report_left = report_size - packet_size; + report_ptr = report + packet_size; + + STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, + report_left ? 0 : EP_STATUS_OUT); + + return report_left ? 1 : 0; +} + int hid_iface_request(usb_uint *ep0_buf_rx, usb_uint *ep0_buf_tx, - const uint8_t *report_desc, int report_size, - const struct usb_hid_descriptor *hid_desc) + const struct usb_hid_config_t *config) { + const uint8_t *report_desc = config->report_desc; + int report_size = config->report_size; + const struct usb_hid_descriptor *hid_desc = config->hid_desc; + if (!ep0_buf_rx) { /* * Continue previous transfer. We ignore report_desc/size here, @@ -89,22 +120,8 @@ int hid_iface_request(usb_uint *ep0_buf_rx, usb_uint *ep0_buf_tx, (USB_REQ_GET_DESCRIPTOR << 8))) { if (ep0_buf_rx[1] == (USB_HID_DT_REPORT << 8)) { /* Setup : HID specific : Get Report descriptor */ - report_size = MIN(ep0_buf_rx[3], report_size); - - if (report_size > USB_MAX_PACKET_SIZE) { - /* Report descriptor doesn't fit in 1 packet. */ - report_left = report_size - USB_MAX_PACKET_SIZE; - report_ptr = report_desc + USB_MAX_PACKET_SIZE; - report_size = USB_MAX_PACKET_SIZE; - } else { - report_left = 0; - } - memcpy_to_usbram((void *) usb_sram_addr(ep0_buf_tx), - report_desc, report_size); - btable_ep[0].tx_count = report_size; - STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, - report_left ? 0 : EP_STATUS_OUT); - return report_left ? 1 : 0; + return send_report(ep0_buf_tx, report_desc, + MIN(ep0_buf_rx[3], report_size)); } else if (ep0_buf_rx[1] == (USB_HID_DT_HID << 8)) { /* Setup : HID specific : Get HID descriptor */ memcpy_to_usbram_ep0_patch(hid_desc, sizeof(*hid_desc)); @@ -113,6 +130,26 @@ int hid_iface_request(usb_uint *ep0_buf_rx, usb_uint *ep0_buf_tx, EP_STATUS_OUT); return 0; } + } else if (ep0_buf_rx[0] == (USB_DIR_IN | + USB_RECIP_INTERFACE | + USB_TYPE_CLASS | + (USB_HID_REQ_GET_REPORT << 8))) { + const uint8_t report_type = (ep0_buf_rx[1] >> 8) & 0xFF; + const uint8_t report_id = ep0_buf_rx[1] & 0xFF; + int retval; + + report_left = ep0_buf_rx[3]; + if (!config->get_report) /* not supported */ + return -1; + + retval = config->get_report(report_id, + report_type, + &report_ptr, + &report_left); + if (retval) + return retval; + + return send_report(ep0_buf_tx, report_ptr, report_left); } return -1; |