📄 tty_io.c
字号:
{
/*
* It worked. Mark the vt to switch to and
* return. The process needs to send us a
* VT_RELDISP ioctl to complete the switch.
*/
vt_cons[fg_console].vt_newvt = new_console;
return;
}
/*
* The controlling process has died, so we revert back to
* normal operation. In this case, we'll also change back
* to KD_TEXT mode. I'm not sure if this is strictly correct
* but it saves the agony when the X server dies and the screen
* remains blanked due to KD_GRAPHICS! It would be nice to do
* this outside of VT_PROCESS but there is no single process
* to account for and tracking tty count may be undesirable.
*/
vt_cons[fg_console].vc_mode = KD_TEXT;
clr_vc_kbd_mode(kbd_table + fg_console, VC_RAW);
clr_vc_kbd_mode(kbd_table + fg_console, VC_MEDIUMRAW);
vt_cons[fg_console].vt_mode.mode = VT_AUTO;
vt_cons[fg_console].vt_mode.waitv = 0;
vt_cons[fg_console].vt_mode.relsig = 0;
vt_cons[fg_console].vt_mode.acqsig = 0;
vt_cons[fg_console].vt_mode.frsig = 0;
vt_cons[fg_console].vt_pid = -1;
vt_cons[fg_console].vt_newvt = -1;
/*
* Fall through to normal (VT_AUTO) handling of the switch...
*/
}
/*
* Ignore all switches in KD_GRAPHICS+VT_AUTO mode
*/
if (vt_cons[fg_console].vc_mode == KD_GRAPHICS)
return;
complete_change_console(new_console);
}
void wait_for_keypress(void)
{
sleep_on(&keypress_wait);
}
void stop_tty(struct tty_struct *tty)
{
if (tty->stopped)
return;
tty->stopped = 1;
if (tty->link && tty->link->packet) {
tty->ctrl_status &= ~TIOCPKT_START;
tty->ctrl_status |= TIOCPKT_STOP;
wake_up_interruptible(&tty->link->secondary.proc_list);
}
if (tty->stop)
(tty->stop)(tty);
if (IS_A_CONSOLE(tty->line)) {
set_vc_kbd_led(kbd_table + fg_console, VC_SCROLLOCK);
set_leds();
}
}
void start_tty(struct tty_struct *tty)
{
if (!tty->stopped)
return;
tty->stopped = 0;
if (tty->link && tty->link->packet) {
tty->ctrl_status &= ~TIOCPKT_STOP;
tty->ctrl_status |= TIOCPKT_START;
wake_up_interruptible(&tty->link->secondary.proc_list);
}
if (tty->start)
(tty->start)(tty);
TTY_WRITE_FLUSH(tty);
if (IS_A_CONSOLE(tty->line)) {
clr_vc_kbd_led(kbd_table + fg_console, VC_SCROLLOCK);
set_leds();
}
}
/* Perform OPOST processing. Returns -1 when the write_q becomes full
and the character must be retried. */
static int opost(unsigned char c, struct tty_struct *tty)
{
if (FULL(&tty->write_q))
return -1;
if (O_OPOST(tty)) {
switch (c) {
case '\n':
if (O_ONLRET(tty))
tty->column = 0;
if (O_ONLCR(tty)) {
if (LEFT(&tty->write_q) < 2)
return -1;
put_tty_queue('\r', &tty->write_q);
tty->column = 0;
}
tty->canon_column = tty->column;
break;
case '\r':
if (O_ONOCR(tty) && tty->column == 0)
return 0;
if (O_OCRNL(tty)) {
c = '\n';
if (O_ONLRET(tty))
tty->canon_column = tty->column = 0;
break;
}
tty->canon_column = tty->column = 0;
break;
case '\t':
if (O_TABDLY(tty) == XTABS) {
if (LEFT(&tty->write_q) < 8)
return -1;
do
put_tty_queue(' ', &tty->write_q);
while (++tty->column % 8);
return 0;
}
tty->column = (tty->column | 7) + 1;
break;
case '\b':
if (tty->column > 0)
tty->column--;
break;
default:
if (O_OLCUC(tty))
c = toupper(c);
if (!iscntrl(c))
tty->column++;
break;
}
}
put_tty_queue(c, &tty->write_q);
return 0;
}
/* Must be called only when L_ECHO(tty) is true. */
static void echo_char(unsigned char c, struct tty_struct *tty)
{
if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t') {
opost('^', tty);
opost(c ^ 0100, tty);
} else
opost(c, tty);
}
static void eraser(unsigned char c, struct tty_struct *tty)
{
enum { ERASE, WERASE, KILL } kill_type;
int seen_alnums;
if (tty->secondary.head == tty->canon_head) {
/* opost('\a', tty); */ /* what do you think? */
return;
}
if (c == ERASE_CHAR(tty))
kill_type = ERASE;
else if (c == WERASE_CHAR(tty))
kill_type = WERASE;
else {
if (!L_ECHO(tty)) {
tty->secondary.head = tty->canon_head;
return;
}
if (!L_ECHOK(tty) || !L_ECHOKE(tty)) {
tty->secondary.head = tty->canon_head;
if (tty->erasing) {
opost('/', tty);
tty->erasing = 0;
}
echo_char(KILL_CHAR(tty), tty);
/* Add a newline if ECHOK is on and ECHOKE is off. */
if (L_ECHOK(tty))
opost('\n', tty);
return;
}
kill_type = KILL;
}
seen_alnums = 0;
while (tty->secondary.head != tty->canon_head) {
c = LAST(&tty->secondary);
if (kill_type == WERASE) {
/* Equivalent to BSD's ALTWERASE. */
if (isalnum(c) || c == '_')
seen_alnums++;
else if (seen_alnums)
break;
}
DEC(tty->secondary.head);
if (L_ECHO(tty)) {
if (L_ECHOPRT(tty)) {
if (!tty->erasing) {
opost('\\', tty);
tty->erasing = 1;
}
echo_char(c, tty);
} else if (!L_ECHOE(tty)) {
echo_char(ERASE_CHAR(tty), tty);
} else if (c == '\t') {
unsigned int col = tty->canon_column;
unsigned long tail = tty->canon_head;
/* Find the column of the last char. */
while (tail != tty->secondary.head) {
c = tty->secondary.buf[tail];
if (c == '\t')
col = (col | 7) + 1;
else if (iscntrl(c)) {
if (L_ECHOCTL(tty))
col += 2;
} else
col++;
INC(tail);
}
/* Now backup to that column. */
while (tty->column > col) {
/* Can't use opost here. */
put_tty_queue('\b', &tty->write_q);
tty->column--;
}
} else {
if (iscntrl(c) && L_ECHOCTL(tty)) {
opost('\b', tty);
opost(' ', tty);
opost('\b', tty);
}
if (!iscntrl(c) || L_ECHOCTL(tty)) {
opost('\b', tty);
opost(' ', tty);
opost('\b', tty);
}
}
}
if (kill_type == ERASE)
break;
}
if (tty->erasing && tty->secondary.head == tty->canon_head) {
opost('/', tty);
tty->erasing = 0;
}
}
static void isig(int sig, struct tty_struct *tty)
{
kill_pg(tty->pgrp, sig, 1);
if (!L_NOFLSH(tty)) {
flush_input(tty);
flush_output(tty);
}
}
static void copy_to_cooked(struct tty_struct * tty)
{
int c, special_flag;
unsigned long flags;
if (!tty) {
printk("copy_to_cooked: called with NULL tty\n");
return;
}
if (!tty->write) {
printk("copy_to_cooked: tty %d has null write routine\n",
tty->line);
}
while (1) {
/*
* Check to see how much room we have left in the
* secondary queue. Send a throttle command or abort
* if necessary.
*/
c = LEFT(&tty->secondary);
if (tty->throttle && (c < SQ_THRESHOLD_LW)
&& !set_bit(TTY_SQ_THROTTLED, &tty->flags))
tty->throttle(tty, TTY_THROTTLE_SQ_FULL);
if (c == 0)
break;
save_flags(flags); cli();
if (!EMPTY(&tty->read_q)) {
c = tty->read_q.buf[tty->read_q.tail];
special_flag = clear_bit(tty->read_q.tail,
&tty->readq_flags);
INC(tty->read_q.tail);
restore_flags(flags);
} else {
restore_flags(flags);
break;
}
if (special_flag) {
tty->char_error = c;
continue;
}
if (tty->char_error) {
if (tty->char_error == TTY_BREAK) {
tty->char_error = 0;
if (I_IGNBRK(tty))
continue;
/* A break is handled by the lower levels. */
if (I_BRKINT(tty))
continue;
if (I_PARMRK(tty)) {
put_tty_queue('\377', &tty->secondary);
put_tty_queue('\0', &tty->secondary);
}
put_tty_queue('\0', &tty->secondary);
continue;
}
if (tty->char_error == TTY_OVERRUN) {
tty->char_error = 0;
printk("tty%d: input overrun\n", tty->line);
continue;
}
/* Must be a parity or frame error */
tty->char_error = 0;
if (I_IGNPAR(tty)) {
continue;
}
if (I_PARMRK(tty)) {
put_tty_queue('\377', &tty->secondary);
put_tty_queue('\0', &tty->secondary);
put_tty_queue(c, &tty->secondary);
} else
put_tty_queue('\0', &tty->secondary);
continue;
}
if (I_ISTRIP(tty))
c &= 0x7f;
if (!tty->lnext) {
if (c == '\r') {
if (I_IGNCR(tty))
continue;
if (I_ICRNL(tty))
c = '\n';
} else if (c == '\n' && I_INLCR(tty))
c = '\r';
}
if (I_IUCLC(tty) && L_IEXTEN(tty))
c=tolower(c);
if (c == __DISABLED_CHAR)
tty->lnext = 1;
if (L_ICANON(tty) && !tty->lnext) {
if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
(c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
eraser(c, tty);
continue;
}
if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
tty->lnext = 1;
if (L_ECHO(tty)) {
if (tty->erasing) {
opost('/', tty);
tty->erasing = 0;
}
if (L_ECHOCTL(tty)) {
opost('^', tty);
opost('\b', tty);
}
}
continue;
}
if (c == REPRINT_CHAR(tty) && L_ECHO(tty) &&
L_IEXTEN(tty)) {
unsigned long tail = tty->canon_head;
if (tty->erasing) {
opost('/', tty);
tty->erasing = 0;
}
echo_char(c, tty);
opost('\n', tty);
while (tail != tty->secondary.head) {
echo_char(tty->secondary.buf[tail],
tty);
INC(tail);
}
continue;
}
}
if (I_IXON(tty) && !tty->lnext) {
if ((tty->stopped && I_IXANY(tty) && L_IEXTEN(tty)) ||
c == START_CHAR(tty)) {
start_tty(tty);
continue;
}
if (c == STOP_CHAR(tty)) {
stop_tty(tty);
continue;
}
}
if (L_ISIG(tty) && !tty->lnext) {
if (c == INTR_CHAR(tty)) {
isig(SIGINT, tty);
continue;
}
if (c == QUIT_CHAR(tty)) {
isig(SIGQUIT, tty);
continue;
}
if (c == SUSP_CHAR(tty)) {
if (!is_orphaned_pgrp(tty->pgrp))
isig(SIGTSTP, tty);
continue;
}
}
if (tty->erasing) {
opost('/', tty);
tty->erasing = 0;
}
if (c == '\n' && !tty->lnext) {
if (L_ECHO(tty) || (L_ICANON(tty) && L_ECHONL(tty)))
opost('\n', tty);
} else if (L_ECHO(tty)) {
/* Don't echo the EOF char in canonical mode. Sun
handles this differently by echoing the char and
then backspacing, but that's a hack. */
if (c != EOF_CHAR(tty) || !L_ICANON(tty) ||
tty->lnext) {
/* Record the column of first canon char. */
if (tty->canon_head == tty->secondary.head)
tty->canon_column = tty->column;
echo_char(c, tty);
}
}
if (I_PARMRK(tty) && c == (unsigned char) '\377' &&
(c != EOF_CHAR(tty) || !L_ICANON(tty) || tty->lnext))
put_tty_queue(c, &tty->secondary);
if (L_ICANON(tty) && !tty->lnext &&
(c == '\n' || c == EOF_CHAR(tty) || c == EOL_CHAR(tty) ||
(c == EOL2_CHAR(tty) && L_IEXTEN(tty)))) {
if (c == EOF_CHAR(tty))
c = __DISABLED_CHAR;
set_bit(tty->secondary.head, &tty->secondary_flags);
put_tty_queue(c, &tty->secondary);
tty->canon_head = tty->secondary.head;
tty->canon_data++;
} else
put_tty_queue(c, &tty->secondary);
tty->lnext = 0;
}
if (!EMPTY(&tty->write_q))
TTY_WRITE_FLUSH(tty);
if (L_ICANON(tty) ? tty->canon_data : !EMPTY(&tty->secondary))
wake_up_interruptible(&tty->secondary.proc_list);
if (tty->throttle && (LEFT(&tty->read_q) >= RQ_THRESHOLD_HW)
&& clear_bit(TTY_RQ_THROTTLED, &tty->flags))
tty->throttle(tty, TTY_THROTTLE_RQ_AVAIL);
}
int is_ignored(int sig)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -