[prev in list] [next in list] [prev in thread] [next in thread]
List: moblin-commits
Subject: [Moblin-Commits] kernel-mid: Changes to 'master'
From: xdu1 () moblin ! org (Alek Du)
Date: 2008-02-29 0:47:25
Message-ID: 20080229084723.EEE6C1E74001 () moblin ! org
[Download RAW message or body]
debian/changelog | 3 +-
debian/patches/00list | 2 +-
debian/patches/usb_highspeed_hub_resume_fix.dpatch | 20 -
debian/patches/usb_reset_resume.dpatch | 462 ++++++++++++++++++++
4 files changed, 465 insertions(+), 22 deletions(-)
New commits:
commit 8d73c774fa43909067e8182f7ab1027267a7bde4
Author: Alek Du <alek.du@intel.com>
Date: Fri Feb 29 11:41:30 2008 +0800
* A better way to fix reset_resume quirk USB devices
Diff in this email is a maximum of 400 lines.
diff --git a/debian/changelog b/debian/changelog
index e7106be..4b31ee9 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -12,8 +12,9 @@ kernel-mid-2.6.22 (2.6.22-25) UNRELEASED; urgency=low
[ Alek Du ]
* Modified "Unknown stepping" from HDA patch
+ * A better way to fix reset_resume quirk USB devices
- -- Alek Du <alek.du@intel.com> Thu, 28 Feb 2008 10:24:27 +0800
+ -- Alek Du <alek.du@intel.com> Fri, 29 Feb 2008 11:40:11 +0800
kernel-mid-2.6.22 (2.6.22-24) gaston; urgency=low
diff --git a/debian/patches/00list b/debian/patches/00list
index 8cfb44a..63a4002 100755
--- a/debian/patches/00list
+++ b/debian/patches/00list
@@ -37,4 +37,4 @@ poulsbo_USBC
# workaround for fix touch screen double-click issue
ts_doubleclick_workaround.dpatch
legacy_usb_int_fix.dpatch
-usb_highspeed_hub_resume_fix
+usb_reset_resume.dpatch
diff --git a/debian/patches/usb_highspeed_hub_resume_fix.dpatch \
b/debian/patches/usb_highspeed_hub_resume_fix.dpatch deleted file mode 100755
index 5d325a2..0000000
--- a/debian/patches/usb_highspeed_hub_resume_fix.dpatch
+++ /dev/null
@@ -1,20 +0,0 @@
-#! /bin/sh /usr/share/dpatch/dpatch-run
-diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
-index bc93e06..3d9a925 100644
---- a/drivers/usb/core/hub.c
-+++ b/drivers/usb/core/hub.c
-@@ -2722,6 +2722,14 @@ static void hub_events(void)
- connect_change = 1;
- }
-
-+ /* Fixed High speed HUB S3 resume issue */
-+ if ((portstatus & USB_PORT_STAT_CONNECTION) &&
-+ (portstatus & USB_PORT_STAT_ENABLE) &&
-+ (portstatus & USB_PORT_STAT_HIGH_SPEED) &&
-+ (portstatus & USB_PORT_STAT_POWER)){
-+ connect_change = 1;
-+ }
-+
- if (portchange & USB_PORT_STAT_C_ENABLE) {
- if (!connect_change)
- dev_dbg (hub_dev,
diff --git a/debian/patches/usb_reset_resume.dpatch \
b/debian/patches/usb_reset_resume.dpatch new file mode 100755
index 0000000..792a735
--- /dev/null
+++ b/debian/patches/usb_reset_resume.dpatch
@@ -0,0 +1,462 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
+index d91b9da..67f949f 100644
+--- a/drivers/hid/usbhid/hid-core.c
++++ b/drivers/hid/usbhid/hid-core.c
+@@ -1064,20 +1064,22 @@ static int hid_resume(struct usb_interface *intf)
+ }
+
+ /* Treat USB reset pretty much the same as suspend/resume */
+-static void hid_pre_reset(struct usb_interface *intf)
++static int hid_pre_reset(struct usb_interface *intf)
+ {
+ /* FIXME: What if the interface is already suspended? */
+ hid_suspend(intf, PMSG_ON);
++ return 0;
+ }
+
+-static void hid_post_reset(struct usb_interface *intf)
++/* Same routine used for post_reset and reset_resume */
++static int hid_post_reset(struct usb_interface *intf)
+ {
+ struct usb_device *dev = interface_to_usbdev (intf);
+
+ hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0);
+ /* FIXME: Any more reinitialization needed? */
+
+- hid_resume(intf);
++ return hid_resume(intf);
+ }
+
+ static struct usb_device_id hid_usb_ids [] = {
+@@ -1094,6 +1096,7 @@ static struct usb_driver hid_driver = {
+ .disconnect = hid_disconnect,
+ .suspend = hid_suspend,
+ .resume = hid_resume,
++ .reset_resume = hid_post_reset,
+ .pre_reset = hid_pre_reset,
+ .post_reset = hid_post_reset,
+ .id_table = hid_usb_ids,
+diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
+index 61699f7..39f141c 100644
+--- a/drivers/usb/core/driver.c
++++ b/drivers/usb/core/driver.c
+@@ -24,6 +24,7 @@
+
+ #include <linux/device.h>
+ #include <linux/usb.h>
++#include <linux/usb/quirks.h>
+ #include <linux/workqueue.h>
+ #include "hcd.h"
+ #include "usb.h"
+@@ -835,6 +836,9 @@ static int usb_resume_device(struct usb_device *udev)
+ goto done;
+ }
+
++ if (udev->quirks & USB_QUIRK_RESET_RESUME)
++ udev->reset_resume = 1;
++
+ udriver = to_usb_device_driver(udev->dev.driver);
+ status = udriver->resume(udev);
+
+@@ -885,7 +889,7 @@ done:
+ }
+
+ /* Caller has locked intf's usb_device's pm_mutex */
+-static int usb_resume_interface(struct usb_interface *intf)
++static int usb_resume_interface(struct usb_interface *intf, int reset_resume)
+ {
+ struct usb_driver *driver;
+ int status = 0;
+@@ -905,23 +909,43 @@ static int usb_resume_interface(struct usb_interface *intf)
+ }
+ driver = to_usb_driver(intf->dev.driver);
+
+- if (driver->resume) {
+- status = driver->resume(intf);
+- if (status)
+- dev_err(&intf->dev, "%s error %d\n",
+- "resume", status);
+- else
+- mark_active(intf);
++ if (reset_resume) {
++ if (driver->reset_resume) {
++ status = driver->reset_resume(intf);
++ if (status)
++ dev_err(&intf->dev, "%s error %d\n",
++ "reset_resume", status);
++ } else {
++ struct usb_device *udev = interface_to_usbdev(intf);
++ struct usb_device *parent_hdev = udev->parent;
++ /* status = -EOPNOTSUPP; */
++ dev_warn(&intf->dev, "no %s for driver %s?\n",
++ "reset_resume", driver->name);
++ if (parent_hdev) {
++ struct usb_hub *parent_hub = \
usb_get_intfdata(parent_hdev->actconfig->interface[0]); \
++ hub_port_logical_disconnect(parent_hub, udev->portnum); ++ }
++ }
+ } else {
+- dev_warn(&intf->dev, "no resume for driver %s?\n",
+- driver->name);
+- mark_active(intf);
++ if (driver->resume) {
++ status = driver->resume(intf);
++ if (status)
++ dev_err(&intf->dev, "%s error %d\n",
++ "resume", status);
++ } else {
++ /* status = -EOPNOTSUPP; */
++ dev_warn(&intf->dev, "no %s for driver %s?\n",
++ "resume", driver->name);
++ }
+ }
+
+ done:
+ // dev_dbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
+ if (status == 0)
+- intf->dev.power.power_state.event = PM_EVENT_ON;
++ mark_active(intf);
++
++ /* FIXME: Unbind the driver and reprobe if the resume failed
++ * (not possible if auto_pm is set) */
+ return status;
+ }
+
+@@ -958,6 +982,18 @@ static int autosuspend_check(struct usb_device *udev)
+ "for autosuspend\n");
+ return -EOPNOTSUPP;
+ }
++
++ /* Don't allow autosuspend if the device will need
++ * a reset-resume and any of its interface drivers
++ * doesn't include support.
++ */
++ if (udev->quirks & USB_QUIRK_RESET_RESUME) {
++ struct usb_driver *driver;
++
++ driver = to_usb_driver(intf->dev.driver);
++ if (!driver->reset_resume)
++ return -EOPNOTSUPP;
++ }
+ }
+ }
+
+@@ -1061,7 +1097,7 @@ static int usb_suspend_both(struct usb_device *udev, \
pm_message_t msg) + if (status != 0) {
+ while (--i >= 0) {
+ intf = udev->actconfig->interface[i];
+- usb_resume_interface(intf);
++ usb_resume_interface(intf, 0);
+ }
+
+ /* Try another autosuspend when the interfaces aren't busy */
+@@ -1131,7 +1167,8 @@ static int usb_resume_both(struct usb_device *udev)
+ status = usb_autoresume_device(parent);
+ if (status == 0) {
+ status = usb_resume_device(udev);
+- if (status) {
++ if (status || udev->state ==
++ USB_STATE_NOTATTACHED) {
+ usb_autosuspend_device(parent);
+
+ /* It's possible usb_resume_device()
+@@ -1168,7 +1205,7 @@ static int usb_resume_both(struct usb_device *udev)
+ if (status == 0 && udev->actconfig) {
+ for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
+ intf = udev->actconfig->interface[i];
+- usb_resume_interface(intf);
++ usb_resume_interface(intf, udev->reset_resume);
+ }
+ }
+
+diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
+index bc93e06..c112534 100644
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -572,32 +572,31 @@ static int hub_port_disable(struct usb_hub *hub, int port1, \
int set_state) +
+
+ /* caller has locked the hub device */
+-static void hub_pre_reset(struct usb_interface *intf)
++static int hub_pre_reset(struct usb_interface *intf)
+ {
+ struct usb_hub *hub = usb_get_intfdata(intf);
+ struct usb_device *hdev = hub->hdev;
+- int port1;
++ int i;
+
+- for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
+- if (hdev->children[port1 - 1]) {
+- usb_disconnect(&hdev->children[port1 - 1]);
+- if (hub->error == 0)
+- hub_port_disable(hub, port1, 0);
+- }
++ /* Disconnect all the children */
++ for (i = 0; i < hdev->maxchild; ++i) {
++ if (hdev->children[i])
++ usb_disconnect(&hdev->children[i]);
+ }
+ hub_quiesce(hub);
++ return 0;
+ }
+
+ /* caller has locked the hub device */
+-static void hub_post_reset(struct usb_interface *intf)
++static int hub_post_reset(struct usb_interface *intf)
+ {
+ struct usb_hub *hub = usb_get_intfdata(intf);
+
+- hub_activate(hub);
+ hub_power_on(hub);
++ hub_activate(hub);
++ return 0;
+ }
+
+-
+ static int hub_configure(struct usb_hub *hub,
+ struct usb_endpoint_descriptor *endpoint)
+ {
+@@ -1577,7 +1576,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
+ * time later khubd will disconnect() any existing usb_device on the port
+ * and will re-enumerate if there actually is a device attached.
+ */
+-static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
++void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
+ {
+ dev_dbg(hub->intfdev, "logical disconnect on port %d\n", port1);
+ hub_port_disable(hub, port1, 1);
+@@ -1594,6 +1593,7 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, \
int port1) + set_bit(port1, hub->change_bits);
+ kick_khubd(hub);
+ }
++EXPORT_SYMBOL(hub_port_logical_disconnect);
+
+ #ifdef CONFIG_PM
+
+@@ -2005,6 +2005,26 @@ static int hub_resume(struct usb_interface *intf)
+ return 0;
+ }
+
++static int hub_reset_resume(struct usb_interface *intf)
++{
++ struct usb_hub *hub = usb_get_intfdata(intf);
++ struct usb_device *hdev = hub->hdev;
++ int port1;
++
++ hub_power_on(hub);
++
++ for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
++ struct usb_device *child = hdev->children[port1-1];
++
++ if (child) {
++ hub_port_logical_disconnect(hub, port1);
++ }
++ }
++
++ hub_activate(hub);
++ return 0;
++}
++
+ #else /* CONFIG_PM */
+
+ static inline int remote_wakeup(struct usb_device *udev)
+@@ -2012,8 +2032,9 @@ static inline int remote_wakeup(struct usb_device *udev)
+ return 0;
+ }
+
+-#define hub_suspend NULL
+-#define hub_resume NULL
++#define hub_suspend NULL
++#define hub_resume NULL
++#define hub_reset_resume NULL
+ #endif
+
+
+@@ -2859,6 +2880,7 @@ static struct usb_driver hub_driver = {
+ .disconnect = hub_disconnect,
+ .suspend = hub_suspend,
+ .resume = hub_resume,
++ .reset_resume = hub_reset_resume,
+ .pre_reset = hub_pre_reset,
+ .post_reset = hub_post_reset,
+ .ioctl = hub_ioctl,
+@@ -2961,6 +2983,11 @@ static int config_descriptors_changed(struct usb_device \
*udev) + * this from a driver probe() routine after downloading new firmware.
+ * For calls that might not occur during probe(), drivers should lock
+ * the device using usb_lock_device_for_reset().
++ *
++ * Locking exception: This routine may also be called from within an
++ * autoresume handler. Such usage won't conflict with other tasks
++ * holding the device lock because these tasks should always call
++ * usb_autopm_resume_device(), thereby preventing any unwanted autoresume.
+ */
+ int usb_reset_device(struct usb_device *udev)
+ {
+@@ -2991,7 +3018,7 @@ int usb_reset_device(struct usb_device *udev)
+ * Other endpoints will be handled by re-enumeration. */
+ ep0_reinit(udev);
+ ret = hub_port_init(parent_hub, udev, port1, i);
+- if (ret >= 0)
++ if (ret >= 0 || ret == -ENOTCONN || ret == -ENODEV)
+ break;
+ }
+ clear_bit(port1, parent_hub->busy_bits);
+diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
+index 739f520..fb138ad 100644
+--- a/drivers/usb/core/quirks.c
++++ b/drivers/usb/core/quirks.c
+@@ -35,6 +35,10 @@ static const struct usb_device_id usb_quirk_list[] = {
+ /* Elsa MicroLink 56k (V.250) */
+ { USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+
++ /* Philips PSC805 audio device */
++ { USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME },
++ /* ASIX Ethernet device */
++ { USB_DEVICE(0x0b95, 0x1720), .driver_info = USB_QUIRK_RESET_RESUME },
+ { } /* terminating entry must be last */
+ };
+
+diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
+index e227f64..1ba19ea 100644
+--- a/drivers/usb/storage/scsiglue.c
++++ b/drivers/usb/storage/scsiglue.c
+@@ -321,10 +321,14 @@ void usb_stor_report_device_reset(struct us_data *us)
+
+ /* Report a driver-initiated bus reset to the SCSI layer.
+ * Calling this for a SCSI-initiated reset is unnecessary but harmless.
+- * The caller must own the SCSI host lock. */
++ * The caller must not own the SCSI host lock. */
+ void usb_stor_report_bus_reset(struct us_data *us)
+ {
+- scsi_report_bus_reset(us_to_host(us), 0);
++ struct Scsi_Host *host = us_to_host(us);
++
++ scsi_lock(host);
++ scsi_report_bus_reset(host, 0);
++ scsi_unlock(host);
+ }
+
+ /***********************************************************************
+diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
+index 8e898e3..a4e6abe 100644
+--- a/drivers/usb/storage/usb.c
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic