On Fri, 19 Jan 2007, Oliver Neukum wrote:

> Hi,
> 
> I did the dirty deed. Could you please tell me which quirky devices
> you know of? I am afraid this list needs to be populated and there
> are outstanding regressions in Adrian's list.

I'll get back to you on the devices.

I think this patch could be generalized.  We may have other quirks to 
worry about besides PM/autosuspend.  This should become a general USB 
blacklist mechanism.

One example that comes up immediately is the HP scanner which crashes 
when we try to read the string descriptors.  Others may crop up in the 
future.


> --- a/include/linux/usb.h     2007-01-18 13:15:25.000000000 +0100
> +++ b/include/linux/usb.h     2007-01-19 12:12:07.000000000 +0100
> @@ -387,6 +387,7 @@
>       struct usb_device *children[USB_MAXCHILDREN];
>  
>       int pm_usage_cnt;               /* usage counter for autosuspend */
> +     int pm_quirks;                  /* quirks of power management */

So this could simply be "quirks", not "pm_quirks", with a corresponding 
change to the comment.

> +/* Power management quirks */
> +#define USB_PM_DISCONNECT    1 /* devices which disconnect when resuming */

Make the name USB_QUIRK_NO_AUTOSUSPEND.  We don't really care that the
device disconnects when resuming; the only important part is that we
should never try to autosuspend it.

The list of quirk flag definitions doesn't belong in include/linux/usb.h.  
We could put it in drivers/usb/core/usb.h or drivers/usb/core/quirks.h.  
Or if you think that some USB drivers might eventually want to use a
quirk, you could put the definitions in include/linux/usb/quirks.h.


> --- a/drivers/usb/core/hub.c  2007-01-17 14:26:17.000000000 +0100
> +++ b/drivers/usb/core/hub.c  2007-01-19 12:31:08.000000000 +0100
> @@ -31,6 +31,7 @@
>  #include "usb.h"
>  #include "hcd.h"
>  #include "hub.h"
> +#include "autosuspend_quirks.h"

And this, of course, should be the name you decide on above.

> @@ -1263,6 +1264,33 @@
>  static int __usb_port_suspend(struct usb_device *, int port1);
>  #endif
>  
> +#ifdef       CONFIG_USB_SUSPEND
> +
> +static int usb_autosuspend_search_quirk(u16 vendor, u16 product, u16 version)
> +{
> +     const struct pm_blacklist *blentry = pm_blacklist;
> +
> +     while (blentry->idVendor) {
> +             if (blentry->idVendor == vendor &&
> +                     blentry->idProduct == product &&
> +                     blentry->bcdVersionMin <= version &&
> +                     blentry->bcdVersionMax >= version)
> +                             return blentry->quirks;
> +             blentry++;
> +     }
> +
> +     return 0;
> +}

I dislike seeing this in hub.c.  That file is already too big, and anyway
managing a blacklist has nothing to do with being a hub driver.  You
should create a new source file: drivers/usb/core/quirks.c.  Put both the
search routine and the initializer for the quirks array in the new file.

Also the prototype is awkward.  It seems pretty unlikely that anyone would 
want to search the blacklist for a device that isn't currently attached.  
So you can simply accept a pointer to struct usb_device instead of the 
vendor, product, and version numbers.

>  static int __usb_new_device(void *void_data)
>  {
>       struct usb_device *udev = void_data;
> @@ -1359,6 +1387,12 @@
>       }
>  #endif
>  
> +     /* Determine power management quirks */
> +     udev->pm_quirks = usb_autosuspend_search_quirk(
> +             le16_to_cpu(udev->descriptor.idVendor),
> +             le16_to_cpu(udev->descriptor.idProduct),
> +             le16_to_cpu(udev->descriptor.bcdDevice));
> +     dev_dbg(&udev->dev, "USB power management quirks: %d\n", 
> udev->pm_quirks);
>       /* Register the device.  The device driver is responsible
>        * for adding the device files to usbfs and sysfs and for
>        * configuring the device.

After the name and prototype changes this will be okay.  You can also 
implement a USB_QUIRK_NO_STRINGS quirk; execute the calls to 
usb_cache_string() only when this quirk isn't set.

> --- /dev/null 2006-05-02 08:46:16.000000000 +0200
> +++ b/drivers/usb/core/autosuspend_quirks.h   2007-01-19 12:29:44.000000000 
> +0100
> @@ -0,0 +1,20 @@
> +/*
> + * This is a list of USB devices which are quirky with respect
> + * to power management. Keep this list ordered by
> + * 1. Vendor
> + * 2. Product
> + * 3. Version, the most specific first
> + */
> +
> +
> +static const struct pm_blacklist {
> +     u16     idVendor; /* vendor id of the quirky device */
> +     u16     idProduct; /* product id of the quirky device */
> +     u16     bcdVersionMin; /* minimum version id of the afflicted devices */
> +     u16     bcdVersionMax; /* maximum version id of the afflicted devices */
> +     int     quirks; /* the actual qirks, several to be joined with binary 
> or */
> +} pm_blacklist[] = {
> +     /* Elsa MicroLink 56k (V.250) */
> +     {0x05cc, 0x2267, 0x0100, 0x0100, USB_PM_DISCONNECT},
> +     {0, 0, 0, 0, 0} /* keep this last */
> +};

Like I said above, this should be a .c file, not a .h.

> --- a/drivers/usb/core/driver.c       2007-01-18 13:13:22.000000000 +0100
> +++ b/drivers/usb/core/driver.c       2007-01-19 12:04:46.000000000 +0100
> @@ -952,7 +952,7 @@
>        * Also fail if any interfaces require remote wakeup but it
>        * isn't available. */
>       udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
> -     if (udev->pm_usage_cnt > 0)
> +     if (udev->pm_usage_cnt > 0 || udev->pm_quirks & USB_PM_DISCONNECT)
>               return -EBUSY;
>       if (udev->actconfig) {
>               for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {

You don't need to make this change here.  Instead, when 
USB_QUIRK_NO_AUTOSUSPEND is set you can simply increment 
udev->pm_usage_cnt.  Or if you prefer not to violate the layering, call 
usb_autoresume_device().

Alan Stern


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to