2019-09-19 14:43:19 +00:00
|
|
|
From 0c6190fa3cfeafd773b51b751a473d6775c23309 Mon Sep 17 00:00:00 2001
|
2019-08-09 17:50:30 +00:00
|
|
|
From: P33M <2474547+P33M@users.noreply.github.com>
|
|
|
|
Date: Wed, 14 Aug 2019 14:35:50 +0100
|
2019-12-23 12:42:55 +00:00
|
|
|
Subject: [PATCH] dwc_otg: use align_buf for small IN control transfers
|
2019-08-09 17:50:30 +00:00
|
|
|
(#3150)
|
|
|
|
|
|
|
|
The hardware will do a 4-byte write to memory on any IN packet received
|
|
|
|
that is between 1 and 3 bytes long. This tramples memory in the uvcvideo
|
|
|
|
driver, as it uses a sequence of 1- and 2-byte control transfers to
|
|
|
|
query the min/max/range/step of each individual camera control and
|
|
|
|
gives us buffers that are offsets into a struct.
|
|
|
|
|
|
|
|
Catch small control transfers in the data phase and use the align_buf
|
|
|
|
to bounce the correct number of bytes into the URB's buffer.
|
|
|
|
|
|
|
|
In general, short packets on non-control endpoints should be OK as URBs
|
|
|
|
should have enough buffer space for a wMaxPacket size transfer.
|
|
|
|
|
|
|
|
See: https://github.com/raspberrypi/linux/issues/3148
|
|
|
|
|
|
|
|
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
|
|
|
|
---
|
|
|
|
drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 18 ++++++++++++++++++
|
|
|
|
1 file changed, 18 insertions(+)
|
|
|
|
|
|
|
|
--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
|
|
|
|
+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
|
|
|
|
@@ -1182,6 +1182,7 @@ static void assign_and_init_hc(dwc_otg_h
|
|
|
|
dwc_otg_qtd_t *qtd;
|
|
|
|
dwc_otg_hcd_urb_t *urb;
|
|
|
|
void* ptr = NULL;
|
|
|
|
+ uint16_t wLength;
|
|
|
|
uint32_t intr_enable;
|
|
|
|
unsigned long flags;
|
|
|
|
gintmsk_data_t gintmsk = { .d32 = 0, };
|
|
|
|
@@ -1293,6 +1294,23 @@ static void assign_and_init_hc(dwc_otg_h
|
|
|
|
break;
|
|
|
|
case DWC_OTG_CONTROL_DATA:
|
|
|
|
DWC_DEBUGPL(DBG_HCDV, " Control data transaction\n");
|
|
|
|
+ /*
|
|
|
|
+ * Hardware bug: small IN packets with length < 4
|
|
|
|
+ * cause a 4-byte write to memory. We can only catch
|
|
|
|
+ * the case where we know a short packet is going to be
|
|
|
|
+ * returned in a control transfer, as the length is
|
|
|
|
+ * specified in the setup packet. This is only an issue
|
|
|
|
+ * for drivers that insist on packing a device's various
|
|
|
|
+ * properties into a struct and querying them one at a
|
|
|
|
+ * time (uvcvideo).
|
|
|
|
+ * Force the use of align_buf so that the subsequent
|
|
|
|
+ * memcpy puts the right number of bytes in the URB's
|
|
|
|
+ * buffer.
|
|
|
|
+ */
|
|
|
|
+ wLength = ((uint16_t *)urb->setup_packet)[3];
|
|
|
|
+ if (hc->ep_is_in && wLength < 4)
|
|
|
|
+ ptr = hc->xfer_buff;
|
|
|
|
+
|
|
|
|
hc->data_pid_start = qtd->data_toggle;
|
|
|
|
break;
|
|
|
|
case DWC_OTG_CONTROL_STATUS:
|