This is a note to let you know that I've just added the patch titled
USB: usbfs: compute urb->actual_length for isochronous
to my usb git tree which can be found at git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git in the usb-next branch.
The patch will show up in the next release of the linux-next tree (usually sometime within the next 24 hours during the week.)
The patch will also be merged in the next major kernel release during the merge window.
If you have any questions about this process, please let me know.
From 2ef47001b3ee3ded579b7532ebdcf8680e4d8c54 Mon Sep 17 00:00:00 2001
From: Alan Stern stern@rowland.harvard.edu Date: Wed, 8 Nov 2017 12:23:17 -0500 Subject: USB: usbfs: compute urb->actual_length for isochronous
The USB kerneldoc says that the actual_length field "is read in non-iso completion functions", but the usbfs driver uses it for all URB types in processcompl(). Since not all of the host controller drivers set actual_length for isochronous URBs, programs using usbfs with some host controllers don't work properly. For example, Minas reports that a USB camera controlled by libusb doesn't work properly with a dwc2 controller.
It doesn't seem worthwhile to change the HCDs and the documentation, since the in-kernel USB class drivers evidently don't rely on actual_length for isochronous transfers. The easiest solution is for usbfs to calculate the actual_length value for itself, by adding up the lengths of the individual packets in an isochronous transfer.
Signed-off-by: Alan Stern stern@rowland.harvard.edu CC: Minas Harutyunyan Minas.Harutyunyan@synopsys.com Reported-and-tested-by: wlf wulf@rock-chips.com CC: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/usb/core/devio.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index c3aaafc25a04..2edb4e7b2ab8 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1820,6 +1820,18 @@ static int proc_unlinkurb(struct usb_dev_state *ps, void __user *arg) return 0; }
+static void compute_isochronous_actual_length(struct urb *urb) +{ + unsigned int i; + + if (urb->number_of_packets > 0) { + urb->actual_length = 0; + for (i = 0; i < urb->number_of_packets; i++) + urb->actual_length += + urb->iso_frame_desc[i].actual_length; + } +} + static int processcompl(struct async *as, void __user * __user *arg) { struct urb *urb = as->urb; @@ -1827,6 +1839,7 @@ static int processcompl(struct async *as, void __user * __user *arg) void __user *addr = as->userurb; unsigned int i;
+ compute_isochronous_actual_length(urb); if (as->userbuffer && urb->actual_length) { if (copy_urb_data_to_user(as->userbuffer, urb)) goto err_out; @@ -1995,6 +2008,7 @@ static int processcompl_compat(struct async *as, void __user * __user *arg) void __user *addr = as->userurb; unsigned int i;
+ compute_isochronous_actual_length(urb); if (as->userbuffer && urb->actual_length) { if (copy_urb_data_to_user(as->userbuffer, urb)) return -EFAULT;
linux-stable-mirror@lists.linaro.org