tty: const: constify remaining tty_operations
[safe/jmp/linux-2.6] / drivers / char / epca.c
index e07d792..17b044a 100644 (file)
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/init.h>
+#include <linux/sched.h>
 #include <linux/serial.h>
 #include <linux/delay.h>
 #include <linux/ctype.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/uaccess.h>
@@ -164,8 +166,6 @@ static int pc_write_room(struct tty_struct *);
 static int pc_chars_in_buffer(struct tty_struct *);
 static void pc_flush_buffer(struct tty_struct *);
 static void pc_flush_chars(struct tty_struct *);
-static int block_til_ready(struct tty_struct *, struct file *,
-                       struct channel *);
 static int pc_open(struct tty_struct *, struct file *);
 static void post_fep_init(unsigned int crd);
 static void epcapoll(unsigned long);
@@ -175,7 +175,7 @@ static unsigned termios2digi_h(struct channel *ch, unsigned);
 static unsigned termios2digi_i(struct channel *ch, unsigned);
 static unsigned termios2digi_c(struct channel *ch, unsigned);
 static void epcaparam(struct tty_struct *, struct channel *);
-static void receive_data(struct channel *);
+static void receive_data(struct channel *, struct tty_struct *tty);
 static int pc_ioctl(struct tty_struct *, struct file *,
                        unsigned int, unsigned long);
 static int info_ioctl(struct tty_struct *, struct file *,
@@ -422,7 +422,6 @@ static void pc_close(struct tty_struct *tty, struct file *filp)
 {
        struct channel *ch;
        struct tty_port *port;
-       unsigned long flags;
        /*
         * verifyChannel returns the channel from the tty struct if it is
         * valid. This serves as a sanity check.
@@ -432,58 +431,15 @@ static void pc_close(struct tty_struct *tty, struct file *filp)
                return;
        port = &ch->port;
 
-       spin_lock_irqsave(&port->lock, flags);
-       if (tty_hung_up_p(filp)) {
-               spin_unlock_irqrestore(&port->lock, flags);
-               return;
-       }
-       if (port->count-- > 1)  {
-               /* Begin channel is open more than once */
-               /*
-                * Return without doing anything. Someone might still
-                * be using the channel.
-                */
-               spin_unlock_irqrestore(&port->lock, flags);
+       if (tty_port_close_start(port, tty, filp) == 0)
                return;
-       }
-       /* Port open only once go ahead with shutdown & reset */
-       WARN_ON(port->count < 0);
-
-       /*
-        * Let the rest of the driver know the channel is being closed.
-        * This becomes important if an open is attempted before close
-        * is finished.
-        */
-       port->flags |= ASYNC_CLOSING;
-       tty->closing = 1;
-
-       spin_unlock_irqrestore(&port->lock, flags);
 
-       if (port->flags & ASYNC_INITIALIZED)  {
-               /* Setup an event to indicate when the
-                  transmit buffer empties */
-               setup_empty_event(tty, ch);
-               /* 30 seconds timeout */
-               tty_wait_until_sent(tty, 3000);
-       }
        pc_flush_buffer(tty);
-       tty_ldisc_flush(tty);
        shutdown(ch, tty);
 
-       spin_lock_irqsave(&port->lock, flags);
-       tty->closing = 0;
-       ch->event = 0;
-       port->tty = NULL;
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       if (port->blocked_open) {
-               if (ch->close_delay)
-                       msleep_interruptible(jiffies_to_msecs(ch->close_delay));
-               wake_up_interruptible(&port->open_wait);
-       }
-       port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED |
-                                                       ASYNC_CLOSING);
-       wake_up_interruptible(&port->close_wait);
+       tty_port_close_end(port, tty);
+       ch->event = 0;  /* FIXME: review ch->event locking */
+       tty_port_tty_set(port, NULL);
 }
 
 static void shutdown(struct channel *ch, struct tty_struct *tty)
@@ -527,7 +483,6 @@ static void shutdown(struct channel *ch, struct tty_struct *tty)
 static void pc_hangup(struct tty_struct *tty)
 {
        struct channel *ch;
-       struct tty_port *port;
 
        /*
         * verifyChannel returns the channel from the tty struct if it is
@@ -535,20 +490,12 @@ static void pc_hangup(struct tty_struct *tty)
         */
        ch = verifyChannel(tty);
        if (ch != NULL) {
-               unsigned long flags;
-               port = &ch->port;
-
                pc_flush_buffer(tty);
                tty_ldisc_flush(tty);
                shutdown(ch, tty);
 
-               spin_lock_irqsave(&port->lock, flags);
-               port->tty = NULL;
                ch->event = 0;  /* FIXME: review locking of ch->event */
-               port->count = 0;
-               port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED);
-               spin_unlock_irqrestore(&port->lock, flags);
-               wake_up_interruptible(&port->open_wait);
+               tty_port_hangup(&ch->port);
        }
 }
 
@@ -792,98 +739,18 @@ static void pc_flush_chars(struct tty_struct *tty)
        }
 }
 
-static int block_til_ready(struct tty_struct *tty,
-                               struct file *filp, struct channel *ch)
+static int epca_carrier_raised(struct tty_port *port)
 {
-       DECLARE_WAITQUEUE(wait, current);
-       int retval, do_clocal = 0;
-       unsigned long flags;
-       struct tty_port *port = &ch->port;
-
-       if (tty_hung_up_p(filp)) {
-               if (port->flags & ASYNC_HUP_NOTIFY)
-                       retval = -EAGAIN;
-               else
-                       retval = -ERESTARTSYS;
-               return retval;
-       }
-
-       /*
-        * If the device is in the middle of being closed, then block until
-        * it's done, and then try again.
-        */
-       if (port->flags & ASYNC_CLOSING) {
-               interruptible_sleep_on(&port->close_wait);
-
-               if (port->flags & ASYNC_HUP_NOTIFY)
-                       return -EAGAIN;
-               else
-                       return -ERESTARTSYS;
-       }
-
-       if (filp->f_flags & O_NONBLOCK)  {
-               /*
-                * If non-blocking mode is set, then make the check up front
-                * and then exit.
-                */
-               port->flags |= ASYNC_NORMAL_ACTIVE;
-               return 0;
-       }
-       if (tty->termios->c_cflag & CLOCAL)
-               do_clocal = 1;
-       /* Block waiting for the carrier detect and the line to become free */
-
-       retval = 0;
-       add_wait_queue(&port->open_wait, &wait);
-
-       spin_lock_irqsave(&port->lock, flags);
-       /* We dec count so that pc_close will know when to free things */
-       if (!tty_hung_up_p(filp))
-               port->count--;
-       port->blocked_open++;
-       while (1) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (tty_hung_up_p(filp) ||
-                               !(port->flags & ASYNC_INITIALIZED)) {
-                       if (port->flags & ASYNC_HUP_NOTIFY)
-                               retval = -EAGAIN;
-                       else
-                               retval = -ERESTARTSYS;
-                       break;
-               }
-               if (!(port->flags & ASYNC_CLOSING) &&
-                         (do_clocal || (ch->imodem & ch->dcd)))
-                       break;
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-               spin_unlock_irqrestore(&port->lock, flags);
-               /*
-                * Allow someone else to be scheduled. We will occasionally go
-                * through this loop until one of the above conditions change.
-                * The below schedule call will allow other processes to enter
-                * and prevent this loop from hogging the cpu.
-                */
-               schedule();
-               spin_lock_irqsave(&port->lock, flags);
-       }
-
-       __set_current_state(TASK_RUNNING);
-       remove_wait_queue(&port->open_wait, &wait);
-       if (!tty_hung_up_p(filp))
-               port->count++;
-       port->blocked_open--;
-
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       if (retval)
-               return retval;
-
-       port->flags |= ASYNC_NORMAL_ACTIVE;
+       struct channel *ch = container_of(port, struct channel, port);
+       if (ch->imodem & ch->dcd)
+               return 1;
        return 0;
 }
 
+static void epca_dtr_rts(struct tty_port *port, int onoff)
+{
+}
+
 static int pc_open(struct tty_struct *tty, struct file *filp)
 {
        struct channel *ch;
@@ -904,7 +771,7 @@ static int pc_open(struct tty_struct *tty, struct file *filp)
        /* Check status of board configured in system.  */
 
        /*
-        * I check to see if the epca_setup routine detected an user error. It
+        * I check to see if the epca_setup routine detected a user error. It
         * might be better to put this in pc_init, but for the moment it goes
         * here.
         */
@@ -978,7 +845,7 @@ static int pc_open(struct tty_struct *tty, struct file *filp)
        port->flags |= ASYNC_INITIALIZED;
        spin_unlock_irqrestore(&port->lock, flags);
 
-       retval = block_til_ready(tty, filp, ch);
+       retval = tty_port_block_til_ready(port, tty, filp);
        if (retval)
                return retval;
        /*
@@ -1029,8 +896,11 @@ static void __exit epca_module_exit(void)
                }
                ch = card_ptr[crd];
                for (count = 0; count < bd->numports; count++, ch++) {
-                       if (ch && ch->port.tty)
-                               tty_hangup(ch->port.tty);
+                       struct tty_struct *tty = tty_port_tty_get(&ch->port);
+                       if (tty) {
+                               tty_hangup(tty);
+                               tty_kref_put(tty);
+                       }
                }
        }
        pci_unregister_driver(&epca_driver);
@@ -1055,12 +925,17 @@ static const struct tty_operations pc_ops = {
        .break_ctl = pc_send_break
 };
 
+static const struct tty_port_operations epca_port_ops = {
+       .carrier_raised = epca_carrier_raised,
+       .dtr_rts = epca_dtr_rts,
+};
+
 static int info_open(struct tty_struct *tty, struct file *filp)
 {
        return 0;
 }
 
-static struct tty_operations info_ops = {
+static const struct tty_operations info_ops = {
        .open = info_open,
        .ioctl = info_ioctl,
 };
@@ -1390,6 +1265,7 @@ static void post_fep_init(unsigned int crd)
                u16 tseg, rseg;
 
                tty_port_init(&ch->port);
+               ch->port.ops = &epca_port_ops;
                ch->brdchan = bc;
                ch->mailbox = gd;
                INIT_WORK(&ch->tqueue, do_softint);
@@ -1441,7 +1317,7 @@ static void post_fep_init(unsigned int crd)
                ch->boardnum   = crd;
                ch->channelnum = i;
                ch->magic      = EPCA_MAGIC;
-               ch->port.tty        = NULL;
+               tty_port_tty_set(&ch->port, NULL);
 
                if (shrinkmem) {
                        fepcmd(ch, SETBUFFER, 32, 0, 0, 0);
@@ -1523,7 +1399,7 @@ static void post_fep_init(unsigned int crd)
                ch->fepstartca = 0;
                ch->fepstopca = 0;
 
-               ch->close_delay = 50;
+               ch->port.close_delay = 50;
 
                spin_unlock_irqrestore(&epca_lock, flags);
        }
@@ -1635,15 +1511,16 @@ static void doevent(int crd)
                if (bc == NULL)
                        goto next;
 
+               tty = tty_port_tty_get(&ch->port);
                if (event & DATA_IND)  { /* Begin DATA_IND */
-                       receive_data(ch);
+                       receive_data(ch, tty);
                        assertgwinon(ch);
                } /* End DATA_IND */
                /* else *//* Fix for DCD transition missed bug */
                if (event & MODEMCHG_IND) {
                        /* A modem signal change has been indicated */
                        ch->imodem = mstat;
-                       if (ch->port.flags & ASYNC_CHECK_CD) {
+                       if (test_bit(ASYNCB_CHECK_CD, &ch->port.flags)) {
                                /* We are now receiving dcd */
                                if (mstat & ch->dcd)
                                        wake_up_interruptible(&ch->port.open_wait);
@@ -1651,7 +1528,6 @@ static void doevent(int crd)
                                        pc_sched_event(ch, EPCA_EVENT_HANGUP);
                        }
                }
-               tty = ch->port.tty;
                if (tty) {
                        if (event & BREAK_IND) {
                                /* A break has been indicated */
@@ -1671,6 +1547,7 @@ static void doevent(int crd)
                                        tty_wakeup(tty);
                                }
                        }
+                       tty_kref_put(tty);
                }
 next:
                globalwinon(ch);
@@ -1890,9 +1767,9 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
                 * that the driver will wait on carrier detect.
                 */
                if (ts->c_cflag & CLOCAL)
-                       ch->port.flags &= ~ASYNC_CHECK_CD;
+                       clear_bit(ASYNCB_CHECK_CD, &ch->port.flags);
                else
-                       ch->port.flags |= ASYNC_CHECK_CD;
+                       set_bit(ASYNCB_CHECK_CD, &ch->port.flags);
                mval = ch->m_dtr | ch->m_rts;
        } /* End CBAUD not detected */
        iflag = termios2digi_i(ch, ts->c_iflag);
@@ -1965,11 +1842,10 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
 }
 
 /* Caller holds lock */
-static void receive_data(struct channel *ch)
+static void receive_data(struct channel *ch, struct tty_struct *tty)
 {
        unchar *rptr;
        struct ktermios *ts = NULL;
-       struct tty_struct *tty;
        struct board_chan __iomem *bc;
        int dataToRead, wrapgap, bytesAvailable;
        unsigned int tail, head;
@@ -1982,7 +1858,6 @@ static void receive_data(struct channel *ch)
        globalwinon(ch);
        if (ch->statusflags & RXSTOPPED)
                return;
-       tty = ch->port.tty;
        if (tty)
                ts = tty->termios;
        bc = ch->brdchan;
@@ -2042,7 +1917,7 @@ static void receive_data(struct channel *ch)
        globalwinon(ch);
        writew(tail, &bc->rout);
        /* Must be called with global data */
-       tty_schedule_flip(ch->port.tty);
+       tty_schedule_flip(tty);
 }
 
 static int info_ioctl(struct tty_struct *tty, struct file *file,
@@ -2241,8 +2116,8 @@ static int pc_ioctl(struct tty_struct *tty, struct file *file,
                        tty_wait_until_sent(tty, 0);
                } else {
                        /* ldisc lock already held in ioctl */
-                       if (tty->ldisc.ops->flush_buffer)
-                               tty->ldisc.ops->flush_buffer(tty);
+                       if (tty->ldisc->ops->flush_buffer)
+                               tty->ldisc->ops->flush_buffer(tty);
                }
                unlock_kernel();
                /* Fall Thru */
@@ -2365,15 +2240,17 @@ static void do_softint(struct work_struct *work)
        struct channel *ch = container_of(work, struct channel, tqueue);
        /* Called in response to a modem change event */
        if (ch && ch->magic == EPCA_MAGIC) {
-               struct tty_struct *tty = ch->port.tty;
+               struct tty_struct *tty = tty_port_tty_get(&ch->port);
 
                if (tty && tty->driver_data) {
                        if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) {
                                tty_hangup(tty);
                                wake_up_interruptible(&ch->port.open_wait);
-                               ch->port.flags &= ~ASYNC_NORMAL_ACTIVE;
+                               clear_bit(ASYNCB_NORMAL_ACTIVE,
+                                               &ch->port.flags);
                        }
                }
+               tty_kref_put(tty);
        }
 }