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 / digi_acceleport.c
index 3c123be..b3f776a 100644 (file)
 #include <linux/workqueue.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
-
-#ifdef CONFIG_USB_SERIAL_DEBUG
-       static int debug = 1;
-#else
-       static int debug;
-#endif
-
+#include <linux/wait.h>
 #include "usb-serial.h"
 
-
 /* Defines */
 
 /*
@@ -463,8 +456,7 @@ static int digi_ioctl( struct usb_serial_port *port, struct file *file,
 static int digi_tiocmget( struct usb_serial_port *port, struct file *file );
 static int digi_tiocmset( struct usb_serial_port *port, struct file *file,
        unsigned int set, unsigned int clear );
-static int digi_write( struct usb_serial_port *port, int from_user,
-       const unsigned char *buf, int count );
+static int digi_write( struct usb_serial_port *port, const unsigned char *buf, int count );
 static void digi_write_bulk_callback( struct urb *urb, struct pt_regs *regs );
 static int digi_write_room( struct usb_serial_port *port );
 static int digi_chars_in_buffer( struct usb_serial_port *port );
@@ -480,6 +472,8 @@ static int digi_read_oob_callback( struct urb *urb );
 
 /* Statics */
 
+static int debug;
+
 static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(DIGI_VENDOR_ID, DIGI_2_ID) },
        { USB_DEVICE(DIGI_VENDOR_ID, DIGI_4_ID) },
@@ -499,20 +493,22 @@ static struct usb_device_id id_table_4 [] = {
 MODULE_DEVICE_TABLE (usb, id_table_combined);
 
 static struct usb_driver digi_driver = {
-       .owner =        THIS_MODULE,
        .name =         "digi_acceleport",
        .probe =        usb_serial_probe,
        .disconnect =   usb_serial_disconnect,
        .id_table =     id_table_combined,
+       .no_dynamic_id =        1,
 };
 
 
 /* device info needed for the Digi serial converter */
 
-static struct usb_serial_device_type digi_acceleport_2_device = {
-       .owner =                        THIS_MODULE,
-       .name =                         "Digi 2 port USB adapter",
-       .short_name =                   "digi_2",
+static struct usb_serial_driver digi_acceleport_2_device = {
+       .driver = {
+               .owner =                THIS_MODULE,
+               .name =                 "digi_2",
+       },
+       .description =                  "Digi 2 port USB adapter",
        .id_table =                     id_table_2,
        .num_interrupt_in =             0,
        .num_bulk_in =                  4,
@@ -536,10 +532,12 @@ static struct usb_serial_device_type digi_acceleport_2_device = {
        .shutdown =                     digi_shutdown,
 };
 
-static struct usb_serial_device_type digi_acceleport_4_device = {
-       .owner =                        THIS_MODULE,
-       .name =                         "Digi 4 port USB adapter",
-       .short_name =                   "digi_4",
+static struct usb_serial_driver digi_acceleport_4_device = {
+       .driver = {
+               .owner =                THIS_MODULE,
+               .name =                 "digi_4",
+       },
+       .description =                  "Digi 4 port USB adapter",
        .id_table =                     id_table_4,
        .num_interrupt_in =             0,
        .num_bulk_in =                  5,
@@ -574,30 +572,23 @@ static struct usb_serial_device_type digi_acceleport_4_device = {
 *  and the sleep.  In other words, spin_unlock_irqrestore and
 *  interruptible_sleep_on_timeout are "atomic" with respect to
 *  wake ups.  This is used to implement condition variables.
+*
+*  interruptible_sleep_on_timeout is deprecated and has been replaced
+*  with the equivalent code.
 */
 
 static inline long cond_wait_interruptible_timeout_irqrestore(
        wait_queue_head_t *q, long timeout,
        spinlock_t *lock, unsigned long flags )
 {
+       DEFINE_WAIT(wait);
 
-       wait_queue_t wait;
-
-
-       init_waitqueue_entry( &wait, current );
-
-       set_current_state( TASK_INTERRUPTIBLE );
-
-       add_wait_queue( q, &wait );
-
-       spin_unlock_irqrestore( lock, flags );
-
+       prepare_to_wait(q, &wait, TASK_INTERRUPTIBLE);
+       spin_unlock_irqrestore(lock, flags);
        timeout = schedule_timeout(timeout);
+       finish_wait(q, &wait);
 
-       remove_wait_queue( q, &wait );
-
-       return( timeout );
-
+       return timeout;
 }
 
 
@@ -630,14 +621,7 @@ static void digi_wakeup_write( struct usb_serial_port *port )
        wake_up_interruptible( &port->write_wait );
 
        /* wake up line discipline */
-       if( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
-       && tty->ldisc.write_wakeup )
-               (tty->ldisc.write_wakeup)(tty);
-
-       /* wake up other tty processes */
-       wake_up_interruptible( &tty->write_wait );
-       /* For 2.2.16 backport -- wake_up_interruptible( &tty->poll_wait ); */
-
+       tty_wakeup(tty);
 }
 
 
@@ -962,13 +946,10 @@ dbg( "digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num );
        spin_lock_irqsave( &priv->dp_port_lock, flags );
 
        /* send any buffered chars from throttle time on to tty subsystem */
-       len = min(priv->dp_in_buf_len, TTY_FLIPBUF_SIZE - tty->flip.count );
+
+       len = tty_buffer_request_room(tty, priv->dp_in_buf_len);
        if( len > 0 ) {
-               memcpy( tty->flip.char_buf_ptr, priv->dp_in_buf, len );
-               memcpy( tty->flip.flag_buf_ptr, priv->dp_in_flag_buf, len );
-               tty->flip.char_buf_ptr += len;
-               tty->flip.flag_buf_ptr += len;
-               tty->flip.count += len;
+               tty_insert_flip_string_flags(tty, priv->dp_in_buf, priv->dp_in_flag_buf, len);
                tty_flip_buffer_push( tty );
        }
 
@@ -1275,26 +1256,21 @@ dbg( "digi_ioctl: TOP: port=%d, cmd=0x%x", priv->dp_port_num, cmd );
 }
 
 
-static int digi_write( struct usb_serial_port *port, int from_user,
-       const unsigned char *buf, int count )
+static int digi_write( struct usb_serial_port *port, const unsigned char *buf, int count )
 {
 
        int ret,data_len,new_len;
        struct digi_port *priv = usb_get_serial_port_data(port);
        unsigned char *data = port->write_urb->transfer_buffer;
-       unsigned char user_buf[64];     /* 64 bytes is max USB bulk packet */
        unsigned long flags = 0;
 
 
-dbg( "digi_write: TOP: port=%d, count=%d, from_user=%d, in_interrupt=%ld",
-priv->dp_port_num, count, from_user, in_interrupt() );
+dbg( "digi_write: TOP: port=%d, count=%d, in_interrupt=%ld",
+priv->dp_port_num, count, in_interrupt() );
 
        /* copy user data (which can sleep) before getting spin lock */
        count = min( count, port->bulk_out_size-2 );
        count = min( 64, count);
-       if( from_user && copy_from_user( user_buf, buf, count ) ) {
-               return( -EFAULT );
-       }
 
        /* be sure only one write proceeds at a time */
        /* there are races on the port private buffer */
@@ -1307,8 +1283,7 @@ priv->dp_port_num, count, from_user, in_interrupt() );
 
                /* buffer data if count is 1 (probably put_char) if possible */
                if( count == 1 && priv->dp_out_buf_len < DIGI_OUT_BUF_SIZE ) {
-                       priv->dp_out_buf[priv->dp_out_buf_len++]
-                               = *(from_user ? user_buf : buf);
+                       priv->dp_out_buf[priv->dp_out_buf_len++] = *buf;
                        new_len = 1;
                } else {
                        new_len = 0;
@@ -1341,7 +1316,7 @@ priv->dp_port_num, count, from_user, in_interrupt() );
        data += priv->dp_out_buf_len;
 
        /* copy in new data */
-       memcpy( data, from_user ? user_buf : buf, new_len );
+       memcpy( data, buf, new_len );
 
        if( (ret=usb_submit_urb(port->write_urb, GFP_ATOMIC)) == 0 ) {
                priv->dp_write_urb_in_use = 1;
@@ -1548,7 +1523,7 @@ dbg( "digi_open: TOP: port=%d, open_count=%d", priv->dp_port_num, port->open_cou
 
 static void digi_close( struct usb_serial_port *port, struct file *filp )
 {
-
+       DEFINE_WAIT(wait);
        int ret;
        unsigned char buf[32];
        struct tty_struct *tty = port->tty;
@@ -1559,13 +1534,17 @@ static void digi_close( struct usb_serial_port *port, struct file *filp )
 dbg( "digi_close: TOP: port=%d, open_count=%d", priv->dp_port_num, port->open_count );
 
 
+       /* if disconnected, just clear flags */
+       if (!usb_get_intfdata(port->serial->interface))
+               goto exit;
+
        /* do cleanup only after final close on this port */
        spin_lock_irqsave( &priv->dp_port_lock, flags );
        priv->dp_in_close = 1;
        spin_unlock_irqrestore( &priv->dp_port_lock, flags );
 
        /* tell line discipline to process only XON/XOFF */
-        tty->closing = 1;
+       tty->closing = 1;
 
        /* wait for output to drain */
        if( (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0 ) {
@@ -1575,8 +1554,7 @@ dbg( "digi_close: TOP: port=%d, open_count=%d", priv->dp_port_num, port->open_co
        /* flush driver and line discipline buffers */
        if( tty->driver->flush_buffer )
                tty->driver->flush_buffer( tty );
-       if( tty->ldisc.flush_buffer )
-               tty->ldisc.flush_buffer( tty );
+       tty_ldisc_flush(tty);
 
        if (port->serial->dev) {
                /* wait for transmit idle */
@@ -1621,15 +1599,17 @@ dbg( "digi_close: TOP: port=%d, open_count=%d", priv->dp_port_num, port->open_co
                        dbg( "digi_close: write oob failed, ret=%d", ret );
 
                /* wait for final commands on oob port to complete */
-               interruptible_sleep_on_timeout( &priv->dp_flush_wait,
-                       DIGI_CLOSE_TIMEOUT );
+               prepare_to_wait(&priv->dp_flush_wait, &wait, TASK_INTERRUPTIBLE);
+               schedule_timeout(DIGI_CLOSE_TIMEOUT);
+               finish_wait(&priv->dp_flush_wait, &wait);
 
                /* shutdown any outstanding bulk writes */
-               usb_unlink_urb (port->write_urb);
+               usb_kill_urb(port->write_urb);
        }
 
        tty->closing = 0;
 
+exit:
        spin_lock_irqsave( &priv->dp_port_lock, flags );
        priv->dp_write_urb_in_use = 0;
        priv->dp_in_close = 0;
@@ -1763,8 +1743,8 @@ dbg( "digi_shutdown: TOP, in_interrupt()=%ld", in_interrupt() );
 
        /* stop reads and writes on all ports */
        for( i=0; i<serial->type->num_ports+1; i++ ) {
-               usb_unlink_urb( serial->port[i]->read_urb );
-               usb_unlink_urb( serial->port[i]->write_urb );
+               usb_kill_urb(serial->port[i]->read_urb);
+               usb_kill_urb(serial->port[i]->write_urb);
        }
 
        /* free the private data structures for all ports */
@@ -1844,6 +1824,7 @@ static int digi_read_inb_callback( struct urb *urb )
        int status = ((unsigned char *)urb->transfer_buffer)[2];
        unsigned char *data = ((unsigned char *)urb->transfer_buffer)+3;
        int flag,throttled;
+       int i;
 
        /* do not process callbacks on closed ports */
        /* but do continue the read chain */
@@ -1902,20 +1883,18 @@ static int digi_read_inb_callback( struct urb *urb )
                        }
 
                } else {
-
-                       len = min( len, TTY_FLIPBUF_SIZE - tty->flip.count );
-
+                       len = tty_buffer_request_room(tty, len);
                        if( len > 0 ) {
-                               memcpy( tty->flip.char_buf_ptr, data, len );
-                               memset( tty->flip.flag_buf_ptr, flag, len );
-                               tty->flip.char_buf_ptr += len;
-                               tty->flip.flag_buf_ptr += len;
-                               tty->flip.count += len;
+                               /* Hot path */
+                               if(flag == TTY_NORMAL)
+                                       tty_insert_flip_string(tty, data, len);
+                               else {
+                                       for(i = 0; i < len; i++)
+                                               tty_insert_flip_char(tty, data[i], flag);
+                               }
                                tty_flip_buffer_push( tty );
                        }
-
                }
-
        }
 
        spin_unlock( &priv->dp_port_lock );
@@ -2068,6 +2047,5 @@ MODULE_AUTHOR( DRIVER_AUTHOR );
 MODULE_DESCRIPTION( DRIVER_DESC );
 MODULE_LICENSE("GPL");
 
-MODULE_PARM(debug, "i");
+module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug enabled or not");
-