root/drivers/tty/tty_baudrate.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tty_termios_baud_rate
  2. tty_termios_input_baud_rate
  3. tty_termios_encode_baud_rate
  4. tty_encode_baud_rate

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

/* [<][>][^][v][top][bottom][index][help] */