LCOV - code coverage report
Current view: top level - drivers/tty - tty_ioctl.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 107 306 35.0 %
Date: 2014-04-07 Functions: 16 27 59.3 %
Branches: 69 262 26.3 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
       3                 :            :  *
       4                 :            :  * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
       5                 :            :  * which can be dynamically activated and de-activated by the line
       6                 :            :  * discipline handling modules (like SLIP).
       7                 :            :  */
       8                 :            : 
       9                 :            : #include <linux/types.h>
      10                 :            : #include <linux/termios.h>
      11                 :            : #include <linux/errno.h>
      12                 :            : #include <linux/sched.h>
      13                 :            : #include <linux/kernel.h>
      14                 :            : #include <linux/major.h>
      15                 :            : #include <linux/tty.h>
      16                 :            : #include <linux/fcntl.h>
      17                 :            : #include <linux/string.h>
      18                 :            : #include <linux/mm.h>
      19                 :            : #include <linux/module.h>
      20                 :            : #include <linux/bitops.h>
      21                 :            : #include <linux/mutex.h>
      22                 :            : #include <linux/compat.h>
      23                 :            : 
      24                 :            : #include <asm/io.h>
      25                 :            : #include <asm/uaccess.h>
      26                 :            : 
      27                 :            : #undef TTY_DEBUG_WAIT_UNTIL_SENT
      28                 :            : 
      29                 :            : #undef  DEBUG
      30                 :            : 
      31                 :            : /*
      32                 :            :  * Internal flag options for termios setting behavior
      33                 :            :  */
      34                 :            : #define TERMIOS_FLUSH   1
      35                 :            : #define TERMIOS_WAIT    2
      36                 :            : #define TERMIOS_TERMIO  4
      37                 :            : #define TERMIOS_OLD     8
      38                 :            : 
      39                 :            : 
      40                 :            : /**
      41                 :            :  *      tty_chars_in_buffer     -       characters pending
      42                 :            :  *      @tty: terminal
      43                 :            :  *
      44                 :            :  *      Return the number of bytes of data in the device private
      45                 :            :  *      output queue. If no private method is supplied there is assumed
      46                 :            :  *      to be no queue on the device.
      47                 :            :  */
      48                 :            : 
      49                 :          0 : int tty_chars_in_buffer(struct tty_struct *tty)
      50                 :            : {
      51   [ +  -  +  - ]:      94538 :         if (tty->ops->chars_in_buffer)
                 [ +  - ]
      52                 :      94538 :                 return tty->ops->chars_in_buffer(tty);
      53                 :            :         else
      54                 :            :                 return 0;
      55                 :            : }
      56                 :            : EXPORT_SYMBOL(tty_chars_in_buffer);
      57                 :            : 
      58                 :            : /**
      59                 :            :  *      tty_write_room          -       write queue space
      60                 :            :  *      @tty: terminal
      61                 :            :  *
      62                 :            :  *      Return the number of bytes that can be queued to this device
      63                 :            :  *      at the present time. The result should be treated as a guarantee
      64                 :            :  *      and the driver cannot offer a value it later shrinks by more than
      65                 :            :  *      the number of bytes written. If no method is provided 2K is always
      66                 :            :  *      returned and data may be lost as there will be no flow control.
      67                 :            :  */
      68                 :            :  
      69                 :          0 : int tty_write_room(struct tty_struct *tty)
      70                 :            : {
      71            [ + ]:     280087 :         if (tty->ops->write_room)
      72                 :     280098 :                 return tty->ops->write_room(tty);
      73                 :            :         return 2048;
      74                 :            : }
      75                 :            : EXPORT_SYMBOL(tty_write_room);
      76                 :            : 
      77                 :            : /**
      78                 :            :  *      tty_driver_flush_buffer -       discard internal buffer
      79                 :            :  *      @tty: terminal
      80                 :            :  *
      81                 :            :  *      Discard the internal output buffer for this device. If no method
      82                 :            :  *      is provided then either the buffer cannot be hardware flushed or
      83                 :            :  *      there is no buffer driver side.
      84                 :            :  */
      85                 :          0 : void tty_driver_flush_buffer(struct tty_struct *tty)
      86                 :            : {
      87 [ -  + ][ +  - ]:        227 :         if (tty->ops->flush_buffer)
      88                 :         99 :                 tty->ops->flush_buffer(tty);
      89                 :          0 : }
      90                 :            : EXPORT_SYMBOL(tty_driver_flush_buffer);
      91                 :            : 
      92                 :            : /**
      93                 :            :  *      tty_throttle            -       flow control
      94                 :            :  *      @tty: terminal
      95                 :            :  *
      96                 :            :  *      Indicate that a tty should stop transmitting data down the stack.
      97                 :            :  *      Takes the termios rwsem to protect against parallel throttle/unthrottle
      98                 :            :  *      and also to ensure the driver can consistently reference its own
      99                 :            :  *      termios data at this point when implementing software flow control.
     100                 :            :  */
     101                 :            : 
     102                 :          0 : void tty_throttle(struct tty_struct *tty)
     103                 :            : {
     104                 :          0 :         down_write(&tty->termios_rwsem);
     105                 :            :         /* check TTY_THROTTLED first so it indicates our state */
     106 [ #  # ][ #  # ]:          0 :         if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
     107                 :          0 :             tty->ops->throttle)
     108                 :          0 :                 tty->ops->throttle(tty);
     109                 :          0 :         tty->flow_change = 0;
     110                 :          0 :         up_write(&tty->termios_rwsem);
     111                 :          0 : }
     112                 :            : EXPORT_SYMBOL(tty_throttle);
     113                 :            : 
     114                 :            : /**
     115                 :            :  *      tty_unthrottle          -       flow control
     116                 :            :  *      @tty: terminal
     117                 :            :  *
     118                 :            :  *      Indicate that a tty may continue transmitting data down the stack.
     119                 :            :  *      Takes the termios rwsem to protect against parallel throttle/unthrottle
     120                 :            :  *      and also to ensure the driver can consistently reference its own
     121                 :            :  *      termios data at this point when implementing software flow control.
     122                 :            :  *
     123                 :            :  *      Drivers should however remember that the stack can issue a throttle,
     124                 :            :  *      then change flow control method, then unthrottle.
     125                 :            :  */
     126                 :            : 
     127                 :          0 : void tty_unthrottle(struct tty_struct *tty)
     128                 :            : {
     129                 :        707 :         down_write(&tty->termios_rwsem);
     130 [ +  + ][ +  - ]:        707 :         if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
     131                 :         82 :             tty->ops->unthrottle)
     132                 :         82 :                 tty->ops->unthrottle(tty);
     133                 :          0 :         tty->flow_change = 0;
     134                 :        707 :         up_write(&tty->termios_rwsem);
     135                 :        707 : }
     136                 :            : EXPORT_SYMBOL(tty_unthrottle);
     137                 :            : 
     138                 :            : /**
     139                 :            :  *      tty_throttle_safe       -       flow control
     140                 :            :  *      @tty: terminal
     141                 :            :  *
     142                 :            :  *      Similar to tty_throttle() but will only attempt throttle
     143                 :            :  *      if tty->flow_change is TTY_THROTTLE_SAFE. Prevents an accidental
     144                 :            :  *      throttle due to race conditions when throttling is conditional
     145                 :            :  *      on factors evaluated prior to throttling.
     146                 :            :  *
     147                 :            :  *      Returns 0 if tty is throttled (or was already throttled)
     148                 :            :  */
     149                 :            : 
     150                 :          0 : int tty_throttle_safe(struct tty_struct *tty)
     151                 :            : {
     152                 :            :         int ret = 0;
     153                 :            : 
     154                 :          0 :         mutex_lock(&tty->throttle_mutex);
     155         [ #  # ]:          0 :         if (!test_bit(TTY_THROTTLED, &tty->flags)) {
     156         [ #  # ]:          0 :                 if (tty->flow_change != TTY_THROTTLE_SAFE)
     157                 :            :                         ret = 1;
     158                 :            :                 else {
     159                 :          0 :                         set_bit(TTY_THROTTLED, &tty->flags);
     160         [ #  # ]:          0 :                         if (tty->ops->throttle)
     161                 :          0 :                                 tty->ops->throttle(tty);
     162                 :            :                 }
     163                 :            :         }
     164                 :          0 :         mutex_unlock(&tty->throttle_mutex);
     165                 :            : 
     166                 :          0 :         return ret;
     167                 :            : }
     168                 :            : 
     169                 :            : /**
     170                 :            :  *      tty_unthrottle_safe     -       flow control
     171                 :            :  *      @tty: terminal
     172                 :            :  *
     173                 :            :  *      Similar to tty_unthrottle() but will only attempt unthrottle
     174                 :            :  *      if tty->flow_change is TTY_UNTHROTTLE_SAFE. Prevents an accidental
     175                 :            :  *      unthrottle due to race conditions when unthrottling is conditional
     176                 :            :  *      on factors evaluated prior to unthrottling.
     177                 :            :  *
     178                 :            :  *      Returns 0 if tty is unthrottled (or was already unthrottled)
     179                 :            :  */
     180                 :            : 
     181                 :          0 : int tty_unthrottle_safe(struct tty_struct *tty)
     182                 :            : {
     183                 :            :         int ret = 0;
     184                 :            : 
     185                 :        370 :         mutex_lock(&tty->throttle_mutex);
     186         [ -  + ]:        370 :         if (test_bit(TTY_THROTTLED, &tty->flags)) {
     187         [ #  # ]:          0 :                 if (tty->flow_change != TTY_UNTHROTTLE_SAFE)
     188                 :            :                         ret = 1;
     189                 :            :                 else {
     190                 :          0 :                         clear_bit(TTY_THROTTLED, &tty->flags);
     191         [ #  # ]:          0 :                         if (tty->ops->unthrottle)
     192                 :          0 :                                 tty->ops->unthrottle(tty);
     193                 :            :                 }
     194                 :            :         }
     195                 :        370 :         mutex_unlock(&tty->throttle_mutex);
     196                 :            : 
     197                 :        370 :         return ret;
     198                 :            : }
     199                 :            : 
     200                 :            : /**
     201                 :            :  *      tty_wait_until_sent     -       wait for I/O to finish
     202                 :            :  *      @tty: tty we are waiting for
     203                 :            :  *      @timeout: how long we will wait
     204                 :            :  *
     205                 :            :  *      Wait for characters pending in a tty driver to hit the wire, or
     206                 :            :  *      for a timeout to occur (eg due to flow control)
     207                 :            :  *
     208                 :            :  *      Locking: none
     209                 :            :  */
     210                 :            : 
     211                 :          0 : void tty_wait_until_sent(struct tty_struct *tty, long timeout)
     212                 :            : {
     213                 :            : #ifdef TTY_DEBUG_WAIT_UNTIL_SENT
     214                 :            :         char buf[64];
     215                 :            : 
     216                 :            :         printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf));
     217                 :            : #endif
     218         [ +  - ]:        146 :         if (!timeout)
     219                 :            :                 timeout = MAX_SCHEDULE_TIMEOUT;
     220 [ -  + ][ +  + ]:        595 :         if (wait_event_interruptible_timeout(tty->write_wait,
         [ -  + ][ +  + ]
         [ +  - ][ +  - ]
     221                 :            :                         !tty_chars_in_buffer(tty), timeout) >= 0) {
     222         [ +  + ]:        146 :                 if (tty->ops->wait_until_sent)
     223                 :         43 :                         tty->ops->wait_until_sent(tty, timeout);
     224                 :            :         }
     225                 :        146 : }
     226                 :            : EXPORT_SYMBOL(tty_wait_until_sent);
     227                 :            : 
     228                 :            : 
     229                 :            : /*
     230                 :            :  *              Termios Helper Methods
     231                 :            :  */
     232                 :            : 
     233                 :          0 : static void unset_locked_termios(struct ktermios *termios,
     234                 :            :                                  struct ktermios *old,
     235                 :            :                                  struct ktermios *locked)
     236                 :            : {
     237                 :            :         int     i;
     238                 :            : 
     239                 :            : #define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
     240                 :            : 
     241         [ -  + ]:        298 :         if (!locked) {
     242                 :          0 :                 printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n");
     243                 :          0 :                 return;
     244                 :            :         }
     245                 :            : 
     246                 :        298 :         NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
     247                 :        298 :         NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
     248                 :        298 :         NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
     249                 :        298 :         NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
     250         [ -  + ]:        298 :         termios->c_line = locked->c_line ? old->c_line : termios->c_line;
     251         [ +  - ]:       5960 :         for (i = 0; i < NCCS; i++)
     252         [ -  + ]:       5662 :                 termios->c_cc[i] = locked->c_cc[i] ?
     253                 :            :                         old->c_cc[i] : termios->c_cc[i];
     254                 :            :         /* FIXME: What should we do for i/ospeed */
     255                 :            : }
     256                 :            : 
     257                 :            : /*
     258                 :            :  * Routine which returns the baud rate of the tty
     259                 :            :  *
     260                 :            :  * Note that the baud_table needs to be kept in sync with the
     261                 :            :  * include/asm/termbits.h file.
     262                 :            :  */
     263                 :            : static const speed_t baud_table[] = {
     264                 :            :         0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
     265                 :            :         9600, 19200, 38400, 57600, 115200, 230400, 460800,
     266                 :            : #ifdef __sparc__
     267                 :            :         76800, 153600, 307200, 614400, 921600
     268                 :            : #else
     269                 :            :         500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
     270                 :            :         2500000, 3000000, 3500000, 4000000
     271                 :            : #endif
     272                 :            : };
     273                 :            : 
     274                 :            : #ifndef __sparc__
     275                 :            : static const tcflag_t baud_bits[] = {
     276                 :            :         B0, B50, B75, B110, B134, B150, B200, B300, B600,
     277                 :            :         B1200, B1800, B2400, B4800, B9600, B19200, B38400,
     278                 :            :         B57600, B115200, B230400, B460800, B500000, B576000,
     279                 :            :         B921600, B1000000, B1152000, B1500000, B2000000, B2500000,
     280                 :            :         B3000000, B3500000, B4000000
     281                 :            : };
     282                 :            : #else
     283                 :            : static const tcflag_t baud_bits[] = {
     284                 :            :         B0, B50, B75, B110, B134, B150, B200, B300, B600,
     285                 :            :         B1200, B1800, B2400, B4800, B9600, B19200, B38400,
     286                 :            :         B57600, B115200, B230400, B460800, B76800, B153600,
     287                 :            :         B307200, B614400, B921600
     288                 :            : };
     289                 :            : #endif
     290                 :            : 
     291                 :            : static int n_baud_table = ARRAY_SIZE(baud_table);
     292                 :            : 
     293                 :            : /**
     294                 :            :  *      tty_termios_baud_rate
     295                 :            :  *      @termios: termios structure
     296                 :            :  *
     297                 :            :  *      Convert termios baud rate data into a speed. This should be called
     298                 :            :  *      with the termios lock held if this termios is a terminal termios
     299                 :            :  *      structure. May change the termios data. Device drivers can call this
     300                 :            :  *      function but should use ->c_[io]speed directly as they are updated.
     301                 :            :  *
     302                 :            :  *      Locking: none
     303                 :            :  */
     304                 :            : 
     305                 :          0 : speed_t tty_termios_baud_rate(struct ktermios *termios)
     306                 :            : {
     307                 :            :         unsigned int cbaud;
     308                 :            : 
     309                 :       1362 :         cbaud = termios->c_cflag & CBAUD;
     310                 :            : 
     311                 :            : #ifdef BOTHER
     312                 :            :         /* Magic token for arbitrary speed via c_ispeed/c_ospeed */
     313         [ -  + ]:       1362 :         if (cbaud == BOTHER)
     314                 :          0 :                 return termios->c_ospeed;
     315                 :            : #endif
     316         [ -  + ]:       1362 :         if (cbaud & CBAUDEX) {
     317                 :          0 :                 cbaud &= ~CBAUDEX;
     318                 :            : 
     319 [ #  # ][ #  # ]:          0 :                 if (cbaud < 1 || cbaud + 15 > n_baud_table)
     320                 :          0 :                         termios->c_cflag &= ~CBAUDEX;
     321                 :            :                 else
     322                 :            :                         cbaud += 15;
     323                 :            :         }
     324                 :       1362 :         return baud_table[cbaud];
     325                 :            : }
     326                 :            : EXPORT_SYMBOL(tty_termios_baud_rate);
     327                 :            : 
     328                 :            : /**
     329                 :            :  *      tty_termios_input_baud_rate
     330                 :            :  *      @termios: termios structure
     331                 :            :  *
     332                 :            :  *      Convert termios baud rate data into a speed. This should be called
     333                 :            :  *      with the termios lock held if this termios is a terminal termios
     334                 :            :  *      structure. May change the termios data. Device drivers can call this
     335                 :            :  *      function but should use ->c_[io]speed directly as they are updated.
     336                 :            :  *
     337                 :            :  *      Locking: none
     338                 :            :  */
     339                 :            : 
     340                 :          0 : speed_t tty_termios_input_baud_rate(struct ktermios *termios)
     341                 :            : {
     342                 :            : #ifdef IBSHIFT
     343                 :        681 :         unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD;
     344                 :            : 
     345         [ +  - ]:        681 :         if (cbaud == B0)
     346                 :        681 :                 return tty_termios_baud_rate(termios);
     347                 :            : 
     348                 :            :         /* Magic token for arbitrary speed via c_ispeed*/
     349         [ #  # ]:          0 :         if (cbaud == BOTHER)
     350                 :          0 :                 return termios->c_ispeed;
     351                 :            : 
     352         [ #  # ]:          0 :         if (cbaud & CBAUDEX) {
     353                 :          0 :                 cbaud &= ~CBAUDEX;
     354                 :            : 
     355 [ #  # ][ #  # ]:          0 :                 if (cbaud < 1 || cbaud + 15 > n_baud_table)
     356                 :          0 :                         termios->c_cflag &= ~(CBAUDEX << IBSHIFT);
     357                 :            :                 else
     358                 :            :                         cbaud += 15;
     359                 :            :         }
     360                 :          0 :         return baud_table[cbaud];
     361                 :            : #else
     362                 :            :         return tty_termios_baud_rate(termios);
     363                 :            : #endif
     364                 :            : }
     365                 :            : EXPORT_SYMBOL(tty_termios_input_baud_rate);
     366                 :            : 
     367                 :            : /**
     368                 :            :  *      tty_termios_encode_baud_rate
     369                 :            :  *      @termios: ktermios structure holding user requested state
     370                 :            :  *      @ispeed: input speed
     371                 :            :  *      @ospeed: output speed
     372                 :            :  *
     373                 :            :  *      Encode the speeds set into the passed termios structure. This is
     374                 :            :  *      used as a library helper for drivers so that they can report back
     375                 :            :  *      the actual speed selected when it differs from the speed requested
     376                 :            :  *
     377                 :            :  *      For maximal back compatibility with legacy SYS5/POSIX *nix behaviour
     378                 :            :  *      we need to carefully set the bits when the user does not get the
     379                 :            :  *      desired speed. We allow small margins and preserve as much of possible
     380                 :            :  *      of the input intent to keep compatibility.
     381                 :            :  *
     382                 :            :  *      Locking: Caller should hold termios lock. This is already held
     383                 :            :  *      when calling this function from the driver termios handler.
     384                 :            :  *
     385                 :            :  *      The ifdefs deal with platforms whose owners have yet to update them
     386                 :            :  *      and will all go away once this is done.
     387                 :            :  */
     388                 :            : 
     389                 :          0 : void tty_termios_encode_baud_rate(struct ktermios *termios,
     390                 :            :                                   speed_t ibaud, speed_t obaud)
     391                 :            : {
     392                 :            :         int i = 0;
     393                 :            :         int ifound = -1, ofound = -1;
     394                 :          0 :         int iclose = ibaud/50, oclose = obaud/50;
     395                 :            :         int ibinput = 0;
     396                 :            : 
     397         [ #  # ]:          0 :         if (obaud == 0)                 /* CD dropped             */
     398                 :            :                 ibaud = 0;              /* Clear ibaud to be sure */
     399                 :            : 
     400                 :          0 :         termios->c_ispeed = ibaud;
     401                 :          0 :         termios->c_ospeed = obaud;
     402                 :            : 
     403                 :            : #ifdef BOTHER
     404                 :            :         /* If the user asked for a precise weird speed give a precise weird
     405                 :            :            answer. If they asked for a Bfoo speed they many have problems
     406                 :            :            digesting non-exact replies so fuzz a bit */
     407                 :            : 
     408         [ #  # ]:          0 :         if ((termios->c_cflag & CBAUD) == BOTHER)
     409                 :            :                 oclose = 0;
     410         [ #  # ]:          0 :         if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)
     411                 :            :                 iclose = 0;
     412         [ #  # ]:          0 :         if ((termios->c_cflag >> IBSHIFT) & CBAUD)
     413                 :            :                 ibinput = 1;    /* An input speed was specified */
     414                 :            : #endif
     415                 :          0 :         termios->c_cflag &= ~CBAUD;
     416                 :            : 
     417                 :            :         /*
     418                 :            :          *      Our goal is to find a close match to the standard baud rate
     419                 :            :          *      returned. Walk the baud rate table and if we get a very close
     420                 :            :          *      match then report back the speed as a POSIX Bxxxx value by
     421                 :            :          *      preference
     422                 :            :          */
     423                 :            : 
     424                 :            :         do {
     425 [ #  # ][ #  # ]:          0 :                 if (obaud - oclose <= baud_table[i] &&
     426                 :          0 :                     obaud + oclose >= baud_table[i]) {
     427                 :          0 :                         termios->c_cflag |= baud_bits[i];
     428                 :            :                         ofound = i;
     429                 :            :                 }
     430 [ #  # ][ #  # ]:          0 :                 if (ibaud - iclose <= baud_table[i] &&
     431                 :          0 :                     ibaud + iclose >= baud_table[i]) {
     432                 :            :                         /* For the case input == output don't set IBAUD bits
     433                 :            :                            if the user didn't do so */
     434         [ #  # ]:          0 :                         if (ofound == i && !ibinput)
     435                 :            :                                 ifound  = i;
     436                 :            : #ifdef IBSHIFT
     437                 :            :                         else {
     438                 :            :                                 ifound = i;
     439                 :          0 :                                 termios->c_cflag |= (baud_bits[i] << IBSHIFT);
     440                 :            :                         }
     441                 :            : #endif
     442                 :            :                 }
     443         [ #  # ]:          0 :         } while (++i < n_baud_table);
     444                 :            : 
     445                 :            :         /*
     446                 :            :          *      If we found no match then use BOTHER if provided or warn
     447                 :            :          *      the user their platform maintainer needs to wake up if not.
     448                 :            :          */
     449                 :            : #ifdef BOTHER
     450         [ #  # ]:          0 :         if (ofound == -1)
     451                 :          0 :                 termios->c_cflag |= BOTHER;
     452                 :            :         /* Set exact input bits only if the input and output differ or the
     453                 :            :            user already did */
     454 [ #  # ][ #  # ]:          0 :         if (ifound == -1 && (ibaud != obaud || ibinput))
     455                 :          0 :                 termios->c_cflag |= (BOTHER << IBSHIFT);
     456                 :            : #else
     457                 :            :         if (ifound == -1 || ofound == -1) {
     458                 :            :                 printk_once(KERN_WARNING "tty: Unable to return correct "
     459                 :            :                           "speed data as your architecture needs updating.\n");
     460                 :            :         }
     461                 :            : #endif
     462                 :          0 : }
     463                 :            : EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
     464                 :            : 
     465                 :            : /**
     466                 :            :  *      tty_encode_baud_rate            -       set baud rate of the tty
     467                 :            :  *      @ibaud: input baud rate
     468                 :            :  *      @obad: output baud rate
     469                 :            :  *
     470                 :            :  *      Update the current termios data for the tty with the new speed
     471                 :            :  *      settings. The caller must hold the termios_rwsem for the tty in
     472                 :            :  *      question.
     473                 :            :  */
     474                 :            : 
     475                 :          0 : void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
     476                 :            : {
     477                 :          0 :         tty_termios_encode_baud_rate(&tty->termios, ibaud, obaud);
     478                 :          0 : }
     479                 :            : EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
     480                 :            : 
     481                 :            : /**
     482                 :            :  *      tty_termios_copy_hw     -       copy hardware settings
     483                 :            :  *      @new: New termios
     484                 :            :  *      @old: Old termios
     485                 :            :  *
     486                 :            :  *      Propagate the hardware specific terminal setting bits from
     487                 :            :  *      the old termios structure to the new one. This is used in cases
     488                 :            :  *      where the hardware does not support reconfiguration or as a helper
     489                 :            :  *      in some cases where only minimal reconfiguration is supported
     490                 :            :  */
     491                 :            : 
     492                 :          0 : void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old)
     493                 :            : {
     494                 :            :         /* The bits a dumb device handles in software. Smart devices need
     495                 :            :            to always provide a set_termios method */
     496                 :        128 :         new->c_cflag &= HUPCL | CREAD | CLOCAL;
     497                 :        128 :         new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
     498                 :        128 :         new->c_ispeed = old->c_ispeed;
     499                 :        128 :         new->c_ospeed = old->c_ospeed;
     500                 :          0 : }
     501                 :            : EXPORT_SYMBOL(tty_termios_copy_hw);
     502                 :            : 
     503                 :            : /**
     504                 :            :  *      tty_termios_hw_change   -       check for setting change
     505                 :            :  *      @a: termios
     506                 :            :  *      @b: termios to compare
     507                 :            :  *
     508                 :            :  *      Check if any of the bits that affect a dumb device have changed
     509                 :            :  *      between the two termios structures, or a speed change is needed.
     510                 :            :  */
     511                 :            : 
     512                 :          0 : int tty_termios_hw_change(struct ktermios *a, struct ktermios *b)
     513                 :            : {
     514 [ #  # ][ #  # ]:          0 :         if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
     515                 :            :                 return 1;
     516         [ #  # ]:          0 :         if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL))
     517                 :            :                 return 1;
     518                 :          0 :         return 0;
     519                 :            : }
     520                 :            : EXPORT_SYMBOL(tty_termios_hw_change);
     521                 :            : 
     522                 :            : /**
     523                 :            :  *      tty_set_termios         -       update termios values
     524                 :            :  *      @tty: tty to update
     525                 :            :  *      @new_termios: desired new value
     526                 :            :  *
     527                 :            :  *      Perform updates to the termios values set on this terminal. There
     528                 :            :  *      is a bit of layering violation here with n_tty in terms of the
     529                 :            :  *      internal knowledge of this function.
     530                 :            :  *
     531                 :            :  *      Locking: termios_rwsem
     532                 :            :  */
     533                 :            : 
     534                 :          0 : int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
     535                 :            : {
     536                 :            :         struct ktermios old_termios;
     537                 :            :         struct tty_ldisc *ld;
     538                 :            :         unsigned long flags;
     539                 :            : 
     540                 :            :         /*
     541                 :            :          *      Perform the actual termios internal changes under lock.
     542                 :            :          */
     543                 :            : 
     544                 :            : 
     545                 :            :         /* FIXME: we need to decide on some locking/ordering semantics
     546                 :            :            for the set_termios notification eventually */
     547                 :        298 :         down_write(&tty->termios_rwsem);
     548                 :        298 :         old_termios = tty->termios;
     549                 :        298 :         tty->termios = *new_termios;
     550                 :        298 :         unset_locked_termios(&tty->termios, &old_termios, &tty->termios_locked);
     551                 :            : 
     552                 :            :         /* See if packet mode change of state. */
     553 [ +  + ][ -  + ]:        298 :         if (tty->link && tty->link->packet) {
     554                 :          0 :                 int extproc = (old_termios.c_lflag & EXTPROC) |
     555                 :          0 :                                 (tty->termios.c_lflag & EXTPROC);
     556                 :          0 :                 int old_flow = ((old_termios.c_iflag & IXON) &&
     557 [ #  # ][ #  # ]:          0 :                                 (old_termios.c_cc[VSTOP] == '\023') &&
     558                 :            :                                 (old_termios.c_cc[VSTART] == '\021'));
     559                 :          0 :                 int new_flow = (I_IXON(tty) &&
     560 [ #  # ][ #  # ]:          0 :                                 STOP_CHAR(tty) == '\023' &&
     561                 :            :                                 START_CHAR(tty) == '\021');
     562         [ #  # ]:          0 :                 if ((old_flow != new_flow) || extproc) {
     563                 :          0 :                         spin_lock_irqsave(&tty->ctrl_lock, flags);
     564         [ #  # ]:          0 :                         if (old_flow != new_flow) {
     565                 :          0 :                                 tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
     566         [ #  # ]:          0 :                                 if (new_flow)
     567                 :          0 :                                         tty->ctrl_status |= TIOCPKT_DOSTOP;
     568                 :            :                                 else
     569                 :          0 :                                         tty->ctrl_status |= TIOCPKT_NOSTOP;
     570                 :            :                         }
     571         [ #  # ]:          0 :                         if (extproc)
     572                 :          0 :                                 tty->ctrl_status |= TIOCPKT_IOCTL;
     573                 :            :                         spin_unlock_irqrestore(&tty->ctrl_lock, flags);
     574                 :          0 :                         wake_up_interruptible(&tty->link->read_wait);
     575                 :            :                 }
     576                 :            :         }
     577                 :            : 
     578         [ +  + ]:        298 :         if (tty->ops->set_termios)
     579                 :        170 :                 (*tty->ops->set_termios)(tty, &old_termios);
     580                 :            :         else
     581                 :            :                 tty_termios_copy_hw(&tty->termios, &old_termios);
     582                 :            : 
     583                 :        298 :         ld = tty_ldisc_ref(tty);
     584         [ +  - ]:        298 :         if (ld != NULL) {
     585         [ +  - ]:        298 :                 if (ld->ops->set_termios)
     586                 :        298 :                         (ld->ops->set_termios)(tty, &old_termios);
     587                 :        298 :                 tty_ldisc_deref(ld);
     588                 :            :         }
     589                 :        298 :         up_write(&tty->termios_rwsem);
     590                 :        298 :         return 0;
     591                 :            : }
     592                 :            : EXPORT_SYMBOL_GPL(tty_set_termios);
     593                 :            : 
     594                 :            : /**
     595                 :            :  *      set_termios             -       set termios values for a tty
     596                 :            :  *      @tty: terminal device
     597                 :            :  *      @arg: user data
     598                 :            :  *      @opt: option information
     599                 :            :  *
     600                 :            :  *      Helper function to prepare termios data and run necessary other
     601                 :            :  *      functions before using tty_set_termios to do the actual changes.
     602                 :            :  *
     603                 :            :  *      Locking:
     604                 :            :  *              Called functions take ldisc and termios_rwsem locks
     605                 :            :  */
     606                 :            : 
     607                 :          0 : static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
     608                 :            : {
     609                 :            :         struct ktermios tmp_termios;
     610                 :            :         struct tty_ldisc *ld;
     611                 :        298 :         int retval = tty_check_change(tty);
     612                 :            : 
     613         [ +  - ]:        298 :         if (retval)
     614                 :            :                 return retval;
     615                 :            : 
     616                 :        298 :         down_read(&tty->termios_rwsem);
     617                 :        298 :         tmp_termios = tty->termios;
     618                 :        298 :         up_read(&tty->termios_rwsem);
     619                 :            : 
     620         [ +  + ]:        596 :         if (opt & TERMIOS_TERMIO) {
     621         [ +  - ]:        131 :                 if (user_termio_to_kernel_termios(&tmp_termios,
     622                 :            :                                                 (struct termio __user *)arg))
     623                 :            :                         return -EFAULT;
     624                 :            : #ifdef TCGETS2
     625         [ +  - ]:        167 :         } else if (opt & TERMIOS_OLD) {
     626         [ +  - ]:        167 :                 if (user_termios_to_kernel_termios_1(&tmp_termios,
     627                 :            :                                                 (struct termios __user *)arg))
     628                 :            :                         return -EFAULT;
     629                 :            :         } else {
     630         [ #  # ]:          0 :                 if (user_termios_to_kernel_termios(&tmp_termios,
     631                 :            :                                                 (struct termios2 __user *)arg))
     632                 :            :                         return -EFAULT;
     633                 :            :         }
     634                 :            : #else
     635                 :            :         } else if (user_termios_to_kernel_termios(&tmp_termios,
     636                 :            :                                         (struct termios __user *)arg))
     637                 :            :                 return -EFAULT;
     638                 :            : #endif
     639                 :            : 
     640                 :            :         /* If old style Bfoo values are used then load c_ispeed/c_ospeed
     641                 :            :          * with the real speed so its unconditionally usable */
     642                 :        298 :         tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
     643                 :        298 :         tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
     644                 :            : 
     645                 :        298 :         ld = tty_ldisc_ref(tty);
     646                 :            : 
     647         [ +  - ]:        298 :         if (ld != NULL) {
     648 [ +  + ][ +  - ]:        298 :                 if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
     649                 :          8 :                         ld->ops->flush_buffer(tty);
     650                 :        298 :                 tty_ldisc_deref(ld);
     651                 :            :         }
     652                 :            : 
     653         [ +  + ]:        298 :         if (opt & TERMIOS_WAIT) {
     654                 :        144 :                 tty_wait_until_sent(tty, 0);
     655         [ +  - ]:        144 :                 if (signal_pending(current))
     656                 :            :                         return -ERESTARTSYS;
     657                 :            :         }
     658                 :            : 
     659                 :        298 :         tty_set_termios(tty, &tmp_termios);
     660                 :            : 
     661                 :            :         /* FIXME: Arguably if tmp_termios == tty->termios AND the
     662                 :            :            actual requested termios was not tmp_termios then we may
     663                 :            :            want to return an error as no user requested change has
     664                 :            :            succeeded */
     665                 :        298 :         return 0;
     666                 :            : }
     667                 :            : 
     668                 :          0 : static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
     669                 :            : {
     670                 :       8758 :         down_read(&tty->termios_rwsem);
     671                 :       8758 :         *kterm = tty->termios;
     672                 :       8758 :         up_read(&tty->termios_rwsem);
     673                 :       8758 : }
     674                 :            : 
     675                 :          0 : static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
     676                 :            : {
     677                 :          0 :         down_read(&tty->termios_rwsem);
     678                 :          0 :         *kterm = tty->termios_locked;
     679                 :          0 :         up_read(&tty->termios_rwsem);
     680                 :          0 : }
     681                 :            : 
     682                 :          0 : static int get_termio(struct tty_struct *tty, struct termio __user *termio)
     683                 :            : {
     684                 :            :         struct ktermios kterm;
     685                 :        257 :         copy_termios(tty, &kterm);
     686         [ +  + ]:        257 :         if (kernel_termios_to_user_termio(termio, &kterm))
     687                 :            :                 return -EFAULT;
     688                 :        129 :         return 0;
     689                 :            : }
     690                 :            : 
     691                 :            : 
     692                 :            : #ifdef TCGETX
     693                 :            : 
     694                 :            : /**
     695                 :            :  *      set_termiox     -       set termiox fields if possible
     696                 :            :  *      @tty: terminal
     697                 :            :  *      @arg: termiox structure from user
     698                 :            :  *      @opt: option flags for ioctl type
     699                 :            :  *
     700                 :            :  *      Implement the device calling points for the SYS5 termiox ioctl
     701                 :            :  *      interface in Linux
     702                 :            :  */
     703                 :            : 
     704                 :          0 : static int set_termiox(struct tty_struct *tty, void __user *arg, int opt)
     705                 :            : {
     706                 :            :         struct termiox tnew;
     707                 :            :         struct tty_ldisc *ld;
     708                 :            : 
     709         [ #  # ]:          0 :         if (tty->termiox == NULL)
     710                 :            :                 return -EINVAL;
     711         [ #  # ]:          0 :         if (copy_from_user(&tnew, arg, sizeof(struct termiox)))
     712                 :            :                 return -EFAULT;
     713                 :            : 
     714                 :          0 :         ld = tty_ldisc_ref(tty);
     715         [ #  # ]:          0 :         if (ld != NULL) {
     716 [ #  # ][ #  # ]:          0 :                 if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
     717                 :          0 :                         ld->ops->flush_buffer(tty);
     718                 :          0 :                 tty_ldisc_deref(ld);
     719                 :            :         }
     720         [ #  # ]:          0 :         if (opt & TERMIOS_WAIT) {
     721                 :          0 :                 tty_wait_until_sent(tty, 0);
     722         [ #  # ]:          0 :                 if (signal_pending(current))
     723                 :            :                         return -ERESTARTSYS;
     724                 :            :         }
     725                 :            : 
     726                 :          0 :         down_write(&tty->termios_rwsem);
     727         [ #  # ]:          0 :         if (tty->ops->set_termiox)
     728                 :          0 :                 tty->ops->set_termiox(tty, &tnew);
     729                 :          0 :         up_write(&tty->termios_rwsem);
     730                 :          0 :         return 0;
     731                 :            : }
     732                 :            : 
     733                 :            : #endif
     734                 :            : 
     735                 :            : 
     736                 :            : #ifdef TIOCGETP
     737                 :            : /*
     738                 :            :  * These are deprecated, but there is limited support..
     739                 :            :  *
     740                 :            :  * The "sg_flags" translation is a joke..
     741                 :            :  */
     742                 :            : static int get_sgflags(struct tty_struct *tty)
     743                 :            : {
     744                 :            :         int flags = 0;
     745                 :            : 
     746                 :            :         if (!(tty->termios.c_lflag & ICANON)) {
     747                 :            :                 if (tty->termios.c_lflag & ISIG)
     748                 :            :                         flags |= 0x02;          /* cbreak */
     749                 :            :                 else
     750                 :            :                         flags |= 0x20;          /* raw */
     751                 :            :         }
     752                 :            :         if (tty->termios.c_lflag & ECHO)
     753                 :            :                 flags |= 0x08;                  /* echo */
     754                 :            :         if (tty->termios.c_oflag & OPOST)
     755                 :            :                 if (tty->termios.c_oflag & ONLCR)
     756                 :            :                         flags |= 0x10;          /* crmod */
     757                 :            :         return flags;
     758                 :            : }
     759                 :            : 
     760                 :            : static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
     761                 :            : {
     762                 :            :         struct sgttyb tmp;
     763                 :            : 
     764                 :            :         down_read(&tty->termios_rwsem);
     765                 :            :         tmp.sg_ispeed = tty->termios.c_ispeed;
     766                 :            :         tmp.sg_ospeed = tty->termios.c_ospeed;
     767                 :            :         tmp.sg_erase = tty->termios.c_cc[VERASE];
     768                 :            :         tmp.sg_kill = tty->termios.c_cc[VKILL];
     769                 :            :         tmp.sg_flags = get_sgflags(tty);
     770                 :            :         up_read(&tty->termios_rwsem);
     771                 :            : 
     772                 :            :         return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
     773                 :            : }
     774                 :            : 
     775                 :            : static void set_sgflags(struct ktermios *termios, int flags)
     776                 :            : {
     777                 :            :         termios->c_iflag = ICRNL | IXON;
     778                 :            :         termios->c_oflag = 0;
     779                 :            :         termios->c_lflag = ISIG | ICANON;
     780                 :            :         if (flags & 0x02) { /* cbreak */
     781                 :            :                 termios->c_iflag = 0;
     782                 :            :                 termios->c_lflag &= ~ICANON;
     783                 :            :         }
     784                 :            :         if (flags & 0x08) {         /* echo */
     785                 :            :                 termios->c_lflag |= ECHO | ECHOE | ECHOK |
     786                 :            :                                     ECHOCTL | ECHOKE | IEXTEN;
     787                 :            :         }
     788                 :            :         if (flags & 0x10) {         /* crmod */
     789                 :            :                 termios->c_oflag |= OPOST | ONLCR;
     790                 :            :         }
     791                 :            :         if (flags & 0x20) { /* raw */
     792                 :            :                 termios->c_iflag = 0;
     793                 :            :                 termios->c_lflag &= ~(ISIG | ICANON);
     794                 :            :         }
     795                 :            :         if (!(termios->c_lflag & ICANON)) {
     796                 :            :                 termios->c_cc[VMIN] = 1;
     797                 :            :                 termios->c_cc[VTIME] = 0;
     798                 :            :         }
     799                 :            : }
     800                 :            : 
     801                 :            : /**
     802                 :            :  *      set_sgttyb              -       set legacy terminal values
     803                 :            :  *      @tty: tty structure
     804                 :            :  *      @sgttyb: pointer to old style terminal structure
     805                 :            :  *
     806                 :            :  *      Updates a terminal from the legacy BSD style terminal information
     807                 :            :  *      structure.
     808                 :            :  *
     809                 :            :  *      Locking: termios_rwsem
     810                 :            :  */
     811                 :            : 
     812                 :            : static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
     813                 :            : {
     814                 :            :         int retval;
     815                 :            :         struct sgttyb tmp;
     816                 :            :         struct ktermios termios;
     817                 :            : 
     818                 :            :         retval = tty_check_change(tty);
     819                 :            :         if (retval)
     820                 :            :                 return retval;
     821                 :            : 
     822                 :            :         if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
     823                 :            :                 return -EFAULT;
     824                 :            : 
     825                 :            :         down_write(&tty->termios_rwsem);
     826                 :            :         termios = tty->termios;
     827                 :            :         termios.c_cc[VERASE] = tmp.sg_erase;
     828                 :            :         termios.c_cc[VKILL] = tmp.sg_kill;
     829                 :            :         set_sgflags(&termios, tmp.sg_flags);
     830                 :            :         /* Try and encode into Bfoo format */
     831                 :            : #ifdef BOTHER
     832                 :            :         tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
     833                 :            :                                                 termios.c_ospeed);
     834                 :            : #endif
     835                 :            :         up_write(&tty->termios_rwsem);
     836                 :            :         tty_set_termios(tty, &termios);
     837                 :            :         return 0;
     838                 :            : }
     839                 :            : #endif
     840                 :            : 
     841                 :            : #ifdef TIOCGETC
     842                 :            : static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
     843                 :            : {
     844                 :            :         struct tchars tmp;
     845                 :            : 
     846                 :            :         down_read(&tty->termios_rwsem);
     847                 :            :         tmp.t_intrc = tty->termios.c_cc[VINTR];
     848                 :            :         tmp.t_quitc = tty->termios.c_cc[VQUIT];
     849                 :            :         tmp.t_startc = tty->termios.c_cc[VSTART];
     850                 :            :         tmp.t_stopc = tty->termios.c_cc[VSTOP];
     851                 :            :         tmp.t_eofc = tty->termios.c_cc[VEOF];
     852                 :            :         tmp.t_brkc = tty->termios.c_cc[VEOL2];       /* what is brkc anyway? */
     853                 :            :         up_read(&tty->termios_rwsem);
     854                 :            :         return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
     855                 :            : }
     856                 :            : 
     857                 :            : static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
     858                 :            : {
     859                 :            :         struct tchars tmp;
     860                 :            : 
     861                 :            :         if (copy_from_user(&tmp, tchars, sizeof(tmp)))
     862                 :            :                 return -EFAULT;
     863                 :            :         down_write(&tty->termios_rwsem);
     864                 :            :         tty->termios.c_cc[VINTR] = tmp.t_intrc;
     865                 :            :         tty->termios.c_cc[VQUIT] = tmp.t_quitc;
     866                 :            :         tty->termios.c_cc[VSTART] = tmp.t_startc;
     867                 :            :         tty->termios.c_cc[VSTOP] = tmp.t_stopc;
     868                 :            :         tty->termios.c_cc[VEOF] = tmp.t_eofc;
     869                 :            :         tty->termios.c_cc[VEOL2] = tmp.t_brkc;       /* what is brkc anyway? */
     870                 :            :         up_write(&tty->termios_rwsem);
     871                 :            :         return 0;
     872                 :            : }
     873                 :            : #endif
     874                 :            : 
     875                 :            : #ifdef TIOCGLTC
     876                 :            : static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
     877                 :            : {
     878                 :            :         struct ltchars tmp;
     879                 :            : 
     880                 :            :         down_read(&tty->termios_rwsem);
     881                 :            :         tmp.t_suspc = tty->termios.c_cc[VSUSP];
     882                 :            :         /* what is dsuspc anyway? */
     883                 :            :         tmp.t_dsuspc = tty->termios.c_cc[VSUSP];
     884                 :            :         tmp.t_rprntc = tty->termios.c_cc[VREPRINT];
     885                 :            :         /* what is flushc anyway? */
     886                 :            :         tmp.t_flushc = tty->termios.c_cc[VEOL2];
     887                 :            :         tmp.t_werasc = tty->termios.c_cc[VWERASE];
     888                 :            :         tmp.t_lnextc = tty->termios.c_cc[VLNEXT];
     889                 :            :         up_read(&tty->termios_rwsem);
     890                 :            :         return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
     891                 :            : }
     892                 :            : 
     893                 :            : static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
     894                 :            : {
     895                 :            :         struct ltchars tmp;
     896                 :            : 
     897                 :            :         if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
     898                 :            :                 return -EFAULT;
     899                 :            : 
     900                 :            :         down_write(&tty->termios_rwsem);
     901                 :            :         tty->termios.c_cc[VSUSP] = tmp.t_suspc;
     902                 :            :         /* what is dsuspc anyway? */
     903                 :            :         tty->termios.c_cc[VEOL2] = tmp.t_dsuspc;
     904                 :            :         tty->termios.c_cc[VREPRINT] = tmp.t_rprntc;
     905                 :            :         /* what is flushc anyway? */
     906                 :            :         tty->termios.c_cc[VEOL2] = tmp.t_flushc;
     907                 :            :         tty->termios.c_cc[VWERASE] = tmp.t_werasc;
     908                 :            :         tty->termios.c_cc[VLNEXT] = tmp.t_lnextc;
     909                 :            :         up_write(&tty->termios_rwsem);
     910                 :            :         return 0;
     911                 :            : }
     912                 :            : #endif
     913                 :            : 
     914                 :            : /**
     915                 :            :  *      send_prio_char          -       send priority character
     916                 :            :  *
     917                 :            :  *      Send a high priority character to the tty even if stopped
     918                 :            :  *
     919                 :            :  *      Locking: none for xchar method, write ordering for write method.
     920                 :            :  */
     921                 :            : 
     922                 :          0 : static int send_prio_char(struct tty_struct *tty, char ch)
     923                 :            : {
     924                 :          0 :         int     was_stopped = tty->stopped;
     925                 :            : 
     926         [ #  # ]:          0 :         if (tty->ops->send_xchar) {
     927                 :          0 :                 tty->ops->send_xchar(tty, ch);
     928                 :          0 :                 return 0;
     929                 :            :         }
     930                 :            : 
     931         [ #  # ]:          0 :         if (tty_write_lock(tty, 0) < 0)
     932                 :            :                 return -ERESTARTSYS;
     933                 :            : 
     934         [ #  # ]:          0 :         if (was_stopped)
     935                 :          0 :                 start_tty(tty);
     936                 :          0 :         tty->ops->write(tty, &ch, 1);
     937         [ #  # ]:          0 :         if (was_stopped)
     938                 :          0 :                 stop_tty(tty);
     939                 :          0 :         tty_write_unlock(tty);
     940                 :          0 :         return 0;
     941                 :            : }
     942                 :            : 
     943                 :            : /**
     944                 :            :  *      tty_change_softcar      -       carrier change ioctl helper
     945                 :            :  *      @tty: tty to update
     946                 :            :  *      @arg: enable/disable CLOCAL
     947                 :            :  *
     948                 :            :  *      Perform a change to the CLOCAL state and call into the driver
     949                 :            :  *      layer to make it visible. All done with the termios rwsem
     950                 :            :  */
     951                 :            : 
     952                 :          0 : static int tty_change_softcar(struct tty_struct *tty, int arg)
     953                 :            : {
     954                 :            :         int ret = 0;
     955         [ #  # ]:          0 :         int bit = arg ? CLOCAL : 0;
     956                 :            :         struct ktermios old;
     957                 :            : 
     958                 :          0 :         down_write(&tty->termios_rwsem);
     959                 :          0 :         old = tty->termios;
     960                 :          0 :         tty->termios.c_cflag &= ~CLOCAL;
     961                 :          0 :         tty->termios.c_cflag |= bit;
     962         [ #  # ]:          0 :         if (tty->ops->set_termios)
     963                 :          0 :                 tty->ops->set_termios(tty, &old);
     964         [ #  # ]:          0 :         if ((tty->termios.c_cflag & CLOCAL) != bit)
     965                 :            :                 ret = -EINVAL;
     966                 :          0 :         up_write(&tty->termios_rwsem);
     967                 :          0 :         return ret;
     968                 :            : }
     969                 :            : 
     970                 :            : /**
     971                 :            :  *      tty_mode_ioctl          -       mode related ioctls
     972                 :            :  *      @tty: tty for the ioctl
     973                 :            :  *      @file: file pointer for the tty
     974                 :            :  *      @cmd: command
     975                 :            :  *      @arg: ioctl argument
     976                 :            :  *
     977                 :            :  *      Perform non line discipline specific mode control ioctls. This
     978                 :            :  *      is designed to be called by line disciplines to ensure they provide
     979                 :            :  *      consistent mode setting.
     980                 :            :  */
     981                 :            : 
     982                 :          0 : int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
     983                 :            :                         unsigned int cmd, unsigned long arg)
     984                 :            : {
     985                 :            :         struct tty_struct *real_tty;
     986                 :       9120 :         void __user *p = (void __user *)arg;
     987                 :            :         int ret = 0;
     988                 :            :         struct ktermios kterm;
     989                 :            : 
     990         [ -  + ]:       9120 :         BUG_ON(file == NULL);
     991                 :            : 
     992         [ +  + ]:       9120 :         if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
     993                 :            :             tty->driver->subtype == PTY_TYPE_MASTER)
     994                 :       1052 :                 real_tty = tty->link;
     995                 :            :         else
     996                 :            :                 real_tty = tty;
     997                 :            : 
     998   [ +  +  +  +  :       9120 :         switch (cmd) {
          -  -  -  -  +  
          +  +  +  -  -  
          -  -  -  -  -  
                   -  + ]
     999                 :            : #ifdef TIOCGETP
    1000                 :            :         case TIOCGETP:
    1001                 :            :                 return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
    1002                 :            :         case TIOCSETP:
    1003                 :            :         case TIOCSETN:
    1004                 :            :                 return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
    1005                 :            : #endif
    1006                 :            : #ifdef TIOCGETC
    1007                 :            :         case TIOCGETC:
    1008                 :            :                 return get_tchars(real_tty, p);
    1009                 :            :         case TIOCSETC:
    1010                 :            :                 return set_tchars(real_tty, p);
    1011                 :            : #endif
    1012                 :            : #ifdef TIOCGLTC
    1013                 :            :         case TIOCGLTC:
    1014                 :            :                 return get_ltchars(real_tty, p);
    1015                 :            :         case TIOCSLTC:
    1016                 :            :                 return set_ltchars(real_tty, p);
    1017                 :            : #endif
    1018                 :            :         case TCSETSF:
    1019                 :          7 :                 return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
    1020                 :            :         case TCSETSW:
    1021                 :        135 :                 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
    1022                 :            :         case TCSETS:
    1023                 :         25 :                 return set_termios(real_tty, p, TERMIOS_OLD);
    1024                 :            : #ifndef TCGETS2
    1025                 :            :         case TCGETS:
    1026                 :            :                 copy_termios(real_tty, &kterm);
    1027                 :            :                 if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
    1028                 :            :                         ret = -EFAULT;
    1029                 :            :                 return ret;
    1030                 :            : #else
    1031                 :            :         case TCGETS:
    1032                 :       8501 :                 copy_termios(real_tty, &kterm);
    1033         [ -  + ]:       8501 :                 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
    1034                 :            :                         ret = -EFAULT;
    1035                 :       8501 :                 return ret;
    1036                 :            :         case TCGETS2:
    1037                 :          0 :                 copy_termios(real_tty, &kterm);
    1038         [ #  # ]:          0 :                 if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm))
    1039                 :            :                         ret = -EFAULT;
    1040                 :          0 :                 return ret;
    1041                 :            :         case TCSETSF2:
    1042                 :          0 :                 return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT);
    1043                 :            :         case TCSETSW2:
    1044                 :          0 :                 return set_termios(real_tty, p, TERMIOS_WAIT);
    1045                 :            :         case TCSETS2:
    1046                 :          0 :                 return set_termios(real_tty, p, 0);
    1047                 :            : #endif
    1048                 :            :         case TCGETA:
    1049                 :        257 :                 return get_termio(real_tty, p);
    1050                 :            :         case TCSETAF:
    1051                 :          1 :                 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
    1052                 :            :         case TCSETAW:
    1053                 :          1 :                 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
    1054                 :            :         case TCSETA:
    1055                 :        129 :                 return set_termios(real_tty, p, TERMIOS_TERMIO);
    1056                 :            : #ifndef TCGETS2
    1057                 :            :         case TIOCGLCKTRMIOS:
    1058                 :            :                 copy_termios_locked(real_tty, &kterm);
    1059                 :            :                 if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
    1060                 :            :                         ret = -EFAULT;
    1061                 :            :                 return ret;
    1062                 :            :         case TIOCSLCKTRMIOS:
    1063                 :            :                 if (!capable(CAP_SYS_ADMIN))
    1064                 :            :                         return -EPERM;
    1065                 :            :                 copy_termios_locked(real_tty, &kterm);
    1066                 :            :                 if (user_termios_to_kernel_termios(&kterm,
    1067                 :            :                                                (struct termios __user *) arg))
    1068                 :            :                         return -EFAULT;
    1069                 :            :                 down_write(&real_tty->termios_rwsem);
    1070                 :            :                 real_tty->termios_locked = kterm;
    1071                 :            :                 up_write(&real_tty->termios_rwsem);
    1072                 :            :                 return 0;
    1073                 :            : #else
    1074                 :            :         case TIOCGLCKTRMIOS:
    1075                 :          0 :                 copy_termios_locked(real_tty, &kterm);
    1076         [ #  # ]:          0 :                 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
    1077                 :            :                         ret = -EFAULT;
    1078                 :          0 :                 return ret;
    1079                 :            :         case TIOCSLCKTRMIOS:
    1080         [ #  # ]:          0 :                 if (!capable(CAP_SYS_ADMIN))
    1081                 :            :                         return -EPERM;
    1082                 :          0 :                 copy_termios_locked(real_tty, &kterm);
    1083         [ #  # ]:          0 :                 if (user_termios_to_kernel_termios_1(&kterm,
    1084                 :            :                                                (struct termios __user *) arg))
    1085                 :            :                         return -EFAULT;
    1086                 :          0 :                 down_write(&real_tty->termios_rwsem);
    1087                 :          0 :                 real_tty->termios_locked = kterm;
    1088                 :          0 :                 up_write(&real_tty->termios_rwsem);
    1089                 :          0 :                 return ret;
    1090                 :            : #endif
    1091                 :            : #ifdef TCGETX
    1092                 :            :         case TCGETX: {
    1093                 :            :                 struct termiox ktermx;
    1094         [ #  # ]:          0 :                 if (real_tty->termiox == NULL)
    1095                 :            :                         return -EINVAL;
    1096                 :          0 :                 down_read(&real_tty->termios_rwsem);
    1097                 :          0 :                 memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox));
    1098                 :          0 :                 up_read(&real_tty->termios_rwsem);
    1099         [ #  # ]:          0 :                 if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
    1100                 :            :                         ret = -EFAULT;
    1101                 :          0 :                 return ret;
    1102                 :            :         }
    1103                 :            :         case TCSETX:
    1104                 :          0 :                 return set_termiox(real_tty, p, 0);
    1105                 :            :         case TCSETXW:
    1106                 :          0 :                 return set_termiox(real_tty, p, TERMIOS_WAIT);
    1107                 :            :         case TCSETXF:
    1108                 :          0 :                 return set_termiox(real_tty, p, TERMIOS_FLUSH);
    1109                 :            : #endif          
    1110                 :            :         case TIOCGSOFTCAR:
    1111                 :          0 :                 copy_termios(real_tty, &kterm);
    1112                 :          0 :                 ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0,
    1113                 :            :                                                 (int __user *)arg);
    1114                 :          0 :                 return ret;
    1115                 :            :         case TIOCSSOFTCAR:
    1116         [ #  # ]:          0 :                 if (get_user(arg, (unsigned int __user *) arg))
    1117                 :            :                         return -EFAULT;
    1118                 :          0 :                 return tty_change_softcar(real_tty, arg);
    1119                 :            :         default:
    1120                 :            :                 return -ENOIOCTLCMD;
    1121                 :            :         }
    1122                 :            : }
    1123                 :            : EXPORT_SYMBOL_GPL(tty_mode_ioctl);
    1124                 :            : 
    1125                 :            : 
    1126                 :            : /* Caller guarantees ldisc reference is held */
    1127                 :          0 : static int __tty_perform_flush(struct tty_struct *tty, unsigned long arg)
    1128                 :            : {
    1129                 :        128 :         struct tty_ldisc *ld = tty->ldisc;
    1130                 :            : 
    1131   [ -  +  -  - ]:        128 :         switch (arg) {
    1132                 :            :         case TCIFLUSH:
    1133 [ #  # ][ #  # ]:          0 :                 if (ld && ld->ops->flush_buffer) {
    1134                 :          0 :                         ld->ops->flush_buffer(tty);
    1135                 :          0 :                         tty_unthrottle(tty);
    1136                 :            :                 }
    1137                 :            :                 break;
    1138                 :            :         case TCIOFLUSH:
    1139 [ +  - ][ +  - ]:        128 :                 if (ld && ld->ops->flush_buffer) {
    1140                 :        128 :                         ld->ops->flush_buffer(tty);
    1141                 :        128 :                         tty_unthrottle(tty);
    1142                 :            :                 }
    1143                 :            :                 /* fall through */
    1144                 :            :         case TCOFLUSH:
    1145                 :            :                 tty_driver_flush_buffer(tty);
    1146                 :            :                 break;
    1147                 :            :         default:
    1148                 :            :                 return -EINVAL;
    1149                 :            :         }
    1150                 :            :         return 0;
    1151                 :            : }
    1152                 :            : 
    1153                 :          0 : int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
    1154                 :            : {
    1155                 :            :         struct tty_ldisc *ld;
    1156                 :          0 :         int retval = tty_check_change(tty);
    1157         [ #  # ]:          0 :         if (retval)
    1158                 :            :                 return retval;
    1159                 :            : 
    1160                 :          0 :         ld = tty_ldisc_ref_wait(tty);
    1161                 :          0 :         retval = __tty_perform_flush(tty, arg);
    1162         [ #  # ]:          0 :         if (ld)
    1163                 :          0 :                 tty_ldisc_deref(ld);
    1164                 :          0 :         return retval;
    1165                 :            : }
    1166                 :            : EXPORT_SYMBOL_GPL(tty_perform_flush);
    1167                 :            : 
    1168                 :          0 : int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
    1169                 :            :                        unsigned int cmd, unsigned long arg)
    1170                 :            : {
    1171                 :            :         int retval;
    1172                 :            : 
    1173      [ -  +  + ]:       9248 :         switch (cmd) {
    1174                 :            :         case TCXONC:
    1175                 :          0 :                 retval = tty_check_change(tty);
    1176         [ #  # ]:          0 :                 if (retval)
    1177                 :            :                         return retval;
    1178   [ #  #  #  #  :          0 :                 switch (arg) {
                      # ]
    1179                 :            :                 case TCOOFF:
    1180         [ #  # ]:          0 :                         if (!tty->flow_stopped) {
    1181                 :          0 :                                 tty->flow_stopped = 1;
    1182                 :          0 :                                 stop_tty(tty);
    1183                 :            :                         }
    1184                 :            :                         break;
    1185                 :            :                 case TCOON:
    1186         [ #  # ]:          0 :                         if (tty->flow_stopped) {
    1187                 :          0 :                                 tty->flow_stopped = 0;
    1188                 :          0 :                                 start_tty(tty);
    1189                 :            :                         }
    1190                 :            :                         break;
    1191                 :            :                 case TCIOFF:
    1192         [ #  # ]:          0 :                         if (STOP_CHAR(tty) != __DISABLED_CHAR)
    1193                 :          0 :                                 return send_prio_char(tty, STOP_CHAR(tty));
    1194                 :            :                         break;
    1195                 :            :                 case TCION:
    1196         [ #  # ]:          0 :                         if (START_CHAR(tty) != __DISABLED_CHAR)
    1197                 :          0 :                                 return send_prio_char(tty, START_CHAR(tty));
    1198                 :            :                         break;
    1199                 :            :                 default:
    1200                 :            :                         return -EINVAL;
    1201                 :            :                 }
    1202                 :            :                 return 0;
    1203                 :            :         case TCFLSH:
    1204                 :        128 :                 retval = tty_check_change(tty);
    1205         [ +  - ]:        128 :                 if (retval)
    1206                 :            :                         return retval;
    1207                 :        128 :                 return __tty_perform_flush(tty, arg);
    1208                 :            :         default:
    1209                 :            :                 /* Try the mode commands */
    1210                 :       9120 :                 return tty_mode_ioctl(tty, file, cmd, arg);
    1211                 :            :         }
    1212                 :            : }
    1213                 :            : EXPORT_SYMBOL(n_tty_ioctl_helper);
    1214                 :            : 
    1215                 :            : #ifdef CONFIG_COMPAT
    1216                 :            : long n_tty_compat_ioctl_helper(struct tty_struct *tty, struct file *file,
    1217                 :            :                                         unsigned int cmd, unsigned long arg)
    1218                 :            : {
    1219                 :            :         switch (cmd) {
    1220                 :            :         case TIOCGLCKTRMIOS:
    1221                 :            :         case TIOCSLCKTRMIOS:
    1222                 :            :                 return tty_mode_ioctl(tty, file, cmd, (unsigned long) compat_ptr(arg));
    1223                 :            :         default:
    1224                 :            :                 return -ENOIOCTLCMD;
    1225                 :            :         }
    1226                 :            : }
    1227                 :            : EXPORT_SYMBOL(n_tty_compat_ioctl_helper);
    1228                 :            : #endif
    1229                 :            : 

Generated by: LCOV version 1.9