[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