# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.571   -> 1.572  
#	drivers/usb/serial/usbserial.c	1.28    -> 1.29   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/03/28	ganesh@veritas.com	1.572
# USB serial core
# 
# Module count of a serial converter driver is currently not
# decremented if a disconnect happens while the tty is held open.
# The fix is to close the device in usb_serial_disconnect() so that
# module refcounts are properly updated.
# --------------------------------------------
#
diff -Nru a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c
--- a/drivers/usb/serial/usbserial.c	Wed Apr  3 16:39:19 2002
+++ b/drivers/usb/serial/usbserial.c	Wed Apr  3 16:39:19 2002
@@ -576,43 +576,45 @@
 	return retval;
 }
 
-static void serial_close(struct tty_struct *tty, struct file * filp)
+static void __serial_close(struct usb_serial_port *port, struct file *filp)
 {
-	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
-
-	if (!serial)
-		return;
-
-	down (&port->sem);
-
-	dbg(__FUNCTION__ " - port %d", port->number);
-
-	if (tty->driver_data == NULL) {
-		/* disconnect beat us to the punch here, so handle it gracefully */
-		goto exit;
-	}
 	if (!port->open_count) {
 		dbg (__FUNCTION__ " - port not opened");
-		goto exit_no_mod_dec;
+		return;
 	}
 
 	--port->open_count;
 	if (port->open_count <= 0) {
 		/* only call the device specific close if this 
 		 * port is being closed by the last owner */
-		if (serial->type->close)
-			serial->type->close(port, filp);
+		if (port->serial->type->close)
+			port->serial->type->close(port, filp);
 		else
 			generic_close(port, filp);
 		port->open_count = 0;
 	}
 
-exit:
-	if (serial->type->owner)
-		__MOD_DEC_USE_COUNT(serial->type->owner);
+	if (port->serial->type->owner)
+		__MOD_DEC_USE_COUNT(port->serial->type->owner);
+}
+
+static void serial_close(struct tty_struct *tty, struct file * filp)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+
+	if (!serial)
+		return;
+
+	down (&port->sem);
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	/* if disconnect beat us to the punch here, there's nothing to do */
+	if (tty->driver_data) {
+		__serial_close(port, filp);
+	}
 
-exit_no_mod_dec:
 	up (&port->sem);
 }
 
@@ -1400,10 +1402,15 @@
 	if (serial) {
 		/* fail all future close/read/write/ioctl/etc calls */
 		for (i = 0; i < serial->num_ports; ++i) {
-			down (&serial->port[i].sem);
-			if (serial->port[i].tty != NULL)
-				serial->port[i].tty->driver_data = NULL;
-			up (&serial->port[i].sem);
+			port = &serial->port[i];
+			down (&port->sem);
+			if (port->tty != NULL) {
+				while (port->open_count > 0) {
+					__serial_close(port, NULL);
+				}
+				port->tty->driver_data = NULL;
+			}
+			up (&port->sem);
 		}
 
 		serial->dev = NULL;
