usb: move struct usb_device->children to struct usb_hub_port->child
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / usb / core / hub.c
index a2aa9d6..6bf7124 100644 (file)
 #endif
 #endif
 
+struct usb_hub_port {
+       void                    *port_owner;
+       struct usb_device       *child;
+};
+
 struct usb_hub {
        struct device           *intfdev;       /* the "interface" device */
        struct usb_device       *hdev;
@@ -81,7 +86,7 @@ struct usb_hub {
        u8                      indicator[USB_MAXCHILDREN];
        struct delayed_work     leds;
        struct delayed_work     init_work;
-       void                    **port_owners;
+       struct usb_hub_port     *port_data;
 };
 
 static inline int hub_is_superspeed(struct usb_device *hdev)
@@ -89,7 +94,7 @@ static inline int hub_is_superspeed(struct usb_device *hdev)
        return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS);
 }
 
-/* Protect struct usb_device->state and ->children members
+/* Protect struct usb_device->state and struct usb_hub_port->child members
  * Note: Both are also protected by ->dev.sem, except that ->state can
  * change to USB_STATE_NOTATTACHED even when the semaphore isn't held. */
 static DEFINE_SPINLOCK(device_state_lock);
@@ -172,7 +177,7 @@ static inline char *portspeed(struct usb_hub *hub, int portstatus)
 /* Note that hdev or one of its children must be locked! */
 static struct usb_hub *hdev_to_hub(struct usb_device *hdev)
 {
-       if (!hdev || !hdev->actconfig)
+       if (!hdev || !hdev->actconfig || !hdev->maxchild)
                return NULL;
        return usb_get_intfdata(hdev->actconfig->interface[0]);
 }
@@ -645,8 +650,8 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
        struct usb_device *hdev = hub->hdev;
        int ret = 0;
 
-       if (hdev->children[port1-1] && set_state)
-               usb_set_device_state(hdev->children[port1-1],
+       if (hub->port_data[port1-1].child && set_state)
+               usb_set_device_state(hub->port_data[port1-1].child,
                                USB_STATE_NOTATTACHED);
        if (!hub->error && !hub_is_superspeed(hub->hdev))
                ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE);
@@ -802,7 +807,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
         * which ports need attention.
         */
        for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
-               struct usb_device *udev = hdev->children[port1-1];
+               struct usb_device *udev = hub->port_data[port1-1].child;
                u16 portstatus, portchange;
 
                portstatus = portchange = 0;
@@ -967,8 +972,8 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)
        if (type != HUB_SUSPEND) {
                /* Disconnect all the children */
                for (i = 0; i < hdev->maxchild; ++i) {
-                       if (hdev->children[i])
-                               usb_disconnect(&hdev->children[i]);
+                       if (hub->port_data[i].child)
+                               usb_disconnect(&hub->port_data[i].child);
                }
        }
 
@@ -1047,10 +1052,9 @@ static int hub_configure(struct usb_hub *hub,
        dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,
                (hdev->maxchild == 1) ? "" : "s");
 
-       hdev->children = kzalloc(hdev->maxchild *
-                               sizeof(struct usb_device *), GFP_KERNEL);
-       hub->port_owners = kzalloc(hdev->maxchild * sizeof(void *), GFP_KERNEL);
-       if (!hdev->children || !hub->port_owners) {
+       hub->port_data = kzalloc(hdev->maxchild * sizeof(struct usb_hub_port),
+                       GFP_KERNEL);
+       if (!hub->port_data) {
                ret = -ENOMEM;
                goto fail;
        }
@@ -1282,7 +1286,6 @@ 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);
 
        /* Take the hub off the event list and don't let it be added again */
        spin_lock_irq(&hub_event_lock);
@@ -1304,8 +1307,7 @@ static void hub_disconnect(struct usb_interface *intf)
                highspeed_hubs--;
 
        usb_free_urb(hub->urb);
-       kfree(hdev->children);
-       kfree(hub->port_owners);
+       kfree(hub->port_data);
        kfree(hub->descriptor);
        kfree(hub->status);
        kfree(hub->buffer);
@@ -1392,6 +1394,7 @@ static int
 hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
 {
        struct usb_device *hdev = interface_to_usbdev (intf);
+       struct usb_hub *hub = usb_get_intfdata(intf);
 
        /* assert ifno == 0 (part of hub spec) */
        switch (code) {
@@ -1405,11 +1408,11 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
                else {
                        info->nports = hdev->maxchild;
                        for (i = 0; i < info->nports; i++) {
-                               if (hdev->children[i] == NULL)
+                               if (hub->port_data[i].child == NULL)
                                        info->port[i] = 0;
                                else
                                        info->port[i] =
-                                               hdev->children[i]->devnum;
+                                               hub->port_data[i].child->devnum;
                        }
                }
                spin_unlock_irq(&device_state_lock);
@@ -1437,7 +1440,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)->port_data[port1 - 1].port_owner);
        return 0;
 }
 
@@ -1472,16 +1475,14 @@ int usb_hub_release_port(struct usb_device *hdev, unsigned port1, void *owner)
 
 void usb_hub_release_all_ports(struct usb_device *hdev, void *owner)
 {
+       struct usb_hub *hub = hdev_to_hub(hdev);
        int n;
-       void **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->port_data[n].port_owner == owner)
+                       hub->port_data[n].port_owner = NULL;
        }
+
 }
 
 /* The caller must hold udev's lock */
@@ -1492,17 +1493,19 @@ 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->port_data[udev->portnum - 1].port_owner;
 }
 
 
 static void recursively_mark_NOTATTACHED(struct usb_device *udev)
 {
+       struct usb_hub  *hub = hdev_to_hub(udev);
        int i;
 
        for (i = 0; i < udev->maxchild; ++i) {
-               if (udev->children[i])
-                       recursively_mark_NOTATTACHED(udev->children[i]);
+               if (hub->port_data[i].child)
+                       recursively_mark_NOTATTACHED(
+                               hub->port_data[i].child);
        }
        if (udev->state == USB_STATE_SUSPENDED)
                udev->active_duration -= jiffies;
@@ -1666,8 +1669,8 @@ static void hub_free_dev(struct usb_device *udev)
 void usb_disconnect(struct usb_device **pdev)
 {
        struct usb_device       *udev = *pdev;
+       struct usb_hub  *hub = hdev_to_hub(udev);
        int                     i;
-       struct usb_hcd          *hcd = bus_to_hcd(udev->bus);
 
        /* mark the device as inactive, so any further urb submissions for
         * this device (and any of its children) will fail immediately.
@@ -1681,8 +1684,8 @@ void usb_disconnect(struct usb_device **pdev)
 
        /* Free up all the children before we remove this device */
        for (i = 0; i < udev->maxchild; i++) {
-               if (udev->children[i])
-                       usb_disconnect(&udev->children[i]);
+               if (hub->port_data[i].child)
+                       usb_disconnect(&hub->port_data[i].child);
        }
 
        /* deallocate hcd/hardware state ... nuking all pending urbs and
@@ -1690,9 +1693,7 @@ void usb_disconnect(struct usb_device **pdev)
         * so that the hardware is now fully quiesced.
         */
        dev_dbg (&udev->dev, "unregistering device\n");
-       mutex_lock(hcd->bandwidth_mutex);
        usb_disable_device(udev, 0);
-       mutex_unlock(hcd->bandwidth_mutex);
        usb_hcd_synchronize_unlinks(udev);
 
        usb_remove_ep_devs(&udev->ep0);
@@ -2765,7 +2766,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
        for (port1 = 1; port1 <= hdev->maxchild; port1++) {
                struct usb_device       *udev;
 
-               udev = hdev->children [port1-1];
+               udev = hub->port_data[port1-1].child;
                if (udev && udev->can_submit) {
                        dev_warn(&intf->dev, "port %d nyet suspended\n", port1);
                        if (PMSG_IS_AUTO(msg))
@@ -3266,7 +3267,7 @@ hub_power_remaining (struct usb_hub *hub)
 
        remaining = hdev->bus_mA - hub->descriptor->bHubContrCurrent;
        for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
-               struct usb_device       *udev = hdev->children[port1 - 1];
+               struct usb_device       *udev = hub->port_data[port1 - 1].child;
                int                     delta;
 
                if (!udev)
@@ -3330,7 +3331,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
 #endif
 
        /* Try to resuscitate an existing device */
-       udev = hdev->children[port1-1];
+       udev = hub->port_data[port1-1].child;
        if ((portstatus & USB_PORT_STAT_CONNECTION) && udev &&
                        udev->state != USB_STATE_NOTATTACHED) {
                usb_lock_device(udev);
@@ -3359,7 +3360,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
 
        /* Disconnect any existing devices under this port */
        if (udev)
-               usb_disconnect(&hdev->children[port1-1]);
+               usb_disconnect(&hub->port_data[port1-1].child);
        clear_bit(port1, hub->change_bits);
 
        /* We can forget about a "removed" device when there's a physical
@@ -3474,7 +3475,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
                                && highspeed_hubs != 0)
                        check_highspeed (hub, udev, port1);
 
-               /* Store the parent's children[] pointer.  At this point
+               /* Store the hub port's child pointer.  At this point
                 * udev becomes globally accessible, although presumably
                 * no one will look at it until hdev is unlocked.
                 */
@@ -3488,7 +3489,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
                if (hdev->state == USB_STATE_NOTATTACHED)
                        status = -ENOTCONN;
                else
-                       hdev->children[port1-1] = udev;
+                       hub->port_data[port1-1].child = udev;
                spin_unlock_irq(&device_state_lock);
 
                /* Run it through the hoops (find a driver, etc) */
@@ -3496,7 +3497,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
                        status = usb_new_device(udev);
                        if (status) {
                                spin_lock_irq(&device_state_lock);
-                               hdev->children[port1-1] = NULL;
+                               hub->port_data[port1-1].child = NULL;
                                spin_unlock_irq(&device_state_lock);
                        }
                }
@@ -3542,7 +3543,7 @@ static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
        int ret;
 
        hdev = hub->hdev;
-       udev = hdev->children[port-1];
+       udev = hub->port_data[port - 1].child;
        if (!hub_is_superspeed(hdev)) {
                if (!(portchange & USB_PORT_STAT_C_SUSPEND))
                        return 0;
@@ -3696,7 +3697,7 @@ static void hub_events(void)
                                 */
                                if (!(portstatus & USB_PORT_STAT_ENABLE)
                                    && !connect_change
-                                   && hdev->children[i-1]) {
+                                   && hub->port_data[i-1].child) {
                                        dev_err (hub_dev,
                                            "port %i "
                                            "disabled by hub (EMI?), "
@@ -4234,3 +4235,15 @@ void usb_queue_reset_device(struct usb_interface *iface)
        schedule_work(&iface->reset_ws);
 }
 EXPORT_SYMBOL_GPL(usb_queue_reset_device);
+
+struct usb_device *usb_get_hub_child_device(struct usb_device *hdev,
+       int port1)
+{
+       struct usb_hub *hub = hdev_to_hub(hdev);
+
+       if (!hub || port1 > hdev->maxchild || port1 < 1)
+               return NULL;
+       return hub->port_data[port1 - 1].child;
+}
+EXPORT_SYMBOL_GPL(usb_get_hub_child_device);
+