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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to