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 <gre...@linuxfoundation.org>
Cc: Alan Stern <st...@rowland.harvard.edu>
Signed-off-by: Dan Williams <dan.j.willi...@intel.com>
---
 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to