brintos

brintos / linux-shallow public Read only

0
0
Text · 5.9 KiB · f9b4993 Raw
216 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds4 */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 tty16 *17 * Note that the baud_table needs to be kept in sync with the18 * include/asm/termbits.h file.19 */20static 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, 200000026#else27	500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,28	2500000, 3000000, 3500000, 400000029#endif30};31 32static 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, B200000038#else39	B500000, B576000, B921600, B1000000, B1152000, B1500000, B2000000,40	B2500000, B3000000, B3500000, B400000041#endif42};43 44static int n_baud_table = ARRAY_SIZE(baud_table);45 46/**47 *	tty_termios_baud_rate48 *	@termios: termios structure49 *50 *	Convert termios baud rate data into a speed. This should be called51 *	with the termios lock held if this termios is a terminal termios52 *	structure. Device drivers can call this function but should use53 *	->c_[io]speed directly as they are updated.54 *55 *	Locking: none56 */57 58speed_t tty_termios_baud_rate(const struct ktermios *termios)59{60	unsigned int cbaud;61 62	cbaud = termios->c_cflag & CBAUD;63 64	/* Magic token for arbitrary speed via c_ispeed/c_ospeed */65	if (cbaud == BOTHER)66		return termios->c_ospeed;67 68	if (cbaud & CBAUDEX) {69		cbaud &= ~CBAUDEX;70		cbaud += 15;71	}72	return cbaud >= n_baud_table ? 0 : baud_table[cbaud];73}74EXPORT_SYMBOL(tty_termios_baud_rate);75 76/**77 *	tty_termios_input_baud_rate78 *	@termios: termios structure79 *80 *	Convert termios baud rate data into a speed. This should be called81 *	with the termios lock held if this termios is a terminal termios82 *	structure. Device drivers can call this function but should use83 *	->c_[io]speed directly as they are updated.84 *85 *	Locking: none86 */87 88speed_t tty_termios_input_baud_rate(const struct ktermios *termios)89{90	unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD;91 92	if (cbaud == B0)93		return tty_termios_baud_rate(termios);94 95	/* Magic token for arbitrary speed via c_ispeed */96	if (cbaud == BOTHER)97		return termios->c_ispeed;98 99	if (cbaud & CBAUDEX) {100		cbaud &= ~CBAUDEX;101		cbaud += 15;102	}103	return cbaud >= n_baud_table ? 0 : baud_table[cbaud];104}105EXPORT_SYMBOL(tty_termios_input_baud_rate);106 107/**108 *	tty_termios_encode_baud_rate109 *	@termios: ktermios structure holding user requested state110 *	@ibaud: input speed111 *	@obaud: output speed112 *113 *	Encode the speeds set into the passed termios structure. This is114 *	used as a library helper for drivers so that they can report back115 *	the actual speed selected when it differs from the speed requested116 *117 *	For maximal back compatibility with legacy SYS5/POSIX *nix behaviour118 *	we need to carefully set the bits when the user does not get the119 *	desired speed. We allow small margins and preserve as much of possible120 *	of the input intent to keep compatibility.121 *122 *	Locking: Caller should hold termios lock. This is already held123 *	when calling this function from the driver termios handler.124 *125 *	The ifdefs deal with platforms whose owners have yet to update them126 *	and will all go away once this is done.127 */128 129void tty_termios_encode_baud_rate(struct ktermios *termios,130				  speed_t ibaud, speed_t obaud)131{132	int i = 0;133	int ifound = -1, ofound = -1;134	int iclose = ibaud/50, oclose = obaud/50;135	int ibinput = 0;136 137	if (obaud == 0)			/* CD dropped */138		ibaud = 0;		/* Clear ibaud to be sure */139 140	termios->c_ispeed = ibaud;141	termios->c_ospeed = obaud;142 143	if (((termios->c_cflag >> IBSHIFT) & CBAUD) != B0)144		ibinput = 1;	/* An input speed was specified */145 146	/* If the user asked for a precise weird speed give a precise weird147	 * answer. If they asked for a Bfoo speed they may have problems148	 * digesting non-exact replies so fuzz a bit.149	 */150 151	if ((termios->c_cflag & CBAUD) == BOTHER) {152		oclose = 0;153		if (!ibinput)154			iclose = 0;155	}156	if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)157		iclose = 0;158 159	termios->c_cflag &= ~CBAUD;160	termios->c_cflag &= ~(CBAUD << IBSHIFT);161 162	/*163	 *	Our goal is to find a close match to the standard baud rate164	 *	returned. Walk the baud rate table and if we get a very close165	 *	match then report back the speed as a POSIX Bxxxx value by166	 *	preference167	 */168 169	do {170		if (obaud - oclose <= baud_table[i] &&171		    obaud + oclose >= baud_table[i]) {172			termios->c_cflag |= baud_bits[i];173			ofound = i;174		}175		if (ibaud - iclose <= baud_table[i] &&176		    ibaud + iclose >= baud_table[i]) {177			/* For the case input == output don't set IBAUD bits178			 * if the user didn't do so.179			 */180			if (ofound == i && !ibinput) {181				ifound  = i;182			} else {183				ifound = i;184				termios->c_cflag |= (baud_bits[i] << IBSHIFT);185			}186		}187	} while (++i < n_baud_table);188 189	/* If we found no match then use BOTHER. */190	if (ofound == -1)191		termios->c_cflag |= BOTHER;192	/* Set exact input bits only if the input and output differ or the193	 * user already did.194	 */195	if (ifound == -1 && (ibaud != obaud || ibinput))196		termios->c_cflag |= (BOTHER << IBSHIFT);197}198EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);199 200/**201 *	tty_encode_baud_rate		-	set baud rate of the tty202 *	@tty:   terminal device203 *	@ibaud: input baud rate204 *	@obaud: output baud rate205 *206 *	Update the current termios data for the tty with the new speed207 *	settings. The caller must hold the termios_rwsem for the tty in208 *	question.209 */210 211void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)212{213	tty_termios_encode_baud_rate(&tty->termios, ibaud, obaud);214}215EXPORT_SYMBOL_GPL(tty_encode_baud_rate);216