Alan Stern wrote:
This also works fine and allows me to clean up the tty_disconnect code so there isOn Sun, 13 Mar 2005, Brian Murphy wrote:
Hi, This line in the acm_probe routine
tty_register_device(acm_tty_driver, minor, &intf->dev);
causes the path to the tty created for each acm to be linked to the usb interface. As long as the device is closed when it is disconnected this is no problem but if the tty is open then the tty deregistering is deferred. When the terminal is closed the interface parent to the tty no longer exists and the kernel crashes in kobject_get_path.
The solution is to not link the two things together and replace &intf->dev above with NULL, see the attached patch.
I believe that someone else had the same problem a few days
ago.
Would another possibility be to call usb_get_intf() before calling tty_register_device() and usb_put_intf() when the link is no longer needed? That way the interface parent to the tty would exist for as long as needed.
Alan Stern
only one copy. This patch is now dependant on my interface removal patch as there is
a slight overlap. See patch attached.
BTW The usb_get_intf and usb_put_intf functions needed to be exported before I
could use them here (included in patch).
/Brian
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.
This patch depends on cdc2.patch posted earlier to this list under the title "cdc acm error removing interface(s)" as there is an overlap. Signed-off-by: [EMAIL PROTECTED] diff -r -u linux-2.6.11-bk7.clean/drivers/usb/class/cdc-acm.c linux-2.6.11-bk7/drivers/usb/class/cdc-acm.c --- linux-2.6.11-bk7.clean/drivers/usb/class/cdc-acm.c 2005-03-13 10:20:11.000000000 +0100 +++ linux-2.6.11-bk7/drivers/usb/class/cdc-acm.c 2005-03-13 08:09:14.000000000 +0100 @@ -321,6 +321,17 @@ 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; @@ -335,14 +346,8 @@ 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); } @@ -764,7 +769,8 @@ 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); @@ -821,12 +827,7 @@ usb_driver_release_interface(&acm_driver, other_interface); 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; } diff -r -u linux-2.6.11-bk7.clean/drivers/usb/core/usb.c linux-2.6.11-bk7/drivers/usb/core/usb.c --- linux-2.6.11-bk7.clean/drivers/usb/core/usb.c 2005-03-12 22:43:31.000000000 +0100 +++ linux-2.6.11-bk7/drivers/usb/core/usb.c 2005-03-13 08:10:35.000000000 +0100 @@ -1499,6 +1499,9 @@ EXPORT_SYMBOL(usb_deregister); EXPORT_SYMBOL(usb_disabled); +EXPORT_SYMBOL(usb_get_intf); +EXPORT_SYMBOL(usb_put_intf); + EXPORT_SYMBOL(usb_alloc_dev); EXPORT_SYMBOL(usb_put_dev); EXPORT_SYMBOL(usb_get_dev);