We jump through a few hoops to support maintaining a usb_port as a sibling of a
usb_device. Namely ->power_is_on and ->did_runtime_put are artifacts of
pm_ignore_children and the organization of the device tree. Re-organize the
hierarchy to enable using the runtime_status as the indicator of whether a
port should be active. To preserve the userspace abi a link from the hub to
the child device is provided.
Before:
# readlink -f /sys/devices/pci0000:00/0000:00:14.0/usb2/2-1
/sys/devices/pci0000:00/0000:00:14.0/usb2/2-1
+-------+
| hub |
+---^---+
|
+-----+----+
| |
+---+---+ +---+---+
| intf | |device |
+---^---+ +-------+
|
+---+---+
| port |
+-------+
After:
# readlink -f /sys/devices/pci0000:00/0000:00:14.0/usb2/2-1
/sys/devices/pci0000:00/0000:00:14.0/usb2/2-0:1.0/port1/2-1
+-------+
| hub |
+---^---+
|
+---+---+
| intf |
+---^---+
|
+---+---+
| port |
+---^---+
|
+---+---+
|device |
+-------+
Cc: Greg Kroah-Hartman <[email protected]>
Cc: Alan Stern <[email protected]>
Signed-off-by: Dan Williams <[email protected]>
---
drivers/usb/core/hub.c | 16 +++++-----------
drivers/usb/core/usb.c | 14 ++++++++++++--
2 files changed, 17 insertions(+), 13 deletions(-)
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 06cec635e703..b78eb4cdf5ed 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2066,9 +2066,9 @@ void usb_disconnect(struct usb_device **pdev)
if (udev->parent) {
struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
struct usb_port *port_dev = hub->ports[udev->portnum - 1];
+ struct usb_device *hdev = udev->parent;
- sysfs_remove_link(&udev->dev.kobj, "port");
- sysfs_remove_link(&port_dev->dev.kobj, "device");
+ sysfs_remove_link(&hdev->dev.kobj, dev_name(&udev->dev));
if (!port_dev->did_runtime_put)
pm_runtime_put(&port_dev->dev);
@@ -2377,19 +2377,13 @@ int usb_new_device(struct usb_device *udev)
if (udev->parent) {
struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
struct usb_port *port_dev = hub->ports[udev->portnum - 1];
+ struct usb_device *hdev = udev->parent;
- err = sysfs_create_link(&udev->dev.kobj,
- &port_dev->dev.kobj, "port");
+ err = sysfs_create_link(&hdev->dev.kobj, &udev->dev.kobj,
+ dev_name(&udev->dev));
if (err)
goto fail;
- err = sysfs_create_link(&port_dev->dev.kobj,
- &udev->dev.kobj, "device");
- if (err) {
- sysfs_remove_link(&udev->dev.kobj, "port");
- goto fail;
- }
-
pm_runtime_get_sync(&port_dev->dev);
}
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 4d1144990d4c..c55711420222 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -42,7 +42,7 @@
#include <linux/mm.h>
#include <linux/dma-mapping.h>
-#include "usb.h"
+#include "hub.h"
const char *usbcore_name = "usbcore";
@@ -458,6 +458,13 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
dev_set_name(&dev->dev, "usb%d", bus->busnum);
root_hub = 1;
} else {
+ struct usb_hub *hub = usb_hub_to_struct_hub(parent);
+
+ if (!hub) {
+ kfree(dev);
+ return NULL;
+ }
+
/* match any labeling on the hubs; it's one-based */
if (parent->devpath[0] == '0') {
snprintf(dev->devpath, sizeof dev->devpath,
@@ -476,7 +483,10 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
(15 << ((parent->level - 1)*4));
}
- dev->dev.parent = &parent->dev;
+ /* usb hierarchy is hub->device device-model hierarchy is
+ * hub->intf->port->device
+ */
+ dev->dev.parent = &hub->ports[port1 - 1]->dev;
dev_set_name(&dev->dev, "%d-%s", bus->busnum, dev->devpath);
/* hub driver sets up TT records */
--
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