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; }