Linux Audio

Check our new training course

Yocto / OpenEmbedded training

Feb 10-13, 2025
Register
Loading...
Note: File does not exist in v3.1.
  1/*
  2 * usb port device code
  3 *
  4 * Copyright (C) 2012 Intel Corp
  5 *
  6 * Author: Lan Tianyu <tianyu.lan@intel.com>
  7 *
  8 * This program is free software; you can redistribute it and/or modify
  9 * it under the terms of the GNU General Public License version 2 as
 10 * published by the Free Software Foundation.
 11 *
 12 * This program is distributed in the hope that it will be useful, but
 13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 14 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 15 * for more details.
 16 *
 17 */
 18
 19#include <linux/slab.h>
 20#include <linux/pm_qos.h>
 21
 22#include "hub.h"
 23
 24static const struct attribute_group *port_dev_group[];
 25
 26static ssize_t connect_type_show(struct device *dev,
 27				 struct device_attribute *attr, char *buf)
 28{
 29	struct usb_port *port_dev = to_usb_port(dev);
 30	char *result;
 31
 32	switch (port_dev->connect_type) {
 33	case USB_PORT_CONNECT_TYPE_HOT_PLUG:
 34		result = "hotplug";
 35		break;
 36	case USB_PORT_CONNECT_TYPE_HARD_WIRED:
 37		result = "hardwired";
 38		break;
 39	case USB_PORT_NOT_USED:
 40		result = "not used";
 41		break;
 42	default:
 43		result = "unknown";
 44		break;
 45	}
 46
 47	return sprintf(buf, "%s\n", result);
 48}
 49static DEVICE_ATTR_RO(connect_type);
 50
 51static struct attribute *port_dev_attrs[] = {
 52	&dev_attr_connect_type.attr,
 53	NULL,
 54};
 55
 56static struct attribute_group port_dev_attr_grp = {
 57	.attrs = port_dev_attrs,
 58};
 59
 60static const struct attribute_group *port_dev_group[] = {
 61	&port_dev_attr_grp,
 62	NULL,
 63};
 64
 65static void usb_port_device_release(struct device *dev)
 66{
 67	struct usb_port *port_dev = to_usb_port(dev);
 68
 69	kfree(port_dev);
 70}
 71
 72#ifdef CONFIG_PM_RUNTIME
 73static int usb_port_runtime_resume(struct device *dev)
 74{
 75	struct usb_port *port_dev = to_usb_port(dev);
 76	struct usb_device *hdev = to_usb_device(dev->parent->parent);
 77	struct usb_interface *intf = to_usb_interface(dev->parent);
 78	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
 79	int port1 = port_dev->portnum;
 80	int retval;
 81
 82	if (!hub)
 83		return -EINVAL;
 84
 85	usb_autopm_get_interface(intf);
 86	set_bit(port1, hub->busy_bits);
 87
 88	retval = usb_hub_set_port_power(hdev, hub, port1, true);
 89	if (port_dev->child && !retval) {
 90		/*
 91		 * Attempt to wait for usb hub port to be reconnected in order
 92		 * to make the resume procedure successful.  The device may have
 93		 * disconnected while the port was powered off, so ignore the
 94		 * return status.
 95		 */
 96		retval = hub_port_debounce_be_connected(hub, port1);
 97		if (retval < 0)
 98			dev_dbg(&port_dev->dev, "can't get reconnection after setting port  power on, status %d\n",
 99					retval);
100		usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE);
101		retval = 0;
102	}
103
104	clear_bit(port1, hub->busy_bits);
105	usb_autopm_put_interface(intf);
106	return retval;
107}
108
109static int usb_port_runtime_suspend(struct device *dev)
110{
111	struct usb_port *port_dev = to_usb_port(dev);
112	struct usb_device *hdev = to_usb_device(dev->parent->parent);
113	struct usb_interface *intf = to_usb_interface(dev->parent);
114	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
115	int port1 = port_dev->portnum;
116	int retval;
117
118	if (!hub)
119		return -EINVAL;
120
121	if (dev_pm_qos_flags(&port_dev->dev, PM_QOS_FLAG_NO_POWER_OFF)
122			== PM_QOS_FLAGS_ALL)
123		return -EAGAIN;
124
125	usb_autopm_get_interface(intf);
126	set_bit(port1, hub->busy_bits);
127	retval = usb_hub_set_port_power(hdev, hub, port1, false);
128	usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION);
129	usb_clear_port_feature(hdev, port1,	USB_PORT_FEAT_C_ENABLE);
130	clear_bit(port1, hub->busy_bits);
131	usb_autopm_put_interface(intf);
132	return retval;
133}
134#endif
135
136static const struct dev_pm_ops usb_port_pm_ops = {
137#ifdef CONFIG_PM_RUNTIME
138	.runtime_suspend =	usb_port_runtime_suspend,
139	.runtime_resume =	usb_port_runtime_resume,
140#endif
141};
142
143struct device_type usb_port_device_type = {
144	.name =		"usb_port",
145	.release =	usb_port_device_release,
146	.pm =		&usb_port_pm_ops,
147};
148
149int usb_hub_create_port_device(struct usb_hub *hub, int port1)
150{
151	struct usb_port *port_dev = NULL;
152	int retval;
153
154	port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL);
155	if (!port_dev) {
156		retval = -ENOMEM;
157		goto exit;
158	}
159
160	hub->ports[port1 - 1] = port_dev;
161	port_dev->portnum = port1;
162	port_dev->power_is_on = true;
163	port_dev->dev.parent = hub->intfdev;
164	port_dev->dev.groups = port_dev_group;
165	port_dev->dev.type = &usb_port_device_type;
166	dev_set_name(&port_dev->dev, "port%d", port1);
167
168	retval = device_register(&port_dev->dev);
169	if (retval)
170		goto error_register;
171
172	pm_runtime_set_active(&port_dev->dev);
173
174	/* It would be dangerous if user space couldn't
175	 * prevent usb device from being powered off. So don't
176	 * enable port runtime pm if failed to expose port's pm qos.
177	 */
178	if (!dev_pm_qos_expose_flags(&port_dev->dev,
179			PM_QOS_FLAG_NO_POWER_OFF))
180		pm_runtime_enable(&port_dev->dev);
181
182	device_enable_async_suspend(&port_dev->dev);
183	return 0;
184
185error_register:
186	put_device(&port_dev->dev);
187exit:
188	return retval;
189}
190
191void usb_hub_remove_port_device(struct usb_hub *hub,
192				       int port1)
193{
194	device_unregister(&hub->ports[port1 - 1]->dev);
195}
196