Hi,

Here's a patch against the usb-serial drivers that fixes a number of SMP
locking issues (like holding a spinlock while calling copy_from_user)
and other not so nice things.

The patch is against 2.4.6-pre1.

thanks,

greg k-h

diff -Nru a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
--- a/drivers/usb/serial/belkin_sa.c    Tue Jun  5 14:02:34 2001
+++ b/drivers/usb/serial/belkin_sa.c    Tue Jun  5 14:02:34 2001
@@ -24,6 +24,9 @@
  * -- Add support for flush commands
  * -- Add everything that is missing :)
  * 
+ * (30-May-2001 gkh
+ *     switched from using spinlock to a semaphore, which fixes lots of problems.
+ *
  * 08-Apr-2001 gb
  *     - Identify version on module load.
  *
@@ -85,7 +88,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.0.0"
+#define DRIVER_VERSION "v1.1"
 #define DRIVER_AUTHOR "William Greathouse <[EMAIL PROTECTED]>"
 #define DRIVER_DESC "USB Belkin Serial converter driver"
 
@@ -282,11 +285,11 @@
 
 static int  belkin_sa_open (struct usb_serial_port *port, struct file *filp)
 {
-       unsigned long flags;
+       int retval = 0;
 
        dbg(__FUNCTION__" port %d", port->number);
 
-       spin_lock_irqsave (&port->port_lock, flags);
+       down (&port->sem);
        
        ++port->open_count;
        MOD_INC_USE_COUNT;
@@ -299,30 +302,32 @@
                 *       enhance buffering.  Win trace shows 16 initial read URBs.
                 */
                port->read_urb->dev = port->serial->dev;
-               if (usb_submit_urb(port->read_urb))
+               retval = usb_submit_urb(port->read_urb);
+               if (retval) {
                        err("usb_submit_urb(read bulk) failed");
+                       goto exit;
+               }
 
                port->interrupt_in_urb->dev = port->serial->dev;
-               if (usb_submit_urb(port->interrupt_in_urb))
+               retval = usb_submit_urb(port->interrupt_in_urb);
+               if (retval)
                        err(" usb_submit_urb(read int) failed");
        }
        
-       spin_unlock_irqrestore (&port->port_lock, flags);
+exit:
+       up (&port->sem);
 
-       return 0;
+       return retval;
 } /* belkin_sa_open */
 
 
 static void belkin_sa_close (struct usb_serial_port *port, struct file *filp)
 {
-       unsigned long flags;
-
        dbg(__FUNCTION__" port %d", port->number);
 
-       spin_lock_irqsave (&port->port_lock, flags);
+       down (&port->sem);
 
        --port->open_count;
-       MOD_DEC_USE_COUNT;
 
        if (port->open_count <= 0) {
                /* shutdown our bulk reads and writes */
@@ -332,7 +337,8 @@
                port->active = 0;
        }
        
-       spin_unlock_irqrestore (&port->port_lock, flags);
+       up (&port->sem);
+       MOD_DEC_USE_COUNT;
 } /* belkin_sa_close */
 
 
diff -Nru a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
--- a/drivers/usb/serial/empeg.c        Tue Jun  5 14:02:34 2001
+++ b/drivers/usb/serial/empeg.c        Tue Jun  5 14:02:34 2001
@@ -1,10 +1,10 @@
 /*
  * USB Empeg empeg-car player driver
  *
- *     Copyright (C) 2000
+ *     Copyright (C) 2000, 2001
  *         Gary Brubaker ([EMAIL PROTECTED])
  *
- *     Copyright (C) 1999, 2000
+ *     Copyright (C) 1999 - 2001
  *         Greg Kroah-Hartman ([EMAIL PROTECTED])
  *
  *     This program is free software; you can redistribute it and/or modify
@@ -13,6 +13,9 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * (05/30/2001) gkh
+ *     switched from using spinlock to a semaphore, which fixes lots of problems.
+ *
  * (04/08/2001) gb
  *      Identify version on module load.
  * 
@@ -71,7 +74,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.0.0"
+#define DRIVER_VERSION "v1.1"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <[EMAIL PROTECTED]>, Gary Brubaker 
<[EMAIL PROTECTED]>"
 #define DRIVER_DESC "USB Empeg Mark I/II Driver"
 
@@ -147,15 +150,14 @@
 static int empeg_open (struct usb_serial_port *port, struct file *filp)
 {
        struct usb_serial *serial = port->serial;
-       unsigned long flags;
-       int result;
+       int result = 0;;
 
        if (port_paranoia_check (port, __FUNCTION__))
                return -ENODEV;
 
        dbg(__FUNCTION__ " - port %d", port->number);
 
-       spin_lock_irqsave (&port->port_lock, flags);
+       down (&port->sem);
 
        ++port->open_count;
        MOD_INC_USE_COUNT;
@@ -236,9 +238,9 @@
 
        }
 
-       spin_unlock_irqrestore (&port->port_lock, flags);
+       up (&port->sem);
 
-       return 0;
+       return result;
 }
 
 
@@ -246,7 +248,6 @@
 {
        struct usb_serial *serial;
        unsigned char *transfer_buffer;
-       unsigned long flags;
 
        if (port_paranoia_check (port, __FUNCTION__))
                return;
@@ -257,7 +258,7 @@
        if (!serial)
                return;
 
-       spin_lock_irqsave (&port->port_lock, flags);
+       down (&port->sem);
 
        --port->open_count;
 
@@ -276,13 +277,12 @@
                port->open_count = 0;
        }
 
-       spin_unlock_irqrestore (&port->port_lock, flags);
+       up (&port->sem);
 
        /* Uncomment the following line if you want to see some statistics in your 
syslog */
        /* info ("Bytes In = %d  Bytes Out = %d", bytes_in, bytes_out); */
 
        MOD_DEC_USE_COUNT;
-
 }
 
 
@@ -377,7 +377,7 @@
 
        dbg(__FUNCTION__ " - port %d", port->number);
 
-       spin_lock_irqsave (&port->port_lock, flags);
+       spin_lock_irqsave (&write_urb_pool_lock, flags);
 
        /* tally up the number of bytes available */
        for (i = 0; i < NUM_URBS; ++i) {
@@ -386,7 +386,7 @@
                }
        } 
 
-       spin_unlock_irqrestore (&port->port_lock, flags);
+       spin_unlock_irqrestore (&write_urb_pool_lock, flags);
 
        dbg(__FUNCTION__ " - returns %d", room);
 
@@ -403,7 +403,7 @@
 
        dbg(__FUNCTION__ " - port %d", port->number);
 
-       spin_lock_irqsave (&port->port_lock, flags);
+       spin_lock_irqsave (&write_urb_pool_lock, flags);
 
        /* tally up the number of bytes waiting */
        for (i = 0; i < NUM_URBS; ++i) {
@@ -412,7 +412,7 @@
                }
        }
 
-       spin_unlock_irqrestore (&port->port_lock, flags);
+       spin_unlock_irqrestore (&write_urb_pool_lock, flags);
 
        dbg (__FUNCTION__ " - returns %d", chars);
 
@@ -514,15 +514,13 @@
 
 static void empeg_throttle (struct usb_serial_port *port)
 {
-       unsigned long flags;
-
        dbg(__FUNCTION__ " - port %d", port->number);
 
-       spin_lock_irqsave (&port->port_lock, flags);
+       down (&port->sem);
 
        usb_unlink_urb (port->read_urb);
 
-       spin_unlock_irqrestore (&port->port_lock, flags);
+       up (&port->sem);
 
        return;
 
@@ -531,12 +529,11 @@
 
 static void empeg_unthrottle (struct usb_serial_port *port)
 {
-       unsigned long flags;
        int result;
 
        dbg(__FUNCTION__ " - port %d", port->number);
 
-       spin_lock_irqsave (&port->port_lock, flags);
+       down (&port->sem);
 
        port->read_urb->dev = port->serial->dev;
 
@@ -545,7 +542,7 @@
        if (result)
                err(__FUNCTION__ " - failed submitting read urb, error %d", result);
 
-       spin_unlock_irqrestore (&port->port_lock, flags);
+       up (&port->sem);
 
        return;
 
diff -Nru a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
--- a/drivers/usb/serial/ftdi_sio.c     Tue Jun  5 14:02:33 2001
+++ b/drivers/usb/serial/ftdi_sio.c     Tue Jun  5 14:02:33 2001
@@ -1,7 +1,7 @@
 /*
  * USB FTDI SIO driver
  *
- *     Copyright (C) 1999, 2000
+ *     Copyright (C) 1999 - 2001
  *         Greg Kroah-Hartman ([EMAIL PROTECTED])
  *          Bill Ryder ([EMAIL PROTECTED])
  *
@@ -15,6 +15,9 @@
  * See http://reality.sgi.com/bryder_wellington/ftdi_sio for upto date testing info
  *     and extra documentation
  * 
+ * (31/May/2001) gkh
+ *     switched from using spinlock to a semaphore, which fixes lots of problems.
+ *
  * (23/May/2001)   Bill Ryder
  *     Added runtime debug patch (thanx Tyson D Sawyer).
  *     Cleaned up comments for 8U232
@@ -301,13 +304,12 @@
 { /* ftdi_sio_open */
        struct termios tmp_termios;
        struct usb_serial *serial = port->serial;
-       unsigned long flags;    /* Used for spinlock */
-       int result;
+       int result = 0;
        char buf[1]; /* Needed for the usb_control_msg I think */
 
        dbg(__FUNCTION__);
 
-       spin_lock_irqsave (&port->port_lock, flags);
+       down (&port->sem);
        
        MOD_INC_USE_COUNT;
        ++port->open_count;
@@ -315,8 +317,6 @@
        if (!port->active){
                port->active = 1;
 
-               spin_unlock_irqrestore (&port->port_lock, flags);
-
                /* This will push the characters through immediately rather 
                   than queue a task to deliver them */
                port->tty->low_latency = 1;
@@ -352,11 +352,10 @@
                result = usb_submit_urb(port->read_urb);
                if (result)
                        err(__FUNCTION__ " - failed submitting read urb, error %d", 
result);
-       } else { /* the port was already active - so no initialisation is done */
-               spin_unlock_irqrestore (&port->port_lock, flags);
        }
 
-       return (0);
+       up (&port->sem);
+       return result;
 } /* ftdi_sio_open */
 
 
@@ -365,15 +364,13 @@
        struct usb_serial *serial = port->serial;
        unsigned int c_cflag = port->tty->termios->c_cflag;
        char buf[1];
-       unsigned long flags;
 
        dbg( __FUNCTION__);
 
-       spin_lock_irqsave (&port->port_lock, flags);
+       down (&port->sem);
        --port->open_count;
 
        if (port->open_count <= 0) {
-               spin_unlock_irqrestore (&port->port_lock, flags);
                if (c_cflag & HUPCL){
                        /* Disable flow control */
                        if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 
0),
@@ -400,8 +397,6 @@
                port->active = 0;
                port->open_count = 0;
        } else {  
-               spin_unlock_irqrestore (&port->port_lock, flags);
-
                /* Send a HUP if necessary */
                if (!(port->tty->termios->c_cflag & CLOCAL)){
                        tty_hangup(port->tty);
@@ -409,6 +404,7 @@
                
        }
 
+       up (&port->sem);
        MOD_DEC_USE_COUNT;
 
 } /* ftdi_sio_close */
diff -Nru a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
--- a/drivers/usb/serial/keyspan.c      Tue Jun  5 14:02:34 2001
+++ b/drivers/usb/serial/keyspan.c      Tue Jun  5 14:02:34 2001
@@ -28,6 +28,9 @@
   open source projects.
 
   Change History
+    Thu May 31 11:56:42 PDT 2001 gkh
+      switched from using spinlock to a semaphore
+   
    (04/08/2001) gb
        Identify version on module load.
    
@@ -833,7 +836,6 @@
        struct usb_serial               *serial = port->serial;
        const keyspan_device_details    *d_details;
        int                             i, already_active, err;
-       unsigned long flags;
        urb_t *urb;
 
        s_priv = (struct keyspan_serial_private *)(serial->private);
@@ -843,11 +845,11 @@
        /*  dbg("keyspan_open called."); */
        MOD_INC_USE_COUNT;
 
-       spin_lock_irqsave (&port->port_lock, flags);
+       down (&port->sem);
        ++port->open_count;
        already_active = port->active;
        port->active = 1;
-       spin_unlock_irqrestore (&port->port_lock, flags);
+       up (&port->sem);
 
        if (already_active)
                return 0;
@@ -887,13 +889,12 @@
        struct usb_serial       *serial = port->serial; /* FIXME should so sanity 
check */
        struct keyspan_serial_private   *s_priv;
        struct keyspan_port_private     *p_priv;
-       unsigned long flags;
 
        /*  dbg("keyspan_close called"); */
        s_priv = (struct keyspan_serial_private *)(serial->private);
        p_priv = (struct keyspan_port_private *)(port->private);
 
-       spin_lock_irqsave (&port->port_lock, flags);
+       down (&port->sem);
 
        if (--port->open_count <= 0) {
                if (port->active) {
@@ -914,7 +915,7 @@
                port->open_count = 0;
                port->tty = 0;
        }
-       spin_unlock_irqrestore (&port->port_lock, flags);
+       up (&port->sem);
 
        MOD_DEC_USE_COUNT;
 }
diff -Nru a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
--- a/drivers/usb/serial/keyspan_pda.c  Tue Jun  5 14:02:33 2001
+++ b/drivers/usb/serial/keyspan_pda.c  Tue Jun  5 14:02:33 2001
@@ -1,7 +1,7 @@
 /*
  * USB Keyspan PDA Converter driver
  *
- * Copyright (c) 1999, 2000 Greg Kroah-Hartman <[EMAIL PROTECTED]>
+ * Copyright (c) 1999 - 2001 Greg Kroah-Hartman        <[EMAIL PROTECTED]>
  * Copyright (c) 1999, 2000 Brian Warner       <[EMAIL PROTECTED]>
  * Copyright (c) 2000 Al Borchers              <[EMAIL PROTECTED]>
  *
@@ -12,6 +12,9 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * (05/31/2001) gkh
+ *     switched from using spinlock to a semaphore, which fixes lots of problems.
+ *
  * (04/08/2001) gb
  *     Identify version on module load.
  * 
@@ -452,7 +455,6 @@
        int request_unthrottle = 0;
        int rc = 0;
        struct keyspan_pda_private *priv;
-       unsigned long flags;
 
        priv = (struct keyspan_pda_private *)(port->private);
        /* guess how much room is left in the device's ring buffer, and if we
@@ -482,7 +484,6 @@
           finished).  Also, the tx process is not throttled. So we are
           ready to write. */
 
-       spin_lock_irqsave (&port->port_lock, flags);
        count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
 
        /* Check if we might overrun the Tx buffer.   If so, ask the
@@ -502,13 +503,12 @@
                                     2*HZ);
                if (rc < 0) {
                        dbg(" roomquery failed");
-                       spin_unlock_irqrestore (&port->port_lock, flags);
-                       return rc; /* failed */
+                       goto exit;
                }
                if (rc == 0) {
                        dbg(" roomquery returned 0 bytes");
-                       spin_unlock_irqrestore (&port->port_lock, flags);
-                       return -EIO; /* device didn't return any data */
+                       rc = -EIO; /* device didn't return any data */
+                       goto exit;
                }
                dbg(" roomquery says %d", room);
                priv->tx_room = room;
@@ -525,8 +525,8 @@
                if (from_user) {
                        if( copy_from_user(port->write_urb->transfer_buffer,
                        buf, count) ) {
-                               spin_unlock_irqrestore (&port->port_lock, flags);
-                               return( -EFAULT );
+                               rc = -EFAULT;
+                               goto exit;
                        }
                }
                else {
@@ -538,10 +538,10 @@
                priv->tx_room -= count;
 
                port->write_urb->dev = port->serial->dev;
-               if (usb_submit_urb(port->write_urb)) {
+               rc = usb_submit_urb(port->write_urb);
+               if (rc) {
                        dbg(" usb_submit_urb(write bulk) failed");
-                       spin_unlock_irqrestore (&port->port_lock, flags);
-                       return (0);
+                       goto exit;
                }
        }
        else {
@@ -557,8 +557,9 @@
                        MOD_DEC_USE_COUNT;
        }
 
-       spin_unlock_irqrestore (&port->port_lock, flags);
-       return (count);
+       rc = count;
+exit:
+       return rc;
 }
 
 
@@ -616,11 +617,10 @@
 {
        struct usb_serial *serial = port->serial;
        unsigned char room;
-       int rc;
+       int rc = 0;
        struct keyspan_pda_private *priv;
-       unsigned long flags;
 
-       spin_lock_irqsave (&port->port_lock, flags);
+       down (&port->sem);
 
        MOD_INC_USE_COUNT;
        ++port->open_count;
@@ -629,7 +629,6 @@
                port->active = 1;
  
                /* find out how much room is in the Tx ring */
-               spin_unlock_irqrestore (&port->port_lock, flags);
                rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
                                     6, /* write_room */
                                     USB_TYPE_VENDOR | USB_RECIP_INTERFACE
@@ -639,7 +638,6 @@
                                     &room,
                                     1,
                                     2*HZ);
-               spin_lock_irqsave (&port->port_lock, flags);
                if (rc < 0) {
                        dbg(__FUNCTION__" - roomquery failed");
                        goto error;
@@ -655,7 +653,6 @@
 
                /* the normal serial device seems to always turn on DTR and RTS here,
                   so do the same */
-               spin_unlock_irqrestore (&port->port_lock, flags);
                if (port->tty->termios->c_cflag & CBAUD)
                        keyspan_pda_set_modem_info(serial, (1<<7) | (1<<2) );
                else
@@ -663,19 +660,22 @@
 
                /*Start reading from the device*/
                port->interrupt_in_urb->dev = serial->dev;
-               if (usb_submit_urb(port->interrupt_in_urb))
+               rc = usb_submit_urb(port->interrupt_in_urb);
+               if (rc) {
                        dbg(__FUNCTION__" - usb_submit_urb(read int) failed");
-       } else {
-               spin_unlock_irqrestore (&port->port_lock, flags);
+                       goto error;
+               }
+
        }
 
 
-       return (0);
+       up (&port->sem);
+       return rc;
 error:
        --port->open_count;
        port->active = 0;
        MOD_DEC_USE_COUNT;
-       spin_unlock_irqrestore (&port->port_lock, flags);
+       up (&port->sem);
        return rc;
 }
 
@@ -683,19 +683,15 @@
 static void keyspan_pda_close(struct usb_serial_port *port, struct file *filp)
 {
        struct usb_serial *serial = port->serial;
-       unsigned long flags;
 
-       spin_lock_irqsave (&port->port_lock, flags);
+       down (&port->sem);
 
        --port->open_count;
-       MOD_DEC_USE_COUNT;
 
        if (port->open_count <= 0) {
                /* the normal serial device seems to always shut off DTR and RTS now */
-               spin_unlock_irqrestore (&port->port_lock, flags);
                if (port->tty->termios->c_cflag & HUPCL)
                        keyspan_pda_set_modem_info(serial, 0);
-               spin_lock_irqsave (&port->port_lock, flags);
 
                /* shutdown our bulk reads and writes */
                usb_unlink_urb (port->write_urb);
@@ -704,7 +700,8 @@
                port->open_count = 0;
        }
 
-       spin_unlock_irqrestore (&port->port_lock, flags);
+       up (&port->sem);
+       MOD_DEC_USE_COUNT;
 }
 
 
diff -Nru a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
--- a/drivers/usb/serial/mct_u232.c     Tue Jun  5 14:02:34 2001
+++ b/drivers/usb/serial/mct_u232.c     Tue Jun  5 14:02:34 2001
@@ -24,6 +24,9 @@
  *   Basic tests have been performed with minicom/zmodem transfers and
  *   modem dialing under Linux 2.4.0-test10 (for me it works fine).
  *
+ * 30-May-2001 Greg Kroah-Hartman
+ *     switched from using spinlock to a semaphore, which fixes lots of problems.
+ *
  * 04-May-2001 Stelian Pop
  *   - Set the maximum bulk output size for Sitecom U232-P25 model to 16 bytes
  *     instead of the device reported 32 (using 32 bytes causes many data
@@ -79,7 +82,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.0.0"
+#define DRIVER_VERSION "v1.1"
 #define DRIVER_AUTHOR "Wolfgang Grandegger <[EMAIL PROTECTED]>"
 #define DRIVER_DESC "Magic Control Technology USB-RS232 converter driver"
 
@@ -391,13 +394,13 @@
 
 static int  mct_u232_open (struct usb_serial_port *port, struct file *filp)
 {
-       unsigned long flags;
        struct usb_serial *serial = port->serial;
        struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
+       int retval = 0;
 
        dbg(__FUNCTION__" port %d", port->number);
 
-       spin_lock_irqsave (&port->port_lock, flags);
+       down (&port->sem);
        
        ++port->open_count;
        MOD_INC_USE_COUNT;
@@ -443,16 +446,21 @@
                }
 
                port->read_urb->dev = port->serial->dev;
-               if (usb_submit_urb(port->read_urb))
+               retval = usb_submit_urb(port->read_urb);
+               if (retval) {
                        err("usb_submit_urb(read bulk) failed");
+                       goto exit;
+               }
 
                port->interrupt_in_urb->dev = port->serial->dev;
-               if (usb_submit_urb(port->interrupt_in_urb))
+               retval = usb_submit_urb(port->interrupt_in_urb);
+               if (retval)
                        err(" usb_submit_urb(read int) failed");
 
        }
 
-       spin_unlock_irqrestore (&port->port_lock, flags);
+exit:
+       up (&port->sem);
        
        return 0;
 } /* mct_u232_open */
@@ -460,14 +468,11 @@
 
 static void mct_u232_close (struct usb_serial_port *port, struct file *filp)
 {
-       unsigned long flags;
-
        dbg(__FUNCTION__" port %d", port->number);
 
-       spin_lock_irqsave (&port->port_lock, flags);
+       down (&port->sem);
 
        --port->open_count;
-       MOD_DEC_USE_COUNT;
 
        if (port->open_count <= 0) {
                /* shutdown our bulk reads and writes */
@@ -478,8 +483,8 @@
                port->active = 0;
        }
        
-       spin_unlock_irqrestore (&port->port_lock, flags);
-
+       up (&port->sem);
+       MOD_DEC_USE_COUNT;
 } /* mct_u232_close */
 
 
@@ -490,7 +495,6 @@
                           const unsigned char *buf, int count)
 {
        struct usb_serial *serial = port->serial;
-       unsigned long flags;
        int result, bytes_sent, size;
 
        dbg(__FUNCTION__ " - port %d", port->number);
@@ -513,7 +517,7 @@
        bytes_sent = 0;
        while (count > 0) {
                
-               spin_lock_irqsave (&port->port_lock, flags);
+               down (&port->sem);
                
                size = (count > port->bulk_out_size) ? port->bulk_out_size : count;
                
@@ -541,11 +545,11 @@
                if (result) {
                        err(__FUNCTION__
                            " - failed submitting write urb, error %d", result);
-                       spin_unlock_irqrestore (&port->port_lock, flags);
-                       return bytes_sent;
+                       up (&port->sem);
+                       return result;
                }
 
-               spin_unlock_irqrestore (&port->port_lock, flags);
+               up (&port->sem);
 
                bytes_sent += size;
                if (write_blocking)
diff -Nru a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
--- a/drivers/usb/serial/omninet.c      Tue Jun  5 14:02:33 2001
+++ b/drivers/usb/serial/omninet.c      Tue Jun  5 14:02:33 2001
@@ -10,6 +10,9 @@
  *
  * Please report both successes and troubles to the author at [EMAIL PROTECTED]
  * 
+ * (05/30/2001) gkh
+ *     switched from using spinlock to a semaphore, which fixes lots of problems.
+ *
  * (04/08/2001) gb
  *     Identify version on module load.
  *
@@ -60,7 +63,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.0.0"
+#define DRIVER_VERSION "v1.1"
 #define DRIVER_AUTHOR "Anonymous"
 #define DRIVER_DESC "USB ZyXEL omni.net LCD PLUS Driver"
 
@@ -145,8 +148,7 @@
        struct usb_serial       *serial;
        struct usb_serial_port  *wport;
        struct omninet_data     *od;
-       unsigned long           flags;
-       int                     result;
+       int                     result = 0;
 
        if (port_paranoia_check (port, __FUNCTION__))
                return -ENODEV;
@@ -157,7 +159,7 @@
        if (!serial)
                return -ENODEV;
 
-       spin_lock_irqsave (&port->port_lock, flags);
+       down (&port->sem);
 
        MOD_INC_USE_COUNT;
        ++port->open_count;
@@ -170,7 +172,7 @@
                        err(__FUNCTION__"- kmalloc(%Zd) failed.", sizeof(struct 
omninet_data));
                        --port->open_count;
                        port->active = 0;
-                       spin_unlock_irqrestore (&port->port_lock, flags);
+                       up (&port->sem);
                        MOD_DEC_USE_COUNT;
                        return -ENOMEM;
                }
@@ -189,9 +191,9 @@
                        err(__FUNCTION__ " - failed submitting read urb, error %d", 
result);
        }
 
-       spin_unlock_irqrestore (&port->port_lock, flags);
+       up (&port->sem);
 
-       return (0);
+       return result;
 }
 
 static void omninet_close (struct usb_serial_port *port, struct file * filp)
@@ -199,7 +201,6 @@
        struct usb_serial       *serial;
        struct usb_serial_port  *wport;
        struct omninet_data     *od;
-       unsigned long           flags;
 
        if (port_paranoia_check (port, __FUNCTION__))
                return;
@@ -210,10 +211,9 @@
        if (!serial)
                return;
 
-       spin_lock_irqsave (&port->port_lock, flags);
+       down (&port->sem);
 
        --port->open_count;
-       MOD_DEC_USE_COUNT;
 
        if (port->open_count <= 0) {
                od = (struct omninet_data *)port->private;
@@ -228,7 +228,8 @@
                        kfree(od);
        }
 
-       spin_unlock_irqrestore (&port->port_lock, flags);
+       up (&port->sem);
+       MOD_DEC_USE_COUNT;
 }
 
 
@@ -296,7 +297,6 @@
        struct omninet_data     *od     = (struct omninet_data   *) port->private;
        struct omninet_header   *header = (struct omninet_header *) 
wport->write_urb->transfer_buffer;
 
-       unsigned long           flags;
        int                     result;
 
 //     dbg("omninet_write port %d", port->number);
@@ -310,12 +310,13 @@
                return (0);
        }
 
-       spin_lock_irqsave (&port->port_lock, flags);
-       
        count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count;
 
        if (from_user) {
-               copy_from_user(wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET, 
buf, count);
+               if (copy_from_user(wport->write_urb->transfer_buffer + 
+OMNINET_DATAOFFSET, buf, count) != 0) {
+                       result = -EFAULT;
+                       goto exit;
+               }
        }
        else {
                memcpy (wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET, buf, 
count);
@@ -333,16 +334,13 @@
 
        wport->write_urb->dev = serial->dev;
        result = usb_submit_urb(wport->write_urb);
-       if (result) {
+       if (result)
                err(__FUNCTION__ " - failed submitting write urb, error %d", result);
-               spin_unlock_irqrestore (&port->port_lock, flags);
-               return 0;
-       }
-
-//     dbg("omninet_write returns %d", count);
+       else
+               result = count;
 
-       spin_unlock_irqrestore (&port->port_lock, flags);
-       return (count);
+exit:  
+       return result;
 }
 
 
diff -Nru a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h
--- a/drivers/usb/serial/usb-serial.h   Tue Jun  5 14:02:33 2001
+++ b/drivers/usb/serial/usb-serial.h   Tue Jun  5 14:02:33 2001
@@ -1,7 +1,7 @@
 /*
  * USB Serial Converter driver
  *
- *     Copyright (C) 1999, 2000
+ *     Copyright (C) 1999 - 2001
  *         Greg Kroah-Hartman ([EMAIL PROTECTED])
  *
  *     This program is free software; you can redistribute it and/or modify
@@ -11,6 +11,9 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
+ * (05/30/2001) gkh
+ *     added sem to port structure and removed port_lock
+ *
  * (10/05/2000) gkh
  *     Added interrupt_in_endpointAddress and bulk_in_endpointAddress to help
  *     fix bug with urb->dev not being set properly, now that the usb core
@@ -77,7 +80,7 @@
 
        struct tq_struct        tqueue;         /* task queue for line discipline 
waking up */
        int                     open_count;     /* number of times this port has been 
opened */
-       spinlock_t              port_lock;
+       struct semaphore        sem;            /* locks this structure */
        
        void *                  private;        /* data private to the specific port */
 };
diff -Nru a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c
--- a/drivers/usb/serial/usbserial.c    Tue Jun  5 14:02:34 2001
+++ b/drivers/usb/serial/usbserial.c    Tue Jun  5 14:02:34 2001
@@ -1,7 +1,7 @@
 /*
  * USB Serial Converter driver
  *
- * Copyright (C) 1999, 2000 Greg Kroah-Hartman ([EMAIL PROTECTED])
+ * Copyright (C) 1999 - 2001 Greg Kroah-Hartman ([EMAIL PROTECTED])
  * Copyright (c) 2000 Peter Berger ([EMAIL PROTECTED])
  * Copyright (c) 2000 Al Borchers ([EMAIL PROTECTED])
  *
@@ -15,6 +15,9 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * (05/30/2001) gkh
+ *     switched from using spinlock to a semaphore, which fixes lots of problems.
+ *
  * (04/08/2001) gb
  *     Identify version on module load.
  *
@@ -288,7 +291,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.0.0"
+#define DRIVER_VERSION "v1.1"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman, [EMAIL PROTECTED], 
http://www.kroah.com/linux-usb/";
 #define DRIVER_DESC "USB Serial Driver"
 
@@ -735,8 +738,7 @@
 static int generic_open (struct usb_serial_port *port, struct file *filp)
 {
        struct usb_serial *serial = port->serial;
-       unsigned long flags;
-       int result;
+       int result = 0;
 
        if (port_paranoia_check (port, __FUNCTION__))
                return -ENODEV;
@@ -745,7 +747,7 @@
 
        dbg(__FUNCTION__ " - port %d", port->number);
 
-       spin_lock_irqsave (&port->port_lock, flags);
+       down (&port->sem);
        
        ++port->open_count;
        
@@ -773,20 +775,19 @@
                }
        }
        
-       spin_unlock_irqrestore (&port->port_lock, flags);
+       up (&port->sem);
        
-       return 0;
+       return result;
 }
 
 
 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);
 
-       spin_lock_irqsave (&port->port_lock, flags);
+       down (&port->sem);
 
        --port->open_count;
 
@@ -801,7 +802,7 @@
                port->open_count = 0;
        }
 
-       spin_unlock_irqrestore (&port->port_lock, flags);
+       up (&port->sem);
        MOD_DEC_USE_COUNT;
 }
 
@@ -809,7 +810,6 @@
 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;
        int result;
 
        dbg(__FUNCTION__ " - port %d", port->number);
@@ -826,7 +826,6 @@
                        return (0);
                }
 
-               spin_lock_irqsave (&port->port_lock, flags);
                count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
 
                if (from_user) {
@@ -849,14 +848,12 @@
 
                /* send the data out the bulk port */
                result = usb_submit_urb(port->write_urb);
-               if (result) {
+               if (result)
                        err(__FUNCTION__ " - failed submitting write urb, error %d", 
result);
-                       spin_unlock_irqrestore (&port->port_lock, flags);
-                       return 0;
-               }
+               else
+                       result = count;
 
-               spin_unlock_irqrestore (&port->port_lock, flags);
-               return (count);
+               return result;
        }
        
        /* no bulk out, so return 0 bytes written */
@@ -871,9 +868,10 @@
 
        dbg(__FUNCTION__ " - port %d", port->number);
        
-       if (serial->num_bulk_out)
+       if (serial->num_bulk_out) {
                if (port->write_urb->status != -EINPROGRESS)
                        room = port->bulk_out_size;
+       }
        
        dbg(__FUNCTION__ " - returns %d", room);
        return (room);
@@ -887,9 +885,10 @@
 
        dbg(__FUNCTION__ " - port %d", port->number);
        
-       if (serial->num_bulk_out)
+       if (serial->num_bulk_out) {
                if (port->write_urb->status == -EINPROGRESS)
                        chars = port->write_urb->transfer_buffer_length;
+       }
 
        dbg (__FUNCTION__ " - returns %d", chars);
        return (chars);
@@ -1222,7 +1221,7 @@
                port->magic = USB_SERIAL_PORT_MAGIC;
                port->tqueue.routine = port_softint;
                port->tqueue.data = port;
-               spin_lock_init (&port->port_lock);
+               init_MUTEX (&port->sem);
        }
        
        /* initialize the devfs nodes for this device and let the user know what ports 
we are bound to */
diff -Nru a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
--- a/drivers/usb/serial/visor.c        Tue Jun  5 14:02:34 2001
+++ b/drivers/usb/serial/visor.c        Tue Jun  5 14:02:34 2001
@@ -11,6 +11,9 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * (05/30/2001) gkh
+ *     switched from using spinlock to a semaphore, which fixes lots of problems.
+ *
  * (05/28/2000) gkh
  *     Added initial support for the Palm m500 and Palm m505 devices.
  *
@@ -112,7 +115,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.1"
+#define DRIVER_VERSION "v1.2"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <[EMAIL PROTECTED]>"
 #define DRIVER_DESC "USB HandSpring Visor driver"
 
@@ -253,15 +256,14 @@
 static int visor_open (struct usb_serial_port *port, struct file *filp)
 {
        struct usb_serial *serial = port->serial;
-       unsigned long flags;
-       int result;
+       int result = 0;
 
        if (port_paranoia_check (port, __FUNCTION__))
                return -ENODEV;
        
        dbg(__FUNCTION__ " - port %d", port->number);
 
-       spin_lock_irqsave (&port->port_lock, flags);
+       down (&port->sem);
        
        ++port->open_count;
        MOD_INC_USE_COUNT;
@@ -286,9 +288,9 @@
                        err(__FUNCTION__ " - failed submitting read urb, error %d", 
result);
        }
        
-       spin_unlock_irqrestore (&port->port_lock, flags);
+       up (&port->sem);
        
-       return 0;
+       return result;
 }
 
 
@@ -296,7 +298,6 @@
 {
        struct usb_serial *serial;
        unsigned char *transfer_buffer;
-       unsigned long flags;
 
        if (port_paranoia_check (port, __FUNCTION__))
                return;
@@ -307,7 +308,7 @@
        if (!serial)
                return;
        
-       spin_lock_irqsave (&port->port_lock, flags);
+       down (&port->sem);
 
        --port->open_count;
 
@@ -328,7 +329,7 @@
                port->open_count = 0;
 
        }
-       spin_unlock_irqrestore (&port->port_lock, flags);
+       up (&port->sem);
 
        /* Uncomment the following line if you want to see some statistics in your 
syslog */
        /* info ("Bytes In = %d  Bytes Out = %d", bytes_in, bytes_out); */
@@ -410,7 +411,7 @@
 
        dbg(__FUNCTION__ " - port %d", port->number);
        
-       spin_lock_irqsave (&port->port_lock, flags);
+       spin_lock_irqsave (&write_urb_pool_lock, flags);
 
        for (i = 0; i < NUM_URBS; ++i) {
                if (write_urb_pool[i]->status != -EINPROGRESS) {
@@ -418,7 +419,7 @@
                }
        }
        
-       spin_unlock_irqrestore (&port->port_lock, flags);
+       spin_unlock_irqrestore (&write_urb_pool_lock, flags);
        
        dbg(__FUNCTION__ " - returns %d", room);
        return (room);
@@ -433,7 +434,7 @@
 
        dbg(__FUNCTION__ " - port %d", port->number);
        
-       spin_lock_irqsave (&port->port_lock, flags);
+       spin_lock_irqsave (&write_urb_pool_lock, flags);
 
        for (i = 0; i < NUM_URBS; ++i) {
                if (write_urb_pool[i]->status == -EINPROGRESS) {
@@ -441,7 +442,7 @@
                }
        }
        
-       spin_unlock_irqrestore (&port->port_lock, flags);
+       spin_unlock_irqrestore (&write_urb_pool_lock, flags);
 
        dbg (__FUNCTION__ " - returns %d", chars);
        return (chars);
@@ -523,15 +524,14 @@
 
 static void visor_throttle (struct usb_serial_port *port)
 {
-       unsigned long flags;
 
        dbg(__FUNCTION__ " - port %d", port->number);
 
-       spin_lock_irqsave (&port->port_lock, flags);
+       down (&port->sem);
 
        usb_unlink_urb (port->read_urb);
 
-       spin_unlock_irqrestore (&port->port_lock, flags);
+       up (&port->sem);
 
        return;
 }
@@ -539,19 +539,18 @@
 
 static void visor_unthrottle (struct usb_serial_port *port)
 {
-       unsigned long flags;
        int result;
 
        dbg(__FUNCTION__ " - port %d", port->number);
 
-       spin_lock_irqsave (&port->port_lock, flags);
+       down (&port->sem);
 
        port->read_urb->dev = port->serial->dev;
        result = usb_submit_urb(port->read_urb);
        if (result)
                err(__FUNCTION__ " - failed submitting read urb, error %d", result);
 
-       spin_unlock_irqrestore (&port->port_lock, flags);
+       up (&port->sem);
 
        return;
 }
diff -Nru a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
--- a/drivers/usb/serial/whiteheat.c    Tue Jun  5 14:02:34 2001
+++ b/drivers/usb/serial/whiteheat.c    Tue Jun  5 14:02:34 2001
@@ -11,6 +11,9 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
+ * (05/30/2001) gkh
+ *     switched from using spinlock to a semaphore, which fixes lots of problems.
+ *
  * (04/08/2001) gb
  *     Identify version on module load.
  * 
@@ -85,7 +88,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.0.0"
+#define DRIVER_VERSION "v1.1"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <[EMAIL PROTECTED]>"
 #define DRIVER_DESC "USB ConnectTech WhiteHEAT driver"
 
@@ -251,6 +254,7 @@
        struct usb_serial_port *port;
        int timeout;
        __u8 *transfer_buffer;
+       int retval = 0;
 
        dbg(__FUNCTION__" - command %d", command);
 
@@ -263,9 +267,10 @@
        memcpy (&transfer_buffer[1], data, datasize);
        port->write_urb->transfer_buffer_length = datasize + 1;
        port->write_urb->dev = serial->dev;
-       if (usb_submit_urb (port->write_urb)) {
+       retval = usb_submit_urb (port->write_urb);
+       if (retval) {
                dbg (__FUNCTION__" - submit urb failed");
-               return -1;
+               goto exit;
        }
 
        /* wait for the command to complete */
@@ -276,20 +281,21 @@
 
        if (info->command_finished == FALSE) {
                dbg (__FUNCTION__ " - command timed out.");
-               return -1;
+               retval = -ETIMEDOUT;
+               goto exit;
        }
 
        if (info->command_finished == WHITEHEAT_CMD_FAILURE) {
                dbg (__FUNCTION__ " - command failed.");
-               return -1;
+               retval = -EIO;
+               goto exit;
        }
 
-       if (info->command_finished == WHITEHEAT_CMD_COMPLETE) {
+       if (info->command_finished == WHITEHEAT_CMD_COMPLETE)
                dbg (__FUNCTION__ " - command completed.");
-               return 0;
-       }
 
-       return 0;
+exit:
+       return retval;
 }
 
 
@@ -298,10 +304,12 @@
        struct whiteheat_min_set        open_command;
        struct usb_serial_port          *command_port;
        struct whiteheat_private        *info;
-       int                             result;
+       int                             retval = 0;
 
        dbg(__FUNCTION__" - port %d", port->number);
 
+       down (&port->sem);
+
        ++port->open_count;
        MOD_INC_USE_COUNT;
        
@@ -314,7 +322,8 @@
                        info = (struct whiteheat_private *)kmalloc (sizeof(struct 
whiteheat_private), GFP_KERNEL);
                        if (info == NULL) {
                                err(__FUNCTION__ " - out of memory");
-                               return -ENOMEM;
+                               retval = -ENOMEM;
+                               goto error_exit;
                        }
                        
                        init_waitqueue_head(&info->wait_command);
@@ -323,27 +332,45 @@
                        command_port->read_urb->complete = command_port_read_callback;
                        command_port->read_urb->dev = port->serial->dev;
                        command_port->tty = port->tty;          /* need this to "fake" 
our our sanity check macros */
-                       usb_submit_urb (command_port->read_urb);
+                       retval = usb_submit_urb (command_port->read_urb);
+                       if (retval) {
+                               err(__FUNCTION__ " - failed submitting read urb, error 
+%d", retval);
+                               goto error_exit;
+                       }
                }
                
                /* Start reading from the device */
                port->read_urb->dev = port->serial->dev;
-               result = usb_submit_urb(port->read_urb);
-               if (result)
-                       err(__FUNCTION__ " - failed submitting read urb, error %d", 
result);
+               retval = usb_submit_urb(port->read_urb);
+               if (retval) {
+                       err(__FUNCTION__ " - failed submitting read urb, error %d", 
+retval);
+                       goto error_exit;
+               }
        
                /* send an open port command */
                /* firmware uses 1 based port numbering */
                open_command.port = port->number - port->serial->minor + 1;
-               whiteheat_send_cmd (port->serial, WHITEHEAT_OPEN, (__u8 
*)&open_command, sizeof(open_command));
+               retval = whiteheat_send_cmd (port->serial, WHITEHEAT_OPEN, (__u8 
+*)&open_command, sizeof(open_command));
+               if (retval)
+                       goto error_exit;
        
                /* Need to do device specific setup here (control lines, baud rate, 
etc.) */
                /* FIXME!!! */
        }
 
        dbg(__FUNCTION__ " - exit");
+       up (&port->sem);
        
-       return 0;
+       return retval;
+
+error_exit:
+       --port->open_count;
+       MOD_DEC_USE_COUNT;
+
+       dbg(__FUNCTION__ " - error_exit");
+       up (&port->sem);
+       
+       return retval;
 }
 
 
@@ -353,6 +380,7 @@
        
        dbg(__FUNCTION__ " - port %d", port->number);
        
+       down (&port->sem);
        --port->open_count;
 
        if (port->open_count <= 0) {
@@ -370,6 +398,7 @@
                port->active = 0;
        }
        MOD_DEC_USE_COUNT;
+       up (&port->sem);
 }
 
 
@@ -388,18 +417,19 @@
 
        dbg(__FUNCTION__ " -port %d", port->number);
 
+       down (&port->sem);
        /* check that they really want us to change something */
        if (old_termios) {
                if ((cflag == old_termios->c_cflag) &&
                    (RELEVANT_IFLAG(port->tty->termios->c_iflag) == 
RELEVANT_IFLAG(old_termios->c_iflag))) {
                        dbg(__FUNCTION__ " - nothing to change...");
-                       return;
+                       goto exit;
                }
        }
 
        if ((!port->tty) || (!port->tty->termios)) {
                dbg(__FUNCTION__" - no tty structures");
-               return;
+               goto exit;
        }
        
        /* set the port number */
@@ -466,6 +496,8 @@
        /* now send the message to the device */
        whiteheat_send_cmd (port->serial, WHITEHEAT_SETUP_PORT, (__u8 
*)&port_settings, sizeof(port_settings));
        
+exit:
+       up (&port->sem);
        return;
 }
 

Reply via email to