linux-stable/drivers/usb/core/port.c
Alan Stern 84ebc10294 USB: remove CONFIG_USB_SUSPEND option
This patch (as1675) removes the CONFIG_USB_SUSPEND option, essentially
replacing it everywhere with CONFIG_PM_RUNTIME (except for one place
in hub.c, where it is replaced with CONFIG_PM because the code needs
to be used in both runtime and system PM).  The net result is code
shrinkage and simplification.

There's very little point in keeping CONFIG_USB_SUSPEND because almost
everybody enables it.  The few that don't will find that the usbcore
module has gotten somewhat bigger and they will have to take active
measures if they want to prevent hubs from being runtime suspended.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
CC: Peter Chen <peter.chen@freescale.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-03-28 11:10:22 -07:00

202 lines
4.9 KiB
C

/*
* usb port device code
*
* Copyright (C) 2012 Intel Corp
*
* Author: Lan Tianyu <tianyu.lan@intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
*/
#include <linux/slab.h>
#include <linux/pm_qos.h>
#include "hub.h"
static const struct attribute_group *port_dev_group[];
static ssize_t show_port_connect_type(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_port *port_dev = to_usb_port(dev);
char *result;
switch (port_dev->connect_type) {
case USB_PORT_CONNECT_TYPE_HOT_PLUG:
result = "hotplug";
break;
case USB_PORT_CONNECT_TYPE_HARD_WIRED:
result = "hardwired";
break;
case USB_PORT_NOT_USED:
result = "not used";
break;
default:
result = "unknown";
break;
}
return sprintf(buf, "%s\n", result);
}
static DEVICE_ATTR(connect_type, S_IRUGO, show_port_connect_type,
NULL);
static struct attribute *port_dev_attrs[] = {
&dev_attr_connect_type.attr,
NULL,
};
static struct attribute_group port_dev_attr_grp = {
.attrs = port_dev_attrs,
};
static const struct attribute_group *port_dev_group[] = {
&port_dev_attr_grp,
NULL,
};
static void usb_port_device_release(struct device *dev)
{
struct usb_port *port_dev = to_usb_port(dev);
dev_pm_qos_hide_flags(dev);
kfree(port_dev);
}
#ifdef CONFIG_PM_RUNTIME
static int usb_port_runtime_resume(struct device *dev)
{
struct usb_port *port_dev = to_usb_port(dev);
struct usb_device *hdev = to_usb_device(dev->parent->parent);
struct usb_interface *intf = to_usb_interface(dev->parent);
struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
int port1 = port_dev->portnum;
int retval;
if (!hub)
return -EINVAL;
usb_autopm_get_interface(intf);
set_bit(port1, hub->busy_bits);
retval = usb_hub_set_port_power(hdev, port1, true);
if (port_dev->child && !retval) {
/*
* Wait for usb hub port to be reconnected in order to make
* the resume procedure successful.
*/
retval = hub_port_debounce_be_connected(hub, port1);
if (retval < 0) {
dev_dbg(&port_dev->dev, "can't get reconnection after setting port power on, status %d\n",
retval);
goto out;
}
usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE);
/* Set return value to 0 if debounce successful */
retval = 0;
}
out:
clear_bit(port1, hub->busy_bits);
usb_autopm_put_interface(intf);
return retval;
}
static int usb_port_runtime_suspend(struct device *dev)
{
struct usb_port *port_dev = to_usb_port(dev);
struct usb_device *hdev = to_usb_device(dev->parent->parent);
struct usb_interface *intf = to_usb_interface(dev->parent);
struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
int port1 = port_dev->portnum;
int retval;
if (!hub)
return -EINVAL;
if (dev_pm_qos_flags(&port_dev->dev, PM_QOS_FLAG_NO_POWER_OFF)
== PM_QOS_FLAGS_ALL)
return -EAGAIN;
usb_autopm_get_interface(intf);
set_bit(port1, hub->busy_bits);
retval = usb_hub_set_port_power(hdev, port1, false);
usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION);
usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE);
clear_bit(port1, hub->busy_bits);
usb_autopm_put_interface(intf);
return retval;
}
#endif
static const struct dev_pm_ops usb_port_pm_ops = {
#ifdef CONFIG_PM_RUNTIME
.runtime_suspend = usb_port_runtime_suspend,
.runtime_resume = usb_port_runtime_resume,
.runtime_idle = pm_generic_runtime_idle,
#endif
};
struct device_type usb_port_device_type = {
.name = "usb_port",
.release = usb_port_device_release,
.pm = &usb_port_pm_ops,
};
int usb_hub_create_port_device(struct usb_hub *hub, int port1)
{
struct usb_port *port_dev = NULL;
int retval;
port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL);
if (!port_dev) {
retval = -ENOMEM;
goto exit;
}
hub->ports[port1 - 1] = port_dev;
port_dev->portnum = port1;
port_dev->power_is_on = true;
port_dev->dev.parent = hub->intfdev;
port_dev->dev.groups = port_dev_group;
port_dev->dev.type = &usb_port_device_type;
dev_set_name(&port_dev->dev, "port%d", port1);
retval = device_register(&port_dev->dev);
if (retval)
goto error_register;
pm_runtime_set_active(&port_dev->dev);
/* It would be dangerous if user space couldn't
* prevent usb device from being powered off. So don't
* enable port runtime pm if failed to expose port's pm qos.
*/
if (!dev_pm_qos_expose_flags(&port_dev->dev,
PM_QOS_FLAG_NO_POWER_OFF))
pm_runtime_enable(&port_dev->dev);
device_enable_async_suspend(&port_dev->dev);
return 0;
error_register:
put_device(&port_dev->dev);
exit:
return retval;
}
void usb_hub_remove_port_device(struct usb_hub *hub,
int port1)
{
device_unregister(&hub->ports[port1 - 1]->dev);
}