From e3c1e2265c732d465f3df90e5ea64bd02f02234f Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Wed, 15 Nov 2017 15:00:12 +0800 Subject: stm32/usb: Patching framework for USB descriptors In some cases, we want to be able to dynamically modify a few bytes in the USB descriptor (in our case, length of referenced items), but it could also be other things like flags. These 2 new functions allow to keep all the USB descriptor in flash, and modify these few bytes before writing them in the USB buffer. BRANCH=none BUG=b:37447752 TEST=Flash hammer, USB descriptors are valid. Change-Id: I8624255fa43f52a0aaa21d20e963f3974f236912 Signed-off-by: Nicolas Boichat Reviewed-on: https://chromium-review.googlesource.com/771057 Reviewed-by: Vincent Palatin --- chip/stm32/usb.c | 36 +++++++++++++++++++++++++++++++++++- chip/stm32/usb_hid.c | 3 +-- chip/stm32/usb_hw.h | 21 +++++++++++++++++++++ 3 files changed, 57 insertions(+), 3 deletions(-) (limited to 'chip/stm32') diff --git a/chip/stm32/usb.c b/chip/stm32/usb.c index 27ea117de5..c97c68f03c 100644 --- a/chip/stm32/usb.c +++ b/chip/stm32/usb.c @@ -119,6 +119,40 @@ void usb_read_setup_packet(usb_uint *buffer, struct usb_setup_packet *packet) packet->wLength = buffer[3]; } +struct usb_descriptor_patch { + const void *address; + uint16_t data; +}; + +static struct usb_descriptor_patch desc_patches[USB_DESC_PATCH_COUNT]; + +void set_descriptor_patch(enum usb_desc_patch_type type, + const void *address, uint16_t data) +{ + desc_patches[type].address = address; + desc_patches[type].data = data; +} + +void *memcpy_to_usbram_ep0_patch(const void *src, size_t n) +{ + int i; + void *ret; + + ret = memcpy_to_usbram((void *)usb_sram_addr(ep0_buf_tx), src, n); + + for (i = 0; i < USB_DESC_PATCH_COUNT; i++) { + unsigned int offset = desc_patches[i].address - src; + + if (offset >= n) + continue; + + memcpy_to_usbram((void *)(usb_sram_addr(ep0_buf_tx) + offset), + &desc_patches[i].data, sizeof(desc_patches[i].data)); + } + + return ret; +} + static void ep0_send_descriptor(const uint8_t *desc, int len, uint16_t fixup_size) { @@ -133,7 +167,7 @@ static void ep0_send_descriptor(const uint8_t *desc, int len, desc_ptr = desc + USB_MAX_PACKET_SIZE; len = USB_MAX_PACKET_SIZE; } - memcpy_to_usbram(EP0_BUF_TX_SRAM_ADDR, desc, len); + memcpy_to_usbram_ep0_patch(desc, len); if (fixup_size) /* set the real descriptor size */ ep0_buf_tx[1] = fixup_size; btable_ep[0].tx_count = len; diff --git a/chip/stm32/usb_hid.c b/chip/stm32/usb_hid.c index f24bdd5982..873d80009a 100644 --- a/chip/stm32/usb_hid.c +++ b/chip/stm32/usb_hid.c @@ -107,8 +107,7 @@ int hid_iface_request(usb_uint *ep0_buf_rx, usb_uint *ep0_buf_tx, return report_left ? 1 : 0; } else if (ep0_buf_rx[1] == (USB_HID_DT_HID << 8)) { /* Setup : HID specific : Get HID descriptor */ - memcpy_to_usbram((void *) usb_sram_addr(ep0_buf_tx), - hid_desc, sizeof(*hid_desc)); + memcpy_to_usbram_ep0_patch(hid_desc, sizeof(*hid_desc)); btable_ep[0].tx_count = sizeof(*hid_desc); STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, EP_STATUS_OUT); diff --git a/chip/stm32/usb_hw.h b/chip/stm32/usb_hw.h index 89c8e9d6f0..94734d8569 100644 --- a/chip/stm32/usb_hw.h +++ b/chip/stm32/usb_hw.h @@ -63,6 +63,27 @@ void usb_read_setup_packet(usb_uint *buffer, struct usb_setup_packet *packet); void *memcpy_to_usbram(void *dest, const void *src, size_t n); void *memcpy_from_usbram(void *dest, const void *src, size_t n); +/* + * Descriptor patching support, useful to change a few values in the descriptor + * (typically, length or bitfields) without having to move descriptors to RAM. + */ + +enum usb_desc_patch_type { + USB_DESC_PATCH_COUNT, +}; + +/* + * Set patch in table: replace uint16_t at address (STM32 flash) with data. + * + * The patches need to be setup before _before_ usb_init is executed (or, at + * least, before the first call to memcpy_to_usbram_ep0_patch). + */ +void set_descriptor_patch(enum usb_desc_patch_type type, + const void *address, uint16_t data); + +/* Copy to USB ram, applying patches to src as required. */ +void *memcpy_to_usbram_ep0_patch(const void *src, size_t n); + /* Compute the address inside dedicate SRAM for the USB controller */ #define usb_sram_addr(x) ((x - __usb_ram_start) * sizeof(uint16_t)) -- cgit v1.2.1