usb: move children to struct usb_port
The usb_device structure contains an array of usb_device "children".
This array is only valid if the usb_device is a hub, so it makes no
sense to store it there. Instead, store the usb_device child
in its parent usb_port structure.
Since usb_port is an internal USB core structure, add a new function to
get the USB device child, usb_hub_find_child(). Add a new macro,
usb_hub_get_each_child(), to iterate over all the children attached to a
particular USB hub.
Remove the printing the USB children array pointer from the usb-ip
driver, since it's really not necessary.
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Lan Tianyu <tianyu.lan@intel.com>
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c
index 70f23026..95beb76 100644
--- a/drivers/staging/usbip/usbip_common.c
+++ b/drivers/staging/usbip/usbip_common.c
@@ -157,8 +157,7 @@
dev_dbg(dev, "have_langid %d, string_langid %d\n",
udev->have_langid, udev->string_langid);
- dev_dbg(dev, "maxchild %d, children %p\n",
- udev->maxchild, udev->children);
+ dev_dbg(dev, "maxchild %d\n", udev->maxchild);
}
static void usbip_dump_request_type(__u8 rt)
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index d956965..f4ead12 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -496,6 +496,7 @@
char *pages_start, *data_end, *speed;
unsigned int length;
ssize_t total_written = 0;
+ struct usb_device *childdev = NULL;
/* don't bother with anything else if we're not writing any data */
if (*nbytes <= 0)
@@ -589,14 +590,12 @@
free_pages((unsigned long)pages_start, 1);
/* Now look at all of this device's children. */
- for (chix = 0; chix < usbdev->maxchild; chix++) {
- struct usb_device *childdev = usbdev->children[chix];
-
+ usb_hub_for_each_child(usbdev, chix, childdev) {
if (childdev) {
usb_lock_device(childdev);
ret = usb_device_dump(buffer, nbytes, skip_bytes,
file_offset, childdev, bus,
- level + 1, chix, ++cnt);
+ level + 1, chix - 1, ++cnt);
usb_unlock_device(childdev);
if (ret == -EFAULT)
return total_written;
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 87df22e..cdbade1 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -40,6 +40,7 @@
#endif
struct usb_port {
+ struct usb_device *child;
struct device dev;
struct dev_state *port_owner;
};
@@ -181,7 +182,7 @@
/* 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]);
}
@@ -876,8 +877,8 @@
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->ports[port1 - 1]->child && set_state)
+ usb_set_device_state(hub->ports[port1 - 1]->child,
USB_STATE_NOTATTACHED);
if (!hub->error && !hub_is_superspeed(hub->hdev))
ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE);
@@ -1033,7 +1034,7 @@
* which ports need attention.
*/
for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
- struct usb_device *udev = hdev->children[port1-1];
+ struct usb_device *udev = hub->ports[port1 - 1]->child;
u16 portstatus, portchange;
portstatus = portchange = 0;
@@ -1198,8 +1199,8 @@
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->ports[i]->child)
+ usb_disconnect(&hub->ports[i]->child);
}
}
@@ -1324,11 +1325,9 @@
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->ports = kzalloc(hdev->maxchild * sizeof(struct usb_port *),
GFP_KERNEL);
- if (!hdev->children || !hub->ports) {
+ if (!hub->ports) {
ret = -ENOMEM;
goto fail;
}
@@ -1591,7 +1590,6 @@
highspeed_hubs--;
usb_free_urb(hub->urb);
- kfree(hdev->children);
kfree(hub->ports);
kfree(hub->descriptor);
kfree(hub->status);
@@ -1679,6 +1677,7 @@
hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
{
struct usb_device *hdev = interface_to_usbdev (intf);
+ struct usb_hub *hub = hdev_to_hub(hdev);
/* assert ifno == 0 (part of hub spec) */
switch (code) {
@@ -1692,11 +1691,11 @@
else {
info->nports = hdev->maxchild;
for (i = 0; i < info->nports; i++) {
- if (hdev->children[i] == NULL)
+ if (hub->ports[i]->child == NULL)
info->port[i] = 0;
else
info->port[i] =
- hdev->children[i]->devnum;
+ hub->ports[i]->child->devnum;
}
}
spin_unlock_irq(&device_state_lock);
@@ -1784,11 +1783,12 @@
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->ports[i]->child)
+ recursively_mark_NOTATTACHED(hub->ports[i]->child);
}
if (udev->state == USB_STATE_SUSPENDED)
udev->active_duration -= jiffies;
@@ -1952,6 +1952,7 @@
void usb_disconnect(struct usb_device **pdev)
{
struct usb_device *udev = *pdev;
+ struct usb_hub *hub = hdev_to_hub(udev);
int i;
/* mark the device as inactive, so any further urb submissions for
@@ -1966,8 +1967,8 @@
/* 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->ports[i]->child)
+ usb_disconnect(&hub->ports[i]->child);
}
/* deallocate hcd/hardware state ... nuking all pending urbs and
@@ -3131,7 +3132,7 @@
for (port1 = 1; port1 <= hdev->maxchild; port1++) {
struct usb_device *udev;
- udev = hdev->children [port1-1];
+ udev = hub->ports[port1 - 1]->child;
if (udev && udev->can_submit) {
dev_warn(&intf->dev, "port %d nyet suspended\n", port1);
if (PMSG_IS_AUTO(msg))
@@ -4058,7 +4059,7 @@
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->ports[port1 - 1]->child;
int delta;
if (!udev)
@@ -4122,7 +4123,7 @@
#endif
/* Try to resuscitate an existing device */
- udev = hdev->children[port1-1];
+ udev = hub->ports[port1 - 1]->child;
if ((portstatus & USB_PORT_STAT_CONNECTION) && udev &&
udev->state != USB_STATE_NOTATTACHED) {
usb_lock_device(udev);
@@ -4151,7 +4152,7 @@
/* Disconnect any existing devices under this port */
if (udev)
- usb_disconnect(&hdev->children[port1-1]);
+ usb_disconnect(&hub->ports[port1 - 1]->child);
clear_bit(port1, hub->change_bits);
/* We can forget about a "removed" device when there's a physical
@@ -4287,7 +4288,7 @@
if (hdev->state == USB_STATE_NOTATTACHED)
status = -ENOTCONN;
else
- hdev->children[port1-1] = udev;
+ hub->ports[port1 - 1]->child = udev;
spin_unlock_irq(&device_state_lock);
/* Run it through the hoops (find a driver, etc) */
@@ -4295,7 +4296,7 @@
status = usb_new_device(udev);
if (status) {
spin_lock_irq(&device_state_lock);
- hdev->children[port1-1] = NULL;
+ hub->ports[port1 - 1]->child = NULL;
spin_unlock_irq(&device_state_lock);
}
}
@@ -4341,7 +4342,7 @@
int ret;
hdev = hub->hdev;
- udev = hdev->children[port-1];
+ udev = hub->ports[port - 1]->child;
if (!hub_is_superspeed(hdev)) {
if (!(portchange & USB_PORT_STAT_C_SUSPEND))
return 0;
@@ -4495,7 +4496,7 @@
*/
if (!(portstatus & USB_PORT_STAT_ENABLE)
&& !connect_change
- && hdev->children[i-1]) {
+ && hub->ports[i - 1]->child) {
dev_err (hub_dev,
"port %i "
"disabled by hub (EMI?), "
@@ -5052,3 +5053,27 @@
schedule_work(&iface->reset_ws);
}
EXPORT_SYMBOL_GPL(usb_queue_reset_device);
+
+/**
+ * usb_hub_find_child - Get the pointer of child device
+ * attached to the port which is specified by @port1.
+ * @hdev: USB device belonging to the usb hub
+ * @port1: port num to indicate which port the child device
+ * is attached to.
+ *
+ * USB drivers call this function to get hub's child device
+ * pointer.
+ *
+ * Return NULL if input param is invalid and
+ * child's usb_device pointer if non-NULL.
+ */
+struct usb_device *usb_hub_find_child(struct usb_device *hdev,
+ int port1)
+{
+ struct usb_hub *hub = hdev_to_hub(hdev);
+
+ if (port1 < 1 || port1 > hdev->maxchild)
+ return NULL;
+ return hub->ports[port1 - 1]->child;
+}
+EXPORT_SYMBOL_GPL(usb_hub_find_child);
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index 4c634eb..fcc09e5 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -2029,15 +2029,14 @@
static void collect_usb_address_map(struct usb_device *udev, unsigned long *map)
{
int chix;
+ struct usb_device *childdev;
if (udev->state == USB_STATE_CONFIGURED &&
udev->parent && udev->parent->devnum > 1 &&
udev->parent->descriptor.bDeviceClass == USB_CLASS_HUB)
map[udev->devnum/32] |= (1 << (udev->devnum % 32));
- for (chix = 0; chix < udev->maxchild; chix++) {
- struct usb_device *childdev = udev->children[chix];
-
+ usb_hub_for_each_child(udev, chix, childdev) {
if (childdev)
collect_usb_address_map(childdev, map);
}