LCOV - code coverage report
Current view: top level - drivers/tty - tty_baudrate.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 35 59 59.3 %
Date: 2021-04-22 12:43:58 Functions: 3 4 75.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
       4             :  */
       5             : 
       6             : #include <linux/types.h>
       7             : #include <linux/kernel.h>
       8             : #include <linux/termios.h>
       9             : #include <linux/tty.h>
      10             : #include <linux/export.h>
      11             : 
      12             : 
      13             : /*
      14             :  * Routine which returns the baud rate of the tty
      15             :  *
      16             :  * Note that the baud_table needs to be kept in sync with the
      17             :  * include/asm/termbits.h file.
      18             :  */
      19             : static const speed_t baud_table[] = {
      20             :         0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400,
      21             :         4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800,
      22             : #ifdef __sparc__
      23             :         76800, 153600, 307200, 614400, 921600, 500000, 576000,
      24             :         1000000, 1152000, 1500000, 2000000
      25             : #else
      26             :         500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
      27             :         2500000, 3000000, 3500000, 4000000
      28             : #endif
      29             : };
      30             : 
      31             : static const tcflag_t baud_bits[] = {
      32             :         B0, B50, B75, B110, B134, B150, B200, B300, B600, B1200, B1800, B2400,
      33             :         B4800, B9600, B19200, B38400, B57600, B115200, B230400, B460800,
      34             : #ifdef __sparc__
      35             :         B76800, B153600, B307200, B614400, B921600, B500000, B576000,
      36             :         B1000000, B1152000, B1500000, B2000000
      37             : #else
      38             :         B500000, B576000, B921600, B1000000, B1152000, B1500000, B2000000,
      39             :         B2500000, B3000000, B3500000, B4000000
      40             : #endif
      41             : };
      42             : 
      43             : static int n_baud_table = ARRAY_SIZE(baud_table);
      44             : 
      45             : /**
      46             :  *      tty_termios_baud_rate
      47             :  *      @termios: termios structure
      48             :  *
      49             :  *      Convert termios baud rate data into a speed. This should be called
      50             :  *      with the termios lock held if this termios is a terminal termios
      51             :  *      structure. May change the termios data. Device drivers can call this
      52             :  *      function but should use ->c_[io]speed directly as they are updated.
      53             :  *
      54             :  *      Locking: none
      55             :  */
      56             : 
      57         338 : speed_t tty_termios_baud_rate(struct ktermios *termios)
      58             : {
      59         338 :         unsigned int cbaud;
      60             : 
      61         338 :         cbaud = termios->c_cflag & CBAUD;
      62             : 
      63             : #ifdef BOTHER
      64             :         /* Magic token for arbitrary speed via c_ispeed/c_ospeed */
      65         338 :         if (cbaud == BOTHER)
      66           0 :                 return termios->c_ospeed;
      67             : #endif
      68         338 :         if (cbaud & CBAUDEX) {
      69           0 :                 cbaud &= ~CBAUDEX;
      70             : 
      71           0 :                 if (cbaud < 1 || cbaud + 15 > n_baud_table)
      72           0 :                         termios->c_cflag &= ~CBAUDEX;
      73             :                 else
      74             :                         cbaud += 15;
      75             :         }
      76         338 :         return cbaud >= n_baud_table ? 0 : baud_table[cbaud];
      77             : }
      78             : EXPORT_SYMBOL(tty_termios_baud_rate);
      79             : 
      80             : /**
      81             :  *      tty_termios_input_baud_rate
      82             :  *      @termios: termios structure
      83             :  *
      84             :  *      Convert termios baud rate data into a speed. This should be called
      85             :  *      with the termios lock held if this termios is a terminal termios
      86             :  *      structure. May change the termios data. Device drivers can call this
      87             :  *      function but should use ->c_[io]speed directly as they are updated.
      88             :  *
      89             :  *      Locking: none
      90             :  */
      91             : 
      92         167 : speed_t tty_termios_input_baud_rate(struct ktermios *termios)
      93             : {
      94             : #ifdef IBSHIFT
      95         167 :         unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD;
      96             : 
      97         167 :         if (cbaud == B0)
      98         167 :                 return tty_termios_baud_rate(termios);
      99             : #ifdef BOTHER
     100             :         /* Magic token for arbitrary speed via c_ispeed*/
     101           0 :         if (cbaud == BOTHER)
     102           0 :                 return termios->c_ispeed;
     103             : #endif
     104           0 :         if (cbaud & CBAUDEX) {
     105           0 :                 cbaud &= ~CBAUDEX;
     106             : 
     107           0 :                 if (cbaud < 1 || cbaud + 15 > n_baud_table)
     108           0 :                         termios->c_cflag &= ~(CBAUDEX << IBSHIFT);
     109             :                 else
     110             :                         cbaud += 15;
     111             :         }
     112           0 :         return cbaud >= n_baud_table ? 0 : baud_table[cbaud];
     113             : #else   /* IBSHIFT */
     114             :         return tty_termios_baud_rate(termios);
     115             : #endif  /* IBSHIFT */
     116             : }
     117             : EXPORT_SYMBOL(tty_termios_input_baud_rate);
     118             : 
     119             : /**
     120             :  *      tty_termios_encode_baud_rate
     121             :  *      @termios: ktermios structure holding user requested state
     122             :  *      @ibaud: input speed
     123             :  *      @obaud: output speed
     124             :  *
     125             :  *      Encode the speeds set into the passed termios structure. This is
     126             :  *      used as a library helper for drivers so that they can report back
     127             :  *      the actual speed selected when it differs from the speed requested
     128             :  *
     129             :  *      For maximal back compatibility with legacy SYS5/POSIX *nix behaviour
     130             :  *      we need to carefully set the bits when the user does not get the
     131             :  *      desired speed. We allow small margins and preserve as much of possible
     132             :  *      of the input intent to keep compatibility.
     133             :  *
     134             :  *      Locking: Caller should hold termios lock. This is already held
     135             :  *      when calling this function from the driver termios handler.
     136             :  *
     137             :  *      The ifdefs deal with platforms whose owners have yet to update them
     138             :  *      and will all go away once this is done.
     139             :  */
     140             : 
     141           3 : void tty_termios_encode_baud_rate(struct ktermios *termios,
     142             :                                   speed_t ibaud, speed_t obaud)
     143             : {
     144           3 :         int i = 0;
     145           3 :         int ifound = -1, ofound = -1;
     146           3 :         int iclose = ibaud/50, oclose = obaud/50;
     147           3 :         int ibinput = 0;
     148             : 
     149           3 :         if (obaud == 0)                 /* CD dropped             */
     150           0 :                 ibaud = 0;              /* Clear ibaud to be sure */
     151             : 
     152           3 :         termios->c_ispeed = ibaud;
     153           3 :         termios->c_ospeed = obaud;
     154             : 
     155             : #ifdef IBSHIFT
     156           3 :         if ((termios->c_cflag >> IBSHIFT) & CBAUD)
     157           0 :                 ibinput = 1;    /* An input speed was specified */
     158             : #endif
     159             : #ifdef BOTHER
     160             :         /* If the user asked for a precise weird speed give a precise weird
     161             :            answer. If they asked for a Bfoo speed they may have problems
     162             :            digesting non-exact replies so fuzz a bit */
     163             : 
     164           3 :         if ((termios->c_cflag & CBAUD) == BOTHER) {
     165           0 :                 oclose = 0;
     166           0 :                 if (!ibinput)
     167           0 :                         iclose = 0;
     168             :         }
     169           3 :         if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)
     170           0 :                 iclose = 0;
     171             : #endif
     172           3 :         termios->c_cflag &= ~CBAUD;
     173             : #ifdef IBSHIFT
     174           3 :         termios->c_cflag &= ~(CBAUD << IBSHIFT);
     175             : #endif
     176             : 
     177             :         /*
     178             :          *      Our goal is to find a close match to the standard baud rate
     179             :          *      returned. Walk the baud rate table and if we get a very close
     180             :          *      match then report back the speed as a POSIX Bxxxx value by
     181             :          *      preference
     182             :          */
     183             : 
     184          93 :         do {
     185          93 :                 if (obaud - oclose <= baud_table[i] &&
     186          54 :                     obaud + oclose >= baud_table[i]) {
     187           3 :                         termios->c_cflag |= baud_bits[i];
     188           3 :                         ofound = i;
     189             :                 }
     190          93 :                 if (ibaud - iclose <= baud_table[i] &&
     191          54 :                     ibaud + iclose >= baud_table[i]) {
     192             :                         /* For the case input == output don't set IBAUD bits
     193             :                            if the user didn't do so */
     194           3 :                         if (ofound == i && !ibinput)
     195             :                                 ifound  = i;
     196             : #ifdef IBSHIFT
     197             :                         else {
     198           0 :                                 ifound = i;
     199           0 :                                 termios->c_cflag |= (baud_bits[i] << IBSHIFT);
     200             :                         }
     201             : #endif
     202             :                 }
     203          93 :         } while (++i < n_baud_table);
     204             : 
     205             :         /*
     206             :          *      If we found no match then use BOTHER if provided or warn
     207             :          *      the user their platform maintainer needs to wake up if not.
     208             :          */
     209             : #ifdef BOTHER
     210           3 :         if (ofound == -1)
     211           0 :                 termios->c_cflag |= BOTHER;
     212             :         /* Set exact input bits only if the input and output differ or the
     213             :            user already did */
     214           3 :         if (ifound == -1 && (ibaud != obaud || ibinput))
     215           0 :                 termios->c_cflag |= (BOTHER << IBSHIFT);
     216             : #else
     217             :         if (ifound == -1 || ofound == -1)
     218             :                 pr_warn_once("tty: Unable to return correct speed data as your architecture needs updating.\n");
     219             : #endif
     220           3 : }
     221             : EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
     222             : 
     223             : /**
     224             :  *      tty_encode_baud_rate            -       set baud rate of the tty
     225             :  *      @tty:   terminal device
     226             :  *      @ibaud: input baud rate
     227             :  *      @obaud: output baud rate
     228             :  *
     229             :  *      Update the current termios data for the tty with the new speed
     230             :  *      settings. The caller must hold the termios_rwsem for the tty in
     231             :  *      question.
     232             :  */
     233             : 
     234           0 : void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
     235             : {
     236           0 :         tty_termios_encode_baud_rate(&tty->termios, ibaud, obaud);
     237           0 : }
     238             : EXPORT_SYMBOL_GPL(tty_encode_baud_rate);

Generated by: LCOV version 1.14