usb: dwc2: host: Fix wMaxPacketSize handling (fix webcam regression)

In commit abb621844f ("usb: ch9: make usb_endpoint_maxp() return
only packet size") the API to usb_endpoint_maxp() changed.  It used to
just return wMaxPacketSize but after that commit it returned
wMaxPacketSize with the high bits (the multiplier) masked off.  If you
wanted to get the multiplier it was now up to your code to call the
new usb_endpoint_maxp_mult() which was introduced in
commit 541b6fe630 ("usb: add helper to extract bits 12:11 of
wMaxPacketSize").

Prior to the API change most host drivers were updated, but no update
was made to dwc2.  Presumably it was assumed that dwc2 was too
simplistic to use the multiplier and thus just didn't support a
certain class of USB devices.  However, it turns out that dwc2 did use
the multiplier and many devices using it were working quite nicely.
That means that many USB devices have been broken since the API
change.  One such device is a Logitech HD Pro Webcam C920.

Specifically, though dwc2 didn't directly call usb_endpoint_maxp(), it
did call usb_maxpacket() which in turn called usb_endpoint_maxp().

Let's update dwc2 to work properly with the new API.

Fixes: abb621844f ("usb: ch9: make usb_endpoint_maxp() return only packet size")
Cc: stable@vger.kernel.org
Acked-by: Minas Harutyunyan <hminas@synopsys.com>
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
Signed-off-by: Douglas Anderson <dianders@chromium.org>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
This commit is contained in:
Douglas Anderson
2019-05-31 13:04:12 -07:00
committed by Felipe Balbi
parent f2c7c76c5d
commit babd183915
4 changed files with 37 additions and 27 deletions

View File

@@ -2608,7 +2608,7 @@ static int dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
chan->dev_addr = dwc2_hcd_get_dev_addr(&urb->pipe_info);
chan->ep_num = dwc2_hcd_get_ep_num(&urb->pipe_info);
chan->speed = qh->dev_speed;
chan->max_packet = dwc2_max_packet(qh->maxp);
chan->max_packet = qh->maxp;
chan->xfer_started = 0;
chan->halt_status = DWC2_HC_XFER_NO_HALT_STATUS;
@@ -2686,7 +2686,7 @@ static int dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
* This value may be modified when the transfer is started
* to reflect the actual transfer length
*/
chan->multi_count = dwc2_hb_mult(qh->maxp);
chan->multi_count = qh->maxp_mult;
if (hsotg->params.dma_desc_enable) {
chan->desc_list_addr = qh->desc_list_dma;
@@ -3806,19 +3806,21 @@ static struct dwc2_hcd_urb *dwc2_hcd_urb_alloc(struct dwc2_hsotg *hsotg,
static void dwc2_hcd_urb_set_pipeinfo(struct dwc2_hsotg *hsotg,
struct dwc2_hcd_urb *urb, u8 dev_addr,
u8 ep_num, u8 ep_type, u8 ep_dir, u16 mps)
u8 ep_num, u8 ep_type, u8 ep_dir,
u16 maxp, u16 maxp_mult)
{
if (dbg_perio() ||
ep_type == USB_ENDPOINT_XFER_BULK ||
ep_type == USB_ENDPOINT_XFER_CONTROL)
dev_vdbg(hsotg->dev,
"addr=%d, ep_num=%d, ep_dir=%1x, ep_type=%1x, mps=%d\n",
dev_addr, ep_num, ep_dir, ep_type, mps);
"addr=%d, ep_num=%d, ep_dir=%1x, ep_type=%1x, maxp=%d (%d mult)\n",
dev_addr, ep_num, ep_dir, ep_type, maxp, maxp_mult);
urb->pipe_info.dev_addr = dev_addr;
urb->pipe_info.ep_num = ep_num;
urb->pipe_info.pipe_type = ep_type;
urb->pipe_info.pipe_dir = ep_dir;
urb->pipe_info.mps = mps;
urb->pipe_info.maxp = maxp;
urb->pipe_info.maxp_mult = maxp_mult;
}
/*
@@ -3909,8 +3911,9 @@ void dwc2_hcd_dump_state(struct dwc2_hsotg *hsotg)
dwc2_hcd_is_pipe_in(&urb->pipe_info) ?
"IN" : "OUT");
dev_dbg(hsotg->dev,
" Max packet size: %d\n",
dwc2_hcd_get_mps(&urb->pipe_info));
" Max packet size: %d (%d mult)\n",
dwc2_hcd_get_maxp(&urb->pipe_info),
dwc2_hcd_get_maxp_mult(&urb->pipe_info));
dev_dbg(hsotg->dev,
" transfer_buffer: %p\n",
urb->buf);
@@ -4510,8 +4513,10 @@ static void dwc2_dump_urb_info(struct usb_hcd *hcd, struct urb *urb,
}
dev_vdbg(hsotg->dev, " Speed: %s\n", speed);
dev_vdbg(hsotg->dev, " Max packet size: %d\n",
usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)));
dev_vdbg(hsotg->dev, " Max packet size: %d (%d mult)\n",
usb_endpoint_maxp(&urb->ep->desc),
usb_endpoint_maxp_mult(&urb->ep->desc));
dev_vdbg(hsotg->dev, " Data buffer length: %d\n",
urb->transfer_buffer_length);
dev_vdbg(hsotg->dev, " Transfer buffer: %p, Transfer DMA: %08lx\n",
@@ -4594,8 +4599,8 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
dwc2_hcd_urb_set_pipeinfo(hsotg, dwc2_urb, usb_pipedevice(urb->pipe),
usb_pipeendpoint(urb->pipe), ep_type,
usb_pipein(urb->pipe),
usb_maxpacket(urb->dev, urb->pipe,
!(usb_pipein(urb->pipe))));
usb_endpoint_maxp(&ep->desc),
usb_endpoint_maxp_mult(&ep->desc));
buf = urb->transfer_buffer;