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>
This commit is contained in:
Родитель
9ce669a892
Коммит
d835933436
|
@ -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,7 +430,13 @@ 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;
|
||||||
dev_set_drvdata(&dev->udev->dev, NULL);
|
/*
|
||||||
|
* 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);
|
||||||
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)
|
||||||
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,
|
||||||
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,
|
||||||
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));
|
||||||
|
|
Загрузка…
Ссылка в новой задаче