LCOV - code coverage report
Current view: top level - tty - tty_baudrate.c (source / functions) Coverage Total Hit
Test: TTY Combined Coverage Lines: 18.2 % 66 12
Test Date: 2025-08-26 15:45:50 Functions: 50.0 % 4 2

            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. Device drivers can call this function but should use
      53              :  *      ->c_[io]speed directly as they are updated.
      54              :  *
      55              :  *      Locking: none
      56              :  */
      57              : 
      58           12 : speed_t tty_termios_baud_rate(const struct ktermios *termios)
      59              : {
      60           12 :         unsigned int cbaud;
      61              : 
      62           12 :         cbaud = termios->c_cflag & CBAUD;
      63              : 
      64              :         /* Magic token for arbitrary speed via c_ispeed/c_ospeed */
      65           12 :         if (cbaud == BOTHER)
      66            0 :                 return termios->c_ospeed;
      67              : 
      68           12 :         if (cbaud & CBAUDEX) {
      69            0 :                 cbaud &= ~CBAUDEX;
      70            0 :                 cbaud += 15;
      71            0 :         }
      72           12 :         return cbaud >= n_baud_table ? 0 : baud_table[cbaud];
      73           12 : }
      74              : EXPORT_SYMBOL(tty_termios_baud_rate);
      75              : 
      76              : /**
      77              :  *      tty_termios_input_baud_rate
      78              :  *      @termios: termios structure
      79              :  *
      80              :  *      Convert termios baud rate data into a speed. This should be called
      81              :  *      with the termios lock held if this termios is a terminal termios
      82              :  *      structure. Device drivers can call this function but should use
      83              :  *      ->c_[io]speed directly as they are updated.
      84              :  *
      85              :  *      Locking: none
      86              :  */
      87              : 
      88            6 : speed_t tty_termios_input_baud_rate(const struct ktermios *termios)
      89              : {
      90            6 :         unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD;
      91              : 
      92            6 :         if (cbaud == B0)
      93            6 :                 return tty_termios_baud_rate(termios);
      94              : 
      95              :         /* Magic token for arbitrary speed via c_ispeed */
      96            0 :         if (cbaud == BOTHER)
      97            0 :                 return termios->c_ispeed;
      98              : 
      99            0 :         if (cbaud & CBAUDEX) {
     100            0 :                 cbaud &= ~CBAUDEX;
     101            0 :                 cbaud += 15;
     102            0 :         }
     103            0 :         return cbaud >= n_baud_table ? 0 : baud_table[cbaud];
     104            6 : }
     105              : EXPORT_SYMBOL(tty_termios_input_baud_rate);
     106              : 
     107              : /**
     108              :  *      tty_termios_encode_baud_rate
     109              :  *      @termios: ktermios structure holding user requested state
     110              :  *      @ibaud: input speed
     111              :  *      @obaud: output speed
     112              :  *
     113              :  *      Encode the speeds set into the passed termios structure. This is
     114              :  *      used as a library helper for drivers so that they can report back
     115              :  *      the actual speed selected when it differs from the speed requested
     116              :  *
     117              :  *      For maximal back compatibility with legacy SYS5/POSIX *nix behaviour
     118              :  *      we need to carefully set the bits when the user does not get the
     119              :  *      desired speed. We allow small margins and preserve as much of possible
     120              :  *      of the input intent to keep compatibility.
     121              :  *
     122              :  *      Locking: Caller should hold termios lock. This is already held
     123              :  *      when calling this function from the driver termios handler.
     124              :  *
     125              :  *      The ifdefs deal with platforms whose owners have yet to update them
     126              :  *      and will all go away once this is done.
     127              :  */
     128              : 
     129            0 : void tty_termios_encode_baud_rate(struct ktermios *termios,
     130              :                                   speed_t ibaud, speed_t obaud)
     131              : {
     132            0 :         int i = 0;
     133            0 :         int ifound = -1, ofound = -1;
     134            0 :         int iclose = ibaud/50, oclose = obaud/50;
     135            0 :         int ibinput = 0;
     136              : 
     137            0 :         if (obaud == 0)                 /* CD dropped */
     138            0 :                 ibaud = 0;              /* Clear ibaud to be sure */
     139              : 
     140            0 :         termios->c_ispeed = ibaud;
     141            0 :         termios->c_ospeed = obaud;
     142              : 
     143            0 :         if (((termios->c_cflag >> IBSHIFT) & CBAUD) != B0)
     144            0 :                 ibinput = 1;    /* An input speed was specified */
     145              : 
     146              :         /* If the user asked for a precise weird speed give a precise weird
     147              :          * answer. If they asked for a Bfoo speed they may have problems
     148              :          * digesting non-exact replies so fuzz a bit.
     149              :          */
     150              : 
     151            0 :         if ((termios->c_cflag & CBAUD) == BOTHER) {
     152            0 :                 oclose = 0;
     153            0 :                 if (!ibinput)
     154            0 :                         iclose = 0;
     155            0 :         }
     156            0 :         if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)
     157            0 :                 iclose = 0;
     158              : 
     159            0 :         termios->c_cflag &= ~CBAUD;
     160            0 :         termios->c_cflag &= ~(CBAUD << IBSHIFT);
     161              : 
     162              :         /*
     163              :          *      Our goal is to find a close match to the standard baud rate
     164              :          *      returned. Walk the baud rate table and if we get a very close
     165              :          *      match then report back the speed as a POSIX Bxxxx value by
     166              :          *      preference
     167              :          */
     168              : 
     169            0 :         do {
     170            0 :                 if (obaud - oclose <= baud_table[i] &&
     171            0 :                     obaud + oclose >= baud_table[i]) {
     172            0 :                         termios->c_cflag |= baud_bits[i];
     173            0 :                         ofound = i;
     174            0 :                 }
     175            0 :                 if (ibaud - iclose <= baud_table[i] &&
     176            0 :                     ibaud + iclose >= baud_table[i]) {
     177              :                         /* For the case input == output don't set IBAUD bits
     178              :                          * if the user didn't do so.
     179              :                          */
     180            0 :                         if (ofound == i && !ibinput) {
     181            0 :                                 ifound  = i;
     182            0 :                         } else {
     183            0 :                                 ifound = i;
     184            0 :                                 termios->c_cflag |= (baud_bits[i] << IBSHIFT);
     185              :                         }
     186            0 :                 }
     187            0 :         } while (++i < n_baud_table);
     188              : 
     189              :         /* If we found no match then use BOTHER. */
     190            0 :         if (ofound == -1)
     191            0 :                 termios->c_cflag |= BOTHER;
     192              :         /* Set exact input bits only if the input and output differ or the
     193              :          * user already did.
     194              :          */
     195            0 :         if (ifound == -1 && (ibaud != obaud || ibinput))
     196            0 :                 termios->c_cflag |= (BOTHER << IBSHIFT);
     197            0 : }
     198              : EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
     199              : 
     200              : /**
     201              :  *      tty_encode_baud_rate            -       set baud rate of the tty
     202              :  *      @tty:   terminal device
     203              :  *      @ibaud: input baud rate
     204              :  *      @obaud: output baud rate
     205              :  *
     206              :  *      Update the current termios data for the tty with the new speed
     207              :  *      settings. The caller must hold the termios_rwsem for the tty in
     208              :  *      question.
     209              :  */
     210              : 
     211            0 : void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
     212              : {
     213            0 :         tty_termios_encode_baud_rate(&tty->termios, ibaud, obaud);
     214            0 : }
     215              : EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
        

Generated by: LCOV version 2.0-1