# 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.554 -> 1.555 # drivers/usb/serial/usbserial.c 1.26 -> 1.27 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/03/21 greg@kroah.com 1.555 # USB serial driver core # # - Moved all manipulation of port->open_count into the core. Now the # individual driver's open and close functions are called only when the # first open() and last close() is called. Making the drivers a bit # smaller and simpler. # - Fixed a bug if a driver didn't have the owner field set. # -------------------------------------------- # 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:51 2002 +++ b/drivers/usb/serial/usbserial.c Wed Apr 3 16:39:51 2002 @@ -15,6 +15,13 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (03/21/2002) gkh + * Moved all manipulation of port->open_count into the core. Now the + * individual driver's open and close functions are called only when the + * first open() and last close() is called. Making the drivers a bit + * smaller and simpler. + * Fixed a bug if a driver didn't have the owner field set. + * * (02/26/2002) gkh * Moved all locking into the main serial_* functions, instead of having * the individual drivers have to grab the port semaphore. This should @@ -500,7 +507,7 @@ struct usb_serial *serial; struct usb_serial_port *port; unsigned int portNumber; - int retval; + int retval = 0; dbg(__FUNCTION__); @@ -525,14 +532,21 @@ if (serial->type->owner) __MOD_INC_USE_COUNT(serial->type->owner); - /* pass on to the driver specific version of this function if it is available */ - if (serial->type->open) - retval = serial->type->open(port, filp); - else - retval = generic_open(port, filp); + ++port->open_count; + if (port->open_count == 1) { + /* only call the device specific open if this + * is the first time the port is opened */ + if (serial->type->open) + retval = serial->type->open(port, filp); + else + retval = generic_open(port, filp); + } - if (retval) - __MOD_DEC_USE_COUNT(serial->type->owner); + if (retval) { + port->open_count = 0; + if (serial->type->owner) + __MOD_DEC_USE_COUNT(serial->type->owner); + } up (&port->sem); return retval; @@ -559,11 +573,16 @@ goto exit_no_mod_dec; } - /* pass on to the driver specific version of this function if it is available */ - if (serial->type->close) - serial->type->close(port, filp); - else - generic_close(port, filp); + --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); + else + generic_close(port, filp); + port->open_count = 0; + } exit: if (serial->type->owner) @@ -791,6 +810,8 @@ static void serial_shutdown (struct usb_serial *serial) { + dbg(__FUNCTION__); + if (serial->type->shutdown) serial->type->shutdown(serial); else @@ -810,54 +831,51 @@ dbg(__FUNCTION__ " - port %d", port->number); - ++port->open_count; - - if (port->open_count == 1) { - /* force low_latency on so that our tty_push actually forces the data through, - otherwise it is scheduled, and with high data rates (like with OHCI) data - can get lost. */ - port->tty->low_latency = 1; - - /* if we have a bulk interrupt, start reading from it */ - if (serial->num_bulk_in) { - /* Start reading from the device */ - usb_fill_bulk_urb (port->read_urb, serial->dev, - usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - ((serial->type->read_bulk_callback) ? - serial->type->read_bulk_callback : - generic_read_bulk_callback), - port); - result = usb_submit_urb(port->read_urb, GFP_KERNEL); - if (result) - err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); - } + /* force low_latency on so that our tty_push actually forces the data through, + otherwise it is scheduled, and with high data rates (like with OHCI) data + can get lost. */ + port->tty->low_latency = 1; + + /* if we have a bulk interrupt, start reading from it */ + if (serial->num_bulk_in) { + /* Start reading from the device */ + usb_fill_bulk_urb (port->read_urb, serial->dev, + usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), + port->read_urb->transfer_buffer, + port->read_urb->transfer_buffer_length, + ((serial->type->read_bulk_callback) ? + serial->type->read_bulk_callback : + generic_read_bulk_callback), + port); + result = usb_submit_urb(port->read_urb, GFP_KERNEL); + if (result) + err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); } return result; } -static void generic_close (struct usb_serial_port *port, struct file * filp) +static void generic_cleanup (struct usb_serial_port *port) { struct usb_serial *serial = port->serial; dbg(__FUNCTION__ " - port %d", port->number); - --port->open_count; - - if (port->open_count <= 0) { - if (serial->dev) { - /* shutdown any bulk reads that might be going on */ - if (serial->num_bulk_out) - usb_unlink_urb (port->write_urb); - if (serial->num_bulk_in) - usb_unlink_urb (port->read_urb); - } - port->open_count = 0; + if (serial->dev) { + /* shutdown any bulk reads that might be going on */ + if (serial->num_bulk_out) + usb_unlink_urb (port->write_urb); + if (serial->num_bulk_in) + usb_unlink_urb (port->read_urb); } } +static void generic_close (struct usb_serial_port *port, struct file * filp) +{ + dbg(__FUNCTION__ " - port %d", port->number); + generic_cleanup (port); +} + static int generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count) { struct usb_serial *serial = port->serial; @@ -1025,10 +1043,7 @@ /* stop reads and writes on all ports */ for (i=0; i < serial->num_ports; ++i) { - down (&serial->port[i].sem); - while (serial->port[i].open_count > 0) - generic_close (&serial->port[i], NULL); - up (&serial->port[i].sem); + generic_cleanup (&serial->port[i]); } } @@ -1040,11 +1055,13 @@ dbg(__FUNCTION__ " - port %d", port->number); - if (!serial) { + if (!serial) return; - } tty = port->tty; + if (!tty) + return; + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) { dbg(__FUNCTION__ " - write wakeup call."); (tty->ldisc.write_wakeup)(tty); @@ -1334,6 +1351,7 @@ struct usb_serial_port *port; int i; + dbg(__FUNCTION__); if (serial) { /* fail all future close/read/write/ioctl/etc calls */ for (i = 0; i < serial->num_ports; ++i) {