Re: [RFC PATCH v2 3/3] usb : Add sysfs files to control usb port's power

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, 1 Jun 2012, Lan Tianyu wrote:

> Change since v1: move sysfs files from usb hub device sysfs directory to usb
> hub interface sysfs directory.
> 
> This patch is to add two sys files for each usb hub ports to control port's power.
> Control port's power through setting or clearing PORT_POWER feature.
> 
> The new sys files is under the usb hub interface sysfs portx directory.
> ls /sys/bus/usb/devices/1-0:1.0
> bAlternateSetting  bInterfaceClass  bInterfaceNumber  bInterfaceProtocol
> bInterfaceSubClass  bNumEndpoints  driver  ep_81  modalias  power
> subsystem  supports_autosuspend  uevent port1 port2 port3 port4
> 
> ls /sys/bus/usb/devices/1-0:1.0/port1
> control state

You need to add entries to Documentation/ABI explaining these new 
files.

> control has three options. "auto", "on" and "off"
> "auto" - if port without device, power off the port.
> 	(This patch only cover ports without device)

Is this option really needed?  Can't userspace check first to see
whether there is a device, and then write "off" if there isn't?

> 	 For ports with device, there is a proposal that if the device was not
> 	in the suspend at that pointer, the power would remain on but it would
> 	power off when it was suspended. If the the device was in the suspend,
> 	"auto" means the device could be put into much lower state so the device
> 	need to resume and suspend again.

That makes more sense.  Without this, however, there is no need for 
"auto".

> "on" - port must be power on.
> "off" - port must be power off.
> 
> state reports usb ports' power state
> "on" - power on
> "off" - power off
> "error" - can't get power state
> 
> Signed-off-by: Lan Tianyu <tianyu.lan@xxxxxxxxx>
> ---
>  drivers/usb/core/hub.c |  181 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 181 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
> index 2ed5244..612eb2d 100644
> --- a/drivers/usb/core/hub.c
> +++ b/drivers/usb/core/hub.c
> @@ -41,12 +41,23 @@
>  #endif
>  #endif
>  
> +enum port_power_policy {
> +	USB_PORT_POWER_AUTO = 0,
> +	USB_PORT_POWER_ON,

USB_PORT_POWER_ON should be 0, because that is the default policy.

> +	USB_PORT_POWER_OFF,
> +};
> +
>  struct usb_hub_port {
>  	void			*port_owner;
>  	struct usb_device	*child;
>  #ifdef CONFIG_ACPI
>  	acpi_handle		port_acpi_handle;
>  #endif
> +	struct attribute_group	port_attr_group;
> +	struct attribute *port_attrs[3];

You don't really need these pointers.  The attribute files can be added 
to and removed from the group by hand, one at a time.

> @@ -97,6 +108,13 @@ struct usb_hub {
>  	struct usb_hub_port	*port_data;
>  };
>  
> +static const char on_string[] = "on";
> +static const char off_string[] = "off";
> +static const char auto_string[] = "auto";
> +static char port_name[USB_MAXCHILDREN][10];

Use [8] instead of [10].  The names are never more than 6 characters.

> @@ -466,6 +484,14 @@ static int set_port_feature(struct usb_device *hdev, int port1, int feature)
>  		NULL, 0, 1000);
>  }
>  
> +static void usb_set_hub_port_power(struct usb_device *hdev, int port1, bool enabled)
> +{
> +	if (enabled)
> +		set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
> +	else
> +		clear_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
> +}

This function isn't needed at all.  Just call set_port_feature() or 
clear_port_feature() directly.

> @@ -2558,6 +2586,27 @@ static int port_is_power_on(struct usb_hub *hub, unsigned portstatus)
>  	return ret;
>  }
>  
> +static int usb_get_hub_port_power_state(struct usb_device *hdev, int port1)
> +{
> +	struct usb_hub *hub = hdev_to_hub(hdev);
> +	u16 portstatus;
> +	int ret;
> +
> +	mutex_lock(&hub->status_mutex);
> +	ret = get_hub_status(hub->hdev, &hub->status->hub);

I told you before: Don't use get_hub_status(); use get_port_status() 
instead.  Then you don't need to lock the status_mutex.

> @@ -4499,6 +4548,137 @@ static int hub_thread(void *__unused)
>  	return 0;
>  }
>  
> +static ssize_t show_port_power_state(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct usb_device *udev = to_usb_device(dev->parent);
> +	struct usb_hub_port *hub_port = container_of(attr,
> +		struct usb_hub_port, port_state_attr);
> +	const char *result;
> +	int port1;
> +
> +	if (sscanf(hub_port->port_attr_group.name, "port%d", &port1) != 1)
> +		return -EINVAL;
> +
> +	if (usb_get_hub_port_power_state(udev, port1) == 1)
> +		result = on_string;
> +	else if (!usb_get_hub_port_power_state(udev, port1))

Don't call usb_get_hub_port_power_state() twice.  Call it once and save 
the result.

> +static ssize_t show_port_power_control(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct usb_hub_port *hub_port = container_of(attr,
> +		struct usb_hub_port, port_control_attr);
> +	enum port_power_policy policy;
> +	int port1;
> +	const char *result;
> +
> +	if (sscanf(hub_port->port_attr_group.name, "port%d", &port1) != 1)
> +		return -EINVAL;

Why is this here?  port1 doesn't get used in this function.

> +	policy = hub_port->port_power_policy;
> +	switch (policy) {

You don't need a separate local variable for policy.  Just do

	switch (hub_port->port_power_policy) {

> +static void usb_hub_port_sysfs_add(struct usb_hub *hub)
> +{
> +	int i, rc;
> +
> +	for (i = 0; i < hub->hdev->maxchild; i++) {
> +		hub->port_data[i].port_control_attr = (struct device_attribute)
> +			__ATTR(control, 0777, show_port_power_control,
> +			store_port_power_control);
> +		hub->port_data[i].port_state_attr = (struct device_attribute)
> +			__ATTR(state, 0777, show_port_power_state, NULL);

Setting the permissions to 0777 doesn't seem like a very good idea.  Do 
you want any user on the system to be able to turn off power to your 
flash drive?

Also, why should the power_state attribute have write permission when 
it doesn't have a store method?

Alan Stern

--
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


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux