summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOliver Neukum <oliver@neukum.org>2008-01-16 17:18:52 +0100
committerGreg Kroah-Hartman <gregkh@suse.de>2008-02-01 23:35:03 +0100
commita1cd7e99b343543af2be4c8c5755e26f6bfd725a (patch)
tree41f8de097dd0889a9c6d02fa0a22b16d5146de46
parentUSB: add support for SuperH OHCI (diff)
downloadlinux-a1cd7e99b343543af2be4c8c5755e26f6bfd725a.tar.xz
linux-a1cd7e99b343543af2be4c8c5755e26f6bfd725a.zip
USB: stop io performed by mos7720 upon close()
This fixes a problem where the mos7720 driver will make io to a device from which it has been logically disconnected. It does so by introducing a flag by which the generic usb serial code can signal the subdrivers their disconnection and appropriate locking. Signed-off-by: Oliver Neukum <oneukum@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/serial/mos7720.c33
-rw-r--r--drivers/usb/serial/usb-serial.c28
-rw-r--r--include/linux/usb/serial.h2
3 files changed, 34 insertions, 29 deletions
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 725991fadc26..40f3a0188807 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -564,22 +564,25 @@ static void mos7720_close(struct usb_serial_port *port, struct file *filp)
}
/* While closing port, shutdown all bulk read, write *
- * and interrupt read if they exists */
- if (serial->dev) {
- dbg("Shutdown bulk write");
- usb_kill_urb(port->write_urb);
- dbg("Shutdown bulk read");
- usb_kill_urb(port->read_urb);
+ * and interrupt read if they exists, otherwise nop */
+ dbg("Shutdown bulk write");
+ usb_kill_urb(port->write_urb);
+ dbg("Shutdown bulk read");
+ usb_kill_urb(port->read_urb);
+
+ mutex_lock(&serial->disc_mutex);
+ /* these commands must not be issued if the device has
+ * been disconnected */
+ if (!serial->disconnected) {
+ data = 0x00;
+ send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
+ 0x04, &data);
+
+ data = 0x00;
+ send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
+ 0x01, &data);
}
-
- data = 0x00;
- send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
- 0x04, &data);
-
- data = 0x00;
- send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
- 0x01, &data);
-
+ mutex_unlock(&serial->disc_mutex);
mos7720_port->open = 0;
dbg("Leaving %s", __FUNCTION__);
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 28315b05c9cc..3ce98e8d7bce 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -634,6 +634,7 @@ static struct usb_serial * create_serial (struct usb_device *dev,
serial->type = driver;
serial->interface = interface;
kref_init(&serial->kref);
+ mutex_init(&serial->disc_mutex);
return serial;
}
@@ -1089,20 +1090,22 @@ void usb_serial_disconnect(struct usb_interface *interface)
usb_serial_console_disconnect(serial);
dbg ("%s", __FUNCTION__);
+ mutex_lock(&serial->disc_mutex);
usb_set_intfdata (interface, NULL);
- if (serial) {
- for (i = 0; i < serial->num_ports; ++i) {
- port = serial->port[i];
- if (port) {
- if (port->tty)
- tty_hangup(port->tty);
- kill_traffic(port);
- }
+ /* must set a flag, to signal subdrivers */
+ serial->disconnected = 1;
+ for (i = 0; i < serial->num_ports; ++i) {
+ port = serial->port[i];
+ if (port) {
+ if (port->tty)
+ tty_hangup(port->tty);
+ kill_traffic(port);
}
- /* let the last holder of this object
- * cause it to be cleaned up */
- usb_serial_put(serial);
}
+ /* let the last holder of this object
+ * cause it to be cleaned up */
+ mutex_unlock(&serial->disc_mutex);
+ usb_serial_put(serial);
dev_info(dev, "device disconnected\n");
}
@@ -1112,9 +1115,6 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
struct usb_serial_port *port;
int i, r = 0;
- if (!serial) /* device has been disconnected */
- return 0;
-
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
if (port)
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
index ef1e430f7bfa..63b29b5332e6 100644
--- a/include/linux/usb/serial.h
+++ b/include/linux/usb/serial.h
@@ -129,6 +129,7 @@ struct usb_serial {
struct usb_device * dev;
struct usb_serial_driver * type;
struct usb_interface * interface;
+ unsigned char disconnected;
unsigned char minor;
unsigned char num_ports;
unsigned char num_port_pointers;
@@ -138,6 +139,7 @@ struct usb_serial {
char num_bulk_out;
struct usb_serial_port * port[MAX_NUM_PORTS];
struct kref kref;
+ struct mutex disc_mutex;
void * private;
};
#define to_usb_serial(d) container_of(d, struct usb_serial, kref)