diff options
-rw-r--r-- | board/twinkie/sniffer.c | 4 | ||||
-rw-r--r-- | chip/stm32/usb.c | 60 | ||||
-rw-r--r-- | chip/stm32/usb_hid.c | 4 | ||||
-rw-r--r-- | include/usb.h | 24 |
4 files changed, 76 insertions, 16 deletions
diff --git a/board/twinkie/sniffer.c b/board/twinkie/sniffer.c index e6a0cff0a4..e1f2d5c8c2 100644 --- a/board/twinkie/sniffer.c +++ b/board/twinkie/sniffer.c @@ -289,8 +289,8 @@ void sniffer_task(void) } ep_buf[u][0] = sample_seq[d >> 3] | (d & 7); ep_buf[u][1] = sample_tstamp[d >> 3]; - memcpy_usbram(ep_buf[u] + 2, - samples[d >> 4]+off, EP_PAYLOAD_SIZE); + memcpy_to_usbram(ep_buf[u] + 2, + samples[d >> 4]+off, EP_PAYLOAD_SIZE); atomic_clear((uint32_t *)&free_usb, 1 << u); u = !u; atomic_clear((uint32_t *)&filled_dma, 1 << d); diff --git a/chip/stm32/usb.c b/chip/stm32/usb.c index 82c1337a40..af9082299e 100644 --- a/chip/stm32/usb.c +++ b/chip/stm32/usb.c @@ -155,7 +155,7 @@ static void ep0_rx(void) desc_ptr = desc + USB_MAX_PACKET_SIZE; len = USB_MAX_PACKET_SIZE; } - memcpy_usbram(ep0_buf_tx, desc, len); + memcpy_to_usbram(ep0_buf_tx, desc, len); if (type == USB_DT_CONFIGURATION) /* set the real descriptor size */ ep0_buf_tx[1] = USB_DESC_SIZE; @@ -166,7 +166,7 @@ static void ep0_rx(void) } else if (req == (USB_DIR_IN | (USB_REQ_GET_STATUS << 8))) { uint16_t zero = 0; /* Get status */ - memcpy_usbram(ep0_buf_tx, (void *)&zero, 2); + memcpy_to_usbram(ep0_buf_tx, (void *)&zero, 2); btable_ep[0].tx_count = 2; STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, EP_STATUS_OUT /*null OUT transaction */); @@ -208,7 +208,7 @@ static void ep0_tx(void) if (desc_ptr) { /* we have an on-going descriptor transfer */ int len = MIN(desc_left, USB_MAX_PACKET_SIZE); - memcpy_usbram(ep0_buf_tx, desc_ptr, len); + memcpy_to_usbram(ep0_buf_tx, desc_ptr, len); btable_ep[0].tx_count = len; desc_left -= len; desc_ptr += len; @@ -341,3 +341,57 @@ int usb_is_enabled(void) { return (STM32_RCC_APB1ENR & STM32_RCC_PB1_USB) ? 1 : 0; } + +void *memcpy_to_usbram(void *dest, const void *src, size_t n) +{ + int i; + uint8_t *s = (uint8_t *) src; + usb_uint *d = (usb_uint *)((uintptr_t) dest & ~1); + + if ((((uintptr_t) dest) & 1) && n) { + /* + * The first destination byte is not aligned, perform a read/ + * modify/write. + */ + *d = (*d & ~0xff00) | (*s << 8); + n--; + s++; + d++; + } + + for (i = 0; i < n / 2; i++, s += 2) + *d++ = (s[1] << 8) | s[0]; + + /* + * There is a trailing byte to write into a final USB packet memory + * location, use a read/modify/write to be safe. + */ + if (n & 1) + *d = (*d & ~0x00ff) | *s; + + return dest; +} + +void *memcpy_from_usbram(void *dest, const void *src, size_t n) +{ + int i; + usb_uint *s = (usb_uint *)((uintptr_t) src & ~1); + uint8_t *d = (uint8_t *) dest; + + if ((((uintptr_t) src) & 1) && n) { + *d++ = *s++ >> 8; + n--; + } + + for (i = 0; i < n / 2; i++) { + usb_uint value = *s++; + + *d++ = (value >> 0) & 0xff; + *d++ = (value >> 8) & 0xff; + } + + if (n & 1) + *d = *s; + + return dest; +} diff --git a/chip/stm32/usb_hid.c b/chip/stm32/usb_hid.c index bdcf09c3f8..8b39778202 100644 --- a/chip/stm32/usb_hid.c +++ b/chip/stm32/usb_hid.c @@ -88,7 +88,7 @@ static usb_uint hid_ep_buf[HID_REPORT_SIZE / 2] __usb_ram; void set_keyboard_report(uint64_t rpt) { - memcpy_usbram(hid_ep_buf, (const uint8_t *)&rpt, sizeof(rpt)); + memcpy_to_usbram(hid_ep_buf, &rpt, sizeof(rpt)); /* enable TX */ STM32_TOGGLE_EP(USB_EP_HID, EP_TX_MASK, EP_TX_VALID, 0); } @@ -124,7 +124,7 @@ static int hid_iface_request(usb_uint *ep0_buf_rx, usb_uint *ep0_buf_tx) (USB_REQ_GET_DESCRIPTOR << 8))) && (ep0_buf_rx[1] == (USB_HID_DT_REPORT << 8))) { /* Setup : HID specific : Get Report descriptor */ - memcpy_usbram(ep0_buf_tx, report_desc, + memcpy_to_usbram(ep0_buf_tx, report_desc, sizeof(report_desc)); btable_ep[0].tx_count = MIN(ep0_buf_rx[3], sizeof(report_desc)); diff --git a/include/usb.h b/include/usb.h index 0c96b19db1..43eb409c1a 100644 --- a/include/usb.h +++ b/include/usb.h @@ -254,15 +254,21 @@ extern struct stm32_endpoint btable_ep[]; /* Read from USB RAM into a usb_setup_packet struct */ void usb_read_setup_packet(usb_uint *buffer, struct usb_setup_packet *packet); -/* Copy data to the USB dedicated RAM and take care of the weird addressing */ -static inline void memcpy_usbram(usb_uint *ebuf, const uint8_t *src, int size) -{ - int i; - for (i = 0; i < size / 2; i++, src += 2) - *ebuf++ = src[0] | (src[1] << 8); - if (size & 1) - *ebuf++ = src[0]; -} +/* + * Copy data to and from the USB dedicated RAM and take care of the weird + * addressing. These functions correctly handle unaligned accesses to the USB + * memory. They have the same prototype as memcpy, allowing them to be used + * in places that expect memcpy. + * + * The USB packet RAM is attached to the processor via the AHB2APB bridge. This + * bridge performs manipulations of read and write accesses as per the note in + * section 2.1 of RM0091. The upshot is that it is OK to read from the packet + * RAM using 8-bit or 16-bit accesses, but not 32-bit, and it is only really OK + * to write to the packet RAM using 16-bit accesses. Thus custom memcpy like + * routines need to be employed. + */ +void *memcpy_to_usbram(void *dest, const void *src, size_t n); +void *memcpy_from_usbram(void *dest, const void *src, size_t n); /* Compute the address inside dedicate SRAM for the USB controller */ #define usb_sram_addr(x) \ |