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 <gregkh@xxxxxxxxxxxxxxxxxxx> Cc: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> Signed-off-by: Dan Williams <dan.j.williams@xxxxxxxxx> --- 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html