Hi Alan,

On 11/8/2017 9:23 PM, Alan Stern wrote:
> 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.

Issue reported not by me, but by William Wu (wlf <[email protected]>)

> 
> 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 <[email protected]>
> CC: Minas Harutyunyan <[email protected]>
> Reported-and-tested-by: wlf <[email protected]>
> CC: <[email protected]>
> 
> ---
> 
> 
> [as1853]
> 
> 
>   drivers/usb/core/devio.c |   14 ++++++++++++++
>   1 file changed, 14 insertions(+)
> 
> Index: usb-4.x/drivers/usb/core/devio.c
> ===================================================================
> --- usb-4.x.orig/drivers/usb/core/devio.c
> +++ usb-4.x/drivers/usb/core/devio.c
> @@ -1828,6 +1828,18 @@ static int proc_unlinkurb(struct usb_dev
>       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;
> @@ -1835,6 +1847,7 @@ static int processcompl(struct async *as
>       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;
> @@ -2003,6 +2016,7 @@ static int processcompl_compat(struct as
>       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;
> 
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to