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

Generated by: LCOV version 1.14