Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 7966
b: refs/heads/master
c: bf193d3
h: refs/heads/master
v: v3
  • Loading branch information
Alan Stern authored and Greg Kroah-Hartman committed Sep 8, 2005
1 parent 641625a commit 615d541
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 13 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 8b28c7526a302bbfa618f7eab4ef961edd68c9a0
refs/heads/master: bf193d3cd2a3b73f2df74f57106114867946c09c
10 changes: 0 additions & 10 deletions trunk/drivers/usb/core/devio.c
Original file line number Diff line number Diff line change
Expand Up @@ -1238,7 +1238,6 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg)
int retval = 0;
struct usb_interface *intf = NULL;
struct usb_driver *driver = NULL;
int i;

/* get input parameters and alloc buffer */
if (copy_from_user(&ctrl, arg, sizeof (ctrl)))
Expand Down Expand Up @@ -1270,15 +1269,6 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg)
/* disconnect kernel driver from interface */
case USBDEVFS_DISCONNECT:

/* don't allow the user to unbind the hub driver from
* a hub with children to manage */
for (i = 0; i < ps->dev->maxchild; ++i) {
if (ps->dev->children[i])
retval = -EBUSY;
}
if (retval)
break;

down_write(&usb_bus_type.subsys.rwsem);
if (intf->dev.driver) {
driver = to_usb_driver(intf->dev.driver);
Expand Down
42 changes: 40 additions & 2 deletions trunk/drivers/usb/core/hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -729,10 +729,29 @@ static int hub_configure(struct usb_hub *hub,

static unsigned highspeed_hubs;

/* Called after the hub driver is unbound from a hub with children */
static void hub_remove_children_work(void *__hub)
{
struct usb_hub *hub = __hub;
struct usb_device *hdev = hub->hdev;
int i;

kfree(hub);

usb_lock_device(hdev);
for (i = 0; i < hdev->maxchild; ++i) {
if (hdev->children[i])
usb_disconnect(&hdev->children[i]);
}
usb_unlock_device(hdev);
usb_put_dev(hdev);
}

static void hub_disconnect(struct usb_interface *intf)
{
struct usb_hub *hub = usb_get_intfdata (intf);
struct usb_device *hdev;
int n, port1;

usb_set_intfdata (intf, NULL);
hdev = hub->hdev;
Expand Down Expand Up @@ -760,8 +779,27 @@ static void hub_disconnect(struct usb_interface *intf)
hub->buffer = NULL;
}

/* Free the memory */
kfree(hub);
/* If there are any children then this is an unbind only, not a
* physical disconnection. The active ports must be disabled
* and later on we must call usb_disconnect(). We can't call
* it now because we may not hold the hub's device lock.
*/
n = 0;
for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
if (hdev->children[port1 - 1]) {
++n;
hub_port_disable(hub, port1, 1);
}
}

if (n == 0)
kfree(hub);
else {
/* Reuse the hub->leds work_struct for our own purposes */
INIT_WORK(&hub->leds, hub_remove_children_work, hub);
schedule_work(&hub->leds);
usb_get_dev(hdev);
}
}

static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
Expand Down

0 comments on commit 615d541

Please sign in to comment.