From 12f1ff8351e235661beb0314d9ae9417a4871688 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 1 Feb 2007 16:08:41 -0500 Subject: usbcore: small changes to hub driver's suspend method This patch (as847) makes some small changes to the hub driver's suspend method: For root hubs, the status URB should be unlinked and other activity stopped _before_ the bus_suspend method is called. The test for hdev->bus being NULL has been removed, since it can never succeed. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) (limited to 'drivers/usb/core/hub.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 590ec82d0515..7d6006573543 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1904,6 +1904,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) struct usb_hub *hub = usb_get_intfdata (intf); struct usb_device *hdev = hub->hdev; unsigned port1; + int status = 0; /* fail if children aren't already suspended */ for (port1 = 1; port1 <= hdev->maxchild; port1++) { @@ -1927,24 +1928,18 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) dev_dbg(&intf->dev, "%s\n", __FUNCTION__); + /* stop khubd and related activity */ + hub_quiesce(hub); + /* "global suspend" of the downstream HC-to-USB interface */ if (!hdev->parent) { - struct usb_bus *bus = hdev->bus; - if (bus) { - int status = hcd_bus_suspend (bus); - - if (status != 0) { - dev_dbg(&hdev->dev, "'global' suspend %d\n", - status); - return status; - } - } else - return -EOPNOTSUPP; + status = hcd_bus_suspend(hdev->bus); + if (status != 0) { + dev_dbg(&hdev->dev, "'global' suspend %d\n", status); + hub_activate(hub); + } } - - /* stop khubd and related activity */ - hub_quiesce(hub); - return 0; + return status; } static int hub_resume(struct usb_interface *intf) -- cgit v1.2.1 From db90e7a15cb4a160610b4e58576f25539ca216e7 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 5 Feb 2007 09:56:15 -0500 Subject: USB: fix concurrent buffer access in the hub driver This patch (as849) fixes a bug in the USB hub driver. A single pre-allocated buffer is used for all port status reads, but nothing guarantees exclusive use of the buffer. A mutex is added to provide this guarantee. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/usb/core/hub.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 7d6006573543..50c0db15304a 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -44,6 +44,7 @@ struct usb_hub { struct usb_hub_status hub; struct usb_port_status port; } *status; /* buffer for status reports */ + struct mutex status_mutex; /* for the status buffer */ int error; /* last reported error */ int nerrors; /* track consecutive errors */ @@ -535,6 +536,7 @@ static int hub_hub_status(struct usb_hub *hub, { int ret; + mutex_lock(&hub->status_mutex); ret = get_hub_status(hub->hdev, &hub->status->hub); if (ret < 0) dev_err (hub->intfdev, @@ -544,6 +546,7 @@ static int hub_hub_status(struct usb_hub *hub, *change = le16_to_cpu(hub->status->hub.wHubChange); ret = 0; } + mutex_unlock(&hub->status_mutex); return ret; } @@ -617,6 +620,7 @@ static int hub_configure(struct usb_hub *hub, ret = -ENOMEM; goto fail; } + mutex_init(&hub->status_mutex); hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL); if (!hub->descriptor) { @@ -1396,6 +1400,7 @@ static int hub_port_status(struct usb_hub *hub, int port1, { int ret; + mutex_lock(&hub->status_mutex); ret = get_port_status(hub->hdev, port1, &hub->status->port); if (ret < 4) { dev_err (hub->intfdev, @@ -1407,6 +1412,7 @@ static int hub_port_status(struct usb_hub *hub, int port1, *change = le16_to_cpu(hub->status->port.wPortChange); ret = 0; } + mutex_unlock(&hub->status_mutex); return ret; } -- cgit v1.2.1 From 7ceec1f1d26f966c0816b86a1aab1e0b3b208757 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 26 Jan 2007 14:26:21 +0100 Subject: USB: add a blacklist for devices that can't handle some things we throw at them. This adds a blacklist to the USB core to handle some autosuspend and string issues that devices have. Originally written by Oliver, but hacked up a lot by Greg. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/usb/core/hub.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 50c0db15304a..41400743ce2c 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1287,6 +1287,9 @@ int usb_new_device(struct usb_device *udev) if (!try_module_get(THIS_MODULE)) return -EINVAL; + /* Determine quirks */ + usb_detect_quirks(udev); + err = usb_get_configuration(udev); if (err < 0) { dev_err(&udev->dev, "can't read configurations, error %d\n", -- cgit v1.2.1 From 7bc4b81dedf54166e967afa8bc03c8bfeb40fd27 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 27 Feb 2007 10:25:00 +0100 Subject: USB: ratelimit debounce error messages flaky hardware can cause a lot of debounce failed messages. To limit the performance impact, a ratelimit should be used. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/core/hub.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 41400743ce2c..ce6c6a0d44bf 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2443,7 +2443,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, if (portchange & USB_PORT_STAT_C_CONNECTION) { status = hub_port_debounce(hub, port1); - if (status < 0) { + if (status < 0 && printk_ratelimit()) { dev_err (hub_dev, "connect-debounce failed, port %d disabled\n", port1); -- cgit v1.2.1 From 5bb16d189f5425f3722bc91d9211afe303ee022b Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 1 Mar 2007 22:31:24 +0100 Subject: USB: kill dead code from hub.c this kills residual obsoletet code from hub.c Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/usb/core/hub.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index ce6c6a0d44bf..b89a98e61323 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1281,12 +1281,6 @@ int usb_new_device(struct usb_device *udev) { int err; - /* Lock ourself into memory in order to keep a probe sequence - * sleeping in a new thread from allowing us to be unloaded. - */ - if (!try_module_get(THIS_MODULE)) - return -EINVAL; - /* Determine quirks */ usb_detect_quirks(udev); @@ -1390,7 +1384,6 @@ int usb_new_device(struct usb_device *udev) usb_autoresume_device(udev->parent); exit: - module_put(THIS_MODULE); return err; fail: -- cgit v1.2.1 From 404d5b185b4eb56d6fa2f7bd27833f8df1c38ce4 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 26 Apr 2007 00:12:10 -0700 Subject: dev_dbg: check dev_dbg() arguments Duplicate what Zach Brown did for pr_debug in commit 8b2a1fd1b394c60eaa2587716102dd5e9b4e5990 [akpm@linux-foundation.org: fix a couple of things which broke] Signed-off-by: Dan Williams Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/usb/core/hub.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index b89a98e61323..7a6028599d62 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -119,8 +119,7 @@ MODULE_PARM_DESC(use_both_schemes, "first one fails"); -#ifdef DEBUG -static inline char *portspeed (int portstatus) +static inline char *portspeed(int portstatus) { if (portstatus & (1 << USB_PORT_FEAT_HIGHSPEED)) return "480 Mb/s"; @@ -129,7 +128,6 @@ static inline char *portspeed (int portstatus) else return "12 Mb/s"; } -#endif /* Note that hdev or one of its children must be locked! */ static inline struct usb_hub *hdev_to_hub(struct usb_device *hdev) -- cgit v1.2.1 From 6b157c9bf3bace6eeb4a973da63923ef24995cce Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 13 Mar 2007 16:37:30 -0400 Subject: USB: separate autosuspend from external suspend This patch (as866) adds new entry points for external USB device suspend and resume requests, as opposed to internally-generated autosuspend or autoresume. It also changes the existing remote-wakeup code paths to use the new routines, since remote wakeup is not the same as autoresume. As part of the change, it turns out to be necessary to do remote wakeup of root hubs from a workqueue. We had been using khubd, but it does autoresume rather than an external resume. Using the ksuspend_usb_wq workqueue for this purpose seemed a logical choice. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'drivers/usb/core/hub.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 7a6028599d62..19abe81babd5 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1855,12 +1855,7 @@ static int remote_wakeup(struct usb_device *udev) usb_lock_device(udev); if (udev->state == USB_STATE_SUSPENDED) { dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-"); - status = usb_autoresume_device(udev); - - /* Give the interface drivers a chance to do something, - * then autosuspend the device again. */ - if (status == 0) - usb_autosuspend_device(udev); + status = usb_external_resume_device(udev); } usb_unlock_device(udev); return status; @@ -1984,13 +1979,6 @@ static inline int remote_wakeup(struct usb_device *udev) #define hub_resume NULL #endif -void usb_resume_root_hub(struct usb_device *hdev) -{ - struct usb_hub *hub = hdev_to_hub(hdev); - - kick_khubd(hub); -} - /* USB 2.0 spec, 7.1.7.3 / fig 7-29: * -- cgit v1.2.1 From 9f8b17e643fe6aa505629658445849397bda4e4f Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Tue, 13 Mar 2007 15:59:31 +0100 Subject: USB: make usbdevices export their device nodes instead of using a separate class o The "real" usb-devices export now a device node which can populate /dev/bus/usb. o The usb_device class is optional now and can be disabled in the kernel config. Major/minor of the "real" devices and class devices are the same. o The environment of the usb-device event contains DEVNUM and BUSNUM to help udev and get rid of the ugly udev rule we need for the class devices. o The usb-devices and usb-interfaces share the same bus, so I used the new "struct device_type" to let these devices identify themselves. This also removes the current logic of using a magic platform-pointer. The name of the device_type is also added to the environment which makes it easier to distinguish the different kinds of devices on the same subsystem. It looks like this: add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1 ACTION=add DEVPATH=/devices/pci0000:00/0000:00:1d.1/usb2/2-1 SUBSYSTEM=usb SEQNUM=1533 MAJOR=189 MINOR=131 DEVTYPE=usb_device PRODUCT=46d/c03e/2000 TYPE=0/0/0 BUSNUM=002 DEVNUM=004 This udev rule works as a replacement for usb_device class devices: SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", \ NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0644" Updated patch, which needs the device_type patches in Greg's tree. I also got a bugzilla assigned for this. :) https://bugzilla.novell.com/show_bug.cgi?id=250659 Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/usb/core/hub.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 19abe81babd5..2a0b15e42bc7 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1367,11 +1367,15 @@ int usb_new_device(struct usb_device *udev) } #endif + /* export the usbdev device-node for libusb */ + udev->dev.devt = MKDEV(USB_DEVICE_MAJOR, + (((udev->bus->busnum-1) * 128) + (udev->devnum-1))); + /* Register the device. The device driver is responsible - * for adding the device files to usbfs and sysfs and for - * configuring the device. + * for adding the device files to sysfs and for configuring + * the device. */ - err = device_add (&udev->dev); + err = device_add(&udev->dev); if (err) { dev_err(&udev->dev, "can't device_add, error %d\n", err); goto fail; -- cgit v1.2.1 From 1941044aa9632aa8debbb94a3c8a5ed0ebddade8 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 27 Mar 2007 13:33:59 -0400 Subject: USB: add "last_busy" field for use in autosuspend This patch (as877) adds a "last_busy" field to struct usb_device, for use by the autosuspend framework. Now if an autosuspend call comes at a time when the device isn't busy but hasn't yet been idle for long enough, the timer can be set to exactly the desired value. And we will be ready to handle things like HID drivers, which can't maintain a useful usage count and must rely on the time-of-last-use to decide when to autosuspend. The patch also makes some related minor improvements: Move the calls to the autosuspend condition-checking routine into usb_suspend_both(), which is the only place where it really matters. If the autosuspend timer is already running, don't stop and restart it. Replace immediate returns with gotos so that the optional debugging ouput won't be bypassed. If autoresume is disabled but the device is already awake, don't return an error for an autoresume call. Don't try to autoresume a device if it isn't suspended. (Yes, this undercuts the previous change -- so sue me.) Don't duplicate existing code in the autosuspend work routine. Fix the kerneldoc in usb_autopm_put_interface(): If an autoresume call fails, the usage counter is left unchanged. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb/core/hub.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 2a0b15e42bc7..bde29ab2b504 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1859,6 +1859,7 @@ static int remote_wakeup(struct usb_device *udev) usb_lock_device(udev); if (udev->state == USB_STATE_SUSPENDED) { dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-"); + usb_mark_last_busy(udev); status = usb_external_resume_device(udev); } usb_unlock_device(udev); -- cgit v1.2.1