Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
0004  */
0005 
0006 #include <linux/types.h>
0007 #include <linux/kernel.h>
0008 #include <linux/termios.h>
0009 #include <linux/tty.h>
0010 #include <linux/export.h>
0011 #include "tty.h"
0012 
0013 
0014 /*
0015  * Routine which returns the baud rate of the tty
0016  *
0017  * Note that the baud_table needs to be kept in sync with the
0018  * include/asm/termbits.h file.
0019  */
0020 static const speed_t baud_table[] = {
0021     0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400,
0022     4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800,
0023 #ifdef __sparc__
0024     76800, 153600, 307200, 614400, 921600, 500000, 576000,
0025     1000000, 1152000, 1500000, 2000000
0026 #else
0027     500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
0028     2500000, 3000000, 3500000, 4000000
0029 #endif
0030 };
0031 
0032 static const tcflag_t baud_bits[] = {
0033     B0, B50, B75, B110, B134, B150, B200, B300, B600, B1200, B1800, B2400,
0034     B4800, B9600, B19200, B38400, B57600, B115200, B230400, B460800,
0035 #ifdef __sparc__
0036     B76800, B153600, B307200, B614400, B921600, B500000, B576000,
0037     B1000000, B1152000, B1500000, B2000000
0038 #else
0039     B500000, B576000, B921600, B1000000, B1152000, B1500000, B2000000,
0040     B2500000, B3000000, B3500000, B4000000
0041 #endif
0042 };
0043 
0044 static int n_baud_table = ARRAY_SIZE(baud_table);
0045 
0046 /**
0047  *  tty_termios_baud_rate
0048  *  @termios: termios structure
0049  *
0050  *  Convert termios baud rate data into a speed. This should be called
0051  *  with the termios lock held if this termios is a terminal termios
0052  *  structure. May change the termios data. Device drivers can call this
0053  *  function but should use ->c_[io]speed directly as they are updated.
0054  *
0055  *  Locking: none
0056  */
0057 
0058 speed_t tty_termios_baud_rate(struct ktermios *termios)
0059 {
0060     unsigned int cbaud;
0061 
0062     cbaud = termios->c_cflag & CBAUD;
0063 
0064     /* Magic token for arbitrary speed via c_ispeed/c_ospeed */
0065     if (cbaud == BOTHER)
0066         return termios->c_ospeed;
0067 
0068     if (cbaud & CBAUDEX) {
0069         cbaud &= ~CBAUDEX;
0070 
0071         if (cbaud < 1 || cbaud + 15 > n_baud_table)
0072             termios->c_cflag &= ~CBAUDEX;
0073         else
0074             cbaud += 15;
0075     }
0076     return cbaud >= n_baud_table ? 0 : baud_table[cbaud];
0077 }
0078 EXPORT_SYMBOL(tty_termios_baud_rate);
0079 
0080 /**
0081  *  tty_termios_input_baud_rate
0082  *  @termios: termios structure
0083  *
0084  *  Convert termios baud rate data into a speed. This should be called
0085  *  with the termios lock held if this termios is a terminal termios
0086  *  structure. May change the termios data. Device drivers can call this
0087  *  function but should use ->c_[io]speed directly as they are updated.
0088  *
0089  *  Locking: none
0090  */
0091 
0092 speed_t tty_termios_input_baud_rate(struct ktermios *termios)
0093 {
0094     unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD;
0095 
0096     if (cbaud == B0)
0097         return tty_termios_baud_rate(termios);
0098 
0099     /* Magic token for arbitrary speed via c_ispeed*/
0100     if (cbaud == BOTHER)
0101         return termios->c_ispeed;
0102 
0103     if (cbaud & CBAUDEX) {
0104         cbaud &= ~CBAUDEX;
0105 
0106         if (cbaud < 1 || cbaud + 15 > n_baud_table)
0107             termios->c_cflag &= ~(CBAUDEX << IBSHIFT);
0108         else
0109             cbaud += 15;
0110     }
0111     return cbaud >= n_baud_table ? 0 : baud_table[cbaud];
0112 }
0113 EXPORT_SYMBOL(tty_termios_input_baud_rate);
0114 
0115 /**
0116  *  tty_termios_encode_baud_rate
0117  *  @termios: ktermios structure holding user requested state
0118  *  @ibaud: input speed
0119  *  @obaud: output speed
0120  *
0121  *  Encode the speeds set into the passed termios structure. This is
0122  *  used as a library helper for drivers so that they can report back
0123  *  the actual speed selected when it differs from the speed requested
0124  *
0125  *  For maximal back compatibility with legacy SYS5/POSIX *nix behaviour
0126  *  we need to carefully set the bits when the user does not get the
0127  *  desired speed. We allow small margins and preserve as much of possible
0128  *  of the input intent to keep compatibility.
0129  *
0130  *  Locking: Caller should hold termios lock. This is already held
0131  *  when calling this function from the driver termios handler.
0132  *
0133  *  The ifdefs deal with platforms whose owners have yet to update them
0134  *  and will all go away once this is done.
0135  */
0136 
0137 void tty_termios_encode_baud_rate(struct ktermios *termios,
0138                   speed_t ibaud, speed_t obaud)
0139 {
0140     int i = 0;
0141     int ifound = -1, ofound = -1;
0142     int iclose = ibaud/50, oclose = obaud/50;
0143     int ibinput = 0;
0144 
0145     if (obaud == 0)         /* CD dropped */
0146         ibaud = 0;      /* Clear ibaud to be sure */
0147 
0148     termios->c_ispeed = ibaud;
0149     termios->c_ospeed = obaud;
0150 
0151     if (((termios->c_cflag >> IBSHIFT) & CBAUD) != B0)
0152         ibinput = 1;    /* An input speed was specified */
0153 
0154     /* If the user asked for a precise weird speed give a precise weird
0155      * answer. If they asked for a Bfoo speed they may have problems
0156      * digesting non-exact replies so fuzz a bit.
0157      */
0158 
0159     if ((termios->c_cflag & CBAUD) == BOTHER) {
0160         oclose = 0;
0161         if (!ibinput)
0162             iclose = 0;
0163     }
0164     if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)
0165         iclose = 0;
0166 
0167     termios->c_cflag &= ~CBAUD;
0168     termios->c_cflag &= ~(CBAUD << IBSHIFT);
0169 
0170     /*
0171      *  Our goal is to find a close match to the standard baud rate
0172      *  returned. Walk the baud rate table and if we get a very close
0173      *  match then report back the speed as a POSIX Bxxxx value by
0174      *  preference
0175      */
0176 
0177     do {
0178         if (obaud - oclose <= baud_table[i] &&
0179             obaud + oclose >= baud_table[i]) {
0180             termios->c_cflag |= baud_bits[i];
0181             ofound = i;
0182         }
0183         if (ibaud - iclose <= baud_table[i] &&
0184             ibaud + iclose >= baud_table[i]) {
0185             /* For the case input == output don't set IBAUD bits
0186              * if the user didn't do so.
0187              */
0188             if (ofound == i && !ibinput) {
0189                 ifound  = i;
0190             } else {
0191                 ifound = i;
0192                 termios->c_cflag |= (baud_bits[i] << IBSHIFT);
0193             }
0194         }
0195     } while (++i < n_baud_table);
0196 
0197     /* If we found no match then use BOTHER. */
0198     if (ofound == -1)
0199         termios->c_cflag |= BOTHER;
0200     /* Set exact input bits only if the input and output differ or the
0201      * user already did.
0202      */
0203     if (ifound == -1 && (ibaud != obaud || ibinput))
0204         termios->c_cflag |= (BOTHER << IBSHIFT);
0205 }
0206 EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
0207 
0208 /**
0209  *  tty_encode_baud_rate        -   set baud rate of the tty
0210  *  @tty:   terminal device
0211  *  @ibaud: input baud rate
0212  *  @obaud: output baud rate
0213  *
0214  *  Update the current termios data for the tty with the new speed
0215  *  settings. The caller must hold the termios_rwsem for the tty in
0216  *  question.
0217  */
0218 
0219 void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
0220 {
0221     tty_termios_encode_baud_rate(&tty->termios, ibaud, obaud);
0222 }
0223 EXPORT_SYMBOL_GPL(tty_encode_baud_rate);