summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/twinkie/sniffer.c4
-rw-r--r--chip/stm32/usb.c60
-rw-r--r--chip/stm32/usb_hid.c4
-rw-r--r--include/usb.h24
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) \