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>
This commit is contained in:
Nicolas Boichat
2017-11-15 15:00:12 +08:00
committed by chrome-bot
parent 2f4fd74df5
commit e3c1e2265c
3 changed files with 57 additions and 3 deletions

View File

@@ -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;

View File

@@ -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);

View File

@@ -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))