欢迎来到虫虫下载站 | 资源下载 资源专辑 关于我们
虫虫下载站

n_tty.c

linux 内核源代码
C
第 1 页 / 共 3 页
字号:
			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);		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;	}	n_tty_set_room(tty);}/** *	n_tty_close		-	close the ldisc for this tty *	@tty: device * *	Called from the terminal layer when this line discipline is  *	being shut down, either because of a close or becsuse of a  *	discipline change. The function will not be called while other *	ldisc methods are in progress. */ static void n_tty_close(struct tty_struct *tty){	n_tty_flush_buffer(tty);	if (tty->read_buf) {		free_buf(tty->read_buf);		tty->read_buf = NULL;	}}/** *	n_tty_open		-	open an ldisc *	@tty: terminal to open * *	Called when this line discipline is being attached to the  *	terminal device. Can sleep. Called serialized so that no *	other events will occur in parallel. No further open will occur *	until a close. */static int n_tty_open(struct tty_struct *tty){	if (!tty)		return -EINVAL;	/* This one is ugly. Currently a malloc failure here can panic */	if (!tty->read_buf) {		tty->read_buf = alloc_buf();		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, NULL);	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;}/** * 	copy_from_read_buf	-	copy read data directly *	@tty: terminal device *	@b: user data *	@nr: size of data * *	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. * *	Called under the tty->atomic_read_lock sem * */ static int copy_from_read_buf(struct tty_struct *tty,				      unsigned char __user **b,				      size_t *nr){	int retval;	size_t n;	unsigned long flags;	retval = 0;	spin_lock_irqsave(&tty->read_lock, flags);	n = min(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail);	n = min(*nr, n);	spin_unlock_irqrestore(&tty->read_lock, flags);	if (n) {		retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);		n -= retval;		tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);		spin_lock_irqsave(&tty->read_lock, flags);		tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);		tty->read_cnt -= n;		spin_unlock_irqrestore(&tty->read_lock, flags);		*b += n;		*nr -= n;	}	return retval;}extern ssize_t redirected_tty_write(struct file *,const char *,size_t,loff_t *);/** *	job_control		-	check job control *	@tty: tty *	@file: file handle * *	Perform job control management checks on this file/tty descriptor *	and if appropriate send any needed signals and return a negative  *	error code if action should be taken. */ static int job_control(struct tty_struct *tty, struct file *file){	/* 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_op->write != redirected_tty_write &&	    current->signal->tty == tty) {		if (!tty->pgrp)			printk("read_chan: no tty->pgrp!\n");		else if (task_pgrp(current) != tty->pgrp) {			if (is_ignored(SIGTTIN) ||			    is_current_pgrp_orphaned())				return -EIO;			kill_pgrp(task_pgrp(current), SIGTTIN, 1);			set_thread_flag(TIF_SIGPENDING);			return -ERESTARTSYS;		}	}	return 0;} /** *	read_chan		-	read function for tty *	@tty: tty device *	@file: file object *	@buf: userspace buffer pointer *	@nr: size of I/O * *	Perform reads for the line discipline. We are guaranteed that the *	line discipline will not be closed under us but we may get multiple *	parallel readers and must handle this ourselves. We may also get *	a hangup. Always called in user context, may sleep. * *	This code must be sure never to sleep through a hangup. */ static ssize_t read_chan(struct tty_struct *tty, struct file *file,			 unsigned char __user *buf, size_t nr){	unsigned char __user *b = buf;	DECLARE_WAITQUEUE(wait, current);	int c;	int minimum, time;	ssize_t retval = 0;	ssize_t size;	long timeout;	unsigned long flags;do_it_again:	if (!tty->read_buf) {		printk("n_tty_read_chan: called with read_buf == NULL?!?\n");		return -EIO;	}	c = job_control(tty, file);	if(c < 0)		return c;		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;		}	}	/*	 *	Internal serialization of reads.	 */	if (file->f_flags & O_NONBLOCK) {		if (!mutex_trylock(&tty->atomic_read_lock))			return -EAGAIN;	}	else {		if (mutex_lock_interruptible(&tty->atomic_read_lock))			return -ERESTARTSYS;	}	add_wait_queue(&tty->read_wait, &wait);	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;			if (tty_put_user(tty, cs, b++)) {				retval = -EFAULT;				b--;				break;			}			nr--;			break;		}		/* This statement must be first before checking for input		   so that any interrupt will set the state back to		   TASK_RUNNING. */		set_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;			}			n_tty_set_room(tty);			timeout = schedule_timeout(timeout);			continue;		}		__set_current_state(TASK_RUNNING);		/* Deal with packet mode. */		if (tty->packet && b == buf) {			if (tty_put_user(tty, TIOCPKT_DATA, b++)) {				retval = -EFAULT;				b--;				break;			}			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];				spin_lock_irqsave(&tty->read_lock, flags);				tty->read_tail = ((tty->read_tail+1) &						  (N_TTY_BUF_SIZE-1));				tty->read_cnt--;				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;				}				spin_unlock_irqrestore(&tty->read_lock, flags);				if (!eol || (c != __DISABLED_CHAR)) {					if (tty_put_user(tty, c, b++)) {						retval = -EFAULT;						b--;						break;					}					nr--;				}				if (eol) {					tty_audit_push(tty);					break;				}			}			if (retval)				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) {			n_tty_set_room(tty);			check_unthrottle(tty);		}		if (b - buf >= minimum)			break;		if (time)			timeout = time;	}	mutex_unlock(&tty->atomic_read_lock);	remove_wait_queue(&tty->read_wait, &wait);	if (!waitqueue_active(&tty->read_wait))		tty->minimum_to_wake = minimum;	__set_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;	n_tty_set_room(tty);	return retval;}/** *	write_chan		-	write function for tty *	@tty: tty device *	@file: file object *	@buf: userspace buffer pointer *	@nr: size of I/O * *	Write function of the terminal device. This is serialized with *	respect to other write callers but not to termios changes, reads *	and other such events. We must be careful with N_TTY as the receive *	code will echo characters, thus calling driver write methods. * *	This code must be sure never to sleep through a hangup. */ static ssize_t write_chan(struct tty_struct * tty, struct file * file,			  const unsigned char * buf, size_t nr){	const unsigned char *b = buf;	DECLARE_WAITQUEUE(wait, current);	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_op->write != redirected_tty_write) {		retval = tty_check_change(tty);		if (retval)			return retval;	}	add_wait_queue(&tty->write_wait, &wait);	while (1) {		set_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) {					if (num == -EAGAIN)						break;					retval = num;					goto break_out;				}				b += num;				nr -= num;				if (nr == 0)					break;				c = *b;				if (opost(c, tty) < 0)					break;				b++; nr--;			}			if (tty->driver->flush_chars)				tty->driver->flush_chars(tty);		} else {			while (nr > 0) {				c = tty->driver->write(tty, b, nr);				if (c < 0) {					retval = c;					goto break_out;				}				if (!c)					break;				b += c;				nr -= c;			}		}		if (!nr)			break;		if (file->f_flags & O_NONBLOCK) {			retval = -EAGAIN;			break;		}		schedule();	}break_out:	__set_current_state(TASK_RUNNING);	remove_wait_queue(&tty->write_wait, &wait);	return (b - buf) ? b - buf : retval;}/** *	normal_poll		-	poll method for N_TTY *	@tty: terminal device *	@file: file accessing it *	@wait: poll table * *	Called when the line discipline is asked to poll() for data or *	for special events. This code is not serialized with respect to *	other events save open/close. * *	This code must be sure never to sleep through a hangup. *	Called without the kernel lock held - fine * *	FIXME: if someone changes the VMIN or discipline settings for the *	terminal while another process is in poll() the poll does not *	recompute the new limits. Possibly set_termios should issue *	a read wakeup to fix this bug. */ 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_is_writelocked(tty) &&			tty->driver->chars_in_buffer(tty) < WAKEUP_CHARS &&			tty->driver->write_room(tty) > 0)		mask |= POLLOUT | POLLWRNORM;	return mask;}struct tty_ldisc tty_ldisc_N_TTY = {	.magic           = TTY_LDISC_MAGIC,	.name            = "n_tty",	.open            = n_tty_open,	.close           = n_tty_close,	.flush_buffer    = n_tty_flush_buffer,	.chars_in_buffer = n_tty_chars_in_buffer,	.read            = read_chan,	.write           = write_chan,	.ioctl           = n_tty_ioctl,	.set_termios     = n_tty_set_termios,	.poll            = normal_poll,	.receive_buf     = n_tty_receive_buf,	.write_wakeup    = n_tty_write_wakeup};

⌨️ 快捷键说明

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