aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/r8a66597-hcd.c
diff options
context:
space:
mode:
authorYoshihiro Shimoda <shimoda.yoshihiro@renesas.com>2010-03-15 23:29:35 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-03-19 10:24:24 -0400
commitd835933436ac0d1e8f5b35fe809fd4e767e55d6e (patch)
tree2fee15b2e08eb15ec31d63ea4bde24f5610e4533 /drivers/usb/host/r8a66597-hcd.c
parent9ce669a8924c61b7321d6e2f27ed67bcd46c1fbb (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.c16
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 */
420static void free_usb_address(struct r8a66597 *r8a66597, 420static 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));