Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / usb / serial / io_edgeport.c
index 14c1dd6..b606c59 100644 (file)
  * Networks technical support, or Peter Berger <pberger@brimson.com>,
  * or Al Borchers <alborchers@steinerpoint.com>.
  *
- * Version history:
- * 
- * 2003_04_03 al borchers
- *  - fixed a bug (that shows up with dosemu) where the tty struct is
- *    used in a callback after it has been freed
- *
- * 2.3 2002_03_08 greg kroah-hartman
- *     - fixed bug when multiple devices were attached at the same time.
- *
- * 2.2 2001_11_14 greg kroah-hartman
- *     - fixed bug in edge_close that kept the port from being used more
- *       than once.
- *     - fixed memory leak on device removal.
- *     - fixed potential double free of memory when command urb submitting
- *       failed.
- *     - other small cleanups when the device is removed
- *     
- * 2.1 2001_07_09 greg kroah-hartman
- *     - added support for TIOCMBIS and TIOCMBIC.
- *
- *     (04/08/2001) gb
- *     - Identify version on module load.
- *
- * 2.0 2001_03_05 greg kroah-hartman
- *     - reworked entire driver to fit properly in with the other usb-serial
- *       drivers.  Occasional oopses still happen, but it's a good start.
- *
- * 1.2.3 (02/23/2001) greg kroah-hartman
- *     - changed device table to work properly for 2.4.x final format.
- *     - fixed problem with dropping data at high data rates.
- *
- * 1.2.2 (11/27/2000) greg kroah-hartman
- *     - cleaned up more NTisms.
- *     - Added device table for 2.4.0-test11
- *
- * 1.2.1 (11/08/2000) greg kroah-hartman
- *     - Started to clean up NTisms.
- *     - Fixed problem with dev field of urb for kernels >= 2.4.0-test9
- *
- * 1.2 (10/17/2000) David Iacovelli
- *     Remove all EPIC code and GPL source
- *  Fix RELEVANT_IFLAG macro to include flow control 
- *  changes port configuration changes.
- *  Fix redefinition of SERIAL_MAGIC
- *  Change all timeout values to 5 seconds
- *  Tried to fix the UHCI multiple urb submission, but failed miserably.
- *  it seems to work fine with OHCI.
- *  ( Greg take a look at the #if 0 at end of WriteCmdUsb() we must 
- *    find a way to work arount this UHCI bug )
- *
- * 1.1 (10/11/2000) David Iacovelli
- *  Fix XON/XOFF flow control to support both IXON and IXOFF
- *
- * 0.9.27 (06/30/2000) David Iacovelli
- *  Added transmit queue and now allocate urb for command writes.
- *
- * 0.9.26 (06/29/2000) David Iacovelli
- *  Add support for 80251 based edgeport
- *
- * 0.9.25 (06/27/2000) David Iacovelli
- *  Do not close the port if it has multiple opens.
- *
- * 0.9.24 (05/26/2000) David Iacovelli
- *  Add IOCTLs to support RXTX and JAVA POS 
- *  and first cut at running BlackBox Demo
- *
- * 0.9.23 (05/24/2000) David Iacovelli
- *  Add IOCTLs to support RXTX and JAVA POS
- *
- * 0.9.22 (05/23/2000) David Iacovelli
- *  fixed bug in enumeration.  If epconfig turns on mapping by
- *  path after a device is already plugged in, we now update
- *  the mapping correctly
- *
- * 0.9.21 (05/16/2000) David Iacovelli
- *  Added BlockUntilChaseResp() to also wait for txcredits
- *  Updated the way we allocate and handle write URBs 
- *     Add debug code to dump buffers
- *
- * 0.9.20 (05/01/2000) David Iacovelli
- *     change driver to use usb/tts/
- *
- * 0.9.19 (05/01/2000) David Iacovelli
- *  Update code to compile if DEBUG is off
- *
- * 0.9.18 (04/28/2000) David Iacovelli
- *  cleanup and test tty_register with devfs
- *
- * 0.9.17 (04/27/2000) greg kroah-hartman
- *     changed tty_register around to be like the way it
- *     was before, but now it works properly with devfs.
- *
- * 0.9.16 (04/26/2000) david iacovelli
- *  Fixed bug in GetProductInfo()
- *
- * 0.9.15 (04/25/2000) david iacovelli
- *     Updated enumeration
- *
- * 0.9.14 (04/24/2000) david iacovelli
- *  Removed all config/status IOCTLS and 
- *  converted to using /proc/edgeport
- *  still playing with devfs
- *
- * 0.9.13 (04/24/2000) david iacovelli
- *  Removed configuration based on ttyUSB0
- *  Added support for configuration using /prod/edgeport
- *  first attempt at using devfs (not working yet!)
- *  Added IOCTL to GetProductInfo()
- *  Added support for custom baud rates
- *     Add support for random port numbers
- *
- * 0.9.12 (04/18/2000) david iacovelli
- *     added additional configuration IOCTLs
- *  use ttyUSB0 for configuration
- *
- * 0.9.11 (04/17/2000) greg kroah-hartman
- *     fixed module initialization race conditions.
- *     made all urbs dynamically allocated.
- *     made driver devfs compatible. now it only registers the tty device
- *     when the device is actually plugged in.
- *
- * 0.9.10 (04/13/2000) greg kroah-hartman
- *     added proc interface framework.
- *
- * 0.9.9 (04/13/2000) david iacovelli
- *     added enumeration code and ioctls to configure the device
- *
- * 0.9.8 (04/12/2000) david iacovelli
- *  Change interrupt read start when device is plugged in
- *  and stop when device is removed
- *     process interrupt reads when all ports are closed 
- *  (keep value of rxBytesAvail consistent with the edgeport)
- *  set the USB_BULK_QUEUE flag so that we can shove a bunch 
- *  of urbs at once down the pipe 
- *
- * 0.9.7 (04/10/2000) david iacovelli
- *     start to add enumeration code.
- *  generate serial number for epic devices
- *  add support for kdb
- *
- * 0.9.6 (03/30/2000) david iacovelli
- *  add IOCTL to get string, manufacture, and boot descriptors
- *
- * 0.9.5 (03/14/2000) greg kroah-hartman
- *     more error checking added to SerialOpen to try to fix UHCI open problem
- *
- * 0.9.4 (03/09/2000) greg kroah-hartman
- *     added more error checking to handle oops when data is hanging
- *     around and tty is abruptly closed.
- *
- * 0.9.3 (03/09/2000) david iacovelli
- *     Add epic support for xon/xoff chars
- *     play with performance
- *
- * 0.9.2 (03/08/2000) greg kroah-hartman
- *     changed most "info" calls to "dbg"
- *     implemented flow control properly in the termios call
- *
- * 0.9.1 (03/08/2000) david iacovelli
- *     added EPIC support
- *     enabled bootloader update
- *
- * 0.9 (03/08/2000) greg kroah-hartman
- *     Release to IO networks.
- *     Integrated changes that David made
- *  made getting urbs for writing SMP safe
- *
- * 0.8 (03/07/2000) greg kroah-hartman
- *     Release to IO networks.
- *     Fixed problems that were seen in code by David.
- *  Now both Edgeport/4 and Edgeport/2 works properly.
- *  Changed most of the functions to use port instead of serial.
- *
- * 0.7 (02/27/2000) greg kroah-hartman
- *     Milestone 3 release.
- *     Release to IO Networks
- *     ioctl for waiting on line change implemented.
- *     ioctl for getting statistics implemented.
- *     multiport support working.
- *     lsr and msr registers are now handled properly.
- *     change break now hooked up and working.
- *     support for all known Edgeport devices.
- *
- * 0.6 (02/22/2000) greg kroah-hartman
- *     Release to IO networks.
- *     CHASE is implemented correctly when port is closed.
- *     SerialOpen now blocks correctly until port is fully opened.
- *
- * 0.5 (02/20/2000) greg kroah-hartman
- *     Release to IO networks.
- *     Known problems:
- *             modem status register changes are not sent on to the user
- *             CHASE is not implemented when the port is closed.
- *
- * 0.4 (02/16/2000) greg kroah-hartman
- *     Second cut at the CeBit demo.
- *     Doesn't leak memory on every write to the port
- *     Still small leaks on startup.
- *     Added support for Edgeport/2 and Edgeport/8
- *
- * 0.3 (02/15/2000) greg kroah-hartman
- *     CeBit demo release.
- *     Force the line settings to 4800, 8, 1, e for the demo.
- *     Warning! This version leaks memory like crazy!
- *
- * 0.2 (01/30/2000) greg kroah-hartman
- *     Milestone 1 release.
- *     Device is found by USB subsystem, enumerated, fimware is downloaded
- *     and the descriptors are printed to the debug log, config is set, and
- *     green light starts to blink. Open port works, and data can be sent
- *     and received at the default settings of the UART. Loopback connector
- *     and debug log confirms this.
- * 
- * 0.1 (01/23/2000) greg kroah-hartman
- *     Initial release to help IO Networks try to set up their test system. 
- *     Edgeport4 is recognized, firmware is downloaded, config is set so 
- *     device blinks green light every 3 sec. Port is bound, but opening,
- *     closing, and sending data do not work properly.
- * 
  */
 
 #include <linux/config.h>
 #include <linux/spinlock.h>
 #include <linux/serial.h>
 #include <linux/ioctl.h>
+#include <linux/wait.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
 #include "usb-serial.h"
@@ -402,7 +184,7 @@ struct divisor_table_entry {
 // These assume a 3.6864MHz crystal, the standard /16, and
 // MCR.7 = 0.
 //
-static struct divisor_table_entry divisor_table[] = {
+static const struct divisor_table_entry divisor_table[] = {
        {   50,         4608},  
        {   75,         3072},  
        {   110,        2095},          /* 2094.545455 => 230450   => .0217 % over */
@@ -460,11 +242,11 @@ static void edge_shutdown         (struct usb_serial *serial);
 #include "io_tables.h" /* all of the devices that this driver supports */
 
 static struct usb_driver io_driver = {
-       .owner =        THIS_MODULE,
        .name =         "io_edgeport",
        .probe =        usb_serial_probe,
        .disconnect =   usb_serial_disconnect,
        .id_table =     id_table_combined,
+       .no_dynamic_id =        1,
 };
 
 /* function prototypes for all of our local functions */
@@ -950,9 +732,7 @@ static void edge_bulk_out_cmd_callback (struct urb *urb, struct pt_regs *regs)
 
 
        /* clean up the transfer buffer */
-       if (urb->transfer_buffer != NULL) {
-               kfree(urb->transfer_buffer);
-       }
+       kfree(urb->transfer_buffer);
 
        /* Free the command urb */
        usb_free_urb (urb);
@@ -971,7 +751,7 @@ static void edge_bulk_out_cmd_callback (struct urb *urb, struct pt_regs *regs)
 
        /* we have completed the command */
        edge_port->commandPending = FALSE;
-       wake_up_interruptible(&edge_port->wait_command);
+       wake_up(&edge_port->wait_command);
 }
 
 
@@ -991,7 +771,6 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
        struct usb_serial *serial;
        struct edgeport_serial *edge_serial;
        int response;
-       int timeout;
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
@@ -1073,10 +852,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
        }
 
        /* now wait for the port to be completely opened */
-       timeout = OPEN_TIMEOUT;
-       while (timeout && edge_port->openPending == TRUE) {
-               timeout = interruptible_sleep_on_timeout (&edge_port->wait_open, timeout);
-       }
+       wait_event_timeout(edge_port->wait_open, (edge_port->openPending != TRUE), OPEN_TIMEOUT);
 
        if (edge_port->open == FALSE) {
                /* open timed out */
@@ -1128,9 +904,10 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
  ************************************************************************/
 static void block_until_chase_response(struct edgeport_port *edge_port)
 {
+       DEFINE_WAIT(wait);
        __u16 lastCredits;
        int timeout = 1*HZ;
-       int wait = 10;
+       int loop = 10;
 
        while (1) {
                // Save Last credits
@@ -1148,12 +925,14 @@ static void block_until_chase_response(struct edgeport_port *edge_port)
                }
 
                // Block the thread for a while
-               interruptible_sleep_on_timeout (&edge_port->wait_chase, timeout);
+               prepare_to_wait(&edge_port->wait_chase, &wait, TASK_UNINTERRUPTIBLE);
+               schedule_timeout(timeout);
+               finish_wait(&edge_port->wait_chase, &wait);
 
                if (lastCredits == edge_port->txCredits) {
                        // No activity.. count down.
-                       wait--;
-                       if (wait == 0) {
+                       loop--;
+                       if (loop == 0) {
                                edge_port->chaseResponsePending = FALSE;
                                dbg("%s - Chase TIMEOUT", __FUNCTION__);
                                return;
@@ -1161,7 +940,7 @@ static void block_until_chase_response(struct edgeport_port *edge_port)
                } else {
                        // Reset timout value back to 10 seconds
                        dbg("%s - Last %d, Current %d", __FUNCTION__, lastCredits, edge_port->txCredits);
-                       wait = 10;
+                       loop = 10;
                }
        }
 }
@@ -1179,10 +958,11 @@ static void block_until_chase_response(struct edgeport_port *edge_port)
  ************************************************************************/
 static void block_until_tx_empty (struct edgeport_port *edge_port)
 {
+       DEFINE_WAIT(wait);
        struct TxFifo *fifo = &edge_port->txfifo;
        __u32 lastCount;
        int timeout = HZ/10;
-       int wait = 30;
+       int loop = 30;
 
        while (1) {
                // Save Last count
@@ -1195,20 +975,22 @@ static void block_until_tx_empty (struct edgeport_port *edge_port)
                }
 
                // Block the thread for a while
-               interruptible_sleep_on_timeout (&edge_port->wait_chase, timeout);
+               prepare_to_wait (&edge_port->wait_chase, &wait, TASK_UNINTERRUPTIBLE);
+               schedule_timeout(timeout);
+               finish_wait(&edge_port->wait_chase, &wait);
 
                dbg("%s wait", __FUNCTION__);
 
                if (lastCount == fifo->count) {
                        // No activity.. count down.
-                       wait--;
-                       if (wait == 0) {
+                       loop--;
+                       if (loop == 0) {
                                dbg("%s - TIMEOUT", __FUNCTION__);
                                return;
                        }
                } else {
                        // Reset timout value back to seconds
-                       wait = 30;
+                       loop = 30;
                }
        }
 }
@@ -1263,16 +1045,12 @@ static void edge_close (struct usb_serial_port *port, struct file * filp)
 
        if (edge_port->write_urb) {
                /* if this urb had a transfer buffer already (old transfer) free it */
-               if (edge_port->write_urb->transfer_buffer != NULL) {
-                       kfree(edge_port->write_urb->transfer_buffer);
-               }
-               usb_free_urb   (edge_port->write_urb);
+               kfree(edge_port->write_urb->transfer_buffer);
+               usb_free_urb(edge_port->write_urb);
                edge_port->write_urb = NULL;
        }
-       if (edge_port->txfifo.fifo) {
-               kfree(edge_port->txfifo.fifo);
-               edge_port->txfifo.fifo = NULL;
-       }
+       kfree(edge_port->txfifo.fifo);
+       edge_port->txfifo.fifo = NULL;
 
        dbg("%s exited", __FUNCTION__);
 }   
@@ -1416,11 +1194,9 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge
        // get a pointer to the write_urb
        urb = edge_port->write_urb;
 
-       /* if this urb had a transfer buffer already (old transfer) free it */
-       if (urb->transfer_buffer != NULL) {
-               kfree(urb->transfer_buffer);
-               urb->transfer_buffer = NULL;
-       }
+       /* make sure transfer buffer is freed */
+       kfree(urb->transfer_buffer);
+       urb->transfer_buffer = NULL;
 
        /* build the data header for the buffer and port that we are about to send out */
        count = fifo->count;
@@ -1817,13 +1593,8 @@ static int get_serial_info(struct edgeport_port *edge_port, struct serial_struct
        tmp.flags               = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
        tmp.xmit_fifo_size      = edge_port->maxTxCredits;
        tmp.baud_base           = 9600;
-       #if HZ < 2185
        tmp.close_delay         = 5*HZ;
        tmp.closing_wait        = 30*HZ;
-       #else
-       tmp.close_delay         = 2*HZ;
-       tmp.closing_wait        = 65534;
-       #endif
 //     tmp.custom_divisor      = state->custom_divisor;
 //     tmp.hub6                = state->hub6;
 //     tmp.io_type             = state->io_type;
@@ -1841,12 +1612,12 @@ static int get_serial_info(struct edgeport_port *edge_port, struct serial_struct
  *****************************************************************************/
 static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg)
 {
+       DEFINE_WAIT(wait);
        struct edgeport_port *edge_port = usb_get_serial_port_data(port);
        struct async_icount cnow;
        struct async_icount cprev;
        struct serial_icounter_struct icount;
 
-
        dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd);
 
        switch (cmd) {
@@ -1873,7 +1644,9 @@ static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned
                        dbg("%s (%d) TIOCMIWAIT", __FUNCTION__,  port->number);
                        cprev = edge_port->icount;
                        while (1) {
-                               interruptible_sleep_on(&edge_port->delta_msr_wait);
+                               prepare_to_wait(&edge_port->delta_msr_wait, &wait, TASK_INTERRUPTIBLE);
+                               schedule();
+                               finish_wait(&edge_port->delta_msr_wait, &wait);
                                /* see if a signal did it */
                                if (signal_pending(current))
                                        return -ERESTARTSYS;
@@ -2113,7 +1886,7 @@ static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2
                                // We could choose to do something else when Byte3 says Timeout on Chase from Edgeport,
                                // like wait longer in block_until_chase_response, but for now we don't. 
                                edge_port->chaseResponsePending = FALSE;
-                               wake_up_interruptible (&edge_port->wait_chase);
+                               wake_up (&edge_port->wait_chase);
                                return;
 
                        case IOSP_EXT_STATUS_RX_CHECK_RSP:
@@ -2136,7 +1909,7 @@ static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2
                /* we have completed the open */
                edge_port->openPending = FALSE;
                edge_port->open = TRUE;
-               wake_up_interruptible(&edge_port->wait_open);
+               wake_up(&edge_port->wait_open);
                return;
        }
 
@@ -2192,20 +1965,14 @@ static void edge_tty_recv(struct device *dev, struct tty_struct *tty, unsigned c
        int cnt;
 
        do {
-               if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-                       tty_flip_buffer_push(tty);
-                       if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-                               dev_err(dev, "%s - dropping data, %d bytes lost\n",
-                                       __FUNCTION__, length);
-                               return;
-                       }
+               cnt = tty_buffer_request_room(tty, length);
+               if (cnt < length) {
+                       dev_err(dev, "%s - dropping data, %d bytes lost\n",
+                                       __FUNCTION__, length - cnt);
+                       if(cnt == 0)
+                               break;
                }
-               cnt = min(length, TTY_FLIPBUF_SIZE - tty->flip.count);
-               memcpy(tty->flip.char_buf_ptr, data, cnt);
-               memset(tty->flip.flag_buf_ptr, 0, cnt);
-               tty->flip.char_buf_ptr += cnt;
-               tty->flip.flag_buf_ptr += cnt;
-               tty->flip.count += cnt;
+               tty_insert_flip_string(tty, data, cnt);
                data += cnt;
                length -= cnt;
        } while (length > 0);
@@ -2505,9 +2272,7 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer
        // wait for command to finish
        timeout = COMMAND_TIMEOUT;
 #if 0
-       while (timeout && edge_port->commandPending == TRUE) {
-               timeout = interruptible_sleep_on_timeout (&edge_port->wait_command, timeout);
-       }
+       wait_event (&edge_port->wait_command, (edge_port->commandPending == FALSE));
 
        if (edge_port->commandPending == TRUE) {
                /* command timed out */
@@ -2582,7 +2347,7 @@ static int calc_baud_rate_divisor (int baudrate, int *divisor)
 
        dbg("%s - %d", __FUNCTION__, baudrate);
 
-       for (i = 0; i < NUM_ENTRIES(divisor_table); i++) {
+       for (i = 0; i < ARRAY_SIZE(divisor_table); i++) {
                if ( divisor_table[i].BaudRate == baudrate ) {
                        *divisor = divisor_table[i].Divisor;
                        return 0;
@@ -2960,12 +2725,11 @@ static int edge_startup (struct usb_serial *serial)
        dev = serial->dev;
 
        /* create our private serial structure */
-       edge_serial = kmalloc (sizeof(struct edgeport_serial), GFP_KERNEL);
+       edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL);
        if (edge_serial == NULL) {
                dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__);
                return -ENOMEM;
        }
-       memset (edge_serial, 0, sizeof(struct edgeport_serial));
        spin_lock_init(&edge_serial->es_lock);
        edge_serial->serial = serial;
        usb_set_serial_data(serial, edge_serial);
@@ -3112,4 +2876,4 @@ module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug enabled or not");
 
 module_param(low_latency, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Low latency enabled or not");
+MODULE_PARM_DESC(low_latency, "Low latency enabled or not");