From e17d5125661f48157cb714d9108d7ae062e33729 Mon Sep 17 00:00:00 2001 From: Vinayak Pane Date: Fri, 30 Mar 2012 20:03:07 -0700 Subject: USB: cdc-acm: disconnect stuck issue and acm_tty_open crash acm_disconnect() should not kill the anchored URB because they are already killed by stop_data_traffic(). Submit read URBs before control urb is sent because there is a possibility of response coming immediately after ctrl is sent. Bug 957744 Bug 961808 (cherry picked from commit 05c10cbe01f0275e5fe121d763692261c51987fc) Reviewed-on: http://git-master/r/93673 Signed-off-by: Vinayak Pane Change-Id: I5597e239ec3722afb6b4c1cd5fbe228e30af2a2d Reviewed-on: http://git-master/r/96585 Reviewed-by: Simone Willett Tested-by: Simone Willett --- drivers/usb/class/cdc-acm.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/usb/class/cdc-acm.c') diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 335fe0504721..8fb105e03658 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -507,6 +507,9 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) goto out; } + if (acm_submit_read_urbs(acm, GFP_KERNEL)) + goto bail_out; + acm->ctrlurb->dev = acm->dev; if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) { dev_err(&acm->control->dev, @@ -520,9 +523,6 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) usb_autopm_put_interface(acm->control); - if (acm_submit_read_urbs(acm, GFP_KERNEL)) - goto bail_out; - set_bit(ASYNCB_INITIALIZED, &acm->port.flags); rv = tty_port_block_til_ready(&acm->port, tty, filp); @@ -1305,6 +1305,7 @@ static void acm_disconnect(struct usb_interface *intf) struct acm *acm = usb_get_intfdata(intf); struct usb_device *usb_dev = interface_to_usbdev(intf); struct tty_struct *tty; + struct urb *res; /* sibling interface is already cleaning up */ if (!acm) @@ -1324,7 +1325,10 @@ static void acm_disconnect(struct usb_interface *intf) stop_data_traffic(acm); - usb_kill_anchored_urbs(&acm->deferred); + /* decrement ref count of anchored urbs */ + while ((res = usb_get_from_anchor(&acm->deferred))) + usb_put_urb(res); + acm_write_buffers_free(acm); usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); -- cgit v1.2.3