LCOV - code coverage report
Current view: top level - drivers/tty - tty_ioctl.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 105 288 36.5 %
Date: 2022-03-28 16:04:14 Functions: 10 22 45.5 %
Branches: 37 193 19.2 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /*
       3                 :            :  *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
       4                 :            :  *
       5                 :            :  * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
       6                 :            :  * which can be dynamically activated and de-activated by the line
       7                 :            :  * discipline handling modules (like SLIP).
       8                 :            :  */
       9                 :            : 
      10                 :            : #include <linux/types.h>
      11                 :            : #include <linux/termios.h>
      12                 :            : #include <linux/errno.h>
      13                 :            : #include <linux/sched/signal.h>
      14                 :            : #include <linux/kernel.h>
      15                 :            : #include <linux/major.h>
      16                 :            : #include <linux/tty.h>
      17                 :            : #include <linux/fcntl.h>
      18                 :            : #include <linux/string.h>
      19                 :            : #include <linux/mm.h>
      20                 :            : #include <linux/module.h>
      21                 :            : #include <linux/bitops.h>
      22                 :            : #include <linux/mutex.h>
      23                 :            : #include <linux/compat.h>
      24                 :            : 
      25                 :            : #include <asm/io.h>
      26                 :            : #include <linux/uaccess.h>
      27                 :            : 
      28                 :            : #undef TTY_DEBUG_WAIT_UNTIL_SENT
      29                 :            : 
      30                 :            : #ifdef TTY_DEBUG_WAIT_UNTIL_SENT
      31                 :            : # define tty_debug_wait_until_sent(tty, f, args...)    tty_debug(tty, f, ##args)
      32                 :            : #else
      33                 :            : # define tty_debug_wait_until_sent(tty, f, args...)    do {} while (0)
      34                 :            : #endif
      35                 :            : 
      36                 :            : #undef  DEBUG
      37                 :            : 
      38                 :            : /*
      39                 :            :  * Internal flag options for termios setting behavior
      40                 :            :  */
      41                 :            : #define TERMIOS_FLUSH   1
      42                 :            : #define TERMIOS_WAIT    2
      43                 :            : #define TERMIOS_TERMIO  4
      44                 :            : #define TERMIOS_OLD     8
      45                 :            : 
      46                 :            : 
      47                 :            : /**
      48                 :            :  *      tty_chars_in_buffer     -       characters pending
      49                 :            :  *      @tty: terminal
      50                 :            :  *
      51                 :            :  *      Return the number of bytes of data in the device private
      52                 :            :  *      output queue. If no private method is supplied there is assumed
      53                 :            :  *      to be no queue on the device.
      54                 :            :  */
      55                 :            : 
      56                 :       1168 : int tty_chars_in_buffer(struct tty_struct *tty)
      57                 :            : {
      58         [ #  # ]:          0 :         if (tty->ops->chars_in_buffer)
      59                 :       1168 :                 return tty->ops->chars_in_buffer(tty);
      60                 :            :         else
      61                 :            :                 return 0;
      62                 :            : }
      63                 :            : EXPORT_SYMBOL(tty_chars_in_buffer);
      64                 :            : 
      65                 :            : /**
      66                 :            :  *      tty_write_room          -       write queue space
      67                 :            :  *      @tty: terminal
      68                 :            :  *
      69                 :            :  *      Return the number of bytes that can be queued to this device
      70                 :            :  *      at the present time. The result should be treated as a guarantee
      71                 :            :  *      and the driver cannot offer a value it later shrinks by more than
      72                 :            :  *      the number of bytes written. If no method is provided 2K is always
      73                 :            :  *      returned and data may be lost as there will be no flow control.
      74                 :            :  */
      75                 :            :  
      76                 :       6162 : int tty_write_room(struct tty_struct *tty)
      77                 :            : {
      78         [ +  - ]:       6162 :         if (tty->ops->write_room)
      79                 :       6162 :                 return tty->ops->write_room(tty);
      80                 :            :         return 2048;
      81                 :            : }
      82                 :            : EXPORT_SYMBOL(tty_write_room);
      83                 :            : 
      84                 :            : /**
      85                 :            :  *      tty_driver_flush_buffer -       discard internal buffer
      86                 :            :  *      @tty: terminal
      87                 :            :  *
      88                 :            :  *      Discard the internal output buffer for this device. If no method
      89                 :            :  *      is provided then either the buffer cannot be hardware flushed or
      90                 :            :  *      there is no buffer driver side.
      91                 :            :  */
      92                 :         13 : void tty_driver_flush_buffer(struct tty_struct *tty)
      93                 :            : {
      94         [ #  # ]:          0 :         if (tty->ops->flush_buffer)
      95                 :         13 :                 tty->ops->flush_buffer(tty);
      96                 :          0 : }
      97                 :            : EXPORT_SYMBOL(tty_driver_flush_buffer);
      98                 :            : 
      99                 :            : /**
     100                 :            :  *      tty_throttle            -       flow control
     101                 :            :  *      @tty: terminal
     102                 :            :  *
     103                 :            :  *      Indicate that a tty should stop transmitting data down the stack.
     104                 :            :  *      Takes the termios rwsem to protect against parallel throttle/unthrottle
     105                 :            :  *      and also to ensure the driver can consistently reference its own
     106                 :            :  *      termios data at this point when implementing software flow control.
     107                 :            :  */
     108                 :            : 
     109                 :          0 : void tty_throttle(struct tty_struct *tty)
     110                 :            : {
     111                 :          0 :         down_write(&tty->termios_rwsem);
     112                 :            :         /* check TTY_THROTTLED first so it indicates our state */
     113         [ #  # ]:          0 :         if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
     114         [ #  # ]:          0 :             tty->ops->throttle)
     115                 :          0 :                 tty->ops->throttle(tty);
     116                 :          0 :         tty->flow_change = 0;
     117                 :          0 :         up_write(&tty->termios_rwsem);
     118                 :          0 : }
     119                 :            : EXPORT_SYMBOL(tty_throttle);
     120                 :            : 
     121                 :            : /**
     122                 :            :  *      tty_unthrottle          -       flow control
     123                 :            :  *      @tty: terminal
     124                 :            :  *
     125                 :            :  *      Indicate that a tty may continue transmitting data down the stack.
     126                 :            :  *      Takes the termios rwsem to protect against parallel throttle/unthrottle
     127                 :            :  *      and also to ensure the driver can consistently reference its own
     128                 :            :  *      termios data at this point when implementing software flow control.
     129                 :            :  *
     130                 :            :  *      Drivers should however remember that the stack can issue a throttle,
     131                 :            :  *      then change flow control method, then unthrottle.
     132                 :            :  */
     133                 :            : 
     134                 :       1194 : void tty_unthrottle(struct tty_struct *tty)
     135                 :            : {
     136                 :       1194 :         down_write(&tty->termios_rwsem);
     137         [ -  + ]:       1194 :         if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
     138         [ #  # ]:          0 :             tty->ops->unthrottle)
     139                 :          0 :                 tty->ops->unthrottle(tty);
     140                 :       1194 :         tty->flow_change = 0;
     141                 :       1194 :         up_write(&tty->termios_rwsem);
     142                 :       1194 : }
     143                 :            : EXPORT_SYMBOL(tty_unthrottle);
     144                 :            : 
     145                 :            : /**
     146                 :            :  *      tty_throttle_safe       -       flow control
     147                 :            :  *      @tty: terminal
     148                 :            :  *
     149                 :            :  *      Similar to tty_throttle() but will only attempt throttle
     150                 :            :  *      if tty->flow_change is TTY_THROTTLE_SAFE. Prevents an accidental
     151                 :            :  *      throttle due to race conditions when throttling is conditional
     152                 :            :  *      on factors evaluated prior to throttling.
     153                 :            :  *
     154                 :            :  *      Returns 0 if tty is throttled (or was already throttled)
     155                 :            :  */
     156                 :            : 
     157                 :          0 : int tty_throttle_safe(struct tty_struct *tty)
     158                 :            : {
     159                 :          0 :         int ret = 0;
     160                 :            : 
     161                 :          0 :         mutex_lock(&tty->throttle_mutex);
     162         [ #  # ]:          0 :         if (!tty_throttled(tty)) {
     163         [ #  # ]:          0 :                 if (tty->flow_change != TTY_THROTTLE_SAFE)
     164                 :            :                         ret = 1;
     165                 :            :                 else {
     166                 :          0 :                         set_bit(TTY_THROTTLED, &tty->flags);
     167         [ #  # ]:          0 :                         if (tty->ops->throttle)
     168                 :          0 :                                 tty->ops->throttle(tty);
     169                 :            :                 }
     170                 :            :         }
     171                 :          0 :         mutex_unlock(&tty->throttle_mutex);
     172                 :            : 
     173                 :          0 :         return ret;
     174                 :            : }
     175                 :            : 
     176                 :            : /**
     177                 :            :  *      tty_unthrottle_safe     -       flow control
     178                 :            :  *      @tty: terminal
     179                 :            :  *
     180                 :            :  *      Similar to tty_unthrottle() but will only attempt unthrottle
     181                 :            :  *      if tty->flow_change is TTY_UNTHROTTLE_SAFE. Prevents an accidental
     182                 :            :  *      unthrottle due to race conditions when unthrottling is conditional
     183                 :            :  *      on factors evaluated prior to unthrottling.
     184                 :            :  *
     185                 :            :  *      Returns 0 if tty is unthrottled (or was already unthrottled)
     186                 :            :  */
     187                 :            : 
     188                 :          0 : int tty_unthrottle_safe(struct tty_struct *tty)
     189                 :            : {
     190                 :          0 :         int ret = 0;
     191                 :            : 
     192                 :          0 :         mutex_lock(&tty->throttle_mutex);
     193         [ #  # ]:          0 :         if (tty_throttled(tty)) {
     194         [ #  # ]:          0 :                 if (tty->flow_change != TTY_UNTHROTTLE_SAFE)
     195                 :            :                         ret = 1;
     196                 :            :                 else {
     197                 :          0 :                         clear_bit(TTY_THROTTLED, &tty->flags);
     198         [ #  # ]:          0 :                         if (tty->ops->unthrottle)
     199                 :          0 :                                 tty->ops->unthrottle(tty);
     200                 :            :                 }
     201                 :            :         }
     202                 :          0 :         mutex_unlock(&tty->throttle_mutex);
     203                 :            : 
     204                 :          0 :         return ret;
     205                 :            : }
     206                 :            : 
     207                 :            : /**
     208                 :            :  *      tty_wait_until_sent     -       wait for I/O to finish
     209                 :            :  *      @tty: tty we are waiting for
     210                 :            :  *      @timeout: how long we will wait
     211                 :            :  *
     212                 :            :  *      Wait for characters pending in a tty driver to hit the wire, or
     213                 :            :  *      for a timeout to occur (eg due to flow control)
     214                 :            :  *
     215                 :            :  *      Locking: none
     216                 :            :  */
     217                 :            : 
     218                 :       1168 : void tty_wait_until_sent(struct tty_struct *tty, long timeout)
     219                 :            : {
     220                 :       1168 :         tty_debug_wait_until_sent(tty, "wait until sent, timeout=%ld\n", timeout);
     221                 :            : 
     222         [ -  + ]:       1168 :         if (!timeout)
     223                 :          0 :                 timeout = MAX_SCHEDULE_TIMEOUT;
     224                 :            : 
     225   [ +  -  -  +  :       2336 :         timeout = wait_event_interruptible_timeout(tty->write_wait,
          -  +  -  -  -  
             -  -  -  -  
                      - ]
     226                 :            :                         !tty_chars_in_buffer(tty), timeout);
     227         [ +  - ]:       1168 :         if (timeout <= 0)
     228                 :            :                 return;
     229                 :            : 
     230         [ -  + ]:       1168 :         if (timeout == MAX_SCHEDULE_TIMEOUT)
     231                 :          0 :                 timeout = 0;
     232                 :            : 
     233         [ +  - ]:       1168 :         if (tty->ops->wait_until_sent)
     234                 :       1168 :                 tty->ops->wait_until_sent(tty, timeout);
     235                 :            : }
     236                 :            : EXPORT_SYMBOL(tty_wait_until_sent);
     237                 :            : 
     238                 :            : 
     239                 :            : /*
     240                 :            :  *              Termios Helper Methods
     241                 :            :  */
     242                 :            : 
     243                 :         13 : static void unset_locked_termios(struct tty_struct *tty, struct ktermios *old)
     244                 :            : {
     245                 :         13 :         struct ktermios *termios = &tty->termios;
     246                 :         13 :         struct ktermios *locked  = &tty->termios_locked;
     247                 :         13 :         int     i;
     248                 :            : 
     249                 :            : #define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
     250                 :            : 
     251                 :         13 :         NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
     252                 :         13 :         NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
     253                 :         13 :         NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
     254                 :         13 :         NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
     255         [ -  + ]:         13 :         termios->c_line = locked->c_line ? old->c_line : termios->c_line;
     256         [ +  + ]:        260 :         for (i = 0; i < NCCS; i++)
     257         [ -  + ]:        247 :                 termios->c_cc[i] = locked->c_cc[i] ?
     258                 :            :                         old->c_cc[i] : termios->c_cc[i];
     259                 :            :         /* FIXME: What should we do for i/ospeed */
     260                 :         13 : }
     261                 :            : 
     262                 :            : /**
     263                 :            :  *      tty_termios_copy_hw     -       copy hardware settings
     264                 :            :  *      @new: New termios
     265                 :            :  *      @old: Old termios
     266                 :            :  *
     267                 :            :  *      Propagate the hardware specific terminal setting bits from
     268                 :            :  *      the old termios structure to the new one. This is used in cases
     269                 :            :  *      where the hardware does not support reconfiguration or as a helper
     270                 :            :  *      in some cases where only minimal reconfiguration is supported
     271                 :            :  */
     272                 :            : 
     273                 :          0 : void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old)
     274                 :            : {
     275                 :            :         /* The bits a dumb device handles in software. Smart devices need
     276                 :            :            to always provide a set_termios method */
     277                 :          0 :         new->c_cflag &= HUPCL | CREAD | CLOCAL;
     278                 :          0 :         new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
     279                 :          0 :         new->c_ispeed = old->c_ispeed;
     280                 :          0 :         new->c_ospeed = old->c_ospeed;
     281                 :          0 : }
     282                 :            : EXPORT_SYMBOL(tty_termios_copy_hw);
     283                 :            : 
     284                 :            : /**
     285                 :            :  *      tty_termios_hw_change   -       check for setting change
     286                 :            :  *      @a: termios
     287                 :            :  *      @b: termios to compare
     288                 :            :  *
     289                 :            :  *      Check if any of the bits that affect a dumb device have changed
     290                 :            :  *      between the two termios structures, or a speed change is needed.
     291                 :            :  */
     292                 :            : 
     293                 :          0 : int tty_termios_hw_change(const struct ktermios *a, const struct ktermios *b)
     294                 :            : {
     295   [ #  #  #  # ]:          0 :         if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
     296                 :            :                 return 1;
     297         [ #  # ]:          0 :         if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL))
     298                 :          0 :                 return 1;
     299                 :            :         return 0;
     300                 :            : }
     301                 :            : EXPORT_SYMBOL(tty_termios_hw_change);
     302                 :            : 
     303                 :            : /**
     304                 :            :  *      tty_set_termios         -       update termios values
     305                 :            :  *      @tty: tty to update
     306                 :            :  *      @new_termios: desired new value
     307                 :            :  *
     308                 :            :  *      Perform updates to the termios values set on this terminal.
     309                 :            :  *      A master pty's termios should never be set.
     310                 :            :  *
     311                 :            :  *      Locking: termios_rwsem
     312                 :            :  */
     313                 :            : 
     314                 :         13 : int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
     315                 :            : {
     316                 :         13 :         struct ktermios old_termios;
     317                 :         13 :         struct tty_ldisc *ld;
     318                 :            : 
     319         [ -  + ]:         13 :         WARN_ON(tty->driver->type == TTY_DRIVER_TYPE_PTY &&
     320                 :            :                 tty->driver->subtype == PTY_TYPE_MASTER);
     321                 :            :         /*
     322                 :            :          *      Perform the actual termios internal changes under lock.
     323                 :            :          */
     324                 :            : 
     325                 :            : 
     326                 :            :         /* FIXME: we need to decide on some locking/ordering semantics
     327                 :            :            for the set_termios notification eventually */
     328                 :         13 :         down_write(&tty->termios_rwsem);
     329                 :         13 :         old_termios = tty->termios;
     330                 :         13 :         tty->termios = *new_termios;
     331                 :         13 :         unset_locked_termios(tty, &old_termios);
     332                 :            : 
     333         [ +  - ]:         13 :         if (tty->ops->set_termios)
     334                 :         13 :                 tty->ops->set_termios(tty, &old_termios);
     335                 :            :         else
     336                 :          0 :                 tty_termios_copy_hw(&tty->termios, &old_termios);
     337                 :            : 
     338                 :         13 :         ld = tty_ldisc_ref(tty);
     339         [ +  - ]:         13 :         if (ld != NULL) {
     340         [ +  - ]:         13 :                 if (ld->ops->set_termios)
     341                 :         13 :                         ld->ops->set_termios(tty, &old_termios);
     342                 :         13 :                 tty_ldisc_deref(ld);
     343                 :            :         }
     344                 :         13 :         up_write(&tty->termios_rwsem);
     345                 :         13 :         return 0;
     346                 :            : }
     347                 :            : EXPORT_SYMBOL_GPL(tty_set_termios);
     348                 :            : 
     349                 :            : /**
     350                 :            :  *      set_termios             -       set termios values for a tty
     351                 :            :  *      @tty: terminal device
     352                 :            :  *      @arg: user data
     353                 :            :  *      @opt: option information
     354                 :            :  *
     355                 :            :  *      Helper function to prepare termios data and run necessary other
     356                 :            :  *      functions before using tty_set_termios to do the actual changes.
     357                 :            :  *
     358                 :            :  *      Locking:
     359                 :            :  *              Called functions take ldisc and termios_rwsem locks
     360                 :            :  */
     361                 :            : 
     362                 :         13 : static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
     363                 :            : {
     364                 :         13 :         struct ktermios tmp_termios;
     365                 :         13 :         struct tty_ldisc *ld;
     366                 :         13 :         int retval = tty_check_change(tty);
     367                 :            : 
     368         [ +  - ]:         13 :         if (retval)
     369                 :            :                 return retval;
     370                 :            : 
     371                 :         13 :         down_read(&tty->termios_rwsem);
     372                 :         13 :         tmp_termios = tty->termios;
     373                 :         13 :         up_read(&tty->termios_rwsem);
     374                 :            : 
     375         [ -  + ]:         13 :         if (opt & TERMIOS_TERMIO) {
     376         [ #  # ]:          0 :                 if (user_termio_to_kernel_termios(&tmp_termios,
     377                 :            :                                                 (struct termio __user *)arg))
     378                 :            :                         return -EFAULT;
     379                 :            : #ifdef TCGETS2
     380         [ +  - ]:         13 :         } else if (opt & TERMIOS_OLD) {
     381         [ +  - ]:         13 :                 if (user_termios_to_kernel_termios_1(&tmp_termios,
     382                 :            :                                                 (struct termios __user *)arg))
     383                 :            :                         return -EFAULT;
     384                 :            :         } else {
     385         [ #  # ]:          0 :                 if (user_termios_to_kernel_termios(&tmp_termios,
     386                 :            :                                                 (struct termios2 __user *)arg))
     387                 :            :                         return -EFAULT;
     388                 :            :         }
     389                 :            : #else
     390                 :            :         } else if (user_termios_to_kernel_termios(&tmp_termios,
     391                 :            :                                         (struct termios __user *)arg))
     392                 :            :                 return -EFAULT;
     393                 :            : #endif
     394                 :            : 
     395                 :            :         /* If old style Bfoo values are used then load c_ispeed/c_ospeed
     396                 :            :          * with the real speed so its unconditionally usable */
     397                 :         13 :         tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
     398                 :         13 :         tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
     399                 :            : 
     400                 :         13 :         ld = tty_ldisc_ref(tty);
     401                 :            : 
     402         [ +  - ]:         13 :         if (ld != NULL) {
     403   [ -  +  -  - ]:         13 :                 if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
     404                 :          0 :                         ld->ops->flush_buffer(tty);
     405                 :         13 :                 tty_ldisc_deref(ld);
     406                 :            :         }
     407                 :            : 
     408         [ -  + ]:         13 :         if (opt & TERMIOS_WAIT) {
     409                 :          0 :                 tty_wait_until_sent(tty, 0);
     410         [ #  # ]:          0 :                 if (signal_pending(current))
     411                 :            :                         return -ERESTARTSYS;
     412                 :            :         }
     413                 :            : 
     414                 :         13 :         tty_set_termios(tty, &tmp_termios);
     415                 :            : 
     416                 :            :         /* FIXME: Arguably if tmp_termios == tty->termios AND the
     417                 :            :            actual requested termios was not tmp_termios then we may
     418                 :            :            want to return an error as no user requested change has
     419                 :            :            succeeded */
     420                 :         13 :         return 0;
     421                 :            : }
     422                 :            : 
     423                 :       1209 : static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
     424                 :            : {
     425                 :       1209 :         down_read(&tty->termios_rwsem);
     426                 :       1209 :         *kterm = tty->termios;
     427                 :       1209 :         up_read(&tty->termios_rwsem);
     428                 :       1209 : }
     429                 :            : 
     430                 :          0 : static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
     431                 :            : {
     432                 :          0 :         down_read(&tty->termios_rwsem);
     433                 :          0 :         *kterm = tty->termios_locked;
     434                 :          0 :         up_read(&tty->termios_rwsem);
     435                 :          0 : }
     436                 :            : 
     437                 :          0 : static int get_termio(struct tty_struct *tty, struct termio __user *termio)
     438                 :            : {
     439                 :          0 :         struct ktermios kterm;
     440                 :          0 :         copy_termios(tty, &kterm);
     441         [ #  # ]:          0 :         if (kernel_termios_to_user_termio(termio, &kterm))
     442                 :          0 :                 return -EFAULT;
     443                 :            :         return 0;
     444                 :            : }
     445                 :            : 
     446                 :            : 
     447                 :            : #ifdef TCGETX
     448                 :            : 
     449                 :            : /**
     450                 :            :  *      set_termiox     -       set termiox fields if possible
     451                 :            :  *      @tty: terminal
     452                 :            :  *      @arg: termiox structure from user
     453                 :            :  *      @opt: option flags for ioctl type
     454                 :            :  *
     455                 :            :  *      Implement the device calling points for the SYS5 termiox ioctl
     456                 :            :  *      interface in Linux
     457                 :            :  */
     458                 :            : 
     459                 :          0 : static int set_termiox(struct tty_struct *tty, void __user *arg, int opt)
     460                 :            : {
     461                 :          0 :         struct termiox tnew;
     462                 :          0 :         struct tty_ldisc *ld;
     463                 :            : 
     464         [ #  # ]:          0 :         if (tty->termiox == NULL)
     465                 :            :                 return -EINVAL;
     466         [ #  # ]:          0 :         if (copy_from_user(&tnew, arg, sizeof(struct termiox)))
     467                 :            :                 return -EFAULT;
     468                 :            : 
     469                 :          0 :         ld = tty_ldisc_ref(tty);
     470         [ #  # ]:          0 :         if (ld != NULL) {
     471   [ #  #  #  # ]:          0 :                 if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
     472                 :          0 :                         ld->ops->flush_buffer(tty);
     473                 :          0 :                 tty_ldisc_deref(ld);
     474                 :            :         }
     475         [ #  # ]:          0 :         if (opt & TERMIOS_WAIT) {
     476                 :          0 :                 tty_wait_until_sent(tty, 0);
     477         [ #  # ]:          0 :                 if (signal_pending(current))
     478                 :            :                         return -ERESTARTSYS;
     479                 :            :         }
     480                 :            : 
     481                 :          0 :         down_write(&tty->termios_rwsem);
     482         [ #  # ]:          0 :         if (tty->ops->set_termiox)
     483                 :          0 :                 tty->ops->set_termiox(tty, &tnew);
     484                 :          0 :         up_write(&tty->termios_rwsem);
     485                 :          0 :         return 0;
     486                 :            : }
     487                 :            : 
     488                 :            : #endif
     489                 :            : 
     490                 :            : 
     491                 :            : #ifdef TIOCGETP
     492                 :            : /*
     493                 :            :  * These are deprecated, but there is limited support..
     494                 :            :  *
     495                 :            :  * The "sg_flags" translation is a joke..
     496                 :            :  */
     497                 :            : static int get_sgflags(struct tty_struct *tty)
     498                 :            : {
     499                 :            :         int flags = 0;
     500                 :            : 
     501                 :            :         if (!L_ICANON(tty)) {
     502                 :            :                 if (L_ISIG(tty))
     503                 :            :                         flags |= 0x02;          /* cbreak */
     504                 :            :                 else
     505                 :            :                         flags |= 0x20;          /* raw */
     506                 :            :         }
     507                 :            :         if (L_ECHO(tty))
     508                 :            :                 flags |= 0x08;                  /* echo */
     509                 :            :         if (O_OPOST(tty))
     510                 :            :                 if (O_ONLCR(tty))
     511                 :            :                         flags |= 0x10;          /* crmod */
     512                 :            :         return flags;
     513                 :            : }
     514                 :            : 
     515                 :            : static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
     516                 :            : {
     517                 :            :         struct sgttyb tmp;
     518                 :            : 
     519                 :            :         down_read(&tty->termios_rwsem);
     520                 :            :         tmp.sg_ispeed = tty->termios.c_ispeed;
     521                 :            :         tmp.sg_ospeed = tty->termios.c_ospeed;
     522                 :            :         tmp.sg_erase = tty->termios.c_cc[VERASE];
     523                 :            :         tmp.sg_kill = tty->termios.c_cc[VKILL];
     524                 :            :         tmp.sg_flags = get_sgflags(tty);
     525                 :            :         up_read(&tty->termios_rwsem);
     526                 :            : 
     527                 :            :         return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
     528                 :            : }
     529                 :            : 
     530                 :            : static void set_sgflags(struct ktermios *termios, int flags)
     531                 :            : {
     532                 :            :         termios->c_iflag = ICRNL | IXON;
     533                 :            :         termios->c_oflag = 0;
     534                 :            :         termios->c_lflag = ISIG | ICANON;
     535                 :            :         if (flags & 0x02) { /* cbreak */
     536                 :            :                 termios->c_iflag = 0;
     537                 :            :                 termios->c_lflag &= ~ICANON;
     538                 :            :         }
     539                 :            :         if (flags & 0x08) {         /* echo */
     540                 :            :                 termios->c_lflag |= ECHO | ECHOE | ECHOK |
     541                 :            :                                     ECHOCTL | ECHOKE | IEXTEN;
     542                 :            :         }
     543                 :            :         if (flags & 0x10) {         /* crmod */
     544                 :            :                 termios->c_oflag |= OPOST | ONLCR;
     545                 :            :         }
     546                 :            :         if (flags & 0x20) { /* raw */
     547                 :            :                 termios->c_iflag = 0;
     548                 :            :                 termios->c_lflag &= ~(ISIG | ICANON);
     549                 :            :         }
     550                 :            :         if (!(termios->c_lflag & ICANON)) {
     551                 :            :                 termios->c_cc[VMIN] = 1;
     552                 :            :                 termios->c_cc[VTIME] = 0;
     553                 :            :         }
     554                 :            : }
     555                 :            : 
     556                 :            : /**
     557                 :            :  *      set_sgttyb              -       set legacy terminal values
     558                 :            :  *      @tty: tty structure
     559                 :            :  *      @sgttyb: pointer to old style terminal structure
     560                 :            :  *
     561                 :            :  *      Updates a terminal from the legacy BSD style terminal information
     562                 :            :  *      structure.
     563                 :            :  *
     564                 :            :  *      Locking: termios_rwsem
     565                 :            :  */
     566                 :            : 
     567                 :            : static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
     568                 :            : {
     569                 :            :         int retval;
     570                 :            :         struct sgttyb tmp;
     571                 :            :         struct ktermios termios;
     572                 :            : 
     573                 :            :         retval = tty_check_change(tty);
     574                 :            :         if (retval)
     575                 :            :                 return retval;
     576                 :            : 
     577                 :            :         if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
     578                 :            :                 return -EFAULT;
     579                 :            : 
     580                 :            :         down_write(&tty->termios_rwsem);
     581                 :            :         termios = tty->termios;
     582                 :            :         termios.c_cc[VERASE] = tmp.sg_erase;
     583                 :            :         termios.c_cc[VKILL] = tmp.sg_kill;
     584                 :            :         set_sgflags(&termios, tmp.sg_flags);
     585                 :            :         /* Try and encode into Bfoo format */
     586                 :            : #ifdef BOTHER
     587                 :            :         tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
     588                 :            :                                                 termios.c_ospeed);
     589                 :            : #endif
     590                 :            :         up_write(&tty->termios_rwsem);
     591                 :            :         tty_set_termios(tty, &termios);
     592                 :            :         return 0;
     593                 :            : }
     594                 :            : #endif
     595                 :            : 
     596                 :            : #ifdef TIOCGETC
     597                 :            : static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
     598                 :            : {
     599                 :            :         struct tchars tmp;
     600                 :            : 
     601                 :            :         down_read(&tty->termios_rwsem);
     602                 :            :         tmp.t_intrc = tty->termios.c_cc[VINTR];
     603                 :            :         tmp.t_quitc = tty->termios.c_cc[VQUIT];
     604                 :            :         tmp.t_startc = tty->termios.c_cc[VSTART];
     605                 :            :         tmp.t_stopc = tty->termios.c_cc[VSTOP];
     606                 :            :         tmp.t_eofc = tty->termios.c_cc[VEOF];
     607                 :            :         tmp.t_brkc = tty->termios.c_cc[VEOL2];       /* what is brkc anyway? */
     608                 :            :         up_read(&tty->termios_rwsem);
     609                 :            :         return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
     610                 :            : }
     611                 :            : 
     612                 :            : static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
     613                 :            : {
     614                 :            :         struct tchars tmp;
     615                 :            : 
     616                 :            :         if (copy_from_user(&tmp, tchars, sizeof(tmp)))
     617                 :            :                 return -EFAULT;
     618                 :            :         down_write(&tty->termios_rwsem);
     619                 :            :         tty->termios.c_cc[VINTR] = tmp.t_intrc;
     620                 :            :         tty->termios.c_cc[VQUIT] = tmp.t_quitc;
     621                 :            :         tty->termios.c_cc[VSTART] = tmp.t_startc;
     622                 :            :         tty->termios.c_cc[VSTOP] = tmp.t_stopc;
     623                 :            :         tty->termios.c_cc[VEOF] = tmp.t_eofc;
     624                 :            :         tty->termios.c_cc[VEOL2] = tmp.t_brkc;       /* what is brkc anyway? */
     625                 :            :         up_write(&tty->termios_rwsem);
     626                 :            :         return 0;
     627                 :            : }
     628                 :            : #endif
     629                 :            : 
     630                 :            : #ifdef TIOCGLTC
     631                 :            : static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
     632                 :            : {
     633                 :            :         struct ltchars tmp;
     634                 :            : 
     635                 :            :         down_read(&tty->termios_rwsem);
     636                 :            :         tmp.t_suspc = tty->termios.c_cc[VSUSP];
     637                 :            :         /* what is dsuspc anyway? */
     638                 :            :         tmp.t_dsuspc = tty->termios.c_cc[VSUSP];
     639                 :            :         tmp.t_rprntc = tty->termios.c_cc[VREPRINT];
     640                 :            :         /* what is flushc anyway? */
     641                 :            :         tmp.t_flushc = tty->termios.c_cc[VEOL2];
     642                 :            :         tmp.t_werasc = tty->termios.c_cc[VWERASE];
     643                 :            :         tmp.t_lnextc = tty->termios.c_cc[VLNEXT];
     644                 :            :         up_read(&tty->termios_rwsem);
     645                 :            :         return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
     646                 :            : }
     647                 :            : 
     648                 :            : static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
     649                 :            : {
     650                 :            :         struct ltchars tmp;
     651                 :            : 
     652                 :            :         if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
     653                 :            :                 return -EFAULT;
     654                 :            : 
     655                 :            :         down_write(&tty->termios_rwsem);
     656                 :            :         tty->termios.c_cc[VSUSP] = tmp.t_suspc;
     657                 :            :         /* what is dsuspc anyway? */
     658                 :            :         tty->termios.c_cc[VEOL2] = tmp.t_dsuspc;
     659                 :            :         tty->termios.c_cc[VREPRINT] = tmp.t_rprntc;
     660                 :            :         /* what is flushc anyway? */
     661                 :            :         tty->termios.c_cc[VEOL2] = tmp.t_flushc;
     662                 :            :         tty->termios.c_cc[VWERASE] = tmp.t_werasc;
     663                 :            :         tty->termios.c_cc[VLNEXT] = tmp.t_lnextc;
     664                 :            :         up_write(&tty->termios_rwsem);
     665                 :            :         return 0;
     666                 :            : }
     667                 :            : #endif
     668                 :            : 
     669                 :            : /**
     670                 :            :  *      tty_change_softcar      -       carrier change ioctl helper
     671                 :            :  *      @tty: tty to update
     672                 :            :  *      @arg: enable/disable CLOCAL
     673                 :            :  *
     674                 :            :  *      Perform a change to the CLOCAL state and call into the driver
     675                 :            :  *      layer to make it visible. All done with the termios rwsem
     676                 :            :  */
     677                 :            : 
     678                 :          0 : static int tty_change_softcar(struct tty_struct *tty, int arg)
     679                 :            : {
     680                 :          0 :         int ret = 0;
     681         [ #  # ]:          0 :         int bit = arg ? CLOCAL : 0;
     682                 :          0 :         struct ktermios old;
     683                 :            : 
     684                 :          0 :         down_write(&tty->termios_rwsem);
     685                 :          0 :         old = tty->termios;
     686                 :          0 :         tty->termios.c_cflag &= ~CLOCAL;
     687                 :          0 :         tty->termios.c_cflag |= bit;
     688         [ #  # ]:          0 :         if (tty->ops->set_termios)
     689                 :          0 :                 tty->ops->set_termios(tty, &old);
     690         [ #  # ]:          0 :         if (C_CLOCAL(tty) != bit)
     691                 :          0 :                 ret = -EINVAL;
     692                 :          0 :         up_write(&tty->termios_rwsem);
     693                 :          0 :         return ret;
     694                 :            : }
     695                 :            : 
     696                 :            : /**
     697                 :            :  *      tty_mode_ioctl          -       mode related ioctls
     698                 :            :  *      @tty: tty for the ioctl
     699                 :            :  *      @file: file pointer for the tty
     700                 :            :  *      @cmd: command
     701                 :            :  *      @arg: ioctl argument
     702                 :            :  *
     703                 :            :  *      Perform non line discipline specific mode control ioctls. This
     704                 :            :  *      is designed to be called by line disciplines to ensure they provide
     705                 :            :  *      consistent mode setting.
     706                 :            :  */
     707                 :            : 
     708                 :       1235 : int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
     709                 :            :                         unsigned int cmd, unsigned long arg)
     710                 :            : {
     711                 :       1235 :         struct tty_struct *real_tty;
     712                 :       1235 :         void __user *p = (void __user *)arg;
     713                 :       1235 :         int ret = 0;
     714                 :       1235 :         struct ktermios kterm;
     715                 :            : 
     716         [ -  + ]:       1235 :         BUG_ON(file == NULL);
     717                 :            : 
     718         [ -  + ]:       1235 :         if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
     719                 :            :             tty->driver->subtype == PTY_TYPE_MASTER)
     720                 :          0 :                 real_tty = tty->link;
     721                 :            :         else
     722                 :            :                 real_tty = tty;
     723                 :            : 
     724   [ -  -  +  +  :       1235 :         switch (cmd) {
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
                   -  + ]
     725                 :            : #ifdef TIOCGETP
     726                 :            :         case TIOCGETP:
     727                 :            :                 return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
     728                 :            :         case TIOCSETP:
     729                 :            :         case TIOCSETN:
     730                 :            :                 return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
     731                 :            : #endif
     732                 :            : #ifdef TIOCGETC
     733                 :            :         case TIOCGETC:
     734                 :            :                 return get_tchars(real_tty, p);
     735                 :            :         case TIOCSETC:
     736                 :            :                 return set_tchars(real_tty, p);
     737                 :            : #endif
     738                 :            : #ifdef TIOCGLTC
     739                 :            :         case TIOCGLTC:
     740                 :            :                 return get_ltchars(real_tty, p);
     741                 :            :         case TIOCSLTC:
     742                 :            :                 return set_ltchars(real_tty, p);
     743                 :            : #endif
     744                 :          0 :         case TCSETSF:
     745                 :          0 :                 return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
     746                 :          0 :         case TCSETSW:
     747                 :          0 :                 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
     748                 :         13 :         case TCSETS:
     749                 :         13 :                 return set_termios(real_tty, p, TERMIOS_OLD);
     750                 :            : #ifndef TCGETS2
     751                 :            :         case TCGETS:
     752                 :            :                 copy_termios(real_tty, &kterm);
     753                 :            :                 if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
     754                 :            :                         ret = -EFAULT;
     755                 :            :                 return ret;
     756                 :            : #else
     757                 :       1209 :         case TCGETS:
     758                 :       1209 :                 copy_termios(real_tty, &kterm);
     759         [ -  + ]:       1209 :                 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
     760                 :          0 :                         ret = -EFAULT;
     761                 :            :                 return ret;
     762                 :          0 :         case TCGETS2:
     763                 :          0 :                 copy_termios(real_tty, &kterm);
     764         [ #  # ]:          0 :                 if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm))
     765                 :          0 :                         ret = -EFAULT;
     766                 :            :                 return ret;
     767                 :          0 :         case TCSETSF2:
     768                 :          0 :                 return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT);
     769                 :          0 :         case TCSETSW2:
     770                 :          0 :                 return set_termios(real_tty, p, TERMIOS_WAIT);
     771                 :          0 :         case TCSETS2:
     772                 :          0 :                 return set_termios(real_tty, p, 0);
     773                 :            : #endif
     774                 :          0 :         case TCGETA:
     775                 :          0 :                 return get_termio(real_tty, p);
     776                 :          0 :         case TCSETAF:
     777                 :          0 :                 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
     778                 :          0 :         case TCSETAW:
     779                 :          0 :                 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
     780                 :          0 :         case TCSETA:
     781                 :          0 :                 return set_termios(real_tty, p, TERMIOS_TERMIO);
     782                 :            : #ifndef TCGETS2
     783                 :            :         case TIOCGLCKTRMIOS:
     784                 :            :                 copy_termios_locked(real_tty, &kterm);
     785                 :            :                 if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
     786                 :            :                         ret = -EFAULT;
     787                 :            :                 return ret;
     788                 :            :         case TIOCSLCKTRMIOS:
     789                 :            :                 if (!capable(CAP_SYS_ADMIN))
     790                 :            :                         return -EPERM;
     791                 :            :                 copy_termios_locked(real_tty, &kterm);
     792                 :            :                 if (user_termios_to_kernel_termios(&kterm,
     793                 :            :                                                (struct termios __user *) arg))
     794                 :            :                         return -EFAULT;
     795                 :            :                 down_write(&real_tty->termios_rwsem);
     796                 :            :                 real_tty->termios_locked = kterm;
     797                 :            :                 up_write(&real_tty->termios_rwsem);
     798                 :            :                 return 0;
     799                 :            : #else
     800                 :          0 :         case TIOCGLCKTRMIOS:
     801                 :          0 :                 copy_termios_locked(real_tty, &kterm);
     802         [ #  # ]:          0 :                 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
     803                 :          0 :                         ret = -EFAULT;
     804                 :            :                 return ret;
     805                 :          0 :         case TIOCSLCKTRMIOS:
     806         [ #  # ]:          0 :                 if (!capable(CAP_SYS_ADMIN))
     807                 :            :                         return -EPERM;
     808                 :          0 :                 copy_termios_locked(real_tty, &kterm);
     809         [ #  # ]:          0 :                 if (user_termios_to_kernel_termios_1(&kterm,
     810                 :            :                                                (struct termios __user *) arg))
     811                 :            :                         return -EFAULT;
     812                 :          0 :                 down_write(&real_tty->termios_rwsem);
     813                 :          0 :                 real_tty->termios_locked = kterm;
     814                 :          0 :                 up_write(&real_tty->termios_rwsem);
     815                 :          0 :                 return ret;
     816                 :            : #endif
     817                 :            : #ifdef TCGETX
     818                 :          0 :         case TCGETX: {
     819                 :          0 :                 struct termiox ktermx;
     820         [ #  # ]:          0 :                 if (real_tty->termiox == NULL)
     821                 :            :                         return -EINVAL;
     822                 :          0 :                 down_read(&real_tty->termios_rwsem);
     823                 :          0 :                 memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox));
     824                 :          0 :                 up_read(&real_tty->termios_rwsem);
     825         [ #  # ]:          0 :                 if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
     826                 :          0 :                         ret = -EFAULT;
     827                 :            :                 return ret;
     828                 :            :         }
     829                 :          0 :         case TCSETX:
     830                 :          0 :                 return set_termiox(real_tty, p, 0);
     831                 :          0 :         case TCSETXW:
     832                 :          0 :                 return set_termiox(real_tty, p, TERMIOS_WAIT);
     833                 :          0 :         case TCSETXF:
     834                 :          0 :                 return set_termiox(real_tty, p, TERMIOS_FLUSH);
     835                 :            : #endif          
     836                 :          0 :         case TIOCGSOFTCAR:
     837                 :          0 :                 copy_termios(real_tty, &kterm);
     838                 :          0 :                 ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0,
     839                 :            :                                                 (int __user *)arg);
     840                 :          0 :                 return ret;
     841                 :            :         case TIOCSSOFTCAR:
     842         [ #  # ]:          0 :                 if (get_user(arg, (unsigned int __user *) arg))
     843                 :            :                         return -EFAULT;
     844                 :          0 :                 return tty_change_softcar(real_tty, arg);
     845                 :            :         default:
     846                 :            :                 return -ENOIOCTLCMD;
     847                 :            :         }
     848                 :            : }
     849                 :            : EXPORT_SYMBOL_GPL(tty_mode_ioctl);
     850                 :            : 
     851                 :            : 
     852                 :            : /* Caller guarantees ldisc reference is held */
     853                 :         13 : static int __tty_perform_flush(struct tty_struct *tty, unsigned long arg)
     854                 :            : {
     855                 :         13 :         struct tty_ldisc *ld = tty->ldisc;
     856                 :            : 
     857   [ -  +  -  - ]:         13 :         switch (arg) {
     858                 :          0 :         case TCIFLUSH:
     859   [ #  #  #  # ]:          0 :                 if (ld && ld->ops->flush_buffer) {
     860                 :          0 :                         ld->ops->flush_buffer(tty);
     861                 :          0 :                         tty_unthrottle(tty);
     862                 :            :                 }
     863                 :            :                 break;
     864                 :         13 :         case TCIOFLUSH:
     865   [ +  -  +  - ]:         13 :                 if (ld && ld->ops->flush_buffer) {
     866                 :         13 :                         ld->ops->flush_buffer(tty);
     867                 :         13 :                         tty_unthrottle(tty);
     868                 :            :                 }
     869                 :            :                 /* fall through */
     870                 :            :         case TCOFLUSH:
     871         [ +  - ]:         13 :                 tty_driver_flush_buffer(tty);
     872                 :            :                 break;
     873                 :            :         default:
     874                 :            :                 return -EINVAL;
     875                 :            :         }
     876                 :            :         return 0;
     877                 :            : }
     878                 :            : 
     879                 :          0 : int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
     880                 :            : {
     881                 :          0 :         struct tty_ldisc *ld;
     882                 :          0 :         int retval = tty_check_change(tty);
     883         [ #  # ]:          0 :         if (retval)
     884                 :            :                 return retval;
     885                 :            : 
     886                 :          0 :         ld = tty_ldisc_ref_wait(tty);
     887                 :          0 :         retval = __tty_perform_flush(tty, arg);
     888         [ #  # ]:          0 :         if (ld)
     889                 :          0 :                 tty_ldisc_deref(ld);
     890                 :            :         return retval;
     891                 :            : }
     892                 :            : EXPORT_SYMBOL_GPL(tty_perform_flush);
     893                 :            : 
     894                 :       1248 : int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
     895                 :            :                        unsigned int cmd, unsigned long arg)
     896                 :            : {
     897                 :       1248 :         int retval;
     898                 :            : 
     899      [ -  +  + ]:       1248 :         switch (cmd) {
     900                 :          0 :         case TCXONC:
     901                 :          0 :                 retval = tty_check_change(tty);
     902         [ #  # ]:          0 :                 if (retval)
     903                 :            :                         return retval;
     904   [ #  #  #  #  :          0 :                 switch (arg) {
                      # ]
     905                 :          0 :                 case TCOOFF:
     906                 :          0 :                         spin_lock_irq(&tty->flow_lock);
     907         [ #  # ]:          0 :                         if (!tty->flow_stopped) {
     908                 :          0 :                                 tty->flow_stopped = 1;
     909                 :          0 :                                 __stop_tty(tty);
     910                 :            :                         }
     911                 :          0 :                         spin_unlock_irq(&tty->flow_lock);
     912                 :            :                         break;
     913                 :          0 :                 case TCOON:
     914                 :          0 :                         spin_lock_irq(&tty->flow_lock);
     915         [ #  # ]:          0 :                         if (tty->flow_stopped) {
     916                 :          0 :                                 tty->flow_stopped = 0;
     917                 :          0 :                                 __start_tty(tty);
     918                 :            :                         }
     919                 :          0 :                         spin_unlock_irq(&tty->flow_lock);
     920                 :            :                         break;
     921                 :          0 :                 case TCIOFF:
     922         [ #  # ]:          0 :                         if (STOP_CHAR(tty) != __DISABLED_CHAR)
     923                 :          0 :                                 retval = tty_send_xchar(tty, STOP_CHAR(tty));
     924                 :            :                         break;
     925                 :          0 :                 case TCION:
     926         [ #  # ]:          0 :                         if (START_CHAR(tty) != __DISABLED_CHAR)
     927                 :          0 :                                 retval = tty_send_xchar(tty, START_CHAR(tty));
     928                 :            :                         break;
     929                 :            :                 default:
     930                 :            :                         return -EINVAL;
     931                 :            :                 }
     932                 :            :                 return retval;
     933                 :         13 :         case TCFLSH:
     934                 :         13 :                 retval = tty_check_change(tty);
     935         [ +  - ]:         13 :                 if (retval)
     936                 :            :                         return retval;
     937                 :         13 :                 return __tty_perform_flush(tty, arg);
     938                 :       1235 :         default:
     939                 :            :                 /* Try the mode commands */
     940                 :       1235 :                 return tty_mode_ioctl(tty, file, cmd, arg);
     941                 :            :         }
     942                 :            : }
     943                 :            : EXPORT_SYMBOL(n_tty_ioctl_helper);

Generated by: LCOV version 1.14