Commit a1cd7e99 authored by Oliver Neukum's avatar Oliver Neukum Committed by Greg Kroah-Hartman

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: default avatarOliver Neukum <oneukum@suse.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 828d55c5
...@@ -564,22 +564,25 @@ static void mos7720_close(struct usb_serial_port *port, struct file *filp) ...@@ -564,22 +564,25 @@ static void mos7720_close(struct usb_serial_port *port, struct file *filp)
} }
/* While closing port, shutdown all bulk read, write * /* While closing port, shutdown all bulk read, write *
* and interrupt read if they exists */ * and interrupt read if they exists, otherwise nop */
if (serial->dev) { dbg("Shutdown bulk write");
dbg("Shutdown bulk write"); usb_kill_urb(port->write_urb);
usb_kill_urb(port->write_urb); dbg("Shutdown bulk read");
dbg("Shutdown bulk read"); usb_kill_urb(port->read_urb);
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);
} }
mutex_unlock(&serial->disc_mutex);
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);
mos7720_port->open = 0; mos7720_port->open = 0;
dbg("Leaving %s", __FUNCTION__); dbg("Leaving %s", __FUNCTION__);
......
...@@ -634,6 +634,7 @@ static struct usb_serial * create_serial (struct usb_device *dev, ...@@ -634,6 +634,7 @@ static struct usb_serial * create_serial (struct usb_device *dev,
serial->type = driver; serial->type = driver;
serial->interface = interface; serial->interface = interface;
kref_init(&serial->kref); kref_init(&serial->kref);
mutex_init(&serial->disc_mutex);
return serial; return serial;
} }
...@@ -1089,20 +1090,22 @@ void usb_serial_disconnect(struct usb_interface *interface) ...@@ -1089,20 +1090,22 @@ void usb_serial_disconnect(struct usb_interface *interface)
usb_serial_console_disconnect(serial); usb_serial_console_disconnect(serial);
dbg ("%s", __FUNCTION__); dbg ("%s", __FUNCTION__);
mutex_lock(&serial->disc_mutex);
usb_set_intfdata (interface, NULL); usb_set_intfdata (interface, NULL);
if (serial) { /* must set a flag, to signal subdrivers */
for (i = 0; i < serial->num_ports; ++i) { serial->disconnected = 1;
port = serial->port[i]; for (i = 0; i < serial->num_ports; ++i) {
if (port) { port = serial->port[i];
if (port->tty) if (port) {
tty_hangup(port->tty); if (port->tty)
kill_traffic(port); 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"); dev_info(dev, "device disconnected\n");
} }
...@@ -1112,9 +1115,6 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message) ...@@ -1112,9 +1115,6 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
struct usb_serial_port *port; struct usb_serial_port *port;
int i, r = 0; int i, r = 0;
if (!serial) /* device has been disconnected */
return 0;
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) if (port)
......
...@@ -129,6 +129,7 @@ struct usb_serial { ...@@ -129,6 +129,7 @@ struct usb_serial {
struct usb_device * dev; struct usb_device * dev;
struct usb_serial_driver * type; struct usb_serial_driver * type;
struct usb_interface * interface; struct usb_interface * interface;
unsigned char disconnected;
unsigned char minor; unsigned char minor;
unsigned char num_ports; unsigned char num_ports;
unsigned char num_port_pointers; unsigned char num_port_pointers;
...@@ -138,6 +139,7 @@ struct usb_serial { ...@@ -138,6 +139,7 @@ struct usb_serial {
char num_bulk_out; char num_bulk_out;
struct usb_serial_port * port[MAX_NUM_PORTS]; struct usb_serial_port * port[MAX_NUM_PORTS];
struct kref kref; struct kref kref;
struct mutex disc_mutex;
void * private; void * private;
}; };
#define to_usb_serial(d) container_of(d, struct usb_serial, kref) #define to_usb_serial(d) container_of(d, struct usb_serial, kref)
......
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