diff options
author | Nicolas Boichat <drinkcat@chromium.org> | 2017-11-15 15:00:12 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-12-12 03:57:19 -0800 |
commit | e3c1e2265c732d465f3df90e5ea64bd02f02234f (patch) | |
tree | 7a6db56d522a6ff448f78691ad696901792e47d8 /chip | |
parent | 2f4fd74df5af5885a24d2c1ddc9deb71dd874315 (diff) | |
download | chrome-ec-e3c1e2265c732d465f3df90e5ea64bd02f02234f.tar.gz |
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 <drinkcat@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/771057
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
Diffstat (limited to 'chip')
-rw-r--r-- | chip/stm32/usb.c | 36 | ||||
-rw-r--r-- | chip/stm32/usb_hid.c | 3 | ||||
-rw-r--r-- | chip/stm32/usb_hw.h | 21 |
3 files changed, 57 insertions, 3 deletions
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)) |