This patch is to make usb port a real device under usb hub interface. Signed-off-by: Lan Tianyu <tianyu.lan@xxxxxxxxx> --- drivers/usb/core/hub.c | 78 ++++++++++++++++++++++++++++++++++++++--------- 1 files changed, 63 insertions(+), 15 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 0d68dcc..f6bbd84 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -37,6 +37,12 @@ #endif #endif +struct usb_port { + struct usb_device *udev; + struct device dev; + struct dev_state *port_owner; +}; + struct usb_hub { struct device *intfdev; /* the "interface" device */ struct usb_device *hdev; @@ -81,7 +87,11 @@ struct usb_hub { u8 indicator[USB_MAXCHILDREN]; struct delayed_work leds; struct delayed_work init_work; - struct dev_state **port_owners; + struct usb_port *ports; +}; + +struct device_type usb_port_device_type = { + .name = "usb_port", }; static inline int hub_is_superspeed(struct usb_device *hdev) @@ -154,6 +164,8 @@ EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem); #define HUB_DEBOUNCE_STEP 25 #define HUB_DEBOUNCE_STABLE 100 +#define to_usb_port(_dev) \ + container_of(_dev, struct usb_port, dev) static int usb_reset_and_verify_device(struct usb_device *udev); @@ -1271,9 +1283,9 @@ static int hub_configure(struct usb_hub *hub, hdev->children = kzalloc(hdev->maxchild * sizeof(struct usb_device *), GFP_KERNEL); - hub->port_owners = kzalloc(hdev->maxchild * sizeof(struct dev_state *), - GFP_KERNEL); - if (!hdev->children || !hub->port_owners) { + hub->ports = kzalloc(hdev->maxchild * sizeof(struct usb_port), + GFP_KERNEL); + if (!hdev->children || !hub->ports) { ret = -ENOMEM; goto fail; } @@ -1500,12 +1512,43 @@ static void hub_release(struct kref *kref) kfree(hub); } +static void usb_hub_remove_port_device(struct usb_hub *hub, + int port1) +{ + device_unregister(&hub->ports[port1 - 1].dev); + hub->ports[port1 - 1].udev = NULL; +} + +static int usb_hub_create_port_device(struct usb_hub *hub, + int port1) +{ + struct usb_port *port_dev = &hub->ports[port1 - 1]; + int retval; + + port_dev->udev = hub->hdev; + port_dev->dev.parent = hub->intfdev; + 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; + +error_register: + put_device(&port_dev->dev); + return retval; +} + static unsigned highspeed_hubs; static void hub_disconnect(struct usb_interface *intf) { struct usb_hub *hub = usb_get_intfdata(intf); struct usb_device *hdev = interface_to_usbdev(intf); + int i; + + for (i = 0; i < hdev->maxchild; i++) + usb_hub_remove_port_device(hub, i + 1); /* Take the hub off the event list and don't let it be added again */ spin_lock_irq(&hub_event_lock); @@ -1528,7 +1571,7 @@ static void hub_disconnect(struct usb_interface *intf) usb_free_urb(hub->urb); kfree(hdev->children); - kfree(hub->port_owners); + kfree(hub->ports); kfree(hub->descriptor); kfree(hub->status); kfree(hub->buffer); @@ -1604,8 +1647,15 @@ descriptor_error: if (hdev->speed == USB_SPEED_HIGH) highspeed_hubs++; - if (hub_configure(hub, endpoint) >= 0) + if (hub_configure(hub, endpoint) >= 0) { + int i; + + for (i = 0; i < hdev->maxchild; i++) + if (usb_hub_create_port_device(hub, i + 1) < 0) + dev_err(&intf->dev, "couldn't create port%d " + "device.\n", i + 1); return 0; + } hub_disconnect (intf); return -ENODEV; @@ -1660,7 +1710,7 @@ static int find_port_owner(struct usb_device *hdev, unsigned port1, /* This assumes that devices not managed by the hub driver * will always have maxchild equal to 0. */ - *ppowner = &(hdev_to_hub(hdev)->port_owners[port1 - 1]); + *ppowner = &(hdev_to_hub(hdev)->ports[port1 - 1].port_owner); return 0; } @@ -1697,16 +1747,14 @@ int usb_hub_release_port(struct usb_device *hdev, unsigned port1, void usb_hub_release_all_ports(struct usb_device *hdev, struct dev_state *owner) { + struct usb_hub *hub = hdev_to_hub(hdev); int n; - struct dev_state **powner; - n = find_port_owner(hdev, 1, &powner); - if (n == 0) { - for (; n < hdev->maxchild; (++n, ++powner)) { - if (*powner == owner) - *powner = NULL; - } + for (n = 0; n < hdev->maxchild; n++) { + if (hub->ports[n].port_owner == owner) + hub->ports[n].port_owner = NULL; } + } /* The caller must hold udev's lock */ @@ -1717,7 +1765,7 @@ bool usb_device_is_owned(struct usb_device *udev) if (udev->state == USB_STATE_NOTATTACHED || !udev->parent) return false; hub = hdev_to_hub(udev->parent); - return !!hub->port_owners[udev->portnum - 1]; + return !!hub->ports[udev->portnum - 1].port_owner; } -- 1.7.6.rc2.8.g28eb -- 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