The CDC ACM driver assumes that the acm_disconnect function is always
called with the control interface as argument but this is not always the
case. If it is called with the data interface first then
acm_disconnect calls usb_driver_release_interface with the data interface and causes the kernel to crash.
I have attached a patch which checks which of the interfaces acm_disconnect is called with and calls usb_driver_release_interface
with the other one.
/Brian
Signed-off-by: [EMAIL PROTECTED]
diff -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-12
22:43:31.000000000 +0100
+++ linux-2.6.11-bk7/drivers/usb/class/cdc-acm.c 2005-03-13
01:35:14.000000000 +0100
@@ -790,6 +790,7 @@
{
struct acm *acm = usb_get_intfdata (intf);
struct usb_device *usb_dev = interface_to_usbdev(intf);
+ struct usb_interface *other_interface = NULL;
if (!acm || !acm->dev) {
dbg("disconnect on nonexisting interface");
@@ -810,7 +811,14 @@
usb_buffer_free(usb_dev, acm->readsize, acm->read_buffer,
acm->read_dma);
usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer,
acm->ctrl_dma);
- usb_driver_release_interface(&acm_driver, acm->data);
+ if (intf == acm->data)
+ other_interface = acm->control;
+ else if (intf == acm->control)
+ other_interface = acm->data;
+ else
+ BUG();
+
+ usb_driver_release_interface(&acm_driver, other_interface);
if (!acm->used) {
tty_unregister_device(acm_tty_driver, acm->minor);
