On 2013/3/29 1:49, Alan Stern wrote:
On Fri, 29 Mar 2013, Lan Tianyu wrote:
On 2013/3/29 0:50, Alan Stern wrote:
On Fri, 29 Mar 2013, Lan Tianyu wrote:
About the path "usb: Add usb port system pm support", do you think it's
ok?
Generally yes. But why doesn't usb_port_system_suspend check for any
PM_QOS constraints? Either on the port itself or on the child device.
Because usb_port_runtime_suspend() will PM Qos flags. If add check in
usb_port_system_suspend(), PM Qos flags would be checked twice and
this seems redundant.
Yes, that's right -- I noticed this the first time I read the patch and
then forgot it again.
I don't see any other problems with that patch.
Alan Stern
Ok. I just refresh patch "usb: introduce usb force power off mechanism"
Please have a look.
From 16f5c7c6dd00830530a9ac758af25b575e0b8731 Mon Sep 17 00:00:00 2001
From: Lan Tianyu <tianyu.lan@xxxxxxxxx>
Date: Tue, 26 Feb 2013 11:12:09 +0800
Subject: [PATCH] usb: introduce usb force power off mechanism
Some devices' firmware will be broken at some points. Power down
and power on device can help device to rework in this case.
This patch is to add ioctl cmd USBDEVFS_POWER_RESET for usbfs node
to repower usb device. First, call hub_port_logical_disconnect() to
disconnect device. Second, Power down and up usb port.
This patch is also helpful fo some QAs who want to do hcd's memleak
test(Plug and unplug device thousand times.)
Signed-off-by: Lan Tianyu <tianyu.lan@xxxxxxxxx>
---
drivers/usb/core/devio.c | 16 ++++++++++++++++
drivers/usb/core/hub.c | 27 +++++++++++++++++++++++++++
drivers/usb/core/usb.h | 2 ++
include/uapi/linux/usbdevice_fs.h | 1 +
4 files changed, 46 insertions(+)
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 8823e98..951e904 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -1102,6 +1102,17 @@ static int proc_resetdevice(struct dev_state *ps)
return usb_reset_device(ps->dev);
}
+static int proc_resetdevicepower(struct dev_state *ps)
+{
+ struct usb_device *udev = ps->dev;
+ struct usb_device *hdev = udev->parent;
+
+ if (!hdev)
+ return -EINVAL;
+
+ return usb_hub_port_power_reset(hdev, udev->portnum);
+}
+
static int proc_setintf(struct dev_state *ps, void __user *arg)
{
struct usbdevfs_setinterface setintf;
@@ -2011,6 +2022,11 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
ret = proc_resetdevice(ps);
break;
+ case USBDEVFS_POWER_RESET:
+ snoop(&dev->dev, "%s: RESET POWER\n", __func__);
+ ret = proc_resetdevicepower(ps);
+ break;
+
case USBDEVFS_CLEAR_HALT:
snoop(&dev->dev, "%s: CLEAR_HALT\n", __func__);
ret = proc_clearhalt(ps, p);
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 6b7f5b9..9729e36 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -948,6 +948,33 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
}
/**
+ * usb_hub_port_power_reset - repower hub port
+ * @hdev: USB device belonging to the usb hub
+ * @port1: port num to be repowered.
+ *
+ * This routine will try to disconnect the device on
+ * the port and then repower the port.
+ */
+int usb_hub_port_power_reset(struct usb_device *hdev, int port1)
+{
+ struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
+ struct usb_interface *intf = to_usb_interface(hub->intfdev);
+ int ret;
+
+ usb_autopm_get_interface(intf);
+ hub_port_logical_disconnect(hub, port1);
+ ret = usb_hub_set_port_power(hdev, port1, false);
+ if (!ret) {
+ /* Wait for power down device */
+ msleep(500);
+ ret = usb_hub_set_port_power(hdev, port1, true);
+ }
+ usb_autopm_put_interface(intf);
+
+ return ret;
+}
+
+/**
* usb_remove_device - disable a device's port on its parent hub
* @udev: device to be disabled and removed
* Context: @udev locked, must be able to sleep.
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index a7f20bd..4e7785c 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -185,6 +185,8 @@ extern void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1,
enum usb_port_connect_type type);
extern void usb_hub_adjust_deviceremovable(struct usb_device *hdev,
struct usb_hub_descriptor *desc);
+extern int usb_hub_port_power_reset(struct usb_device *hdev,
+ int port1);
#ifdef CONFIG_ACPI
extern int usb_acpi_register(void);
diff --git a/include/uapi/linux/usbdevice_fs.h b/include/uapi/linux/usbdevice_fs.h
index 0c65e4b..b6e0d17 100644
--- a/include/uapi/linux/usbdevice_fs.h
+++ b/include/uapi/linux/usbdevice_fs.h
@@ -176,5 +176,6 @@ struct usbdevfs_disconnect_claim {
#define USBDEVFS_RELEASE_PORT _IOR('U', 25, unsigned int)
#define USBDEVFS_GET_CAPABILITIES _IOR('U', 26, __u32)
#define USBDEVFS_DISCONNECT_CLAIM _IOR('U', 27, struct usbdevfs_disconnect_claim)
+#define USBDEVFS_POWER_RESET _IO('U', 28)
#endif /* _UAPI_LINUX_USBDEVICE_FS_H */
--
1.7.10.4
--
Best Regards
Tianyu Lan
linux kernel enabling team
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html