]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/char/synclink.c
tty: Introduce a tty_port generic block_til_ready
[linux-2.6-omap-h63xx.git] / drivers / char / synclink.c
index 500f5176b6ba801c3daa81f4d878dadf4a9b418e..0ded4ed3da3c023c95836a15e82c70a7b2f5edf7 100644 (file)
@@ -3281,6 +3281,35 @@ static void mgsl_hangup(struct tty_struct *tty)
        
 }      /* end of mgsl_hangup() */
 
+/*
+ * carrier_raised()
+ *
+ *     Return true if carrier is raised
+ */
+
+static int carrier_raised(struct tty_port *port)
+{
+       unsigned long flags;
+       struct mgsl_struct *info = container_of(port, struct mgsl_struct, port);
+       
+       spin_lock_irqsave(&info->irq_spinlock, flags);
+       usc_get_serial_signals(info);
+       spin_unlock_irqrestore(&info->irq_spinlock, flags);
+       return (info->serial_signals & SerialSignal_DCD) ? 1 : 0;
+}
+
+static void raise_dtr_rts(struct tty_port *port)
+{
+       struct mgsl_struct *info = container_of(port, struct mgsl_struct, port);
+       unsigned long flags;
+
+       spin_lock_irqsave(&info->irq_spinlock,flags);
+       info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
+       usc_set_serial_signals(info);
+       spin_unlock_irqrestore(&info->irq_spinlock,flags);
+}
+
+
 /* block_til_ready()
  * 
  *     Block the current process until the specified port
@@ -3302,6 +3331,8 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
        bool            do_clocal = false;
        bool            extra_count = false;
        unsigned long   flags;
+       int             dcd;
+       struct tty_port *port = &info->port;
        
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):block_til_ready on %s\n",
@@ -3309,7 +3340,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
 
        if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
                /* nonblock mode is set or port is not enabled */
-               info->port.flags |= ASYNC_NORMAL_ACTIVE;
+               port->flags |= ASYNC_NORMAL_ACTIVE;
                return 0;
        }
 
@@ -3318,50 +3349,42 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
 
        /* Wait for carrier detect and the line to become
         * free (i.e., not in use by the callout).  While we are in
-        * this loop, info->port.count is dropped by one, so that
+        * this loop, port->count is dropped by one, so that
         * mgsl_close() knows when to free things.  We restore it upon
         * exit, either normal or abnormal.
         */
         
        retval = 0;
-       add_wait_queue(&info->port.open_wait, &wait);
+       add_wait_queue(&port->open_wait, &wait);
        
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):block_til_ready before block on %s count=%d\n",
-                        __FILE__,__LINE__, tty->driver->name, info->port.count );
+                        __FILE__,__LINE__, tty->driver->name, port->count );
 
        spin_lock_irqsave(&info->irq_spinlock, flags);
        if (!tty_hung_up_p(filp)) {
                extra_count = true;
-               info->port.count--;
+               port->count--;
        }
        spin_unlock_irqrestore(&info->irq_spinlock, flags);
-       info->port.blocked_open++;
+       port->blocked_open++;
        
        while (1) {
-               if (tty->termios->c_cflag & CBAUD) {
-                       spin_lock_irqsave(&info->irq_spinlock,flags);
-                       info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
-                       usc_set_serial_signals(info);
-                       spin_unlock_irqrestore(&info->irq_spinlock,flags);
-               }
+               if (tty->termios->c_cflag & CBAUD)
+                       tty_port_raise_dtr_rts(port);
                
                set_current_state(TASK_INTERRUPTIBLE);
                
-               if (tty_hung_up_p(filp) || !(info->port.flags & ASYNC_INITIALIZED)){
-                       retval = (info->port.flags & ASYNC_HUP_NOTIFY) ?
+               if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)){
+                       retval = (port->flags & ASYNC_HUP_NOTIFY) ?
                                        -EAGAIN : -ERESTARTSYS;
                        break;
                }
                
-               spin_lock_irqsave(&info->irq_spinlock,flags);
-               usc_get_serial_signals(info);
-               spin_unlock_irqrestore(&info->irq_spinlock,flags);
+               dcd = tty_port_carrier_raised(&info->port);
                
-               if (!(info->port.flags & ASYNC_CLOSING) &&
-                   (do_clocal || (info->serial_signals & SerialSignal_DCD)) ) {
+               if (!(port->flags & ASYNC_CLOSING) && (do_clocal || dcd))
                        break;
-               }
                        
                if (signal_pending(current)) {
                        retval = -ERESTARTSYS;
@@ -3370,24 +3393,25 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
                
                if (debug_level >= DEBUG_LEVEL_INFO)
                        printk("%s(%d):block_til_ready blocking on %s count=%d\n",
-                                __FILE__,__LINE__, tty->driver->name, info->port.count );
+                                __FILE__,__LINE__, tty->driver->name, port->count );
                                 
                schedule();
        }
        
        set_current_state(TASK_RUNNING);
-       remove_wait_queue(&info->port.open_wait, &wait);
+       remove_wait_queue(&port->open_wait, &wait);
        
+       /* FIXME: Racy on hangup during close wait */
        if (extra_count)
-               info->port.count++;
-       info->port.blocked_open--;
+               port->count++;
+       port->blocked_open--;
        
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):block_til_ready after blocking on %s count=%d\n",
-                        __FILE__,__LINE__, tty->driver->name, info->port.count );
+                        __FILE__,__LINE__, tty->driver->name, port->count );
                         
        if (!retval)
-               info->port.flags |= ASYNC_NORMAL_ACTIVE;
+               port->flags |= ASYNC_NORMAL_ACTIVE;
                
        return retval;
        
@@ -4304,6 +4328,12 @@ static void mgsl_add_device( struct mgsl_struct *info )
 
 }      /* end of mgsl_add_device() */
 
+static const struct tty_port_operations mgsl_port_ops = {
+       .carrier_raised = carrier_raised,
+       .raise_dtr_rts = raise_dtr_rts,
+};
+
+
 /* mgsl_allocate_device()
  * 
  *     Allocate and initialize a device instance structure
@@ -4322,6 +4352,7 @@ static struct mgsl_struct* mgsl_allocate_device(void)
                printk("Error can't allocate device instance data\n");
        } else {
                tty_port_init(&info->port);
+               info->port.ops = &mgsl_port_ops;
                info->magic = MGSL_MAGIC;
                INIT_WORK(&info->task, mgsl_bh_handler);
                info->max_frame_size = 4096;