aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOliver Neukum <oliver@neukum.org>2008-01-16 11:18:52 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2008-02-01 17:35:03 -0500
commita1cd7e99b343543af2be4c8c5755e26f6bfd725a (patch)
tree41f8de097dd0889a9c6d02fa0a22b16d5146de46
parent828d55c58cba6b652fd30e00c3d940cb7c523e3c (diff)
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)
564 } 564 }
565 565
566 /* While closing port, shutdown all bulk read, write * 566 /* While closing port, shutdown all bulk read, write *
567 * and interrupt read if they exists */ 567 * and interrupt read if they exists, otherwise nop */
568 if (serial->dev) { 568 dbg("Shutdown bulk write");
569 dbg("Shutdown bulk write"); 569 usb_kill_urb(port->write_urb);
570 usb_kill_urb(port->write_urb); 570 dbg("Shutdown bulk read");
571 dbg("Shutdown bulk read"); 571 usb_kill_urb(port->read_urb);
572 usb_kill_urb(port->read_urb); 572
573 mutex_lock(&serial->disc_mutex);
574 /* these commands must not be issued if the device has
575 * been disconnected */
576 if (!serial->disconnected) {
577 data = 0x00;
578 send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
579 0x04, &data);
580
581 data = 0x00;
582 send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
583 0x01, &data);
573 } 584 }
574 585 mutex_unlock(&serial->disc_mutex);
575 data = 0x00;
576 send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
577 0x04, &data);
578
579 data = 0x00;
580 send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
581 0x01, &data);
582
583 mos7720_port->open = 0; 586 mos7720_port->open = 0;
584 587
585 dbg("Leaving %s", __FUNCTION__); 588 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,
634 serial->type = driver; 634 serial->type = driver;
635 serial->interface = interface; 635 serial->interface = interface;
636 kref_init(&serial->kref); 636 kref_init(&serial->kref);
637 mutex_init(&serial->disc_mutex);
637 638
638 return serial; 639 return serial;
639} 640}
@@ -1089,20 +1090,22 @@ void usb_serial_disconnect(struct usb_interface *interface)
1089 usb_serial_console_disconnect(serial); 1090 usb_serial_console_disconnect(serial);
1090 dbg ("%s", __FUNCTION__); 1091 dbg ("%s", __FUNCTION__);
1091 1092
1093 mutex_lock(&serial->disc_mutex);
1092 usb_set_intfdata (interface, NULL); 1094 usb_set_intfdata (interface, NULL);
1093 if (serial) { 1095 /* must set a flag, to signal subdrivers */
1094 for (i = 0; i < serial->num_ports; ++i) { 1096 serial->disconnected = 1;
1095 port = serial->port[i]; 1097 for (i = 0; i < serial->num_ports; ++i) {
1096 if (port) { 1098 port = serial->port[i];
1097 if (port->tty) 1099 if (port) {
1098 tty_hangup(port->tty); 1100 if (port->tty)
1099 kill_traffic(port); 1101 tty_hangup(port->tty);
1100 } 1102 kill_traffic(port);
1101 } 1103 }
1102 /* let the last holder of this object
1103 * cause it to be cleaned up */
1104 usb_serial_put(serial);
1105 } 1104 }
1105 /* let the last holder of this object
1106 * cause it to be cleaned up */
1107 mutex_unlock(&serial->disc_mutex);
1108 usb_serial_put(serial);
1106 dev_info(dev, "device disconnected\n"); 1109 dev_info(dev, "device disconnected\n");
1107} 1110}
1108 1111
@@ -1112,9 +1115,6 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
1112 struct usb_serial_port *port; 1115 struct usb_serial_port *port;
1113 int i, r = 0; 1116 int i, r = 0;
1114 1117
1115 if (!serial) /* device has been disconnected */
1116 return 0;
1117
1118 for (i = 0; i < serial->num_ports; ++i) { 1118 for (i = 0; i < serial->num_ports; ++i) {
1119 port = serial->port[i]; 1119 port = serial->port[i];
1120 if (port) 1120 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 {
129 struct usb_device * dev; 129 struct usb_device * dev;
130 struct usb_serial_driver * type; 130 struct usb_serial_driver * type;
131 struct usb_interface * interface; 131 struct usb_interface * interface;
132 unsigned char disconnected;
132 unsigned char minor; 133 unsigned char minor;
133 unsigned char num_ports; 134 unsigned char num_ports;
134 unsigned char num_port_pointers; 135 unsigned char num_port_pointers;
@@ -138,6 +139,7 @@ struct usb_serial {
138 char num_bulk_out; 139 char num_bulk_out;
139 struct usb_serial_port * port[MAX_NUM_PORTS]; 140 struct usb_serial_port * port[MAX_NUM_PORTS];
140 struct kref kref; 141 struct kref kref;
142 struct mutex disc_mutex;
141 void * private; 143 void * private;
142}; 144};
143#define to_usb_serial(d) container_of(d, struct usb_serial, kref) 145#define to_usb_serial(d) container_of(d, struct usb_serial, kref)