#include <linux/bits.h>
#include <linux/types.h>
#include <linux/termios.h>
#include <linux/errno.h>
#include <linux/sched/signal.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 <linux/compat.h>
#include <linux/termios_internal.h>
#include "tty.h"
#include <asm/io.h>
#include <linux/uaccess.h>
#undef DEBUG
#define TERMIOS_FLUSH …
#define TERMIOS_WAIT …
#define TERMIOS_TERMIO …
#define TERMIOS_OLD …
unsigned int tty_chars_in_buffer(struct tty_struct *tty)
{ … }
EXPORT_SYMBOL(…);
unsigned int tty_write_room(struct tty_struct *tty)
{ … }
EXPORT_SYMBOL(…);
void tty_driver_flush_buffer(struct tty_struct *tty)
{ … }
EXPORT_SYMBOL(…);
void tty_unthrottle(struct tty_struct *tty)
{ … }
EXPORT_SYMBOL(…);
bool tty_throttle_safe(struct tty_struct *tty)
{ … }
bool tty_unthrottle_safe(struct tty_struct *tty)
{ … }
void tty_wait_until_sent(struct tty_struct *tty, long timeout)
{ … }
EXPORT_SYMBOL(…);
static void unset_locked_termios(struct tty_struct *tty, const struct ktermios *old)
{ … }
void tty_termios_copy_hw(struct ktermios *new, const struct ktermios *old)
{ … }
EXPORT_SYMBOL(…);
bool tty_termios_hw_change(const struct ktermios *a, const struct ktermios *b)
{ … }
EXPORT_SYMBOL(…);
unsigned char tty_get_char_size(unsigned int cflag)
{ … }
EXPORT_SYMBOL_GPL(…);
unsigned char tty_get_frame_size(unsigned int cflag)
{ … }
EXPORT_SYMBOL_GPL(…);
int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
{ … }
EXPORT_SYMBOL_GPL(…);
__weak int user_termio_to_kernel_termios(struct ktermios *termios,
struct termio __user *termio)
{ … }
__weak int kernel_termios_to_user_termio(struct termio __user *termio,
struct ktermios *termios)
{ … }
#ifdef TCGETS2
__weak int user_termios_to_kernel_termios(struct ktermios *k,
struct termios2 __user *u)
{ … }
__weak int kernel_termios_to_user_termios(struct termios2 __user *u,
struct ktermios *k)
{ … }
__weak int user_termios_to_kernel_termios_1(struct ktermios *k,
struct termios __user *u)
{ … }
__weak int kernel_termios_to_user_termios_1(struct termios __user *u,
struct ktermios *k)
{ … }
#else
__weak int user_termios_to_kernel_termios(struct ktermios *k,
struct termios __user *u)
{
return copy_from_user(k, u, sizeof(struct termios));
}
__weak int kernel_termios_to_user_termios(struct termios __user *u,
struct ktermios *k)
{
return copy_to_user(u, k, sizeof(struct termios));
}
#endif
static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
{ … }
static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
{ … }
static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
{ … }
static int get_termio(struct tty_struct *tty, struct termio __user *termio)
{ … }
#ifdef TIOCGETP
static int get_sgflags(struct tty_struct *tty)
{
int flags = 0;
if (!L_ICANON(tty)) {
if (L_ISIG(tty))
flags |= 0x02;
else
flags |= 0x20;
}
if (L_ECHO(tty))
flags |= 0x08;
if (O_OPOST(tty))
if (O_ONLCR(tty))
flags |= 0x10;
return flags;
}
static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
{
struct sgttyb tmp;
down_read(&tty->termios_rwsem);
tmp.sg_ispeed = tty->termios.c_ispeed;
tmp.sg_ospeed = tty->termios.c_ospeed;
tmp.sg_erase = tty->termios.c_cc[VERASE];
tmp.sg_kill = tty->termios.c_cc[VKILL];
tmp.sg_flags = get_sgflags(tty);
up_read(&tty->termios_rwsem);
return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
static void set_sgflags(struct ktermios *termios, int flags)
{
termios->c_iflag = ICRNL | IXON;
termios->c_oflag = 0;
termios->c_lflag = ISIG | ICANON;
if (flags & 0x02) {
termios->c_iflag = 0;
termios->c_lflag &= ~ICANON;
}
if (flags & 0x08) {
termios->c_lflag |= ECHO | ECHOE | ECHOK |
ECHOCTL | ECHOKE | IEXTEN;
}
if (flags & 0x10) {
termios->c_oflag |= OPOST | ONLCR;
}
if (flags & 0x20) {
termios->c_iflag = 0;
termios->c_lflag &= ~(ISIG | ICANON);
}
if (!(termios->c_lflag & ICANON)) {
termios->c_cc[VMIN] = 1;
termios->c_cc[VTIME] = 0;
}
}
static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
{
int retval;
struct sgttyb tmp;
struct ktermios termios;
retval = tty_check_change(tty);
if (retval)
return retval;
if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
return -EFAULT;
down_write(&tty->termios_rwsem);
termios = tty->termios;
termios.c_cc[VERASE] = tmp.sg_erase;
termios.c_cc[VKILL] = tmp.sg_kill;
set_sgflags(&termios, tmp.sg_flags);
tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
termios.c_ospeed);
up_write(&tty->termios_rwsem);
tty_set_termios(tty, &termios);
return 0;
}
#endif
#ifdef TIOCGETC
static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
{
struct tchars tmp;
down_read(&tty->termios_rwsem);
tmp.t_intrc = tty->termios.c_cc[VINTR];
tmp.t_quitc = tty->termios.c_cc[VQUIT];
tmp.t_startc = tty->termios.c_cc[VSTART];
tmp.t_stopc = tty->termios.c_cc[VSTOP];
tmp.t_eofc = tty->termios.c_cc[VEOF];
tmp.t_brkc = tty->termios.c_cc[VEOL2];
up_read(&tty->termios_rwsem);
return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
{
struct tchars tmp;
if (copy_from_user(&tmp, tchars, sizeof(tmp)))
return -EFAULT;
down_write(&tty->termios_rwsem);
tty->termios.c_cc[VINTR] = tmp.t_intrc;
tty->termios.c_cc[VQUIT] = tmp.t_quitc;
tty->termios.c_cc[VSTART] = tmp.t_startc;
tty->termios.c_cc[VSTOP] = tmp.t_stopc;
tty->termios.c_cc[VEOF] = tmp.t_eofc;
tty->termios.c_cc[VEOL2] = tmp.t_brkc;
up_write(&tty->termios_rwsem);
return 0;
}
#endif
#ifdef TIOCGLTC
static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
{
struct ltchars tmp;
down_read(&tty->termios_rwsem);
tmp.t_suspc = tty->termios.c_cc[VSUSP];
tmp.t_dsuspc = tty->termios.c_cc[VSUSP];
tmp.t_rprntc = tty->termios.c_cc[VREPRINT];
tmp.t_flushc = tty->termios.c_cc[VEOL2];
tmp.t_werasc = tty->termios.c_cc[VWERASE];
tmp.t_lnextc = tty->termios.c_cc[VLNEXT];
up_read(&tty->termios_rwsem);
return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
{
struct ltchars tmp;
if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
return -EFAULT;
down_write(&tty->termios_rwsem);
tty->termios.c_cc[VSUSP] = tmp.t_suspc;
tty->termios.c_cc[VEOL2] = tmp.t_dsuspc;
tty->termios.c_cc[VREPRINT] = tmp.t_rprntc;
tty->termios.c_cc[VEOL2] = tmp.t_flushc;
tty->termios.c_cc[VWERASE] = tmp.t_werasc;
tty->termios.c_cc[VLNEXT] = tmp.t_lnextc;
up_write(&tty->termios_rwsem);
return 0;
}
#endif
static int tty_change_softcar(struct tty_struct *tty, bool enable)
{ … }
int tty_mode_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
{ … }
EXPORT_SYMBOL_GPL(…);
static int __tty_perform_flush(struct tty_struct *tty, unsigned long arg)
{ … }
int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
{ … }
EXPORT_SYMBOL_GPL(…);
int n_tty_ioctl_helper(struct tty_struct *tty, unsigned int cmd,
unsigned long arg)
{ … }
EXPORT_SYMBOL(…);