On Fri, 9 Nov 2012, Lan Tianyu wrote:
> This patch is to add usb port auto power off mechanism.
> When usb device is suspending, usb core will send clear usb port's
> POWER feature requst to power off port if all conditions were met.
> These conditions are remote wakeup enable, pm qos NO_POWER_OFF flags
> and persist feature. When device is suspended and power off, usb core
You got the conditions wrong. You need remote wakeup to be
disabled, NO_POWER_OFF clear, and persist enabled.
> will ignore port's connect and enable change event to keep the device
> not being disconnected. When it resumes, power on port again.
> @@ -47,6 +48,7 @@ struct usb_port {
> struct device dev;
> struct dev_state *port_owner;
> enum usb_port_connect_type connect_type;
> + unsigned power_state:1;
What's with the peculiar spacing?
> };
>
> struct usb_hub {
> @@ -166,6 +168,11 @@ MODULE_PARM_DESC(use_both_schemes,
> DECLARE_RWSEM(ehci_cf_port_reset_rwsem);
> EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem);
>
> +#define USB_PORT_POWER_STATE_ON 0
> +#define USB_PORT_POWER_STATE_OFF 1
Just call the new field power_on (and make it bool rather than
unsigned). Then these symbols won't be needed.
> @@ -2970,6 +2984,23 @@ int usb_port_suspend(struct usb_device *udev,
> pm_message_t msg)
> udev->port_is_suspended = 1;
> msleep(10);
> }
> +
> + /*
> + * Check whether current status is meeting requirement of
> + * usb port power off mechanism
> + */
> + if (!udev->do_remote_wakeup
> + && !(dev_pm_qos_flags(&port_dev->dev,
> + PM_QOS_FLAG_NO_POWER_OFF) == PM_QOS_FLAGS_ALL)
Why write it this complicated way? Just use !=.
> + && udev->persist_enabled
> + && !status) {
> + port_dev->power_state = USB_PORT_POWER_STATE_OFF;
> + if (clear_port_feature(udev->parent, port1,
> + USB_PORT_FEAT_POWER)) {
> + port_dev->power_state = USB_PORT_POWER_STATE_ON;
Do this the other way around: If clear_port_feature() succeeds, clear
port_dev->power_on.
> @@ -3094,6 +3144,25 @@ int usb_port_resume(struct usb_device *udev,
> pm_message_t msg)
> int status;
> u16 portchange, portstatus;
>
> +
> + set_bit(port1, hub->busy_bits);
> +
> + if (hub->ports[port1 - 1]->power_state == USB_PORT_POWER_STATE_OFF) {
> + set_port_feature(udev->parent, port1, USB_PORT_FEAT_POWER);
At this point you should set the port's power_on flag.
> +
> + /*
> + * Wait for usb hub port to be reconnected in order to make
> + * the resume procedure successful.
> + */
> + status = usb_port_wait_for_connected(hub, port1);
> + if (status < 0) {
> + dev_dbg(&udev->dev, "can't get reconnection after
> setting port power on, status %d\n",
> + status);
> + return status;
> + }
> + hub->ports[port1 - 1]->power_state = USB_PORT_POWER_STATE_ON;
Not here. The way you've got it, the power_on flag will be wrong if
usb_port_wait_for_connected fails.
Alan Stern
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html