Here's an improved patch, with the changes that Pete Zaitcev pointed out. It is against 2.4.5-ac5. I realize that most of the usb-serial drivers don't do the write logic correctly for SMP. The visor and empeg drivers do it well using an urb pool, but they don't handle the case "if you run out of urbs and are called from an interrupt due to being in echo mode" problem. digi-acceleport seems to handle things the best. I'll be working on these problems, and the interruptable_sleep_on bug soon. thanks, greg k-h
diff -Naur -X dontdiff linux-2.4.5-ac5/drivers/usb/serial/belkin_sa.c linux-2.4.5-ac5-greg/drivers/usb/serial/belkin_sa.c --- linux-2.4.5-ac5/drivers/usb/serial/belkin_sa.c Sat May 26 11:32:30 2001 +++ linux-2.4.5-ac5-greg/drivers/usb/serial/belkin_sa.c Fri Jun 1 00:19:46 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 -Naur -X dontdiff linux-2.4.5-ac5/drivers/usb/serial/empeg.c linux-2.4.5-ac5-greg/drivers/usb/serial/empeg.c --- linux-2.4.5-ac5/drivers/usb/serial/empeg.c Sat May 26 11:32:30 2001 +++ linux-2.4.5-ac5-greg/drivers/usb/serial/empeg.c Fri Jun 1 00:19:46 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 -Naur -X dontdiff linux-2.4.5-ac5/drivers/usb/serial/ftdi_sio.c linux-2.4.5-ac5-greg/drivers/usb/serial/ftdi_sio.c --- linux-2.4.5-ac5/drivers/usb/serial/ftdi_sio.c Sat May 26 11:32:30 2001 +++ linux-2.4.5-ac5-greg/drivers/usb/serial/ftdi_sio.c Fri Jun 1 00:19:46 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 -Naur -X dontdiff linux-2.4.5-ac5/drivers/usb/serial/keyspan.c linux-2.4.5-ac5-greg/drivers/usb/serial/keyspan.c --- linux-2.4.5-ac5/drivers/usb/serial/keyspan.c Sat May 26 11:32:31 2001 +++ linux-2.4.5-ac5-greg/drivers/usb/serial/keyspan.c Fri Jun 1 00:19:46 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 -Naur -X dontdiff linux-2.4.5-ac5/drivers/usb/serial/keyspan_pda.c linux-2.4.5-ac5-greg/drivers/usb/serial/keyspan_pda.c --- linux-2.4.5-ac5/drivers/usb/serial/keyspan_pda.c Sat May 26 11:32:31 2001 +++ linux-2.4.5-ac5-greg/drivers/usb/serial/keyspan_pda.c Fri Jun 1 00:19:46 +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 -Naur -X dontdiff linux-2.4.5-ac5/drivers/usb/serial/mct_u232.c linux-2.4.5-ac5-greg/drivers/usb/serial/mct_u232.c --- linux-2.4.5-ac5/drivers/usb/serial/mct_u232.c Sat May 26 11:32:31 2001 +++ linux-2.4.5-ac5-greg/drivers/usb/serial/mct_u232.c Fri Jun 1 00:19:46 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 -Naur -X dontdiff linux-2.4.5-ac5/drivers/usb/serial/omninet.c linux-2.4.5-ac5-greg/drivers/usb/serial/omninet.c --- linux-2.4.5-ac5/drivers/usb/serial/omninet.c Sat May 26 11:32:31 2001 +++ linux-2.4.5-ac5-greg/drivers/usb/serial/omninet.c Fri Jun 1 00:19:46 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 -Naur -X dontdiff linux-2.4.5-ac5/drivers/usb/serial/usb-serial.h linux-2.4.5-ac5-greg/drivers/usb/serial/usb-serial.h --- linux-2.4.5-ac5/drivers/usb/serial/usb-serial.h Wed May 23 22:22:56 2001 +++ linux-2.4.5-ac5-greg/drivers/usb/serial/usb-serial.h Fri Jun 1 00:19:46 +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 -Naur -X dontdiff linux-2.4.5-ac5/drivers/usb/serial/usbserial.c linux-2.4.5-ac5-greg/drivers/usb/serial/usbserial.c --- linux-2.4.5-ac5/drivers/usb/serial/usbserial.c Fri Jun 1 00:20:36 2001 +++ linux-2.4.5-ac5-greg/drivers/usb/serial/usbserial.c Fri Jun 1 00:19:46 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); @@ -1224,7 +1223,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 -Naur -X dontdiff linux-2.4.5-ac5/drivers/usb/serial/visor.c linux-2.4.5-ac5-greg/drivers/usb/serial/visor.c --- linux-2.4.5-ac5/drivers/usb/serial/visor.c Sat May 26 11:32:31 2001 +++ linux-2.4.5-ac5-greg/drivers/usb/serial/visor.c Fri Jun 1 00:19:46 2001 @@ -1,7 +1,7 @@ /* * USB HandSpring Visor 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,12 @@ * * 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. + * * (04/08/2001) gb * Identify version on module load. * @@ -109,7 +115,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.0.0" +#define DRIVER_VERSION "v1.2" #define DRIVER_AUTHOR "Greg Kroah-Hartman <[EMAIL PROTECTED]>" #define DRIVER_DESC "USB HandSpring Visor driver" @@ -131,8 +137,26 @@ static void visor_read_bulk_callback (struct urb *urb); +static __devinitdata struct usb_device_id visor_id_table [] = { + { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) }, + { } /* Terminating entry */ +}; + +static __devinitdata struct usb_device_id palm_m500_id_table [] = { + { USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) }, + { } /* Terminating entry */ +}; + +static __devinitdata struct usb_device_id palm_m505_id_table [] = { + { USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) }, + { } /* Terminating entry */ +}; + + static __devinitdata struct usb_device_id id_table [] = { { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) }, + { USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) }, + { USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) }, { } /* Terminating entry */ }; @@ -143,7 +167,7 @@ /* All of the device info needed for the Handspring Visor */ struct usb_serial_device_type handspring_device = { name: "Handspring Visor", - id_table: id_table, + id_table: visor_id_table, needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */ needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ @@ -166,6 +190,57 @@ read_bulk_callback: visor_read_bulk_callback, }; +/* device info for the Palm M500 */ +struct usb_serial_device_type palm_m500_device = { + name: "Palm M500", + id_table: palm_m500_id_table, + needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have +an interrupt in endpoint */ + needs_bulk_in: MUST_HAVE, /* this device must have a +bulk in endpoint */ + needs_bulk_out: MUST_HAVE, /* this device must have a +bulk out endpoint */ + num_interrupt_in: 0, + num_bulk_in: 2, + num_bulk_out: 2, + num_ports: 2, + open: visor_open, + close: visor_close, + throttle: visor_throttle, + unthrottle: visor_unthrottle, + startup: visor_startup, + shutdown: visor_shutdown, + ioctl: visor_ioctl, + set_termios: visor_set_termios, + write: visor_write, + write_room: visor_write_room, + chars_in_buffer: visor_chars_in_buffer, + write_bulk_callback: visor_write_bulk_callback, + read_bulk_callback: visor_read_bulk_callback, +}; + +/* device info for the Palm M505 */ +struct usb_serial_device_type palm_m505_device = { + name: "Palm M505", + id_table: palm_m505_id_table, + needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have +an interrupt in endpoint */ + needs_bulk_in: MUST_HAVE, /* this device must have a +bulk in endpoint */ + needs_bulk_out: MUST_HAVE, /* this device must have a +bulk out endpoint */ + num_interrupt_in: 0, + num_bulk_in: 2, + num_bulk_out: 2, + num_ports: 2, + open: visor_open, + close: visor_close, + throttle: visor_throttle, + unthrottle: visor_unthrottle, + startup: visor_startup, + shutdown: visor_shutdown, + ioctl: visor_ioctl, + set_termios: visor_set_termios, + write: visor_write, + write_room: visor_write_room, + chars_in_buffer: visor_chars_in_buffer, + write_bulk_callback: visor_write_bulk_callback, + read_bulk_callback: visor_read_bulk_callback, +}; #define NUM_URBS 24 #define URB_TRANSFER_BUFFER_SIZE 768 @@ -181,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; @@ -214,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; } @@ -224,7 +298,6 @@ { struct usb_serial *serial; unsigned char *transfer_buffer; - unsigned long flags; if (port_paranoia_check (port, __FUNCTION__)) return; @@ -235,7 +308,7 @@ if (!serial) return; - spin_lock_irqsave (&port->port_lock, flags); + down (&port->sem); --port->open_count; @@ -256,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); */ @@ -338,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) { @@ -346,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); @@ -361,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) { @@ -369,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); @@ -451,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; } @@ -467,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; } @@ -496,6 +567,10 @@ return -ENOMEM; } + /* force debugging on for the palm devices for now */ + if (serial->dev->descriptor.idVendor == PALM_VENDOR_ID) + debug = 1; + dbg(__FUNCTION__); dbg(__FUNCTION__ " - Set config to 1"); @@ -537,6 +612,28 @@ } } + if (serial->dev->descriptor.idVendor == PALM_VENDOR_ID) { + /* Palm USB Hack */ + response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, +0), + PALM_GET_SOME_UNKNOWN_INFORMATION, + 0xc2, 0x0000, 0x0000, transfer_buffer, + 0x14, 300); + if (response < 0) { + err(__FUNCTION__ " - error getting first unknown palm +command"); + } else { + usb_serial_debug_data (__FILE__, __FUNCTION__, 0x14, +transfer_buffer); + } + response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, +0), + PALM_GET_SOME_UNKNOWN_INFORMATION, + 0xc2, 0x0000, 0x0000, transfer_buffer, + 0x14, 300); + if (response < 0) { + err(__FUNCTION__ " - error getting second unknown palm +command"); + } else { + usb_serial_debug_data (__FILE__, __FUNCTION__, 0x14, +transfer_buffer); + } + } + /* ask for the number of bytes available, but ignore the response as it is broken */ response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_REQUEST_BYTES_AVAILABLE, 0xc2, 0x0000, 0x0005, transfer_buffer, 0x02, 300); @@ -645,6 +742,8 @@ int i; usb_serial_register (&handspring_device); + usb_serial_register (&palm_m500_device); + usb_serial_register (&palm_m505_device); /* create our write urb pool and transfer buffers */ spin_lock_init (&write_urb_pool_lock); @@ -677,6 +776,8 @@ unsigned long flags; usb_serial_deregister (&handspring_device); + usb_serial_deregister (&palm_m500_device); + usb_serial_deregister (&palm_m505_device); spin_lock_irqsave (&write_urb_pool_lock, flags); diff -Naur -X dontdiff linux-2.4.5-ac5/drivers/usb/serial/visor.h linux-2.4.5-ac5-greg/drivers/usb/serial/visor.h --- linux-2.4.5-ac5/drivers/usb/serial/visor.h Wed May 23 22:22:56 2001 +++ linux-2.4.5-ac5-greg/drivers/usb/serial/visor.h Fri Jun 1 00:19:46 2001 @@ -1,7 +1,7 @@ /* * USB HandSpring Visor 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 @@ -20,6 +20,10 @@ #define HANDSPRING_VENDOR_ID 0x082d #define HANDSPRING_VISOR_ID 0x0100 +#define PALM_VENDOR_ID 0x0830 +#define PALM_M500_ID 0x0001 +#define PALM_M505_ID 0x0002 + /**************************************************************************** * Handspring Visor Vendor specific request codes (bRequest values) * A big thank you to Handspring for providing the following information. @@ -69,6 +73,13 @@ #define VISOR_FUNCTION_HOTSYNC 0x02 #define VISOR_FUNCTION_CONSOLE 0x03 #define VISOR_FUNCTION_REMOTE_FILE_SYS 0x04 + + +/**************************************************************************** + * PALM_GET_SOME_UNKNOWN_INFORMATION is sent by the host during enumeration to + * get some information from the M series devices, that is currently unknown. + ****************************************************************************/ +#define PALM_GET_SOME_UNKNOWN_INFORMATION 0x04 #endif diff -Naur -X dontdiff linux-2.4.5-ac5/drivers/usb/serial/whiteheat.c linux-2.4.5-ac5-greg/drivers/usb/serial/whiteheat.c --- linux-2.4.5-ac5/drivers/usb/serial/whiteheat.c Sat May 26 11:32:31 2001 +++ linux-2.4.5-ac5-greg/drivers/usb/serial/whiteheat.c Fri Jun 1 00:19:46 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; }