⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 n_tty.c

📁 unix/linux 编程实践一书的所有源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * n_tty.c --- implements the N_TTY line discipline. *  * This code used to be in tty_io.c, but things are getting hairy * enough that it made sense to split things off.  (The N_TTY * processing has changed so much that it's hardly recognizable, * anyway...) * * Note that the open routine for N_TTY is guaranteed never to return * an error.  This is because Linux will fall back to setting a line * to N_TTY if it can not switch to any other line discipline.   * * Written by Theodore Ts'o, Copyright 1994. *  * This file also contains code originally written by Linus Torvalds, * Copyright 1991, 1992, 1993, and by Julian Cowley, Copyright 1994. *  * This file may be redistributed under the terms of the GNU Public * License. */#include <linux/types.h>#include <linux/major.h>#include <linux/errno.h>#include <linux/signal.h>#include <linux/fcntl.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/tty.h>#include <linux/timer.h>#include <linux/ctype.h>#include <linux/kd.h>#include <linux/mm.h>#include <linux/string.h>#include <linux/malloc.h>#include <linux/poll.h>#include <asm/uaccess.h>#include <asm/system.h>#include <asm/bitops.h>#define CONSOLE_DEV MKDEV(TTY_MAJOR,0)#define SYSCONS_DEV  MKDEV(TTYAUX_MAJOR,1)#ifndef MIN#define MIN(a,b)	((a) < (b) ? (a) : (b))#endif/* number of characters left in xmit buffer before select has we have room */#define WAKEUP_CHARS 256/* * This defines the low- and high-watermarks for throttling and * unthrottling the TTY driver.  These watermarks are used for * controlling the space in the read buffer. */#define TTY_THRESHOLD_THROTTLE		128 /* now based on remaining room */#define TTY_THRESHOLD_UNTHROTTLE 	128static inline void put_tty_queue(unsigned char c, struct tty_struct *tty){	if (tty->read_cnt < N_TTY_BUF_SIZE) {		tty->read_buf[tty->read_head] = c;		tty->read_head = (tty->read_head + 1) & (N_TTY_BUF_SIZE-1);		tty->read_cnt++;	}}/*  * Check whether to call the driver.unthrottle function. * We test the TTY_THROTTLED bit first so that it always * indicates the current state. */static void check_unthrottle(struct tty_struct * tty){	if (tty->count &&	    test_and_clear_bit(TTY_THROTTLED, &tty->flags) && 	    tty->driver.unthrottle)		tty->driver.unthrottle(tty);}/* * Reset the read buffer counters, clear the flags,  * and make sure the driver is unthrottled. Called * from n_tty_open() and n_tty_flush_buffer(). */static void reset_buffer_flags(struct tty_struct *tty){	tty->read_head = tty->read_tail = tty->read_cnt = 0;	tty->canon_head = tty->canon_data = tty->erasing = 0;	memset(&tty->read_flags, 0, sizeof tty->read_flags);	check_unthrottle(tty);}/* * Flush the input buffer */void n_tty_flush_buffer(struct tty_struct * tty){	/* clear everything and unthrottle the driver */	reset_buffer_flags(tty);		if (!tty->link)		return;	if (tty->link->packet) {		tty->ctrl_status |= TIOCPKT_FLUSHREAD;		wake_up_interruptible(&tty->link->read_wait);	}}/* * Return number of characters buffered to be delivered to user */ssize_t n_tty_chars_in_buffer(struct tty_struct *tty){	if (tty->icanon) {		if (!tty->canon_data) return 0;		return (tty->canon_head > tty->read_tail) ?			tty->canon_head - tty->read_tail :			tty->canon_head + (N_TTY_BUF_SIZE - tty->read_tail);	}	return tty->read_cnt;}/* * Perform OPOST processing.  Returns -1 when the output device is * full and the character must be retried. */static int opost(unsigned char c, struct tty_struct *tty){	int	space, spaces;	space = tty->driver.write_room(tty);	if (!space)		return -1;	if (O_OPOST(tty)) {		switch (c) {		case '\n':			if (O_ONLRET(tty))				tty->column = 0;			if (O_ONLCR(tty)) {				if (space < 2)					return -1;				tty->driver.put_char(tty, '\r');				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':			spaces = 8 - (tty->column & 7);			if (O_TABDLY(tty) == XTABS) {				if (space < spaces)					return -1;				tty->column += spaces;				tty->driver.write(tty, 0, "        ", spaces);				return 0;			}			tty->column += spaces;			break;		case '\b':			if (tty->column > 0)				tty->column--;			break;		default:			if (O_OLCUC(tty))				c = toupper(c);			if (!iscntrl(c))				tty->column++;			break;		}	}	tty->driver.put_char(tty, c);	return 0;}/* * opost_block --- to speed up block console writes, among other * things. */static ssize_t opost_block(struct tty_struct * tty,		       const unsigned char * inbuf, unsigned int nr){	char	buf[80];	int	space;	int 	i;	char	*cp;	space = tty->driver.write_room(tty);	if (!space)		return 0;	if (nr > space)		nr = space;	if (nr > sizeof(buf))	    nr = sizeof(buf);	nr -= copy_from_user(buf, inbuf, nr);	if (!nr)		return 0;		for (i = 0, cp = buf; i < nr; i++, cp++) {		switch (*cp) {		case '\n':			if (O_ONLRET(tty))				tty->column = 0;			if (O_ONLCR(tty))				goto break_out;			tty->canon_column = tty->column;			break;		case '\r':			if (O_ONOCR(tty) && tty->column == 0)				goto break_out;			if (O_OCRNL(tty)) {				*cp = '\n';				if (O_ONLRET(tty))					tty->canon_column = tty->column = 0;				break;			}			tty->canon_column = tty->column = 0;			break;		case '\t':			goto break_out;		case '\b':			if (tty->column > 0)				tty->column--;			break;		default:			if (O_OLCUC(tty))				*cp = toupper(*cp);			if (!iscntrl(*cp))				tty->column++;			break;		}	}break_out:	if (tty->driver.flush_chars)		tty->driver.flush_chars(tty);	i = tty->driver.write(tty, 0, buf, i);		return i;}static inline void put_char(unsigned char c, struct tty_struct *tty){	tty->driver.put_char(tty, c);}/* 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') {		put_char('^', tty);		put_char(c ^ 0100, tty);		tty->column += 2;	} else		opost(c, tty);}static inline void finish_erasing(struct tty_struct *tty){	if (tty->erasing) {		put_char('/', tty);		tty->column += 2;		tty->erasing = 0;	}}static void eraser(unsigned char c, struct tty_struct *tty){	enum { ERASE, WERASE, KILL } kill_type;	int head, seen_alnums;	if (tty->read_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->read_cnt -= ((tty->read_head - tty->canon_head) &					  (N_TTY_BUF_SIZE - 1));			tty->read_head = tty->canon_head;			return;		}		if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) {			tty->read_cnt -= ((tty->read_head - tty->canon_head) &					  (N_TTY_BUF_SIZE - 1));			tty->read_head = tty->canon_head;			finish_erasing(tty);			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->read_head != tty->canon_head) {		head = (tty->read_head - 1) & (N_TTY_BUF_SIZE-1);		c = tty->read_buf[head];		if (kill_type == WERASE) {			/* Equivalent to BSD's ALTWERASE. */			if (isalnum(c) || c == '_')				seen_alnums++;			else if (seen_alnums)				break;		}		tty->read_head = head;		tty->read_cnt--;		if (L_ECHO(tty)) {			if (L_ECHOPRT(tty)) {				if (!tty->erasing) {					put_char('\\', tty);					tty->column++;					tty->erasing = 1;				}				echo_char(c, tty);			} else if (kill_type == ERASE && !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->read_head) {					c = tty->read_buf[tail];					if (c == '\t')						col = (col | 7) + 1;					else if (iscntrl(c)) {						if (L_ECHOCTL(tty))							col += 2;					} else						col++;					tail = (tail+1) & (N_TTY_BUF_SIZE-1);				}				/* should never happen */				if (tty->column > 0x80000000)					tty->column = 0; 				/* Now backup to that column. */				while (tty->column > col) {					/* Can't use opost here. */					put_char('\b', tty);					if (tty->column > 0)						tty->column--;				}			} else {				if (iscntrl(c) && L_ECHOCTL(tty)) {					put_char('\b', tty);					put_char(' ', tty);					put_char('\b', tty);					if (tty->column > 0)						tty->column--;				}				if (!iscntrl(c) || L_ECHOCTL(tty)) {					put_char('\b', tty);					put_char(' ', tty);					put_char('\b', tty);					if (tty->column > 0)						tty->column--;				}			}		}		if (kill_type == ERASE)			break;	}	if (tty->read_head == tty->canon_head)		finish_erasing(tty);}static inline void isig(int sig, struct tty_struct *tty, int flush){	if (tty->pgrp > 0)		kill_pg(tty->pgrp, sig, 1);	if (flush || !L_NOFLSH(tty)) {		n_tty_flush_buffer(tty);		if (tty->driver.flush_buffer)			tty->driver.flush_buffer(tty);	}}static inline void n_tty_receive_break(struct tty_struct *tty){	if (I_IGNBRK(tty))		return;	if (I_BRKINT(tty)) {		isig(SIGINT, tty, 1);		return;	}	if (I_PARMRK(tty)) {		put_tty_queue('\377', tty);		put_tty_queue('\0', tty);	}	put_tty_queue('\0', tty);	wake_up_interruptible(&tty->read_wait);}static inline void n_tty_receive_overrun(struct tty_struct *tty){	char buf[64];	tty->num_overrun++;	if (time_before(tty->overrun_time, jiffies - HZ)) {		printk("%s: %d input overrun(s)\n", tty_name(tty, buf),		       tty->num_overrun);		tty->overrun_time = jiffies;		tty->num_overrun = 0;	}}static inline void n_tty_receive_parity_error(struct tty_struct *tty,					      unsigned char c){	if (I_IGNPAR(tty)) {		return;	}	if (I_PARMRK(tty)) {		put_tty_queue('\377', tty);		put_tty_queue('\0', tty);		put_tty_queue(c, tty);	} else	if (I_INPCK(tty))		put_tty_queue('\0', tty);	else		put_tty_queue(c, tty);	wake_up_interruptible(&tty->read_wait);}static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c){	if (tty->raw) {		put_tty_queue(c, tty);		return;	}		if (tty->stopped && !tty->flow_stopped &&	    I_IXON(tty) && I_IXANY(tty)) {		start_tty(tty);		return;	}		if (I_ISTRIP(tty))		c &= 0x7f;	if (I_IUCLC(tty) && L_IEXTEN(tty))		c=tolower(c);	if (tty->closing) {		if (I_IXON(tty)) {			if (c == START_CHAR(tty))				start_tty(tty);			else if (c == STOP_CHAR(tty))				stop_tty(tty);		}		return;	}	/*	 * If the previous character was LNEXT, or we know that this	 * character is not one of the characters that we'll have to	 * handle specially, do shortcut processing to speed things	 * up.	 */	if (!test_bit(c, &tty->process_char_map) || tty->lnext) {		finish_erasing(tty);		tty->lnext = 0;		if (L_ECHO(tty)) {			if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {				put_char('\a', tty); /* beep if no space */				return;			}			/* Record the column of first canon char. */			if (tty->canon_head == tty->read_head)				tty->canon_column = tty->column;			echo_char(c, tty);		}		if (I_PARMRK(tty) && c == (unsigned char) '\377')			put_tty_queue(c, tty);		put_tty_queue(c, tty);		return;	}			if (c == '\r') {		if (I_IGNCR(tty))			return;		if (I_ICRNL(tty))			c = '\n';	} else if (c == '\n' && I_INLCR(tty))		c = '\r';	if (I_IXON(tty)) {		if (c == START_CHAR(tty)) {			start_tty(tty);			return;		}		if (c == STOP_CHAR(tty)) {			stop_tty(tty);			return;		}	}	if (L_ISIG(tty)) {		int signal;		signal = SIGINT;		if (c == INTR_CHAR(tty))			goto send_signal;		signal = SIGQUIT;		if (c == QUIT_CHAR(tty))			goto send_signal;		signal = SIGTSTP;		if (c == SUSP_CHAR(tty)) {send_signal:			isig(signal, tty, 0);			return;		}	}	if (tty->icanon) {		if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||		    (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {			eraser(c, tty);			return;		}		if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {			tty->lnext = 1;			if (L_ECHO(tty)) {				finish_erasing(tty);				if (L_ECHOCTL(tty)) {					put_char('^', tty);					put_char('\b', tty);				}			}			return;		}		if (c == REPRINT_CHAR(tty) && L_ECHO(tty) &&		    L_IEXTEN(tty)) {			unsigned long tail = tty->canon_head;			finish_erasing(tty);			echo_char(c, tty);			opost('\n', tty);			while (tail != tty->read_head) {				echo_char(tty->read_buf[tail], tty);				tail = (tail+1) & (N_TTY_BUF_SIZE-1);			}			return;		}		if (c == '\n') {			if (L_ECHO(tty) || L_ECHONL(tty)) {				if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {					put_char('\a', tty);					return;				}				opost('\n', tty);			}			goto handle_newline;		}		if (c == EOF_CHAR(tty)) {		        if (tty->canon_head != tty->read_head)			        set_bit(TTY_PUSH, &tty->flags);			c = __DISABLED_CHAR;			goto handle_newline;		}		if ((c == EOL_CHAR(tty)) ||		    (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {			/*			 * XXX are EOL_CHAR and EOL2_CHAR echoed?!?			 */			if (L_ECHO(tty)) {				if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {					put_char('\a', tty);					return;				}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -