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, 4800,
21 9600, 19200, 38400, 57600, 115200, 230400, 460800,
23 76800, 153600, 307200, 614400, 921600
25 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
26 2500000, 3000000, 3500000, 4000000
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
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
47 static int n_baud_table
= ARRAY_SIZE(baud_table
);
50 * tty_termios_baud_rate
51 * @termios: termios structure
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.
61 speed_t
tty_termios_baud_rate(struct ktermios
*termios
)
65 cbaud
= termios
->c_cflag
& CBAUD
;
68 /* Magic token for arbitrary speed via c_ispeed/c_ospeed */
70 return termios
->c_ospeed
;
72 if (cbaud
& CBAUDEX
) {
75 if (cbaud
< 1 || cbaud
+ 15 > n_baud_table
)
76 termios
->c_cflag
&= ~CBAUDEX
;
80 return cbaud
>= n_baud_table
? 0 : baud_table
[cbaud
];
82 EXPORT_SYMBOL(tty_termios_baud_rate
);
85 * tty_termios_input_baud_rate
86 * @termios: termios structure
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.
96 speed_t
tty_termios_input_baud_rate(struct ktermios
*termios
)
99 unsigned int cbaud
= (termios
->c_cflag
>> IBSHIFT
) & CBAUD
;
102 return tty_termios_baud_rate(termios
);
104 /* Magic token for arbitrary speed via c_ispeed*/
106 return termios
->c_ispeed
;
108 if (cbaud
& CBAUDEX
) {
111 if (cbaud
< 1 || cbaud
+ 15 > n_baud_table
)
112 termios
->c_cflag
&= ~(CBAUDEX
<< IBSHIFT
);
116 return cbaud
>= n_baud_table
? 0 : baud_table
[cbaud
];
118 return tty_termios_baud_rate(termios
);
121 EXPORT_SYMBOL(tty_termios_input_baud_rate
);
124 * tty_termios_encode_baud_rate
125 * @termios: ktermios structure holding user requested state
126 * @ispeed: input speed
127 * @ospeed: output speed
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
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.
138 * Locking: Caller should hold termios lock. This is already held
139 * when calling this function from the driver termios handler.
141 * The ifdefs deal with platforms whose owners have yet to update them
142 * and will all go away once this is done.
145 void tty_termios_encode_baud_rate(struct ktermios
*termios
,
146 speed_t ibaud
, speed_t obaud
)
149 int ifound
= -1, ofound
= -1;
150 int iclose
= ibaud
/50, oclose
= obaud
/50;
153 if (obaud
== 0) /* CD dropped */
154 ibaud
= 0; /* Clear ibaud to be sure */
156 termios
->c_ispeed
= ibaud
;
157 termios
->c_ospeed
= obaud
;
160 if ((termios
->c_cflag
>> IBSHIFT
) & CBAUD
)
161 ibinput
= 1; /* An input speed was specified */
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 */
168 if ((termios
->c_cflag
& CBAUD
) == BOTHER
) {
173 if (((termios
->c_cflag
>> IBSHIFT
) & CBAUD
) == BOTHER
)
176 termios
->c_cflag
&= ~CBAUD
;
178 termios
->c_cflag
&= ~(CBAUD
<< IBSHIFT
);
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
189 if (obaud
- oclose
<= baud_table
[i
] &&
190 obaud
+ oclose
>= baud_table
[i
]) {
191 termios
->c_cflag
|= baud_bits
[i
];
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
)
203 termios
->c_cflag
|= (baud_bits
[i
] << IBSHIFT
);
207 } while (++i
< n_baud_table
);
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.
215 termios
->c_cflag
|= BOTHER
;
216 /* Set exact input bits only if the input and output differ or the
218 if (ifound
== -1 && (ibaud
!= obaud
|| ibinput
))
219 termios
->c_cflag
|= (BOTHER
<< IBSHIFT
);
221 if (ifound
== -1 || ofound
== -1)
222 pr_warn_once("tty: Unable to return correct speed data as your architecture needs updating.\n");
225 EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate
);
228 * tty_encode_baud_rate - set baud rate of the tty
229 * @ibaud: input baud rate
230 * @obad: output baud rate
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
237 void tty_encode_baud_rate(struct tty_struct
*tty
, speed_t ibaud
, speed_t obaud
)
239 tty_termios_encode_baud_rate(&tty
->termios
, ibaud
, obaud
);
241 EXPORT_SYMBOL_GPL(tty_encode_baud_rate
);