Commit d8359334 authored by Yoshihiro Shimoda's avatar Yoshihiro Shimoda Committed by Greg Kroah-Hartman

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: default avatarMarkus Pietrek <Markus.Pietrek@emtrion.de>
Signed-off-by: default avatarYoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
Cc: stable <stable@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 9ce669a8
...@@ -418,7 +418,7 @@ static u8 alloc_usb_address(struct r8a66597 *r8a66597, struct urb *urb) ...@@ -418,7 +418,7 @@ static u8 alloc_usb_address(struct r8a66597 *r8a66597, struct urb *urb)
/* this function must be called with interrupt disabled */ /* this function must be called with interrupt disabled */
static void free_usb_address(struct r8a66597 *r8a66597, static void free_usb_address(struct r8a66597 *r8a66597,
struct r8a66597_device *dev) struct r8a66597_device *dev, int reset)
{ {
int port; int port;
...@@ -430,6 +430,12 @@ static void free_usb_address(struct r8a66597 *r8a66597, ...@@ -430,6 +430,12 @@ static void free_usb_address(struct r8a66597 *r8a66597,
dev->state = USB_STATE_DEFAULT; dev->state = USB_STATE_DEFAULT;
r8a66597->address_map &= ~(1 << dev->address); r8a66597->address_map &= ~(1 << dev->address);
dev->address = 0; dev->address = 0;
/*
* Only when resetting USB, it is necessary to erase drvdata. When
* a usb device with usb hub is disconnect, "dev->udev" is already
* freed on usb_desconnect(). So we cannot access the data.
*/
if (reset)
dev_set_drvdata(&dev->udev->dev, NULL); dev_set_drvdata(&dev->udev->dev, NULL);
list_del(&dev->device_list); list_del(&dev->device_list);
kfree(dev); kfree(dev);
...@@ -1069,7 +1075,7 @@ static void r8a66597_usb_disconnect(struct r8a66597 *r8a66597, int port) ...@@ -1069,7 +1075,7 @@ static void r8a66597_usb_disconnect(struct r8a66597 *r8a66597, int port)
struct r8a66597_device *dev = r8a66597->root_hub[port].dev; struct r8a66597_device *dev = r8a66597->root_hub[port].dev;
disable_r8a66597_pipe_all(r8a66597, dev); disable_r8a66597_pipe_all(r8a66597, dev);
free_usb_address(r8a66597, dev); free_usb_address(r8a66597, dev, 0);
start_root_hub_sampling(r8a66597, port, 0); start_root_hub_sampling(r8a66597, port, 0);
} }
...@@ -2085,7 +2091,7 @@ static void update_usb_address_map(struct r8a66597 *r8a66597, ...@@ -2085,7 +2091,7 @@ static void update_usb_address_map(struct r8a66597 *r8a66597,
spin_lock_irqsave(&r8a66597->lock, flags); spin_lock_irqsave(&r8a66597->lock, flags);
dev = get_r8a66597_device(r8a66597, addr); dev = get_r8a66597_device(r8a66597, addr);
disable_r8a66597_pipe_all(r8a66597, dev); disable_r8a66597_pipe_all(r8a66597, dev);
free_usb_address(r8a66597, dev); free_usb_address(r8a66597, dev, 0);
put_child_connect_map(r8a66597, addr); put_child_connect_map(r8a66597, addr);
spin_unlock_irqrestore(&r8a66597->lock, flags); spin_unlock_irqrestore(&r8a66597->lock, flags);
} }
...@@ -2228,7 +2234,7 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -2228,7 +2234,7 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
rh->port |= (1 << USB_PORT_FEAT_RESET); rh->port |= (1 << USB_PORT_FEAT_RESET);
disable_r8a66597_pipe_all(r8a66597, dev); disable_r8a66597_pipe_all(r8a66597, dev);
free_usb_address(r8a66597, dev); free_usb_address(r8a66597, dev, 1);
r8a66597_mdfy(r8a66597, USBRST, USBRST | UACT, r8a66597_mdfy(r8a66597, USBRST, USBRST | UACT,
get_dvstctr_reg(port)); get_dvstctr_reg(port));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment