Commit 9fb1cce0 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

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.
parent 16c12b0b
...@@ -15,6 +15,13 @@ ...@@ -15,6 +15,13 @@
* *
* See Documentation/usb/usb-serial.txt for more information on using this driver * 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 * (02/26/2002) gkh
* Moved all locking into the main serial_* functions, instead of having * Moved all locking into the main serial_* functions, instead of having
* the individual drivers have to grab the port semaphore. This should * the individual drivers have to grab the port semaphore. This should
...@@ -500,7 +507,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp) ...@@ -500,7 +507,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
struct usb_serial *serial; struct usb_serial *serial;
struct usb_serial_port *port; struct usb_serial_port *port;
unsigned int portNumber; unsigned int portNumber;
int retval; int retval = 0;
dbg(__FUNCTION__); dbg(__FUNCTION__);
...@@ -525,14 +532,21 @@ static int serial_open (struct tty_struct *tty, struct file * filp) ...@@ -525,14 +532,21 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
if (serial->type->owner) if (serial->type->owner)
__MOD_INC_USE_COUNT(serial->type->owner); __MOD_INC_USE_COUNT(serial->type->owner);
/* pass on to the driver specific version of this function if it is available */ ++port->open_count;
if (serial->type->open) if (port->open_count == 1) {
retval = serial->type->open(port, filp); /* only call the device specific open if this
else * is the first time the port is opened */
retval = generic_open(port, filp); if (serial->type->open)
retval = serial->type->open(port, filp);
else
retval = generic_open(port, filp);
}
if (retval) if (retval) {
__MOD_DEC_USE_COUNT(serial->type->owner); port->open_count = 0;
if (serial->type->owner)
__MOD_DEC_USE_COUNT(serial->type->owner);
}
up (&port->sem); up (&port->sem);
return retval; return retval;
...@@ -559,11 +573,16 @@ static void serial_close(struct tty_struct *tty, struct file * filp) ...@@ -559,11 +573,16 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
goto exit_no_mod_dec; goto exit_no_mod_dec;
} }
/* pass on to the driver specific version of this function if it is available */ --port->open_count;
if (serial->type->close) if (port->open_count <= 0) {
serial->type->close(port, filp); /* only call the device specific close if this
else * port is being closed by the last owner */
generic_close(port, filp); if (serial->type->close)
serial->type->close(port, filp);
else
generic_close(port, filp);
port->open_count = 0;
}
exit: exit:
if (serial->type->owner) if (serial->type->owner)
...@@ -791,6 +810,8 @@ static void serial_break (struct tty_struct *tty, int break_state) ...@@ -791,6 +810,8 @@ static void serial_break (struct tty_struct *tty, int break_state)
static void serial_shutdown (struct usb_serial *serial) static void serial_shutdown (struct usb_serial *serial)
{ {
dbg(__FUNCTION__);
if (serial->type->shutdown) if (serial->type->shutdown)
serial->type->shutdown(serial); serial->type->shutdown(serial);
else else
...@@ -810,54 +831,51 @@ static int generic_open (struct usb_serial_port *port, struct file *filp) ...@@ -810,54 +831,51 @@ static int generic_open (struct usb_serial_port *port, struct file *filp)
dbg(__FUNCTION__ " - port %d", port->number); dbg(__FUNCTION__ " - port %d", port->number);
++port->open_count; /* 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
if (port->open_count == 1) { can get lost. */
/* force low_latency on so that our tty_push actually forces the data through, port->tty->low_latency = 1;
otherwise it is scheduled, and with high data rates (like with OHCI) data
can get lost. */ /* if we have a bulk interrupt, start reading from it */
port->tty->low_latency = 1; if (serial->num_bulk_in) {
/* Start reading from the device */
/* if we have a bulk interrupt, start reading from it */ usb_fill_bulk_urb (port->read_urb, serial->dev,
if (serial->num_bulk_in) { usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
/* Start reading from the device */ port->read_urb->transfer_buffer,
usb_fill_bulk_urb (port->read_urb, serial->dev, port->read_urb->transfer_buffer_length,
usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), ((serial->type->read_bulk_callback) ?
port->read_urb->transfer_buffer, serial->type->read_bulk_callback :
port->read_urb->transfer_buffer_length, generic_read_bulk_callback),
((serial->type->read_bulk_callback) ? port);
serial->type->read_bulk_callback : result = usb_submit_urb(port->read_urb, GFP_KERNEL);
generic_read_bulk_callback), if (result)
port); err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
result = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (result)
err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
}
} }
return 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; struct usb_serial *serial = port->serial;
dbg(__FUNCTION__ " - port %d", port->number); dbg(__FUNCTION__ " - port %d", port->number);
--port->open_count; if (serial->dev) {
/* shutdown any bulk reads that might be going on */
if (port->open_count <= 0) { if (serial->num_bulk_out)
if (serial->dev) { usb_unlink_urb (port->write_urb);
/* shutdown any bulk reads that might be going on */ if (serial->num_bulk_in)
if (serial->num_bulk_out) usb_unlink_urb (port->read_urb);
usb_unlink_urb (port->write_urb);
if (serial->num_bulk_in)
usb_unlink_urb (port->read_urb);
}
port->open_count = 0;
} }
} }
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) static int generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
{ {
struct usb_serial *serial = port->serial; struct usb_serial *serial = port->serial;
...@@ -1025,10 +1043,7 @@ static void generic_shutdown (struct usb_serial *serial) ...@@ -1025,10 +1043,7 @@ static void generic_shutdown (struct usb_serial *serial)
/* stop reads and writes on all ports */ /* stop reads and writes on all ports */
for (i=0; i < serial->num_ports; ++i) { for (i=0; i < serial->num_ports; ++i) {
down (&serial->port[i].sem); generic_cleanup (&serial->port[i]);
while (serial->port[i].open_count > 0)
generic_close (&serial->port[i], NULL);
up (&serial->port[i].sem);
} }
} }
...@@ -1040,11 +1055,13 @@ static void port_softint(void *private) ...@@ -1040,11 +1055,13 @@ static void port_softint(void *private)
dbg(__FUNCTION__ " - port %d", port->number); dbg(__FUNCTION__ " - port %d", port->number);
if (!serial) { if (!serial)
return; return;
}
tty = port->tty; tty = port->tty;
if (!tty)
return;
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) { if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
dbg(__FUNCTION__ " - write wakeup call."); dbg(__FUNCTION__ " - write wakeup call.");
(tty->ldisc.write_wakeup)(tty); (tty->ldisc.write_wakeup)(tty);
...@@ -1334,6 +1351,7 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr) ...@@ -1334,6 +1351,7 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
struct usb_serial_port *port; struct usb_serial_port *port;
int i; int i;
dbg(__FUNCTION__);
if (serial) { if (serial) {
/* fail all future close/read/write/ioctl/etc calls */ /* fail all future close/read/write/ioctl/etc calls */
for (i = 0; i < serial->num_ports; ++i) { for (i = 0; i < serial->num_ports; ++i) {
......
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