summaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/usbserial.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial/usbserial.c')
-rw-r--r--drivers/usb/serial/usbserial.c129
1 files changed, 73 insertions, 56 deletions
diff --git a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c
index 735aecaed..86c8755b8 100644
--- a/drivers/usb/serial/usbserial.c
+++ b/drivers/usb/serial/usbserial.c
@@ -15,6 +15,14 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (09/11/2000) gkh
+ * Removed DEBUG #ifdefs with call to usb_serial_debug_data
+ *
+ * (08/28/2000) gkh
+ * Added port_lock to port structure.
+ * Added locks for SMP safeness to generic driver
+ * Fixed the ability to open a generic device's port more than once.
+ *
* (07/23/2000) gkh
* Added bulk_out_endpointAddress to port structure.
*
@@ -264,6 +272,7 @@ static int generic_write_room (struct usb_serial_port *port);
static int generic_chars_in_buffer (struct usb_serial_port *port);
static void generic_read_bulk_callback (struct urb *urb);
static void generic_write_bulk_callback (struct urb *urb);
+static void generic_shutdown (struct usb_serial *serial);
#ifdef CONFIG_USB_SERIAL_GENERIC
@@ -287,6 +296,7 @@ static struct usb_serial_device_type generic_device = {
num_bulk_in: NUM_DONT_CARE,
num_bulk_out: NUM_DONT_CARE,
num_ports: 1,
+ shutdown: generic_shutdown,
};
#endif
@@ -321,21 +331,6 @@ static struct usb_serial *serial_table[SERIAL_TTY_MINORS] = {NULL, };
LIST_HEAD(usb_serial_driver_list);
-static inline struct usb_serial* get_usb_serial (struct usb_serial_port *port, const char *function)
-{
- /* if no port was specified, or it fails a paranoia check */
- if (!port ||
- port_paranoia_check (port, function) ||
- serial_paranoia_check (port->serial, function)) {
- /* then say that we dont have a valid usb_serial thing, which will
- * end up genrating -ENODEV return values */
- return NULL;
- }
-
- return port->serial;
-}
-
-
static struct usb_serial *get_serial_by_minor (int minor)
{
return serial_table[minor];
@@ -697,47 +692,65 @@ static void serial_break (struct tty_struct *tty, int break_state)
static int generic_open (struct usb_serial_port *port, struct file *filp)
{
struct usb_serial *serial = port->serial;
+ unsigned long flags;
+
+ if (port_paranoia_check (port, __FUNCTION__))
+ return -ENODEV;
dbg(__FUNCTION__ " - port %d", port->number);
- if (port->active) {
- dbg (__FUNCTION__ " - device already open");
- return -EINVAL;
- }
- port->active = 1;
-
- /* if we have a bulk interrupt, start reading from it */
- if (serial->num_bulk_in) {
- /*Start reading from the device*/
- if (usb_submit_urb(port->read_urb))
- dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed");
- }
+ spin_lock_irqsave (&port->port_lock, flags);
+
+ ++port->open_count;
+ MOD_INC_USE_COUNT;
+
+ if (!port->active) {
+ port->active = 1;
- return (0);
+ /* if we have a bulk interrupt, start reading from it */
+ if (serial->num_bulk_in) {
+ /*Start reading from the device*/
+ if (usb_submit_urb(port->read_urb))
+ dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed");
+ }
+ }
+
+ spin_unlock_irqrestore (&port->port_lock, flags);
+
+ return 0;
}
static void generic_close (struct usb_serial_port *port, struct file * filp)
{
struct usb_serial *serial = port->serial;
+ unsigned long flags;
dbg(__FUNCTION__ " - port %d", port->number);
-
- /* 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);
+
+ spin_lock_irqsave (&port->port_lock, flags);
+
+ --port->open_count;
+
+ if (port->open_count <= 0) {
+ /* 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->active = 0;
+ port->open_count = 0;
}
- port->active = 0;
+ spin_unlock_irqrestore (&port->port_lock, flags);
}
static int generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
{
struct usb_serial *serial = port->serial;
+ unsigned long flags;
dbg(__FUNCTION__ " - port %d", port->number);
@@ -753,18 +766,10 @@ static int generic_write (struct usb_serial_port *port, int from_user, const uns
return (0);
}
+ spin_lock_irqsave (&port->port_lock, flags);
count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
-#ifdef DEBUG
- {
- int i;
- printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", count);
- for (i = 0; i < count; ++i) {
- printk ("%.2x ", buf[i]);
- }
- printk ("\n");
- }
-#endif
+ usb_serial_debug_data (__FILE__, __FUNCTION__, count, buf);
if (from_user) {
copy_from_user(port->write_urb->transfer_buffer, buf, count);
@@ -776,9 +781,13 @@ static int generic_write (struct usb_serial_port *port, int from_user, const uns
/* send the data out the bulk port */
port->write_urb->transfer_buffer_length = count;
- if (usb_submit_urb(port->write_urb))
+ if (usb_submit_urb(port->write_urb)) {
dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed");
+ spin_unlock_irqrestore (&port->port_lock, flags);
+ return 0;
+ }
+ spin_unlock_irqrestore (&port->port_lock, flags);
return (count);
}
@@ -839,15 +848,7 @@ static void generic_read_bulk_callback (struct urb *urb)
return;
}
-#ifdef DEBUG
- if (urb->actual_length) {
- printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ "- length = %d, data = ", urb->actual_length);
- for (i = 0; i < urb->actual_length; ++i) {
- printk ("%.2x ", data[i]);
- }
- printk ("\n");
- }
-#endif
+ usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
tty = port->tty;
if (urb->actual_length) {
@@ -889,6 +890,21 @@ static void generic_write_bulk_callback (struct urb *urb)
}
+static void generic_shutdown (struct usb_serial *serial)
+{
+ int i;
+
+ dbg (__FUNCTION__);
+
+ /* stop reads and writes on all ports */
+ for (i=0; i < serial->num_ports; ++i) {
+ while (serial->port[i].open_count > 0) {
+ generic_close (&serial->port[i], NULL);
+ }
+ }
+}
+
+
static void port_softint(void *private)
{
struct usb_serial_port *port = (struct usb_serial_port *)private;
@@ -1127,6 +1143,7 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
port->magic = USB_SERIAL_PORT_MAGIC;
port->tqueue.routine = port_softint;
port->tqueue.data = port;
+ spin_lock_init (&port->port_lock);
}
/* initialize the devfs nodes for this device and let the user know what ports we are bound to */