Commit 03d9ca5f authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

[PATCH] USB: fix usb serial port release problem by untieing it from the usb_serial structure.

This fixes the kobject messages when disconnecting a usb serial device that
people have been complaining about.
parent d6ecf7ed
...@@ -466,7 +466,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp) ...@@ -466,7 +466,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
/* set up our port structure making the tty driver remember our port object, and us it */ /* set up our port structure making the tty driver remember our port object, and us it */
portNumber = tty->index - serial->minor; portNumber = tty->index - serial->minor;
port = &serial->port[portNumber]; port = serial->port[portNumber];
tty->driver_data = port; tty->driver_data = port;
port->tty = tty; port->tty = tty;
...@@ -863,13 +863,13 @@ static void destroy_serial (struct kobject *kobj) ...@@ -863,13 +863,13 @@ static void destroy_serial (struct kobject *kobj)
struct usb_serial_port *port; struct usb_serial_port *port;
int i; int i;
dbg ("%s", __FUNCTION__); dbg ("%s - %s", __FUNCTION__, kobj->name);
serial = to_usb_serial(kobj); serial = to_usb_serial(kobj);
/* fail all future close/read/write/ioctl/etc calls */ /* fail all future close/read/write/ioctl/etc calls */
for (i = 0; i < serial->num_ports; ++i) { for (i = 0; i < serial->num_ports; ++i) {
port = &serial->port[i]; port = serial->port[i];
if (port->tty != NULL) { if (port->tty != NULL) {
port->tty->driver_data = NULL; port->tty->driver_data = NULL;
while (port->open_count > 0) { while (port->open_count > 0) {
...@@ -881,41 +881,41 @@ static void destroy_serial (struct kobject *kobj) ...@@ -881,41 +881,41 @@ static void destroy_serial (struct kobject *kobj)
serial_shutdown (serial); serial_shutdown (serial);
for (i = 0; i < serial->num_ports; ++i) /* return the minor range that this device had */
device_unregister(&serial->port[i].dev); return_serial(serial);
for (i = 0; i < serial->num_ports; ++i) for (i = 0; i < serial->num_ports; ++i)
serial->port[i].open_count = 0; serial->port[i]->open_count = 0;
for (i = 0; i < serial->num_bulk_in; ++i) { /* the ports are cleaned up and released in port_release() */
port = &serial->port[i]; for (i = 0; i < serial->num_ports; ++i)
if (port->read_urb) { device_unregister(&serial->port[i]->dev);
usb_unlink_urb (port->read_urb);
usb_free_urb (port->read_urb); /* If this is a "fake" port, we have to clean it up here, as it will
} * not get cleaned up in port_release() as it was never registered with
if (port->bulk_in_buffer) * the driver core */
kfree (port->bulk_in_buffer); if (serial->num_ports < serial->num_port_pointers) {
} for (i = serial->num_ports; i < serial->num_port_pointers; ++i) {
for (i = 0; i < serial->num_bulk_out; ++i) { port = serial->port[i];
port = &serial->port[i]; if (!port)
if (port->write_urb) { continue;
usb_unlink_urb (port->write_urb); if (port->read_urb) {
usb_free_urb (port->write_urb); usb_unlink_urb(port->read_urb);
} usb_free_urb(port->read_urb);
if (port->bulk_out_buffer) }
kfree (port->bulk_out_buffer); if (port->write_urb) {
} usb_unlink_urb(port->write_urb);
for (i = 0; i < serial->num_interrupt_in; ++i) { usb_free_urb(port->write_urb);
port = &serial->port[i]; }
if (port->interrupt_in_urb) { if (port->interrupt_in_urb) {
usb_unlink_urb (port->interrupt_in_urb); usb_unlink_urb(port->interrupt_in_urb);
usb_free_urb (port->interrupt_in_urb); usb_free_urb(port->interrupt_in_urb);
}
kfree(port->bulk_in_buffer);
kfree(port->bulk_out_buffer);
kfree(port->interrupt_in_buffer);
} }
if (port->interrupt_in_buffer)
kfree (port->interrupt_in_buffer);
} }
/* return the minor range that this device had */
return_serial (serial);
usb_put_dev(serial->dev); usb_put_dev(serial->dev);
...@@ -927,6 +927,29 @@ static struct kobj_type usb_serial_kobj_type = { ...@@ -927,6 +927,29 @@ static struct kobj_type usb_serial_kobj_type = {
.release = destroy_serial, .release = destroy_serial,
}; };
static void port_release(struct device *dev)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
dbg ("%s - %s", __FUNCTION__, dev->bus_id);
if (port->read_urb) {
usb_unlink_urb(port->read_urb);
usb_free_urb(port->read_urb);
}
if (port->write_urb) {
usb_unlink_urb(port->write_urb);
usb_free_urb(port->write_urb);
}
if (port->interrupt_in_urb) {
usb_unlink_urb(port->interrupt_in_urb);
usb_free_urb(port->interrupt_in_urb);
}
kfree(port->bulk_in_buffer);
kfree(port->bulk_out_buffer);
kfree(port->interrupt_in_buffer);
kfree(port);
}
static struct usb_serial * create_serial (struct usb_device *dev, static struct usb_serial * create_serial (struct usb_device *dev,
struct usb_interface *interface, struct usb_interface *interface,
struct usb_serial_device_type *type) struct usb_serial_device_type *type)
...@@ -1124,10 +1147,29 @@ int usb_serial_probe(struct usb_interface *interface, ...@@ -1124,10 +1147,29 @@ int usb_serial_probe(struct usb_interface *interface,
serial->num_bulk_out = num_bulk_out; serial->num_bulk_out = num_bulk_out;
serial->num_interrupt_in = num_interrupt_in; serial->num_interrupt_in = num_interrupt_in;
/* create our ports, we need as many as the max endpoints */
/* we don't use num_ports here cauz some devices have more endpoint pairs than ports */
max_endpoints = max(num_bulk_in, num_bulk_out);
max_endpoints = max(max_endpoints, num_interrupt_in);
max_endpoints = max(max_endpoints, (int)serial->num_ports);
serial->num_port_pointers = max_endpoints;
dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints);
for (i = 0; i < max_endpoints; ++i) {
port = kmalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
if (!port)
goto probe_error;
memset(port, 0x00, sizeof(struct usb_serial_port));
port->number = i + serial->minor;
port->serial = serial;
port->magic = USB_SERIAL_PORT_MAGIC;
INIT_WORK(&port->work, usb_serial_port_softint, port);
serial->port[i] = port;
}
/* set up the endpoint information */ /* set up the endpoint information */
for (i = 0; i < num_bulk_in; ++i) { for (i = 0; i < num_bulk_in; ++i) {
endpoint = bulk_in_endpoint[i]; endpoint = bulk_in_endpoint[i];
port = &serial->port[i]; port = serial->port[i];
port->read_urb = usb_alloc_urb (0, GFP_KERNEL); port->read_urb = usb_alloc_urb (0, GFP_KERNEL);
if (!port->read_urb) { if (!port->read_urb) {
dev_err(&interface->dev, "No free urbs available\n"); dev_err(&interface->dev, "No free urbs available\n");
...@@ -1152,7 +1194,7 @@ int usb_serial_probe(struct usb_interface *interface, ...@@ -1152,7 +1194,7 @@ int usb_serial_probe(struct usb_interface *interface,
for (i = 0; i < num_bulk_out; ++i) { for (i = 0; i < num_bulk_out; ++i) {
endpoint = bulk_out_endpoint[i]; endpoint = bulk_out_endpoint[i];
port = &serial->port[i]; port = serial->port[i];
port->write_urb = usb_alloc_urb(0, GFP_KERNEL); port->write_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!port->write_urb) { if (!port->write_urb) {
dev_err(&interface->dev, "No free urbs available\n"); dev_err(&interface->dev, "No free urbs available\n");
...@@ -1178,7 +1220,7 @@ int usb_serial_probe(struct usb_interface *interface, ...@@ -1178,7 +1220,7 @@ int usb_serial_probe(struct usb_interface *interface,
for (i = 0; i < num_interrupt_in; ++i) { for (i = 0; i < num_interrupt_in; ++i) {
endpoint = interrupt_in_endpoint[i]; endpoint = interrupt_in_endpoint[i];
port = &serial->port[i]; port = serial->port[i];
port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!port->interrupt_in_urb) { if (!port->interrupt_in_urb) {
dev_err(&interface->dev, "No free urbs available\n"); dev_err(&interface->dev, "No free urbs available\n");
...@@ -1199,20 +1241,6 @@ int usb_serial_probe(struct usb_interface *interface, ...@@ -1199,20 +1241,6 @@ int usb_serial_probe(struct usb_interface *interface,
endpoint->bInterval); endpoint->bInterval);
} }
/* initialize some parts of the port structures */
/* we don't use num_ports here cauz some devices have more endpoint pairs than ports */
max_endpoints = max(num_bulk_in, num_bulk_out);
max_endpoints = max(max_endpoints, num_interrupt_in);
max_endpoints = max(max_endpoints, (int)serial->num_ports);
dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints);
for (i = 0; i < max_endpoints; ++i) {
port = &serial->port[i];
port->number = i + serial->minor;
port->serial = serial;
port->magic = USB_SERIAL_PORT_MAGIC;
INIT_WORK(&port->work, usb_serial_port_softint, port);
}
/* if this device type has an attach function, call it */ /* if this device type has an attach function, call it */
if (type->attach) { if (type->attach) {
if (!try_module_get(type->owner)) { if (!try_module_get(type->owner)) {
...@@ -1232,10 +1260,11 @@ int usb_serial_probe(struct usb_interface *interface, ...@@ -1232,10 +1260,11 @@ int usb_serial_probe(struct usb_interface *interface,
/* register all of the individual ports with the driver core */ /* register all of the individual ports with the driver core */
for (i = 0; i < num_ports; ++i) { for (i = 0; i < num_ports; ++i) {
port = &serial->port[i]; port = serial->port[i];
port->dev.parent = &serial->dev->dev; port->dev.parent = &serial->dev->dev;
port->dev.driver = NULL; port->dev.driver = NULL;
port->dev.bus = &usb_serial_bus_type; port->dev.bus = &usb_serial_bus_type;
port->dev.release = &port_release;
snprintf (&port->dev.bus_id[0], sizeof(port->dev.bus_id), "ttyUSB%d", port->number); snprintf (&port->dev.bus_id[0], sizeof(port->dev.bus_id), "ttyUSB%d", port->number);
dbg ("%s - registering %s", __FUNCTION__, port->dev.bus_id); dbg ("%s - registering %s", __FUNCTION__, port->dev.bus_id);
...@@ -1249,34 +1278,38 @@ int usb_serial_probe(struct usb_interface *interface, ...@@ -1249,34 +1278,38 @@ int usb_serial_probe(struct usb_interface *interface,
usb_set_intfdata (interface, serial); usb_set_intfdata (interface, serial);
return 0; return 0;
probe_error: probe_error:
for (i = 0; i < num_bulk_in; ++i) { for (i = 0; i < num_bulk_in; ++i) {
port = &serial->port[i]; port = serial->port[i];
if (!port)
continue;
if (port->read_urb) if (port->read_urb)
usb_free_urb (port->read_urb); usb_free_urb (port->read_urb);
if (port->bulk_in_buffer) kfree(port->bulk_in_buffer);
kfree (port->bulk_in_buffer);
} }
for (i = 0; i < num_bulk_out; ++i) { for (i = 0; i < num_bulk_out; ++i) {
port = &serial->port[i]; port = serial->port[i];
if (!port)
continue;
if (port->write_urb) if (port->write_urb)
usb_free_urb (port->write_urb); usb_free_urb (port->write_urb);
if (port->bulk_out_buffer) kfree(port->bulk_out_buffer);
kfree (port->bulk_out_buffer);
} }
for (i = 0; i < num_interrupt_in; ++i) { for (i = 0; i < num_interrupt_in; ++i) {
port = &serial->port[i]; port = serial->port[i];
if (!port)
continue;
if (port->interrupt_in_urb) if (port->interrupt_in_urb)
usb_free_urb (port->interrupt_in_urb); usb_free_urb (port->interrupt_in_urb);
if (port->interrupt_in_buffer) kfree(port->interrupt_in_buffer);
kfree (port->interrupt_in_buffer);
} }
/* return the minor range that this device had */ /* return the minor range that this device had */
return_serial (serial); return_serial (serial);
/* free up any memory that we allocated */ /* free up any memory that we allocated */
for (i = 0; i < serial->num_port_pointers; ++i)
kfree(serial->port[i]);
kfree (serial); kfree (serial);
return -EIO; return -EIO;
} }
......
...@@ -156,12 +156,13 @@ struct usb_serial { ...@@ -156,12 +156,13 @@ struct usb_serial {
struct usb_interface * interface; struct usb_interface * interface;
unsigned char minor; unsigned char minor;
unsigned char num_ports; unsigned char num_ports;
unsigned char num_port_pointers;
char num_interrupt_in; char num_interrupt_in;
char num_bulk_in; char num_bulk_in;
char num_bulk_out; char num_bulk_out;
__u16 vendor; __u16 vendor;
__u16 product; __u16 product;
struct usb_serial_port port[MAX_NUM_PORTS]; struct usb_serial_port * port[MAX_NUM_PORTS];
struct kobject kobj; struct kobject kobj;
void * private; void * private;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment