ChangeSet 1.1722.97.59, 2004/06/09 11:10:09-07:00, [EMAIL PROTECTED]
[PATCH] USB: Minor tidying up of hub driver
After my last few changesets there were a few small items that needed to
be tidied up.
Update kerneldoc to reflect the actual operation of
usb_disconnect() and usb_new_device(). The new locking
requirements are listed too, though they aren't all
implemented yet.
Fulfill the new locking requirement in hcd_panic().
Remove unneeded local variables to conserve stack space in
usb_disconnect(), which calls itself recursively.
In hub_port_connect_change(), store the parent's children[]
pointer as late as possible and don't lock the new device until
then (that's when it becomes globally accessible). This will
minimize the time that the not-fully-configured device structure
is visible to other parts of the kernel.
Signed-off-by: Alan Stern <[EMAIL PROTECTED]>
Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>
drivers/usb/core/hcd.c | 2 ++
drivers/usb/core/hub.c | 48 +++++++++++++++++++++++++-----------------------
2 files changed, 27 insertions(+), 23 deletions(-)
diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
--- a/drivers/usb/core/hcd.c Fri Jun 18 10:57:17 2004
+++ b/drivers/usb/core/hcd.c Fri Jun 18 10:57:17 2004
@@ -1579,11 +1579,13 @@
unsigned i;
/* hc's root hub is removed later removed in hcd->stop() */
+ down (&hub->serialize);
hub->state = USB_STATE_NOTATTACHED;
for (i = 0; i < hub->maxchild; i++) {
if (hub->children [i])
usb_disconnect (&hub->children [i]);
}
+ up (&hub->serialize);
}
/**
diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
--- a/drivers/usb/core/hub.c Fri Jun 18 10:57:17 2004
+++ b/drivers/usb/core/hub.c Fri Jun 18 10:57:17 2004
@@ -868,6 +868,9 @@
* Context: !in_interrupt ()
*
* Something got disconnected. Get rid of it, and all of its children.
+ * If *pdev is a normal device then the parent hub should be locked.
+ * If *pdev is a root hub then this routine will acquire the
+ * usb_bus_list_lock on behalf of the caller.
*
* Only hub drivers (including virtual root hub drivers for host
* controllers) should ever call this.
@@ -877,20 +880,12 @@
void usb_disconnect(struct usb_device **pdev)
{
struct usb_device *udev = *pdev;
- struct usb_bus *bus;
- struct usb_operations *ops;
int i;
if (!udev) {
pr_debug ("%s nodev\n", __FUNCTION__);
return;
}
- bus = udev->bus;
- if (!bus) {
- pr_debug ("%s nobus\n", __FUNCTION__);
- return;
- }
- ops = bus->op;
/* mark the device as inactive, so any further urb submissions for
* this device will fail.
@@ -906,9 +901,8 @@
/* Free up all the children before we remove this device */
for (i = 0; i < USB_MAXCHILDREN; i++) {
- struct usb_device **child = udev->children + i;
- if (*child)
- usb_disconnect(child);
+ if (udev->children[i])
+ usb_disconnect(&udev->children[i]);
}
/* deallocate hcd/hardware state ... nuking all pending urbs and
@@ -987,21 +981,23 @@
/*
* usb_new_device - perform initial device setup (usbcore-internal)
- * @dev: newly addressed device (in ADDRESS state)
+ * @udev: newly addressed device (in ADDRESS state)
*
* This is called with devices which have been enumerated, but not yet
* configured. The device descriptor is available, but not descriptors
- * for any device configuration. The caller owns dev->serialize, and
- * the device is not visible through sysfs or other filesystem code.
+ * for any device configuration. The caller must have locked udev and
+ * either the parent hub (if udev is a normal device) or else the
+ * usb_bus_list_lock (if udev is a root hub). The parent's pointer to
+ * udev has already been installed, but udev is not yet visible through
+ * sysfs or other filesystem code.
*
* Returns 0 for success (device is configured and listed, with its
- * interfaces, in sysfs); else a negative errno value. On error, one
- * reference count to the device has been dropped.
+ * interfaces, in sysfs); else a negative errno value.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Only the hub driver should ever call this; root hub registration
- * uses it only indirectly.
+ * uses it indirectly.
*/
int usb_new_device(struct usb_device *udev)
{
@@ -1052,6 +1048,7 @@
if (err) {
dev_err(&udev->dev, "can't set config #%d, error %d\n",
c, err);
+ usb_remove_sysfs_dev_files(udev);
device_del(&udev->dev);
goto fail;
}
@@ -1548,8 +1545,6 @@
udev->speed = USB_SPEED_LOW;
else
udev->speed = USB_SPEED_UNKNOWN;
-
- down (&udev->serialize);
/* set the address */
choose_address(udev);
@@ -1610,10 +1605,20 @@
&& highspeed_hubs != 0)
check_highspeed (hub, udev, port);
- /* Run it through the hoops (find a driver, etc) */
+ /* Store the parent's children[] pointer. At this point
+ * udev becomes globally accessible, although presumably
+ * no one will look at it until hdev is unlocked.
+ */
+ down (&udev->serialize);
hdev->children[port] = udev;
+
+ /* Run it through the hoops (find a driver, etc) */
status = usb_new_device(udev);
if (status)
+ hdev->children[port] = NULL;
+
+ up (&udev->serialize);
+ if (status)
goto loop;
status = hub_power_remaining(hub, hdev);
@@ -1622,16 +1627,13 @@
"%dmA power budget left\n",
2 * status);
- up (&udev->serialize);
return;
loop:
- hdev->children[port] = NULL;
hub_port_disable(hdev, port);
usb_disable_endpoint(udev, 0 + USB_DIR_IN);
usb_disable_endpoint(udev, 0 + USB_DIR_OUT);
release_address(udev);
- up (&udev->serialize);
usb_put_dev(udev);
if (status == -ENOTCONN)
break;
-------------------------------------------------------
This SF.Net email is sponsored by The 2004 JavaOne(SM) Conference
Learn from the experts at JavaOne(SM), Sun's Worldwide Java Developer
Conference, June 28 - July 1 at the Moscone Center in San Francisco, CA
REGISTER AND SAVE! http://java.sun.com/javaone/sf Priority Code NWMGYKND
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel