1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
6 #include <linux/types.h>
7 #include <linux/kernel.h>
8 #include <linux/termios.h>
10 #include <linux/export.h>
14 * Routine which returns the baud rate of the tty
16 * Note that the baud_table needs to be kept in sync with the
17 * include/asm/termbits.h file.
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,
23 76800, 153600, 307200, 614400, 921600, 500000, 576000,
24 1000000, 1152000, 1500000, 2000000
26 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
27 2500000, 3000000, 3500000, 4000000
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
,
35 B76800
, B153600
, B307200
, B614400
, B921600
, B500000
, B576000
,
36 B1000000
, B1152000
, B1500000
, B2000000
38 B500000
, B576000
, B921600
, B1000000
, B1152000
, B1500000
, B2000000
,
39 B2500000
, B3000000
, B3500000
, B4000000
43 static int n_baud_table
= ARRAY_SIZE(baud_table
);
46 * tty_termios_baud_rate
47 * @termios: termios structure
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.
57 speed_t
tty_termios_baud_rate(struct ktermios
*termios
)
61 cbaud
= termios
->c_cflag
& CBAUD
;
64 /* Magic token for arbitrary speed via c_ispeed/c_ospeed */
66 return termios
->c_ospeed
;
68 if (cbaud
& CBAUDEX
) {
71 if (cbaud
< 1 || cbaud
+ 15 > n_baud_table
)
72 termios
->c_cflag
&= ~CBAUDEX
;
76 return cbaud
>= n_baud_table
? 0 : baud_table
[cbaud
];
78 EXPORT_SYMBOL(tty_termios_baud_rate
);
81 * tty_termios_input_baud_rate
82 * @termios: termios structure
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.
92 speed_t
tty_termios_input_baud_rate(struct ktermios
*termios
)
95 unsigned int cbaud
= (termios
->c_cflag
>> IBSHIFT
) & CBAUD
;
98 return tty_termios_baud_rate(termios
);
100 /* Magic token for arbitrary speed via c_ispeed*/
102 return termios
->c_ispeed
;
104 if (cbaud
& CBAUDEX
) {
107 if (cbaud
< 1 || cbaud
+ 15 > n_baud_table
)
108 termios
->c_cflag
&= ~(CBAUDEX
<< IBSHIFT
);
112 return cbaud
>= n_baud_table
? 0 : baud_table
[cbaud
];
114 return tty_termios_baud_rate(termios
);
117 EXPORT_SYMBOL(tty_termios_input_baud_rate
);
120 * tty_termios_encode_baud_rate
121 * @termios: ktermios structure holding user requested state
122 * @ispeed: input speed
123 * @ospeed: output speed
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
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.
134 * Locking: Caller should hold termios lock. This is already held
135 * when calling this function from the driver termios handler.
137 * The ifdefs deal with platforms whose owners have yet to update them
138 * and will all go away once this is done.
141 void tty_termios_encode_baud_rate(struct ktermios
*termios
,
142 speed_t ibaud
, speed_t obaud
)
145 int ifound
= -1, ofound
= -1;
146 int iclose
= ibaud
/50, oclose
= obaud
/50;
149 if (obaud
== 0) /* CD dropped */
150 ibaud
= 0; /* Clear ibaud to be sure */
152 termios
->c_ispeed
= ibaud
;
153 termios
->c_ospeed
= obaud
;
156 if ((termios
->c_cflag
>> IBSHIFT
) & CBAUD
)
157 ibinput
= 1; /* An input speed was specified */
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 */
164 if ((termios
->c_cflag
& CBAUD
) == BOTHER
) {
169 if (((termios
->c_cflag
>> IBSHIFT
) & CBAUD
) == BOTHER
)
172 termios
->c_cflag
&= ~CBAUD
;
174 termios
->c_cflag
&= ~(CBAUD
<< IBSHIFT
);
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
185 if (obaud
- oclose
<= baud_table
[i
] &&
186 obaud
+ oclose
>= baud_table
[i
]) {
187 termios
->c_cflag
|= baud_bits
[i
];
190 if (ibaud
- iclose
<= baud_table
[i
] &&
191 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 if (ofound
== i
&& !ibinput
)
199 termios
->c_cflag
|= (baud_bits
[i
] << IBSHIFT
);
203 } while (++i
< n_baud_table
);
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.
211 termios
->c_cflag
|= BOTHER
;
212 /* Set exact input bits only if the input and output differ or the
214 if (ifound
== -1 && (ibaud
!= obaud
|| ibinput
))
215 termios
->c_cflag
|= (BOTHER
<< IBSHIFT
);
217 if (ifound
== -1 || ofound
== -1)
218 pr_warn_once("tty: Unable to return correct speed data as your architecture needs updating.\n");
221 EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate
);
224 * tty_encode_baud_rate - set baud rate of the tty
225 * @ibaud: input baud rate
226 * @obad: output baud rate
228 * Update the current termios data for the tty with the new speed
229 * settings. The caller must hold the termios_rwsem for the tty in
233 void tty_encode_baud_rate(struct tty_struct
*tty
, speed_t ibaud
, speed_t obaud
)
235 tty_termios_encode_baud_rate(&tty
->termios
, ibaud
, obaud
);
237 EXPORT_SYMBOL_GPL(tty_encode_baud_rate
);