LCOV - code coverage report
Current view: top level - tty - tty_port.c (source / functions) Coverage Total Hit
Test: TTY Combined Coverage Lines: 54.8 % 310 170
Test Date: 2025-08-26 15:45:50 Functions: 66.7 % 30 20

            Line data    Source code
       1              : // SPDX-License-Identifier: GPL-2.0
       2              : /*
       3              :  * Tty port functions
       4              :  */
       5              : 
       6              : #include <linux/types.h>
       7              : #include <linux/errno.h>
       8              : #include <linux/tty.h>
       9              : #include <linux/tty_driver.h>
      10              : #include <linux/tty_flip.h>
      11              : #include <linux/serial.h>
      12              : #include <linux/timer.h>
      13              : #include <linux/string.h>
      14              : #include <linux/slab.h>
      15              : #include <linux/sched/signal.h>
      16              : #include <linux/wait.h>
      17              : #include <linux/bitops.h>
      18              : #include <linux/delay.h>
      19              : #include <linux/module.h>
      20              : #include <linux/serdev.h>
      21              : #include "tty.h"
      22              : 
      23           21 : static size_t tty_port_default_receive_buf(struct tty_port *port, const u8 *p,
      24              :                                            const u8 *f, size_t count)
      25              : {
      26           21 :         struct tty_struct *tty;
      27           21 :         struct tty_ldisc *ld;
      28              : 
      29           21 :         tty = READ_ONCE(port->itty);
      30           21 :         if (!tty)
      31            0 :                 return 0;
      32              : 
      33           21 :         ld = tty_ldisc_ref(tty);
      34           21 :         if (!ld)
      35            0 :                 return 0;
      36              : 
      37           21 :         count = tty_ldisc_receive_buf(ld, p, f, count);
      38              : 
      39           21 :         tty_ldisc_deref(ld);
      40              : 
      41           21 :         return count;
      42           21 : }
      43              : 
      44            0 : static void tty_port_default_lookahead_buf(struct tty_port *port, const u8 *p,
      45              :                                            const u8 *f, size_t count)
      46              : {
      47            0 :         struct tty_struct *tty;
      48            0 :         struct tty_ldisc *ld;
      49              : 
      50            0 :         tty = READ_ONCE(port->itty);
      51            0 :         if (!tty)
      52            0 :                 return;
      53              : 
      54            0 :         ld = tty_ldisc_ref(tty);
      55            0 :         if (!ld)
      56            0 :                 return;
      57              : 
      58            0 :         if (ld->ops->lookahead_buf)
      59            0 :                 ld->ops->lookahead_buf(ld->tty, p, f, count);
      60              : 
      61            0 :         tty_ldisc_deref(ld);
      62            0 : }
      63              : 
      64           91 : static void tty_port_default_wakeup(struct tty_port *port)
      65              : {
      66           91 :         struct tty_struct *tty = tty_port_tty_get(port);
      67              : 
      68           91 :         if (tty) {
      69           91 :                 tty_wakeup(tty);
      70           91 :                 tty_kref_put(tty);
      71           91 :         }
      72           91 : }
      73              : 
      74              : const struct tty_port_client_operations tty_port_default_client_ops = {
      75              :         .receive_buf = tty_port_default_receive_buf,
      76              :         .lookahead_buf = tty_port_default_lookahead_buf,
      77              :         .write_wakeup = tty_port_default_wakeup,
      78              : };
      79              : EXPORT_SYMBOL_GPL(tty_port_default_client_ops);
      80              : 
      81              : /**
      82              :  * tty_port_init - initialize tty_port
      83              :  * @port: tty_port to initialize
      84              :  *
      85              :  * Initializes the state of struct tty_port. When a port was initialized using
      86              :  * this function, one has to destroy the port by tty_port_destroy(). Either
      87              :  * indirectly by using &tty_port refcounting (tty_port_put()) or directly if
      88              :  * refcounting is not used.
      89              :  */
      90            1 : void tty_port_init(struct tty_port *port)
      91              : {
      92            1 :         memset(port, 0, sizeof(*port));
      93            1 :         tty_buffer_init(port);
      94            1 :         init_waitqueue_head(&port->open_wait);
      95            1 :         init_waitqueue_head(&port->delta_msr_wait);
      96            1 :         mutex_init(&port->mutex);
      97            1 :         mutex_init(&port->buf_mutex);
      98            1 :         spin_lock_init(&port->lock);
      99            1 :         port->close_delay = (50 * HZ) / 100;
     100            1 :         port->closing_wait = (3000 * HZ) / 100;
     101            1 :         port->client_ops = &tty_port_default_client_ops;
     102            1 :         kref_init(&port->kref);
     103            1 : }
     104              : EXPORT_SYMBOL(tty_port_init);
     105              : 
     106              : /**
     107              :  * tty_port_link_device - link tty and tty_port
     108              :  * @port: tty_port of the device
     109              :  * @driver: tty_driver for this device
     110              :  * @index: index of the tty
     111              :  *
     112              :  * Provide the tty layer with a link from a tty (specified by @index) to a
     113              :  * tty_port (@port). Use this only if neither tty_port_register_device() nor
     114              :  * tty_port_install() is used in the driver. If used, this has to be called
     115              :  * before tty_register_driver().
     116              :  */
     117            1 : void tty_port_link_device(struct tty_port *port,
     118              :                 struct tty_driver *driver, unsigned index)
     119              : {
     120            1 :         if (WARN_ON(index >= driver->num))
     121            0 :                 return;
     122            1 :         driver->ports[index] = port;
     123            1 : }
     124              : EXPORT_SYMBOL_GPL(tty_port_link_device);
     125              : 
     126              : /**
     127              :  * tty_port_register_device - register tty device
     128              :  * @port: tty_port of the device
     129              :  * @driver: tty_driver for this device
     130              :  * @index: index of the tty
     131              :  * @device: parent if exists, otherwise NULL
     132              :  *
     133              :  * It is the same as tty_register_device() except the provided @port is linked
     134              :  * to a concrete tty specified by @index. Use this or tty_port_install() (or
     135              :  * both). Call tty_port_link_device() as a last resort.
     136              :  */
     137            1 : struct device *tty_port_register_device(struct tty_port *port,
     138              :                 struct tty_driver *driver, unsigned index,
     139              :                 struct device *device)
     140              : {
     141            1 :         return tty_port_register_device_attr(port, driver, index, device, NULL, NULL);
     142              : }
     143              : EXPORT_SYMBOL_GPL(tty_port_register_device);
     144              : 
     145              : /**
     146              :  * tty_port_register_device_attr - register tty device
     147              :  * @port: tty_port of the device
     148              :  * @driver: tty_driver for this device
     149              :  * @index: index of the tty
     150              :  * @device: parent if exists, otherwise NULL
     151              :  * @drvdata: Driver data to be set to device.
     152              :  * @attr_grp: Attribute group to be set on device.
     153              :  *
     154              :  * It is the same as tty_register_device_attr() except the provided @port is
     155              :  * linked to a concrete tty specified by @index. Use this or tty_port_install()
     156              :  * (or both). Call tty_port_link_device() as a last resort.
     157              :  */
     158            1 : struct device *tty_port_register_device_attr(struct tty_port *port,
     159              :                 struct tty_driver *driver, unsigned index,
     160              :                 struct device *device, void *drvdata,
     161              :                 const struct attribute_group **attr_grp)
     162              : {
     163            1 :         tty_port_link_device(port, driver, index);
     164            2 :         return tty_register_device_attr(driver, index, device, drvdata,
     165            1 :                         attr_grp);
     166              : }
     167              : EXPORT_SYMBOL_GPL(tty_port_register_device_attr);
     168              : 
     169              : /**
     170              :  * tty_port_register_device_attr_serdev - register tty or serdev device
     171              :  * @port: tty_port of the device
     172              :  * @driver: tty_driver for this device
     173              :  * @index: index of the tty
     174              :  * @host: serial port hardware device
     175              :  * @parent: parent if exists, otherwise NULL
     176              :  * @drvdata: driver data for the device
     177              :  * @attr_grp: attribute group for the device
     178              :  *
     179              :  * Register a serdev or tty device depending on if the parent device has any
     180              :  * defined serdev clients or not.
     181              :  */
     182            0 : struct device *tty_port_register_device_attr_serdev(struct tty_port *port,
     183              :                 struct tty_driver *driver, unsigned index,
     184              :                 struct device *host, struct device *parent, void *drvdata,
     185              :                 const struct attribute_group **attr_grp)
     186              : {
     187            0 :         struct device *dev;
     188              : 
     189            0 :         tty_port_link_device(port, driver, index);
     190              : 
     191            0 :         dev = serdev_tty_port_register(port, host, parent, driver, index);
     192            0 :         if (PTR_ERR(dev) != -ENODEV) {
     193              :                 /* Skip creating cdev if we registered a serdev device */
     194            0 :                 return dev;
     195              :         }
     196              : 
     197            0 :         return tty_register_device_attr(driver, index, parent, drvdata,
     198            0 :                         attr_grp);
     199            0 : }
     200              : EXPORT_SYMBOL_GPL(tty_port_register_device_attr_serdev);
     201              : 
     202              : /**
     203              :  * tty_port_unregister_device - deregister a tty or serdev device
     204              :  * @port: tty_port of the device
     205              :  * @driver: tty_driver for this device
     206              :  * @index: index of the tty
     207              :  *
     208              :  * If a tty or serdev device is registered with a call to
     209              :  * tty_port_register_device_serdev() then this function must be called when
     210              :  * the device is gone.
     211              :  */
     212            1 : void tty_port_unregister_device(struct tty_port *port,
     213              :                 struct tty_driver *driver, unsigned index)
     214              : {
     215            1 :         int ret;
     216              : 
     217            1 :         ret = serdev_tty_port_unregister(port);
     218            1 :         if (ret == 0)
     219            0 :                 return;
     220              : 
     221            1 :         tty_unregister_device(driver, index);
     222            1 : }
     223              : EXPORT_SYMBOL_GPL(tty_port_unregister_device);
     224              : 
     225            0 : int tty_port_alloc_xmit_buf(struct tty_port *port)
     226              : {
     227              :         /* We may sleep in get_zeroed_page() */
     228            0 :         mutex_lock(&port->buf_mutex);
     229            0 :         if (port->xmit_buf == NULL) {
     230            0 :                 port->xmit_buf = (u8 *)get_zeroed_page(GFP_KERNEL);
     231            0 :                 if (port->xmit_buf)
     232            0 :                         kfifo_init(&port->xmit_fifo, port->xmit_buf, PAGE_SIZE);
     233            0 :         }
     234            0 :         mutex_unlock(&port->buf_mutex);
     235            0 :         if (port->xmit_buf == NULL)
     236            0 :                 return -ENOMEM;
     237            0 :         return 0;
     238            0 : }
     239              : EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
     240              : 
     241            0 : void tty_port_free_xmit_buf(struct tty_port *port)
     242              : {
     243            0 :         mutex_lock(&port->buf_mutex);
     244            0 :         free_page((unsigned long)port->xmit_buf);
     245            0 :         port->xmit_buf = NULL;
     246            0 :         INIT_KFIFO(port->xmit_fifo);
     247            0 :         mutex_unlock(&port->buf_mutex);
     248            0 : }
     249              : EXPORT_SYMBOL(tty_port_free_xmit_buf);
     250              : 
     251              : /**
     252              :  * tty_port_destroy - destroy inited port
     253              :  * @port: tty port to be destroyed
     254              :  *
     255              :  * When a port was initialized using tty_port_init(), one has to destroy the
     256              :  * port by this function. Either indirectly by using &tty_port refcounting
     257              :  * (tty_port_put()) or directly if refcounting is not used.
     258              :  */
     259            1 : void tty_port_destroy(struct tty_port *port)
     260              : {
     261            1 :         tty_buffer_cancel_work(port);
     262            1 :         tty_buffer_free_all(port);
     263            1 : }
     264              : EXPORT_SYMBOL(tty_port_destroy);
     265              : 
     266            0 : static void tty_port_destructor(struct kref *kref)
     267              : {
     268            0 :         struct tty_port *port = container_of(kref, struct tty_port, kref);
     269              : 
     270              :         /* check if last port ref was dropped before tty release */
     271            0 :         if (WARN_ON(port->itty))
     272            0 :                 return;
     273            0 :         free_page((unsigned long)port->xmit_buf);
     274            0 :         tty_port_destroy(port);
     275            0 :         if (port->ops && port->ops->destruct)
     276            0 :                 port->ops->destruct(port);
     277              :         else
     278            0 :                 kfree(port);
     279            0 : }
     280              : 
     281              : /**
     282              :  * tty_port_put - drop a reference to tty_port
     283              :  * @port: port to drop a reference of (can be NULL)
     284              :  *
     285              :  * The final put will destroy and free up the @port using
     286              :  * @port->ops->destruct() hook, or using kfree() if not provided.
     287              :  */
     288            0 : void tty_port_put(struct tty_port *port)
     289              : {
     290            0 :         if (port)
     291            0 :                 kref_put(&port->kref, tty_port_destructor);
     292            0 : }
     293              : EXPORT_SYMBOL(tty_port_put);
     294              : 
     295              : /**
     296              :  * tty_port_tty_get     -       get a tty reference
     297              :  * @port: tty port
     298              :  *
     299              :  * Return a refcount protected tty instance or %NULL if the port is not
     300              :  * associated with a tty (eg due to close or hangup).
     301              :  */
     302           91 : struct tty_struct *tty_port_tty_get(struct tty_port *port)
     303              : {
     304           91 :         unsigned long flags;
     305           91 :         struct tty_struct *tty;
     306              : 
     307           91 :         spin_lock_irqsave(&port->lock, flags);
     308           91 :         tty = tty_kref_get(port->tty);
     309           91 :         spin_unlock_irqrestore(&port->lock, flags);
     310          182 :         return tty;
     311           91 : }
     312              : EXPORT_SYMBOL(tty_port_tty_get);
     313              : 
     314              : /**
     315              :  * tty_port_tty_set     -       set the tty of a port
     316              :  * @port: tty port
     317              :  * @tty: the tty
     318              :  *
     319              :  * Associate the port and tty pair. Manages any internal refcounts. Pass %NULL
     320              :  * to deassociate a port.
     321              :  */
     322           12 : void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
     323              : {
     324           12 :         unsigned long flags;
     325              : 
     326           12 :         spin_lock_irqsave(&port->lock, flags);
     327           12 :         tty_kref_put(port->tty);
     328           12 :         port->tty = tty_kref_get(tty);
     329           12 :         spin_unlock_irqrestore(&port->lock, flags);
     330           12 : }
     331              : EXPORT_SYMBOL(tty_port_tty_set);
     332              : 
     333              : /**
     334              :  * tty_port_shutdown - internal helper to shutdown the device
     335              :  * @port: tty port to be shut down
     336              :  * @tty: the associated tty
     337              :  *
     338              :  * It is used by tty_port_hangup() and tty_port_close(). Its task is to
     339              :  * shutdown the device if it was initialized (note consoles remain
     340              :  * functioning). It lowers DTR/RTS (if @tty has HUPCL set) and invokes
     341              :  * @port->ops->shutdown().
     342              :  */
     343            6 : static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty)
     344              : {
     345            6 :         mutex_lock(&port->mutex);
     346            6 :         if (port->console)
     347            0 :                 goto out;
     348              : 
     349           12 :         if (tty_port_initialized(port)) {
     350            6 :                 tty_port_set_initialized(port, false);
     351              :                 /*
     352              :                  * Drop DTR/RTS if HUPCL is set. This causes any attached
     353              :                  * modem to hang up the line.
     354              :                  */
     355            6 :                 if (tty && C_HUPCL(tty))
     356            6 :                         tty_port_lower_dtr_rts(port);
     357              : 
     358            6 :                 if (port->ops->shutdown)
     359            4 :                         port->ops->shutdown(port);
     360            6 :         }
     361              : out:
     362            6 :         mutex_unlock(&port->mutex);
     363            6 : }
     364              : 
     365              : /**
     366              :  * tty_port_hangup              -       hangup helper
     367              :  * @port: tty port
     368              :  *
     369              :  * Perform port level tty hangup flag and count changes. Drop the tty
     370              :  * reference.
     371              :  *
     372              :  * Caller holds tty lock.
     373              :  */
     374            0 : void tty_port_hangup(struct tty_port *port)
     375              : {
     376            0 :         struct tty_struct *tty;
     377            0 :         unsigned long flags;
     378              : 
     379            0 :         spin_lock_irqsave(&port->lock, flags);
     380            0 :         port->count = 0;
     381            0 :         tty = port->tty;
     382            0 :         if (tty)
     383            0 :                 set_bit(TTY_IO_ERROR, &tty->flags);
     384            0 :         port->tty = NULL;
     385            0 :         spin_unlock_irqrestore(&port->lock, flags);
     386            0 :         tty_port_set_active(port, false);
     387            0 :         tty_port_shutdown(port, tty);
     388            0 :         tty_kref_put(tty);
     389            0 :         wake_up_interruptible(&port->open_wait);
     390            0 :         wake_up_interruptible(&port->delta_msr_wait);
     391            0 : }
     392              : EXPORT_SYMBOL(tty_port_hangup);
     393              : 
     394            0 : void __tty_port_tty_hangup(struct tty_port *port, bool check_clocal, bool async)
     395              : {
     396            0 :         struct tty_struct *tty = tty_port_tty_get(port);
     397              : 
     398            0 :         if (tty && (!check_clocal || !C_CLOCAL(tty))) {
     399            0 :                 if (async)
     400            0 :                         tty_hangup(tty);
     401              :                 else
     402            0 :                         tty_vhangup(tty);
     403            0 :         }
     404            0 :         tty_kref_put(tty);
     405            0 : }
     406              : EXPORT_SYMBOL_GPL(__tty_port_tty_hangup);
     407              : 
     408              : /**
     409              :  * tty_port_tty_wakeup - helper to wake up a tty
     410              :  * @port: tty port
     411              :  */
     412           91 : void tty_port_tty_wakeup(struct tty_port *port)
     413              : {
     414           91 :         port->client_ops->write_wakeup(port);
     415           91 : }
     416              : EXPORT_SYMBOL_GPL(tty_port_tty_wakeup);
     417              : 
     418              : /**
     419              :  * tty_port_carrier_raised      -       carrier raised check
     420              :  * @port: tty port
     421              :  *
     422              :  * Wrapper for the carrier detect logic. For the moment this is used
     423              :  * to hide some internal details. This will eventually become entirely
     424              :  * internal to the tty port.
     425              :  */
     426            6 : bool tty_port_carrier_raised(struct tty_port *port)
     427              : {
     428            6 :         if (port->ops->carrier_raised == NULL)
     429            2 :                 return true;
     430            4 :         return port->ops->carrier_raised(port);
     431            6 : }
     432              : EXPORT_SYMBOL(tty_port_carrier_raised);
     433              : 
     434              : /**
     435              :  * tty_port_raise_dtr_rts       -       Raise DTR/RTS
     436              :  * @port: tty port
     437              :  *
     438              :  * Wrapper for the DTR/RTS raise logic. For the moment this is used to hide
     439              :  * some internal details. This will eventually become entirely internal to the
     440              :  * tty port.
     441              :  */
     442            6 : void tty_port_raise_dtr_rts(struct tty_port *port)
     443              : {
     444            6 :         if (port->ops->dtr_rts)
     445            0 :                 port->ops->dtr_rts(port, true);
     446            6 : }
     447              : EXPORT_SYMBOL(tty_port_raise_dtr_rts);
     448              : 
     449              : /**
     450              :  * tty_port_lower_dtr_rts       -       Lower DTR/RTS
     451              :  * @port: tty port
     452              :  *
     453              :  * Wrapper for the DTR/RTS raise logic. For the moment this is used to hide
     454              :  * some internal details. This will eventually become entirely internal to the
     455              :  * tty port.
     456              :  */
     457            6 : void tty_port_lower_dtr_rts(struct tty_port *port)
     458              : {
     459            6 :         if (port->ops->dtr_rts)
     460            0 :                 port->ops->dtr_rts(port, false);
     461            6 : }
     462              : EXPORT_SYMBOL(tty_port_lower_dtr_rts);
     463              : 
     464              : /**
     465              :  * tty_port_block_til_ready     -       Waiting logic for tty open
     466              :  * @port: the tty port being opened
     467              :  * @tty: the tty device being bound
     468              :  * @filp: the file pointer of the opener or %NULL
     469              :  *
     470              :  * Implement the core POSIX/SuS tty behaviour when opening a tty device.
     471              :  * Handles:
     472              :  *
     473              :  *      - hangup (both before and during)
     474              :  *      - non blocking open
     475              :  *      - rts/dtr/dcd
     476              :  *      - signals
     477              :  *      - port flags and counts
     478              :  *
     479              :  * The passed @port must implement the @port->ops->carrier_raised method if it
     480              :  * can do carrier detect and the @port->ops->dtr_rts method if it supports
     481              :  * software management of these lines. Note that the dtr/rts raise is done each
     482              :  * iteration as a hangup may have previously dropped them while we wait.
     483              :  *
     484              :  * Caller holds tty lock.
     485              :  *
     486              :  * Note: May drop and reacquire tty lock when blocking, so @tty and @port may
     487              :  * have changed state (eg., may have been hung up).
     488              :  */
     489            6 : int tty_port_block_til_ready(struct tty_port *port,
     490              :                                 struct tty_struct *tty, struct file *filp)
     491              : {
     492            6 :         int do_clocal = 0, retval;
     493            6 :         unsigned long flags;
     494            6 :         DEFINE_WAIT(wait);
     495              : 
     496              :         /* if non-blocking mode is set we can pass directly to open unless
     497              :          * the port has just hung up or is in another error state.
     498              :          */
     499            6 :         if (tty_io_error(tty)) {
     500            0 :                 tty_port_set_active(port, true);
     501            0 :                 return 0;
     502              :         }
     503            6 :         if (filp == NULL || (filp->f_flags & O_NONBLOCK)) {
     504              :                 /* Indicate we are open */
     505            0 :                 if (C_BAUD(tty))
     506            0 :                         tty_port_raise_dtr_rts(port);
     507            0 :                 tty_port_set_active(port, true);
     508            0 :                 return 0;
     509              :         }
     510              : 
     511            6 :         if (C_CLOCAL(tty))
     512            0 :                 do_clocal = 1;
     513              : 
     514              :         /* Block waiting until we can proceed. We may need to wait for the
     515              :          * carrier, but we must also wait for any close that is in progress
     516              :          * before the next open may complete.
     517              :          */
     518              : 
     519            6 :         retval = 0;
     520              : 
     521              :         /* The port lock protects the port counts */
     522            6 :         spin_lock_irqsave(&port->lock, flags);
     523            6 :         port->count--;
     524            6 :         port->blocked_open++;
     525            6 :         spin_unlock_irqrestore(&port->lock, flags);
     526              : 
     527            6 :         while (1) {
     528              :                 /* Indicate we are open */
     529            6 :                 if (C_BAUD(tty) && tty_port_initialized(port))
     530            6 :                         tty_port_raise_dtr_rts(port);
     531              : 
     532            6 :                 prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
     533              :                 /* Check for a hangup or uninitialised port.
     534              :                  * Return accordingly.
     535              :                  */
     536            6 :                 if (tty_hung_up_p(filp) || !tty_port_initialized(port)) {
     537            0 :                         if (port->flags & ASYNC_HUP_NOTIFY)
     538            0 :                                 retval = -EAGAIN;
     539              :                         else
     540            0 :                                 retval = -ERESTARTSYS;
     541            0 :                         break;
     542              :                 }
     543              :                 /*
     544              :                  * Probe the carrier. For devices with no carrier detect
     545              :                  * tty_port_carrier_raised will always return true.
     546              :                  * Never ask drivers if CLOCAL is set, this causes troubles
     547              :                  * on some hardware.
     548              :                  */
     549            6 :                 if (do_clocal || tty_port_carrier_raised(port))
     550            6 :                         break;
     551            0 :                 if (signal_pending(current)) {
     552            0 :                         retval = -ERESTARTSYS;
     553            0 :                         break;
     554              :                 }
     555            0 :                 tty_unlock(tty);
     556            0 :                 schedule();
     557            0 :                 tty_lock(tty);
     558              :         }
     559            6 :         finish_wait(&port->open_wait, &wait);
     560              : 
     561              :         /* Update counts. A parallel hangup will have set count to zero and
     562              :          * we must not mess that up further.
     563              :          */
     564            6 :         spin_lock_irqsave(&port->lock, flags);
     565            6 :         if (!tty_hung_up_p(filp))
     566            6 :                 port->count++;
     567            6 :         port->blocked_open--;
     568            6 :         spin_unlock_irqrestore(&port->lock, flags);
     569            6 :         if (retval == 0)
     570            6 :                 tty_port_set_active(port, true);
     571            6 :         return retval;
     572            6 : }
     573              : EXPORT_SYMBOL(tty_port_block_til_ready);
     574              : 
     575            0 : static void tty_port_drain_delay(struct tty_port *port, struct tty_struct *tty)
     576              : {
     577            0 :         unsigned int bps = tty_get_baud_rate(tty);
     578            0 :         long timeout;
     579              : 
     580            0 :         if (bps > 1200) {
     581            0 :                 timeout = (HZ * 10 * port->drain_delay) / bps;
     582            0 :                 timeout = max_t(long, timeout, HZ / 10);
     583            0 :         } else {
     584            0 :                 timeout = 2 * HZ;
     585              :         }
     586            0 :         schedule_timeout_interruptible(timeout);
     587            0 : }
     588              : 
     589              : /**
     590              :  * tty_port_close_start - helper for tty->ops->close, part 1/2
     591              :  * @port: tty_port of the device
     592              :  * @tty: tty being closed
     593              :  * @filp: passed file pointer
     594              :  *
     595              :  * Decrements and checks open count. Flushes the port if this is the last
     596              :  * close. That means, dropping the data from the outpu buffer on the device and
     597              :  * waiting for sending logic to finish. The rest of close handling is performed
     598              :  * in tty_port_close_end().
     599              :  *
     600              :  * Locking: Caller holds tty lock.
     601              :  *
     602              :  * Return: 1 if this is the last close, otherwise 0
     603              :  */
     604            6 : int tty_port_close_start(struct tty_port *port,
     605              :                                 struct tty_struct *tty, struct file *filp)
     606              : {
     607            6 :         unsigned long flags;
     608              : 
     609            6 :         if (tty_hung_up_p(filp))
     610            0 :                 return 0;
     611              : 
     612            6 :         spin_lock_irqsave(&port->lock, flags);
     613            6 :         if (tty->count == 1 && port->count != 1) {
     614            0 :                 tty_warn(tty, "%s: tty->count = 1 port count = %d\n", __func__,
     615              :                          port->count);
     616            0 :                 port->count = 1;
     617            0 :         }
     618            6 :         if (--port->count < 0) {
     619            0 :                 tty_warn(tty, "%s: bad port count (%d)\n", __func__,
     620              :                          port->count);
     621            0 :                 port->count = 0;
     622            0 :         }
     623              : 
     624            6 :         if (port->count) {
     625            0 :                 spin_unlock_irqrestore(&port->lock, flags);
     626            0 :                 return 0;
     627              :         }
     628            6 :         spin_unlock_irqrestore(&port->lock, flags);
     629              : 
     630            6 :         tty->closing = 1;
     631              : 
     632            6 :         if (tty_port_initialized(port)) {
     633              :                 /* Don't block on a stalled port, just pull the chain */
     634            6 :                 if (tty->flow.tco_stopped)
     635            0 :                         tty_driver_flush_buffer(tty);
     636            6 :                 if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
     637            6 :                         tty_wait_until_sent(tty, port->closing_wait);
     638            6 :                 if (port->drain_delay)
     639            0 :                         tty_port_drain_delay(port, tty);
     640            6 :         }
     641              :         /* Flush the ldisc buffering */
     642            6 :         tty_ldisc_flush(tty);
     643              : 
     644              :         /* Report to caller this is the last port reference */
     645            6 :         return 1;
     646            6 : }
     647              : EXPORT_SYMBOL(tty_port_close_start);
     648              : 
     649              : /**
     650              :  * tty_port_close_end - helper for tty->ops->close, part 2/2
     651              :  * @port: tty_port of the device
     652              :  * @tty: tty being closed
     653              :  *
     654              :  * This is a continuation of the first part: tty_port_close_start(). This
     655              :  * should be called after turning off the device. It flushes the data from the
     656              :  * line discipline and delays the close by @port->close_delay.
     657              :  *
     658              :  * Locking: Caller holds tty lock.
     659              :  */
     660            6 : void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
     661              : {
     662            6 :         unsigned long flags;
     663              : 
     664            6 :         tty_ldisc_flush(tty);
     665            6 :         tty->closing = 0;
     666              : 
     667            6 :         spin_lock_irqsave(&port->lock, flags);
     668              : 
     669            6 :         if (port->blocked_open) {
     670            0 :                 spin_unlock_irqrestore(&port->lock, flags);
     671            0 :                 if (port->close_delay)
     672            0 :                         msleep_interruptible(jiffies_to_msecs(port->close_delay));
     673            0 :                 spin_lock_irqsave(&port->lock, flags);
     674            0 :                 wake_up_interruptible(&port->open_wait);
     675            0 :         }
     676            6 :         spin_unlock_irqrestore(&port->lock, flags);
     677            6 :         tty_port_set_active(port, false);
     678            6 : }
     679              : EXPORT_SYMBOL(tty_port_close_end);
     680              : 
     681              : /**
     682              :  * tty_port_close - generic tty->ops->close handler
     683              :  * @port: tty_port of the device
     684              :  * @tty: tty being closed
     685              :  * @filp: passed file pointer
     686              :  *
     687              :  * It is a generic helper to be used in driver's @tty->ops->close. It wraps a
     688              :  * sequence of tty_port_close_start(), tty_port_shutdown(), and
     689              :  * tty_port_close_end(). The latter two are called only if this is the last
     690              :  * close. See the respective functions for the details.
     691              :  *
     692              :  * Locking: Caller holds tty lock
     693              :  */
     694            6 : void tty_port_close(struct tty_port *port, struct tty_struct *tty,
     695              :                                                         struct file *filp)
     696              : {
     697            6 :         if (tty_port_close_start(port, tty, filp) == 0)
     698            0 :                 return;
     699            6 :         tty_port_shutdown(port, tty);
     700            6 :         if (!port->console)
     701            6 :                 set_bit(TTY_IO_ERROR, &tty->flags);
     702            6 :         tty_port_close_end(port, tty);
     703            6 :         tty_port_tty_set(port, NULL);
     704            6 : }
     705              : EXPORT_SYMBOL(tty_port_close);
     706              : 
     707              : /**
     708              :  * tty_port_install - generic tty->ops->install handler
     709              :  * @port: tty_port of the device
     710              :  * @driver: tty_driver for this device
     711              :  * @tty: tty to be installed
     712              :  *
     713              :  * It is the same as tty_standard_install() except the provided @port is linked
     714              :  * to a concrete tty specified by @tty. Use this or tty_port_register_device()
     715              :  * (or both). Call tty_port_link_device() as a last resort.
     716              :  */
     717            0 : int tty_port_install(struct tty_port *port, struct tty_driver *driver,
     718              :                 struct tty_struct *tty)
     719              : {
     720            0 :         tty->port = port;
     721            0 :         return tty_standard_install(driver, tty);
     722              : }
     723              : EXPORT_SYMBOL_GPL(tty_port_install);
     724              : 
     725              : /**
     726              :  * tty_port_open - generic tty->ops->open handler
     727              :  * @port: tty_port of the device
     728              :  * @tty: tty to be opened
     729              :  * @filp: passed file pointer
     730              :  *
     731              :  * It is a generic helper to be used in driver's @tty->ops->open. It activates
     732              :  * the devices using @port->ops->activate if not active already. And waits for
     733              :  * the device to be ready using tty_port_block_til_ready() (e.g.  raises
     734              :  * DTR/CTS and waits for carrier).
     735              :  *
     736              :  * Note that @port->ops->shutdown is not called when @port->ops->activate
     737              :  * returns an error (on the contrary, @tty->ops->close is).
     738              :  *
     739              :  * Locking: Caller holds tty lock.
     740              :  *
     741              :  * Note: may drop and reacquire tty lock (in tty_port_block_til_ready()) so
     742              :  * @tty and @port may have changed state (eg., may be hung up now).
     743              :  */
     744            6 : int tty_port_open(struct tty_port *port, struct tty_struct *tty,
     745              :                                                         struct file *filp)
     746              : {
     747            6 :         spin_lock_irq(&port->lock);
     748            6 :         ++port->count;
     749            6 :         spin_unlock_irq(&port->lock);
     750            6 :         tty_port_tty_set(port, tty);
     751              : 
     752              :         /*
     753              :          * Do the device-specific open only if the hardware isn't
     754              :          * already initialized. Serialize open and shutdown using the
     755              :          * port mutex.
     756              :          */
     757              : 
     758            6 :         mutex_lock(&port->mutex);
     759              : 
     760            6 :         if (!tty_port_initialized(port)) {
     761            6 :                 clear_bit(TTY_IO_ERROR, &tty->flags);
     762            6 :                 if (port->ops->activate) {
     763            0 :                         int retval = port->ops->activate(port, tty);
     764              : 
     765            0 :                         if (retval) {
     766            0 :                                 mutex_unlock(&port->mutex);
     767            0 :                                 return retval;
     768              :                         }
     769            0 :                 }
     770            6 :                 tty_port_set_initialized(port, true);
     771            6 :         }
     772            6 :         mutex_unlock(&port->mutex);
     773            6 :         return tty_port_block_til_ready(port, tty, filp);
     774            6 : }
     775              : EXPORT_SYMBOL(tty_port_open);
        

Generated by: LCOV version 2.0-1