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

📄 n_tty.c

📁 unix/linux 编程实践一书的所有源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
				/* Record the column of first canon char. */				if (tty->canon_head == tty->read_head)					tty->canon_column = tty->column;				echo_char(c, tty);			}			/*			 * XXX does PARMRK doubling happen for			 * EOL_CHAR and EOL2_CHAR?			 */			if (I_PARMRK(tty) && c == (unsigned char) '\377')				put_tty_queue(c, tty);		handle_newline:			set_bit(tty->read_head, &tty->read_flags);			put_tty_queue(c, tty);			tty->canon_head = tty->read_head;			tty->canon_data++;			if (tty->fasync)				kill_fasync(tty->fasync, SIGIO);			if (tty->read_wait)				wake_up_interruptible(&tty->read_wait);			return;		}	}		finish_erasing(tty);	if (L_ECHO(tty)) {		if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {			put_char('\a', tty); /* beep if no space */			return;		}		if (c == '\n')			opost('\n', tty);		else {			/* 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);}	static int n_tty_receive_room(struct tty_struct *tty){	int	left = N_TTY_BUF_SIZE - tty->read_cnt - 1;	/*	 * If we are doing input canonicalization, and there are no	 * pending newlines, let characters through without limit, so	 * that erase characters will be handled.  Other excess	 * characters will be beeped.	 */	if (tty->icanon && !tty->canon_data)		return N_TTY_BUF_SIZE;	if (left > 0)		return left;	return 0;}static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,			      char *fp, int count){	const unsigned char *p;	char *f, flags = TTY_NORMAL;	int	i;	char	buf[64];	if (!tty->read_buf)		return;	if (tty->real_raw) {		i = MIN(count, MIN(N_TTY_BUF_SIZE - tty->read_cnt,				   N_TTY_BUF_SIZE - tty->read_head));		memcpy(tty->read_buf + tty->read_head, cp, i);		tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);		tty->read_cnt += i;		cp += i;		count -= i;		i = MIN(count, MIN(N_TTY_BUF_SIZE - tty->read_cnt,			       N_TTY_BUF_SIZE - tty->read_head));		memcpy(tty->read_buf + tty->read_head, cp, i);		tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);		tty->read_cnt += i;	} else {		for (i=count, p = cp, f = fp; i; i--, p++) {			if (f)				flags = *f++;			switch (flags) {			case TTY_NORMAL:				n_tty_receive_char(tty, *p);				break;			case TTY_BREAK:				n_tty_receive_break(tty);				break;			case TTY_PARITY:			case TTY_FRAME:				n_tty_receive_parity_error(tty, *p);				break;			case TTY_OVERRUN:				n_tty_receive_overrun(tty);				break;			default:				printk("%s: unknown flag %d\n",				       tty_name(tty, buf), flags);				break;			}		}		if (tty->driver.flush_chars)			tty->driver.flush_chars(tty);	}	if (!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) {		if (tty->fasync)			kill_fasync(tty->fasync, SIGIO);		if (tty->read_wait)			wake_up_interruptible(&tty->read_wait);	}	/*	 * Check the remaining room for the input canonicalization	 * mode.  We don't want to throttle the driver if we're in	 * canonical mode and don't have a newline yet!	 */	if (n_tty_receive_room(tty) < TTY_THRESHOLD_THROTTLE) {		/* check TTY_THROTTLED first so it indicates our state */		if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&		    tty->driver.throttle)			tty->driver.throttle(tty);	}}int is_ignored(int sig){	return (sigismember(&current->blocked, sig) ||	        current->sig->action[sig-1].sa.sa_handler == SIG_IGN);}static void n_tty_set_termios(struct tty_struct *tty, struct termios * old){	if (!tty)		return;		tty->icanon = (L_ICANON(tty) != 0);	if (test_bit(TTY_HW_COOK_IN, &tty->flags)) {		tty->raw = 1;		tty->real_raw = 1;		return;	}	if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) ||	    I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||	    I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||	    I_PARMRK(tty)) {		cli();		memset(tty->process_char_map, 0, 256/8);		if (I_IGNCR(tty) || I_ICRNL(tty))			set_bit('\r', &tty->process_char_map);		if (I_INLCR(tty))			set_bit('\n', &tty->process_char_map);		if (L_ICANON(tty)) {			set_bit(ERASE_CHAR(tty), &tty->process_char_map);			set_bit(KILL_CHAR(tty), &tty->process_char_map);			set_bit(EOF_CHAR(tty), &tty->process_char_map);			set_bit('\n', &tty->process_char_map);			set_bit(EOL_CHAR(tty), &tty->process_char_map);			if (L_IEXTEN(tty)) {				set_bit(WERASE_CHAR(tty),					&tty->process_char_map);				set_bit(LNEXT_CHAR(tty),					&tty->process_char_map);				set_bit(EOL2_CHAR(tty),					&tty->process_char_map);				if (L_ECHO(tty))					set_bit(REPRINT_CHAR(tty),						&tty->process_char_map);			}		}		if (I_IXON(tty)) {			set_bit(START_CHAR(tty), &tty->process_char_map);			set_bit(STOP_CHAR(tty), &tty->process_char_map);		}		if (L_ISIG(tty)) {			set_bit(INTR_CHAR(tty), &tty->process_char_map);			set_bit(QUIT_CHAR(tty), &tty->process_char_map);			set_bit(SUSP_CHAR(tty), &tty->process_char_map);		}		clear_bit(__DISABLED_CHAR, &tty->process_char_map);		sti();		tty->raw = 0;		tty->real_raw = 0;	} else {		tty->raw = 1;		if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) &&		    (I_IGNPAR(tty) || !I_INPCK(tty)) &&		    (tty->driver.flags & TTY_DRIVER_REAL_RAW))			tty->real_raw = 1;		else			tty->real_raw = 0;	}}static void n_tty_close(struct tty_struct *tty){	n_tty_flush_buffer(tty);	if (tty->read_buf) {		free_page((unsigned long) tty->read_buf);		tty->read_buf = 0;	}}static int n_tty_open(struct tty_struct *tty){	if (!tty)		return -EINVAL;	if (!tty->read_buf) {		tty->read_buf = (unsigned char *)			get_free_page(in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);		if (!tty->read_buf)			return -ENOMEM;	}	memset(tty->read_buf, 0, N_TTY_BUF_SIZE);	reset_buffer_flags(tty);	tty->column = 0;	n_tty_set_termios(tty, 0);	tty->minimum_to_wake = 1;	tty->closing = 0;	return 0;}static inline int input_available_p(struct tty_struct *tty, int amt){	if (tty->icanon) {		if (tty->canon_data)			return 1;	} else if (tty->read_cnt >= (amt ? amt : 1))		return 1;	return 0;}/* * Helper function to speed up read_chan.  It is only called when * ICANON is off; it copies characters straight from the tty queue to * user space directly.  It can be profitably called twice; once to * drain the space from the tail pointer to the (physical) end of the * buffer, and once to drain the space from the (physical) beginning of * the buffer to head pointer. */static inline int copy_from_read_buf(struct tty_struct *tty,				      unsigned char **b,				      size_t *nr){	int retval;	ssize_t n;	retval = 0;	n = MIN(*nr, MIN(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail));	if (n) {		mb();		retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);		n -= retval;		tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);		tty->read_cnt -= n;		*b += n;		*nr -= n;	}	return retval;}static ssize_t read_chan(struct tty_struct *tty, struct file *file,			 unsigned char *buf, size_t nr){	unsigned char *b = buf;	struct wait_queue wait = { current, NULL };	int c;	int minimum, time;	ssize_t retval = 0;	ssize_t size;	long timeout;do_it_again:	if (!tty->read_buf) {		printk("n_tty_read_chan: called with read_buf == NULL?!?\n");		return -EIO;	}	/* Job control check -- must be done at start and after	   every sleep (POSIX.1 7.1.1.4). */	/* NOTE: not yet done after every sleep pending a thorough	   check of the logic of this change. -- jlc */	/* don't stop on /dev/console */	if (file->f_dentry->d_inode->i_rdev != CONSOLE_DEV &&	    file->f_dentry->d_inode->i_rdev != SYSCONS_DEV &&	    current->tty == tty) {		if (tty->pgrp <= 0)			printk("read_chan: tty->pgrp <= 0!\n");		else if (current->pgrp != tty->pgrp) {			if (is_ignored(SIGTTIN) ||			    is_orphaned_pgrp(current->pgrp))				return -EIO;			kill_pg(current->pgrp, SIGTTIN, 1);			return -ERESTARTSYS;		}	}	minimum = time = 0;	timeout = MAX_SCHEDULE_TIMEOUT;	if (!tty->icanon) {		time = (HZ / 10) * TIME_CHAR(tty);		minimum = MIN_CHAR(tty);		if (minimum) {			if (time)				tty->minimum_to_wake = 1;			else if (!waitqueue_active(&tty->read_wait) ||				 (tty->minimum_to_wake > minimum))				tty->minimum_to_wake = minimum;		} else {			timeout = 0;			if (time) {				timeout = time;				time = 0;			}			tty->minimum_to_wake = minimum = 1;		}	}	if (file->f_flags & O_NONBLOCK) {		if (down_trylock(&tty->atomic_read))			return -EAGAIN;	}	else {		if (down_interruptible(&tty->atomic_read))			return -ERESTARTSYS;	}	add_wait_queue(&tty->read_wait, &wait);	set_bit(TTY_DONT_FLIP, &tty->flags);	while (nr) {		/* First test for status change. */		if (tty->packet && tty->link->ctrl_status) {			unsigned char cs;			if (b != buf)				break;			cs = tty->link->ctrl_status;			tty->link->ctrl_status = 0;			put_user(cs, b++);			nr--;			break;		}		/* This statement must be first before checking for input		   so that any interrupt will set the state back to		   TASK_RUNNING. */		current->state = TASK_INTERRUPTIBLE;				if (((minimum - (b - buf)) < tty->minimum_to_wake) &&		    ((minimum - (b - buf)) >= 1))			tty->minimum_to_wake = (minimum - (b - buf));				if (!input_available_p(tty, 0)) {			if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {				retval = -EIO;				break;			}			if (tty_hung_up_p(file))				break;			if (!timeout)				break;			if (file->f_flags & O_NONBLOCK) {				retval = -EAGAIN;				break;			}			if (signal_pending(current)) {				retval = -ERESTARTSYS;				break;			}			clear_bit(TTY_DONT_FLIP, &tty->flags);			timeout = schedule_timeout(timeout);			set_bit(TTY_DONT_FLIP, &tty->flags);			continue;		}		current->state = TASK_RUNNING;		/* Deal with packet mode. */		if (tty->packet && b == buf) {			put_user(TIOCPKT_DATA, b++);			nr--;		}		if (tty->icanon) {			/* N.B. avoid overrun if nr == 0 */			while (nr && tty->read_cnt) { 				int eol;				eol = test_and_clear_bit(tty->read_tail,						&tty->read_flags);				c = tty->read_buf[tty->read_tail];				tty->read_tail = ((tty->read_tail+1) &						  (N_TTY_BUF_SIZE-1));				tty->read_cnt--;				if (!eol || (c != __DISABLED_CHAR)) {					put_user(c, b++);					nr--;				}				if (eol) {					/* this test should be redundant:					 * we shouldn't be reading data if					 * canon_data is 0					 */					if (--tty->canon_data < 0)						tty->canon_data = 0;					break;				}			}		} else {			int uncopied;			uncopied = copy_from_read_buf(tty, &b, &nr);			uncopied += copy_from_read_buf(tty, &b, &nr);			if (uncopied) {				retval = -EFAULT;				break;			}		}		/* If there is enough space in the read buffer now, let the		 * low-level driver know. We use n_tty_chars_in_buffer() to		 * check the buffer, as it now knows about canonical mode.		 * Otherwise, if the driver is throttled and the line is		 * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,		 * we won't get any more characters.		 */		if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE)			check_unthrottle(tty);		if (b - buf >= minimum)			break;		if (time)			timeout = time;	}	clear_bit(TTY_DONT_FLIP, &tty->flags);	up(&tty->atomic_read);	remove_wait_queue(&tty->read_wait, &wait);	if (!waitqueue_active(&tty->read_wait))		tty->minimum_to_wake = minimum;	current->state = TASK_RUNNING;	size = b - buf;	if (size) {		retval = size;		if (nr)	       		clear_bit(TTY_PUSH, &tty->flags);	} else if (test_and_clear_bit(TTY_PUSH, &tty->flags))		 goto do_it_again;	return retval;}static ssize_t write_chan(struct tty_struct * tty, struct file * file,			  const unsigned char * buf, size_t nr){	const unsigned char *b = buf;	struct wait_queue wait = { current, NULL };	int c;	ssize_t retval = 0;	/* Job control check -- must be done at start (POSIX.1 7.1.1.4). */	if (L_TOSTOP(tty) && 	    file->f_dentry->d_inode->i_rdev != CONSOLE_DEV &&	    file->f_dentry->d_inode->i_rdev != SYSCONS_DEV) {		retval = tty_check_change(tty);		if (retval)			return retval;	}	add_wait_queue(&tty->write_wait, &wait);	while (1) {		current->state = TASK_INTERRUPTIBLE;		if (signal_pending(current)) {			retval = -ERESTARTSYS;			break;		}		if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) {			retval = -EIO;			break;		}		if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {			while (nr > 0) {				ssize_t num = opost_block(tty, b, nr);				if (num < 0) {					retval = num;					goto break_out;				}				b += num;				nr -= num;				if (nr == 0)					break;				current->state = TASK_RUNNING;				get_user(c, b);				current->state = TASK_INTERRUPTIBLE;				if (opost(c, tty) < 0)					break;				b++; nr--;			}			if (tty->driver.flush_chars)				tty->driver.flush_chars(tty);		} else {			current->state = TASK_RUNNING;			c = tty->driver.write(tty, 1, b, nr);			current->state = TASK_INTERRUPTIBLE;			if (c < 0) {				retval = c;				goto break_out;			}			b += c;			nr -= c;		}		if (!nr)			break;		if (file->f_flags & O_NONBLOCK) {			retval = -EAGAIN;			break;		}		schedule();	}break_out:	current->state = TASK_RUNNING;	remove_wait_queue(&tty->write_wait, &wait);	return (b - buf) ? b - buf : retval;}static unsigned int normal_poll(struct tty_struct * tty, struct file * file, poll_table *wait){	unsigned int mask = 0;	poll_wait(file, &tty->read_wait, wait);	poll_wait(file, &tty->write_wait, wait);	if (input_available_p(tty, TIME_CHAR(tty) ? 0 : MIN_CHAR(tty)))		mask |= POLLIN | POLLRDNORM;	if (tty->packet && tty->link->ctrl_status)		mask |= POLLPRI | POLLIN | POLLRDNORM;	if (test_bit(TTY_OTHER_CLOSED, &tty->flags))		mask |= POLLHUP;	if (tty_hung_up_p(file))		mask |= POLLHUP;	if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) {		if (MIN_CHAR(tty) && !TIME_CHAR(tty))			tty->minimum_to_wake = MIN_CHAR(tty);		else			tty->minimum_to_wake = 1;	}	if (tty->driver.chars_in_buffer(tty) < WAKEUP_CHARS)		mask |= POLLOUT | POLLWRNORM;	return mask;}struct tty_ldisc tty_ldisc_N_TTY = {	TTY_LDISC_MAGIC,	/* magic */	"n_tty",		/* name */	0,			/* num */	0,			/* flags */	n_tty_open,		/* open */	n_tty_close,		/* close */	n_tty_flush_buffer,	/* flush_buffer */	n_tty_chars_in_buffer,	/* chars_in_buffer */	read_chan,		/* read */	write_chan,		/* write */	n_tty_ioctl,		/* ioctl */	n_tty_set_termios,	/* set_termios */	normal_poll,		/* poll */	n_tty_receive_buf,	/* receive_buf */	n_tty_receive_room,	/* receive_room */	0			/* write_wakeup */};

⌨️ 快捷键说明

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