aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorbrian@murphy.dk <brian@murphy.dk>2005-06-29 16:53:29 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2005-07-12 11:52:57 -0700
commit83ef344a7539aa55a787790bc036f0bf3466e191 (patch)
tree3a49e9eb5e690a3b0f6609ef0f24f403b3828a39 /drivers
parent[PATCH] USB: export usb_get_intf() and usb_put_intf() (diff)
downloadlinux-dev-83ef344a7539aa55a787790bc036f0bf3466e191.tar.xz
linux-dev-83ef344a7539aa55a787790bc036f0bf3466e191.zip
[PATCH] USB: fix usb reference count bug in cdc-acm driver
This increases the reference count on the usb cdc acm control interface which is referred to by the tty interface provided by the driver. This allows the deferred removal of the tty after the physical device is disconnected if the tty is held open at the time of disconnection. Signed-off-by: brian@murphy.dk Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/class/cdc-acm.c31
1 files changed, 16 insertions, 15 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 69e859e0f51d..adff5a77e31f 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -422,6 +422,17 @@ bail_out:
return -EIO;
}
+static void acm_tty_unregister(struct acm *acm)
+{
+ tty_unregister_device(acm_tty_driver, acm->minor);
+ usb_put_intf(acm->control);
+ acm_table[acm->minor] = NULL;
+ usb_free_urb(acm->ctrlurb);
+ usb_free_urb(acm->readurb);
+ usb_free_urb(acm->writeurb);
+ kfree(acm);
+}
+
static void acm_tty_close(struct tty_struct *tty, struct file *filp)
{
struct acm *acm = tty->driver_data;
@@ -436,14 +447,8 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
usb_kill_urb(acm->ctrlurb);
usb_kill_urb(acm->writeurb);
usb_kill_urb(acm->readurb);
- } else {
- tty_unregister_device(acm_tty_driver, acm->minor);
- acm_table[acm->minor] = NULL;
- usb_free_urb(acm->ctrlurb);
- usb_free_urb(acm->readurb);
- usb_free_urb(acm->writeurb);
- kfree(acm);
- }
+ } else
+ acm_tty_unregister(acm);
}
up(&open_sem);
}
@@ -905,7 +910,8 @@ skip_normal_probe:
usb_driver_claim_interface(&acm_driver, data_interface, acm);
- tty_register_device(acm_tty_driver, minor, &intf->dev);
+ usb_get_intf(control_interface);
+ tty_register_device(acm_tty_driver, minor, &control_interface->dev);
acm_table[minor] = acm;
usb_set_intfdata (intf, acm);
@@ -954,12 +960,7 @@ static void acm_disconnect(struct usb_interface *intf)
usb_driver_release_interface(&acm_driver, acm->data);
if (!acm->used) {
- tty_unregister_device(acm_tty_driver, acm->minor);
- acm_table[acm->minor] = NULL;
- usb_free_urb(acm->ctrlurb);
- usb_free_urb(acm->readurb);
- usb_free_urb(acm->writeurb);
- kfree(acm);
+ acm_tty_unregister(acm);
up(&open_sem);
return;
}