Skip to content

Commit

Permalink
dwc_otg: use align_buf for small IN control transfers (#3150)
Browse files Browse the repository at this point in the history
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: #3148

Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
  • Loading branch information
P33M authored and popcornmix committed Oct 11, 2019
1 parent 060d6fc commit c4c05a2
Showing 1 changed file with 18 additions and 0 deletions.
18 changes: 18 additions & 0 deletions drivers/usb/host/dwc_otg/dwc_otg_hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1182,6 +1182,7 @@ static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
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, };
Expand Down Expand Up @@ -1293,6 +1294,23 @@ static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
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:
Expand Down

0 comments on commit c4c05a2

Please sign in to comment.