tty: expose new methods needed for drivers to get termios right
This adds three new functions (or in one case to be more exact makes it always available) tty_termios_copy_hw Copies all the hardware settings from one termios structure to the other. This is intended for drivers that support little or no hardware setting tty_termios_encode_baud_rate Allows you to set the input and output baud rate in a termios structure. A driver is supposed to set the resulting baud rate from a request so most will want to use this function to set the resulting input and output rates to match the hardware values. Internally it knows about keeping Bxxx encoding when possible to maximise compatibility. tty_encode_baud_rate As above but for the tty's own current termios structure I suspect this will initially need some tweaking as it gets enabled by driver patches over the next few mm cycles so consider this lot -mm only for the moment so it can stabilize and end up neat before it goes to base. I've tried not to break any obscure architectures - if you get a speed you can't represent the code will print warnings on non updated termios systems but not break. Once this is merged and seems sane I've got a growing pile of driver updates to use it - notably for USB serial drivers. [akpm@linux-foundation.org: cleanups] Signed-off-by: Alan Cox <alan@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
ca025282e9
commit
5f519d7281
|
@ -206,8 +206,6 @@ speed_t tty_termios_input_baud_rate(struct ktermios *termios)
|
||||||
|
|
||||||
EXPORT_SYMBOL(tty_termios_input_baud_rate);
|
EXPORT_SYMBOL(tty_termios_input_baud_rate);
|
||||||
|
|
||||||
#ifdef BOTHER
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tty_termios_encode_baud_rate
|
* tty_termios_encode_baud_rate
|
||||||
* @termios: ktermios structure holding user requested state
|
* @termios: ktermios structure holding user requested state
|
||||||
|
@ -225,6 +223,9 @@ EXPORT_SYMBOL(tty_termios_input_baud_rate);
|
||||||
*
|
*
|
||||||
* Locking: Caller should hold termios lock. This is already held
|
* Locking: Caller should hold termios lock. This is already held
|
||||||
* when calling this function from the driver termios handler.
|
* when calling this function from the driver termios handler.
|
||||||
|
*
|
||||||
|
* The ifdefs deal with platforms whose owners have yet to update them
|
||||||
|
* and will all go away once this is done.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud)
|
void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud)
|
||||||
|
@ -234,9 +235,13 @@ void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed
|
||||||
int iclose = ibaud/50, oclose = obaud/50;
|
int iclose = ibaud/50, oclose = obaud/50;
|
||||||
int ibinput = 0;
|
int ibinput = 0;
|
||||||
|
|
||||||
|
if (obaud == 0) /* CD dropped */
|
||||||
|
ibaud = 0; /* Clear ibaud to be sure */
|
||||||
|
|
||||||
termios->c_ispeed = ibaud;
|
termios->c_ispeed = ibaud;
|
||||||
termios->c_ospeed = obaud;
|
termios->c_ospeed = obaud;
|
||||||
|
|
||||||
|
#ifdef BOTHER
|
||||||
/* If the user asked for a precise weird speed give a precise weird
|
/* If the user asked for a precise weird speed give a precise weird
|
||||||
answer. If they asked for a Bfoo speed they many have problems
|
answer. If they asked for a Bfoo speed they many have problems
|
||||||
digesting non-exact replies so fuzz a bit */
|
digesting non-exact replies so fuzz a bit */
|
||||||
|
@ -247,32 +252,60 @@ void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed
|
||||||
iclose = 0;
|
iclose = 0;
|
||||||
if ((termios->c_cflag >> IBSHIFT) & CBAUD)
|
if ((termios->c_cflag >> IBSHIFT) & CBAUD)
|
||||||
ibinput = 1; /* An input speed was specified */
|
ibinput = 1; /* An input speed was specified */
|
||||||
|
#endif
|
||||||
termios->c_cflag &= ~CBAUD;
|
termios->c_cflag &= ~CBAUD;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Our goal is to find a close match to the standard baud rate
|
||||||
|
* returned. Walk the baud rate table and if we get a very close
|
||||||
|
* match then report back the speed as a POSIX Bxxxx value by
|
||||||
|
* preference
|
||||||
|
*/
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (obaud - oclose >= baud_table[i] && obaud + oclose <= baud_table[i]) {
|
if (obaud - oclose >= baud_table[i] && obaud + oclose <= baud_table[i]) {
|
||||||
termios->c_cflag |= baud_bits[i];
|
termios->c_cflag |= baud_bits[i];
|
||||||
ofound = i;
|
ofound = i;
|
||||||
}
|
}
|
||||||
if (ibaud - iclose >= baud_table[i] && ibaud + iclose <= baud_table[i]) {
|
if (ibaud - iclose >= baud_table[i] && ibaud + iclose <= baud_table[i]) {
|
||||||
/* For the case input == output don't set IBAUD bits if the user didn't do so */
|
if (ofound == i && !ibinput)
|
||||||
if (ofound != i || ibinput)
|
ifound = i;
|
||||||
|
#ifdef IBSHIFT
|
||||||
|
else {
|
||||||
|
ifound = i;
|
||||||
termios->c_cflag |= (baud_bits[i] << IBSHIFT);
|
termios->c_cflag |= (baud_bits[i] << IBSHIFT);
|
||||||
ifound = i;
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
} while (++i < n_baud_table);
|
} while (++i < n_baud_table);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we found no match then use BOTHER if provided or warn
|
||||||
|
* the user their platform maintainer needs to wake up if not.
|
||||||
|
*/
|
||||||
|
#ifdef BOTHER
|
||||||
if (ofound == -1)
|
if (ofound == -1)
|
||||||
termios->c_cflag |= BOTHER;
|
termios->c_cflag |= BOTHER;
|
||||||
/* Set exact input bits only if the input and output differ or the
|
/* Set exact input bits only if the input and output differ or the
|
||||||
user already did */
|
user already did */
|
||||||
if (ifound == -1 && (ibaud != obaud || ibinput))
|
if (ifound == -1 && (ibaud != obaud || ibinput))
|
||||||
termios->c_cflag |= (BOTHER << IBSHIFT);
|
termios->c_cflag |= (BOTHER << IBSHIFT);
|
||||||
|
#else
|
||||||
|
if (ifound == -1 || ofound == -1) {
|
||||||
|
static int warned;
|
||||||
|
if (!warned++)
|
||||||
|
printk(KERN_WARNING "tty: Unable to return correct "
|
||||||
|
"speed data as your architecture needs updating.\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
|
EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
|
||||||
|
|
||||||
#endif
|
void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
|
||||||
|
{
|
||||||
|
tty_termios_encode_baud_rate(tty->termios, ibaud, obaud);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tty_get_baud_rate - get tty bit rates
|
* tty_get_baud_rate - get tty bit rates
|
||||||
|
@ -303,6 +336,29 @@ speed_t tty_get_baud_rate(struct tty_struct *tty)
|
||||||
|
|
||||||
EXPORT_SYMBOL(tty_get_baud_rate);
|
EXPORT_SYMBOL(tty_get_baud_rate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tty_termios_copy_hw - copy hardware settings
|
||||||
|
* @new: New termios
|
||||||
|
* @old: Old termios
|
||||||
|
*
|
||||||
|
* Propogate the hardware specific terminal setting bits from
|
||||||
|
* the old termios structure to the new one. This is used in cases
|
||||||
|
* where the hardware does not support reconfiguration or as a helper
|
||||||
|
* in some cases where only minimal reconfiguration is supported
|
||||||
|
*/
|
||||||
|
|
||||||
|
void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old)
|
||||||
|
{
|
||||||
|
/* The bits a dumb device handles in software. Smart devices need
|
||||||
|
to always provide a set_termios method */
|
||||||
|
new->c_cflag &= HUPCL | CREAD | CLOCAL;
|
||||||
|
new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
|
||||||
|
new->c_ispeed = old->c_ispeed;
|
||||||
|
new->c_ospeed = old->c_ospeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT_SYMBOL(tty_termios_copy_hw);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* change_termios - update termios values
|
* change_termios - update termios values
|
||||||
* @tty: tty to update
|
* @tty: tty to update
|
||||||
|
@ -340,13 +396,12 @@ static void change_termios(struct tty_struct * tty, struct ktermios * new_termio
|
||||||
tty->erasing = 0;
|
tty->erasing = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This bit should be in the ldisc code */
|
||||||
if (canon_change && !L_ICANON(tty) && tty->read_cnt)
|
if (canon_change && !L_ICANON(tty) && tty->read_cnt)
|
||||||
/* Get characters left over from canonical mode. */
|
/* Get characters left over from canonical mode. */
|
||||||
wake_up_interruptible(&tty->read_wait);
|
wake_up_interruptible(&tty->read_wait);
|
||||||
|
|
||||||
/* See if packet mode change of state. */
|
/* See if packet mode change of state. */
|
||||||
|
|
||||||
if (tty->link && tty->link->packet) {
|
if (tty->link && tty->link->packet) {
|
||||||
int old_flow = ((old_termios.c_iflag & IXON) &&
|
int old_flow = ((old_termios.c_iflag & IXON) &&
|
||||||
(old_termios.c_cc[VSTOP] == '\023') &&
|
(old_termios.c_cc[VSTOP] == '\023') &&
|
||||||
|
@ -366,6 +421,8 @@ static void change_termios(struct tty_struct * tty, struct ktermios * new_termio
|
||||||
|
|
||||||
if (tty->driver->set_termios)
|
if (tty->driver->set_termios)
|
||||||
(*tty->driver->set_termios)(tty, &old_termios);
|
(*tty->driver->set_termios)(tty, &old_termios);
|
||||||
|
else
|
||||||
|
tty_termios_copy_hw(tty->termios, &old_termios);
|
||||||
|
|
||||||
ld = tty_ldisc_ref(tty);
|
ld = tty_ldisc_ref(tty);
|
||||||
if (ld != NULL) {
|
if (ld != NULL) {
|
||||||
|
@ -440,6 +497,11 @@ static int set_termios(struct tty_struct * tty, void __user *arg, int opt)
|
||||||
}
|
}
|
||||||
|
|
||||||
change_termios(tty, &tmp_termios);
|
change_termios(tty, &tmp_termios);
|
||||||
|
|
||||||
|
/* FIXME: Arguably if tmp_termios == tty->termios AND the
|
||||||
|
actual requested termios was not tmp_termios then we may
|
||||||
|
want to return an error as no user requested change has
|
||||||
|
succeeded */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -316,6 +316,9 @@ extern void tty_flip_buffer_push(struct tty_struct *tty);
|
||||||
extern speed_t tty_get_baud_rate(struct tty_struct *tty);
|
extern speed_t tty_get_baud_rate(struct tty_struct *tty);
|
||||||
extern speed_t tty_termios_baud_rate(struct ktermios *termios);
|
extern speed_t tty_termios_baud_rate(struct ktermios *termios);
|
||||||
extern speed_t tty_termios_input_baud_rate(struct ktermios *termios);
|
extern speed_t tty_termios_input_baud_rate(struct ktermios *termios);
|
||||||
|
extern void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud);
|
||||||
|
extern void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud);
|
||||||
|
extern void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old);
|
||||||
|
|
||||||
extern struct tty_ldisc *tty_ldisc_ref(struct tty_struct *);
|
extern struct tty_ldisc *tty_ldisc_ref(struct tty_struct *);
|
||||||
extern void tty_ldisc_deref(struct tty_ldisc *);
|
extern void tty_ldisc_deref(struct tty_ldisc *);
|
||||||
|
|
Loading…
Reference in a new issue