/*
* linux/drivers/char/tty_ioctl.c
*
* Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
*
* Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
* which can be dynamically activated and de-activated by the line
* discipline handling modules (like SLIP).
*/
#include <linux/types.h>
#include <linux/termios.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/tty.h>
#include <linux/fcntl.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/mutex.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#undef TTY_DEBUG_WAIT_UNTIL_SENT
#undef DEBUG
/*
* Internal flag options for termios setting behavior
*/
#define TERMIOS_FLUSH 1
#define TERMIOS_WAIT 2
#define TERMIOS_TERMIO 4
#define TERMIOS_OLD 8
/**
* tty_wait_until_sent - wait for I/O to finish
* @tty: tty we are waiting for
* @timeout: how long we will wait
*
* Wait for characters pending in a tty driver to hit the wire, or
* for a timeout to occur (eg due to flow control)
*
* Locking: none
*/
void tty_wait_until_sent(struct tty_struct * tty, long timeout)
{
#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
char buf[64];
printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf));
#endif
if (!tty->driver->chars_in_buffer)
return;
if (!timeout)
timeout = MAX_SCHEDULE_TIMEOUT;
if (wait_event_interruptible_timeout(tty->write_wait,
!tty->driver->chars_in_buffer(tty), timeout))
return;
if (tty->driver->wait_until_sent)
tty->driver->wait_until_sent(tty, timeout);
}
EXPORT_SYMBOL(tty_wait_until_sent);
static void unset_locked_termios(struct ktermios *termios,
struct ktermios *old,
struct ktermios *locked)
{
int i;
#define NOSET_MASK(x,y,z) (x = ((x) & ~(z)) | ((y) & (z)))
if (!locked) {
printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n");
return;
}
NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
termios->c_line = locked->c_line ? old->c_line : termios->c_line;
for (i=0; i < NCCS; i++)
termios->c_cc[i] = locked->c_cc[i] ?
old->c_cc[i] : termios->c_cc[i];
/* FIXME: What should we do for i/ospeed */
}
/*
* Routine which returns the baud rate of the tty
*
* Note that the baud_table needs to be kept in sync with the
* include/asm/termbits.h file.
*/
static const speed_t baud_table[] = {
0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
9600, 19200, 38400, 57600, 115200, 230400, 460800,
#ifdef __sparc__
76800, 153600, 307200, 614400, 921600
#else
500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
2500000, 3000000, 3500000, 4000000
#endif
};
#ifndef __sparc__
static const tcflag_t baud_bits[] = {
B0, B50, B75, B110, B134, B150, B200, B300, B600,
B1200, B1800, B2400, B4800, B9600, B19200, B38400,
B57600, B115200, B230400, B460800, B500000, B576000,
B921600, B1000000, B1152000, B1500000, B2000000, B2500000,
B3000000, B3500000, B4000000
};
#else
static const tcflag_t baud_bits[] = {
B0, B50, B75, B110, B134, B150, B200, B300, B600,
B1200, B1800, B2400, B4800, B9600, B19200, B38400,
B57600, B115200, B230400, B460800, B76800, B153600,
B307200, B614400, B921600
};
#endif
static int n_baud_table = ARRAY_SIZE(baud_table);
/**
* tty_termios_baud_rate
* @termios: termios structure
*
* Convert termios baud rate data into a speed. This should be called
* with the termios lock held if this termios is a terminal termios
* structure. May change the termios data. Device drivers can call this
* function but should use ->c_[io]speed directly as they are updated.
*
* Locking: none
*/
speed_t tty_termios_baud_rate(struct ktermios *termios)
{
unsigned int cbaud;
cbaud = termios->c_cflag & CBAUD;
#ifdef BOTHER
/* Magic token for arbitary speed via c_ispeed/c_ospeed */
if (cbaud == BOTHER)
return termios->c_ospeed;
#endif
if (cbaud & CBAUDEX) {
cbaud &= ~CBAUDEX;
if (cbaud < 1 || cbaud + 15 > n_baud_table)
termios->c_cflag &= ~CBAUDEX;
else