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>
This commit is contained in:
parent
828d55c58c
commit
a1cd7e99b3
|
@ -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,
|
||||||
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)
|
||||||
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)
|
||||||
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 {
|
||||||
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 {
|
||||||
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)
|
||||||
|
|
Loading…
Reference in New Issue