linux/drivers/char/tty_port.c
<<
>>
Prefs
   1/*
   2 * Tty port functions
   3 */
   4
   5#include <linux/types.h>
   6#include <linux/errno.h>
   7#include <linux/tty.h>
   8#include <linux/tty_driver.h>
   9#include <linux/tty_flip.h>
  10#include <linux/serial.h>
  11#include <linux/timer.h>
  12#include <linux/string.h>
  13#include <linux/slab.h>
  14#include <linux/sched.h>
  15#include <linux/init.h>
  16#include <linux/wait.h>
  17#include <linux/bitops.h>
  18#include <linux/delay.h>
  19#include <linux/module.h>
  20
  21void tty_port_init(struct tty_port *port)
  22{
  23        memset(port, 0, sizeof(*port));
  24        init_waitqueue_head(&port->open_wait);
  25        init_waitqueue_head(&port->close_wait);
  26        init_waitqueue_head(&port->delta_msr_wait);
  27        mutex_init(&port->mutex);
  28        spin_lock_init(&port->lock);
  29        port->close_delay = (50 * HZ) / 100;
  30        port->closing_wait = (3000 * HZ) / 100;
  31}
  32EXPORT_SYMBOL(tty_port_init);
  33
  34int tty_port_alloc_xmit_buf(struct tty_port *port)
  35{
  36        /* We may sleep in get_zeroed_page() */
  37        mutex_lock(&port->mutex);
  38        if (port->xmit_buf == NULL)
  39                port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
  40        mutex_unlock(&port->mutex);
  41        if (port->xmit_buf == NULL)
  42                return -ENOMEM;
  43        return 0;
  44}
  45EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
  46
  47void tty_port_free_xmit_buf(struct tty_port *port)
  48{
  49        mutex_lock(&port->mutex);
  50        if (port->xmit_buf != NULL) {
  51                free_page((unsigned long)port->xmit_buf);
  52                port->xmit_buf = NULL;
  53        }
  54        mutex_unlock(&port->mutex);
  55}
  56EXPORT_SYMBOL(tty_port_free_xmit_buf);
  57
  58
  59/**
  60 *      tty_port_tty_get        -       get a tty reference
  61 *      @port: tty port
  62 *
  63 *      Return a refcount protected tty instance or NULL if the port is not
  64 *      associated with a tty (eg due to close or hangup)
  65 */
  66
  67struct tty_struct *tty_port_tty_get(struct tty_port *port)
  68{
  69        unsigned long flags;
  70        struct tty_struct *tty;
  71
  72        spin_lock_irqsave(&port->lock, flags);
  73        tty = tty_kref_get(port->tty);
  74        spin_unlock_irqrestore(&port->lock, flags);
  75        return tty;
  76}
  77EXPORT_SYMBOL(tty_port_tty_get);
  78
  79/**
  80 *      tty_port_tty_set        -       set the tty of a port
  81 *      @port: tty port
  82 *      @tty: the tty
  83 *
  84 *      Associate the port and tty pair. Manages any internal refcounts.
  85 *      Pass NULL to deassociate a port
  86 */
  87
  88void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
  89{
  90        unsigned long flags;
  91
  92        spin_lock_irqsave(&port->lock, flags);
  93        if (port->tty)
  94                tty_kref_put(port->tty);
  95        port->tty = tty_kref_get(tty);
  96        spin_unlock_irqrestore(&port->lock, flags);
  97}
  98EXPORT_SYMBOL(tty_port_tty_set);
  99
 100static void tty_port_shutdown(struct tty_port *port)
 101{
 102        if (port->ops->shutdown &&
 103                test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
 104                        port->ops->shutdown(port);
 105
 106}
 107
 108/**
 109 *      tty_port_hangup         -       hangup helper
 110 *      @port: tty port
 111 *
 112 *      Perform port level tty hangup flag and count changes. Drop the tty
 113 *      reference.
 114 */
 115
 116void tty_port_hangup(struct tty_port *port)
 117{
 118        unsigned long flags;
 119
 120        spin_lock_irqsave(&port->lock, flags);
 121        port->count = 0;
 122        port->flags &= ~ASYNC_NORMAL_ACTIVE;
 123        if (port->tty)
 124                tty_kref_put(port->tty);
 125        port->tty = NULL;
 126        spin_unlock_irqrestore(&port->lock, flags);
 127        wake_up_interruptible(&port->open_wait);
 128        wake_up_interruptible(&port->delta_msr_wait);
 129        tty_port_shutdown(port);
 130}
 131EXPORT_SYMBOL(tty_port_hangup);
 132
 133/**
 134 *      tty_port_carrier_raised -       carrier raised check
 135 *      @port: tty port
 136 *
 137 *      Wrapper for the carrier detect logic. For the moment this is used
 138 *      to hide some internal details. This will eventually become entirely
 139 *      internal to the tty port.
 140 */
 141
 142int tty_port_carrier_raised(struct tty_port *port)
 143{
 144        if (port->ops->carrier_raised == NULL)
 145                return 1;
 146        return port->ops->carrier_raised(port);
 147}
 148EXPORT_SYMBOL(tty_port_carrier_raised);
 149
 150/**
 151 *      tty_port_raise_dtr_rts  -       Raise DTR/RTS
 152 *      @port: tty port
 153 *
 154 *      Wrapper for the DTR/RTS raise logic. For the moment this is used
 155 *      to hide some internal details. This will eventually become entirely
 156 *      internal to the tty port.
 157 */
 158
 159void tty_port_raise_dtr_rts(struct tty_port *port)
 160{
 161        if (port->ops->dtr_rts)
 162                port->ops->dtr_rts(port, 1);
 163}
 164EXPORT_SYMBOL(tty_port_raise_dtr_rts);
 165
 166/**
 167 *      tty_port_lower_dtr_rts  -       Lower DTR/RTS
 168 *      @port: tty port
 169 *
 170 *      Wrapper for the DTR/RTS raise logic. For the moment this is used
 171 *      to hide some internal details. This will eventually become entirely
 172 *      internal to the tty port.
 173 */
 174
 175void tty_port_lower_dtr_rts(struct tty_port *port)
 176{
 177        if (port->ops->dtr_rts)
 178                port->ops->dtr_rts(port, 0);
 179}
 180EXPORT_SYMBOL(tty_port_lower_dtr_rts);
 181
 182/**
 183 *      tty_port_block_til_ready        -       Waiting logic for tty open
 184 *      @port: the tty port being opened
 185 *      @tty: the tty device being bound
 186 *      @filp: the file pointer of the opener
 187 *
 188 *      Implement the core POSIX/SuS tty behaviour when opening a tty device.
 189 *      Handles:
 190 *              - hangup (both before and during)
 191 *              - non blocking open
 192 *              - rts/dtr/dcd
 193 *              - signals
 194 *              - port flags and counts
 195 *
 196 *      The passed tty_port must implement the carrier_raised method if it can
 197 *      do carrier detect and the dtr_rts method if it supports software
 198 *      management of these lines. Note that the dtr/rts raise is done each
 199 *      iteration as a hangup may have previously dropped them while we wait.
 200 */
 201 
 202int tty_port_block_til_ready(struct tty_port *port,
 203                                struct tty_struct *tty, struct file *filp)
 204{
 205        int do_clocal = 0, retval;
 206        unsigned long flags;
 207        DEFINE_WAIT(wait);
 208        int cd;
 209
 210        /* block if port is in the process of being closed */
 211        if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
 212                wait_event_interruptible(port->close_wait,
 213                                !(port->flags & ASYNC_CLOSING));
 214                if (port->flags & ASYNC_HUP_NOTIFY)
 215                        return -EAGAIN;
 216                else
 217                        return -ERESTARTSYS;
 218        }
 219
 220        /* if non-blocking mode is set we can pass directly to open unless
 221           the port has just hung up or is in another error state */
 222        if (tty->flags & (1 << TTY_IO_ERROR)) {
 223                port->flags |= ASYNC_NORMAL_ACTIVE;
 224                return 0;
 225        }
 226        if (filp->f_flags & O_NONBLOCK) {
 227                /* Indicate we are open */
 228                if (tty->termios->c_cflag & CBAUD)
 229                        tty_port_raise_dtr_rts(port);
 230                port->flags |= ASYNC_NORMAL_ACTIVE;
 231                return 0;
 232        }
 233
 234        if (C_CLOCAL(tty))
 235                do_clocal = 1;
 236
 237        /* Block waiting until we can proceed. We may need to wait for the
 238           carrier, but we must also wait for any close that is in progress
 239           before the next open may complete */
 240
 241        retval = 0;
 242
 243        /* The port lock protects the port counts */
 244        spin_lock_irqsave(&port->lock, flags);
 245        if (!tty_hung_up_p(filp))
 246                port->count--;
 247        port->blocked_open++;
 248        spin_unlock_irqrestore(&port->lock, flags);
 249
 250        while (1) {
 251                /* Indicate we are open */
 252                if (tty->termios->c_cflag & CBAUD)
 253                        tty_port_raise_dtr_rts(port);
 254
 255                prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
 256                /* Check for a hangup or uninitialised port. Return accordingly */
 257                if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
 258                        if (port->flags & ASYNC_HUP_NOTIFY)
 259                                retval = -EAGAIN;
 260                        else
 261                                retval = -ERESTARTSYS;
 262                        break;
 263                }
 264                /* Probe the carrier. For devices with no carrier detect this
 265                   will always return true */
 266                cd = tty_port_carrier_raised(port);
 267                if (!(port->flags & ASYNC_CLOSING) &&
 268                                (do_clocal || cd))
 269                        break;
 270                if (signal_pending(current)) {
 271                        retval = -ERESTARTSYS;
 272                        break;
 273                }
 274                schedule();
 275        }
 276        finish_wait(&port->open_wait, &wait);
 277
 278        /* Update counts. A parallel hangup will have set count to zero and
 279           we must not mess that up further */
 280        spin_lock_irqsave(&port->lock, flags);
 281        if (!tty_hung_up_p(filp))
 282                port->count++;
 283        port->blocked_open--;
 284        if (retval == 0)
 285                port->flags |= ASYNC_NORMAL_ACTIVE;
 286        spin_unlock_irqrestore(&port->lock, flags);
 287        return retval;
 288        
 289}
 290EXPORT_SYMBOL(tty_port_block_til_ready);
 291
 292int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct file *filp)
 293{
 294        unsigned long flags;
 295
 296        spin_lock_irqsave(&port->lock, flags);
 297        if (tty_hung_up_p(filp)) {
 298                spin_unlock_irqrestore(&port->lock, flags);
 299                return 0;
 300        }
 301
 302        if( tty->count == 1 && port->count != 1) {
 303                printk(KERN_WARNING
 304                    "tty_port_close_start: tty->count = 1 port count = %d.\n",
 305                                                                port->count);
 306                port->count = 1;
 307        }
 308        if (--port->count < 0) {
 309                printk(KERN_WARNING "tty_port_close_start: count = %d\n",
 310                                                                port->count);
 311                port->count = 0;
 312        }
 313
 314        if (port->count) {
 315                spin_unlock_irqrestore(&port->lock, flags);
 316                if (port->ops->drop)
 317                        port->ops->drop(port);
 318                return 0;
 319        }
 320        set_bit(ASYNCB_CLOSING, &port->flags);
 321        tty->closing = 1;
 322        spin_unlock_irqrestore(&port->lock, flags);
 323        /* Don't block on a stalled port, just pull the chain */
 324        if (tty->flow_stopped)
 325                tty_driver_flush_buffer(tty);
 326        if (test_bit(ASYNCB_INITIALIZED, &port->flags) &&
 327                        port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
 328                tty_wait_until_sent(tty, port->closing_wait);
 329        if (port->drain_delay) {
 330                unsigned int bps = tty_get_baud_rate(tty);
 331                long timeout;
 332
 333                if (bps > 1200)
 334                        timeout = max_t(long, (HZ * 10 * port->drain_delay) / bps,
 335                                                                HZ / 10);
 336                else
 337                        timeout = 2 * HZ;
 338                schedule_timeout_interruptible(timeout);
 339        }
 340        /* Don't call port->drop for the last reference. Callers will want
 341           to drop the last active reference in ->shutdown() or the tty
 342           shutdown path */
 343        return 1;
 344}
 345EXPORT_SYMBOL(tty_port_close_start);
 346
 347void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
 348{
 349        unsigned long flags;
 350
 351        tty_ldisc_flush(tty);
 352
 353        if (tty->termios->c_cflag & HUPCL)
 354                tty_port_lower_dtr_rts(port);
 355
 356        spin_lock_irqsave(&port->lock, flags);
 357        tty->closing = 0;
 358
 359        if (port->blocked_open) {
 360                spin_unlock_irqrestore(&port->lock, flags);
 361                if (port->close_delay) {
 362                        msleep_interruptible(
 363                                jiffies_to_msecs(port->close_delay));
 364                }
 365                spin_lock_irqsave(&port->lock, flags);
 366                wake_up_interruptible(&port->open_wait);
 367        }
 368        port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
 369        wake_up_interruptible(&port->close_wait);
 370        spin_unlock_irqrestore(&port->lock, flags);
 371}
 372EXPORT_SYMBOL(tty_port_close_end);
 373
 374void tty_port_close(struct tty_port *port, struct tty_struct *tty,
 375                                                        struct file *filp)
 376{
 377        if (tty_port_close_start(port, tty, filp) == 0)
 378                return;
 379        tty_port_shutdown(port);
 380        tty_port_close_end(port, tty);
 381        tty_port_tty_set(port, NULL);
 382}
 383EXPORT_SYMBOL(tty_port_close);
 384
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.