diff options
author | Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com> | 2010-03-15 23:29:35 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-03-19 10:24:24 -0400 |
commit | d835933436ac0d1e8f5b35fe809fd4e767e55d6e (patch) | |
tree | 2fee15b2e08eb15ec31d63ea4bde24f5610e4533 /drivers/usb/host/r8a66597-hcd.c | |
parent | 9ce669a8924c61b7321d6e2f27ed67bcd46c1fbb (diff) |
usb: r8a66597-hcd: fix removed from an attached hub
fix the problem that when a USB hub is attached to the r8a66597-hcd and
a device is removed from that hub, it's likely that a kernel panic follows.
Reported-by: Markus Pietrek <Markus.Pietrek@emtrion.de>
Signed-off-by: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
Cc: stable <stable@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/r8a66597-hcd.c')
-rw-r--r-- | drivers/usb/host/r8a66597-hcd.c | 16 |
1 files changed, 11 insertions, 5 deletions
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index bee558aed427..f71a73a93d0c 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c | |||
@@ -418,7 +418,7 @@ static u8 alloc_usb_address(struct r8a66597 *r8a66597, struct urb *urb) | |||
418 | 418 | ||
419 | /* this function must be called with interrupt disabled */ | 419 | /* this function must be called with interrupt disabled */ |
420 | static void free_usb_address(struct r8a66597 *r8a66597, | 420 | static void free_usb_address(struct r8a66597 *r8a66597, |
421 | struct r8a66597_device *dev) | 421 | struct r8a66597_device *dev, int reset) |
422 | { | 422 | { |
423 | int port; | 423 | int port; |
424 | 424 | ||
@@ -430,7 +430,13 @@ static void free_usb_address(struct r8a66597 *r8a66597, | |||
430 | dev->state = USB_STATE_DEFAULT; | 430 | dev->state = USB_STATE_DEFAULT; |
431 | r8a66597->address_map &= ~(1 << dev->address); | 431 | r8a66597->address_map &= ~(1 << dev->address); |
432 | dev->address = 0; | 432 | dev->address = 0; |
433 | dev_set_drvdata(&dev->udev->dev, NULL); | 433 | /* |
434 | * Only when resetting USB, it is necessary to erase drvdata. When | ||
435 | * a usb device with usb hub is disconnect, "dev->udev" is already | ||
436 | * freed on usb_desconnect(). So we cannot access the data. | ||
437 | */ | ||
438 | if (reset) | ||
439 | dev_set_drvdata(&dev->udev->dev, NULL); | ||
434 | list_del(&dev->device_list); | 440 | list_del(&dev->device_list); |
435 | kfree(dev); | 441 | kfree(dev); |
436 | 442 | ||
@@ -1069,7 +1075,7 @@ static void r8a66597_usb_disconnect(struct r8a66597 *r8a66597, int port) | |||
1069 | struct r8a66597_device *dev = r8a66597->root_hub[port].dev; | 1075 | struct r8a66597_device *dev = r8a66597->root_hub[port].dev; |
1070 | 1076 | ||
1071 | disable_r8a66597_pipe_all(r8a66597, dev); | 1077 | disable_r8a66597_pipe_all(r8a66597, dev); |
1072 | free_usb_address(r8a66597, dev); | 1078 | free_usb_address(r8a66597, dev, 0); |
1073 | 1079 | ||
1074 | start_root_hub_sampling(r8a66597, port, 0); | 1080 | start_root_hub_sampling(r8a66597, port, 0); |
1075 | } | 1081 | } |
@@ -2085,7 +2091,7 @@ static void update_usb_address_map(struct r8a66597 *r8a66597, | |||
2085 | spin_lock_irqsave(&r8a66597->lock, flags); | 2091 | spin_lock_irqsave(&r8a66597->lock, flags); |
2086 | dev = get_r8a66597_device(r8a66597, addr); | 2092 | dev = get_r8a66597_device(r8a66597, addr); |
2087 | disable_r8a66597_pipe_all(r8a66597, dev); | 2093 | disable_r8a66597_pipe_all(r8a66597, dev); |
2088 | free_usb_address(r8a66597, dev); | 2094 | free_usb_address(r8a66597, dev, 0); |
2089 | put_child_connect_map(r8a66597, addr); | 2095 | put_child_connect_map(r8a66597, addr); |
2090 | spin_unlock_irqrestore(&r8a66597->lock, flags); | 2096 | spin_unlock_irqrestore(&r8a66597->lock, flags); |
2091 | } | 2097 | } |
@@ -2228,7 +2234,7 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
2228 | rh->port |= (1 << USB_PORT_FEAT_RESET); | 2234 | rh->port |= (1 << USB_PORT_FEAT_RESET); |
2229 | 2235 | ||
2230 | disable_r8a66597_pipe_all(r8a66597, dev); | 2236 | disable_r8a66597_pipe_all(r8a66597, dev); |
2231 | free_usb_address(r8a66597, dev); | 2237 | free_usb_address(r8a66597, dev, 1); |
2232 | 2238 | ||
2233 | r8a66597_mdfy(r8a66597, USBRST, USBRST | UACT, | 2239 | r8a66597_mdfy(r8a66597, USBRST, USBRST | UACT, |
2234 | get_dvstctr_reg(port)); | 2240 | get_dvstctr_reg(port)); |