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

📄 tty_io.c

📁 unix/linux 编程实践一书的所有源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *  linux/drivers/char/tty_io.c * *  Copyright (C) 1991, 1992  Linus Torvalds *//* * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles * or rs-channels. It also implements echoing, cooked mode etc. * * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0. * * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the * tty_struct and tty_queue structures.  Previously there was an array * of 256 tty_struct's which was statically allocated, and the * tty_queue structures were allocated at boot time.  Both are now * dynamically allocated only when the tty is open. * * Also restructured routines so that there is more of a separation * between the high-level tty routines (tty_io.c and tty_ioctl.c) and * the low-level tty routines (serial.c, pty.c, console.c).  This * makes for cleaner and more compact code.  -TYT, 9/17/92  * * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines * which can be dynamically activated and de-activated by the line * discipline handling modules (like SLIP). * * NOTE: pay no attention to the line discipline code (yet); its * interface is still subject to change in this version... * -- TYT, 1/31/92 * * Added functionality to the OPOST tty handling.  No delays, but all * other bits should be there. *	-- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993. * * Rewrote canonical mode and added more termios flags. * 	-- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94 * * Reorganized FASYNC support so mouse code can share it. *	-- ctm@ardi.com, 9Sep95 * * New TIOCLINUX variants added. *	-- mj@k332.feld.cvut.cz, 19-Nov-95 *  * Restrict vt switching via ioctl() *      -- grif@cs.ucr.edu, 5-Dec-95 * * Rewrote init_dev and release_dev to eliminate races. *	-- Bill Hawes <whawes@star.net>, June 97 */#include <linux/config.h>#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/tty_flip.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 <asm/segment.h>#include <asm/system.h>#include <asm/bitops.h>#include <linux/scc.h>#include "kbd_kern.h"#include "vt_kern.h"#include "selection.h"#ifdef CONFIG_KERNELD#include <linux/kerneld.h>#endif#define CONSOLE_DEV MKDEV(TTY_MAJOR,0)#define TTY_DEV MKDEV(TTYAUX_MAJOR,0)#undef TTY_DEBUG_HANGUP#define TTY_PARANOIA_CHECK#define CHECK_TTY_COUNTextern void do_blank_screen(int nopowersave);extern void set_vesa_blanking(const unsigned long arg);struct termios tty_std_termios;		/* for the benefit of tty drivers  */struct tty_driver *tty_drivers = NULL;	/* linked list of tty drivers */struct tty_ldisc ldiscs[NR_LDISCS];	/* line disc dispatch table	*//* * fg_console is the current virtual console, * last_console is the last used one, * want_console is the console we want to switch to, * kmsg_redirect is the console for kernel messages, * redirect is the pseudo-tty that console output * is redirected to if asked by TIOCCONS. */int fg_console = 0;int last_console = 0;int want_console = -1;int kmsg_redirect = 0;struct tty_struct * redirect = NULL;struct wait_queue * keypress_wait = NULL;char vt_dont_switch = 0;static void initialize_tty_struct(struct tty_struct *tty);static int tty_read(struct inode *, struct file *, char *, int);static int tty_write(struct inode *, struct file *, const char *, int);static int tty_select(struct inode *, struct file *, int, select_table *);static int tty_open(struct inode *, struct file *);static void tty_release(struct inode *, struct file *);static int tty_ioctl(struct inode * inode, struct file * file,		     unsigned int cmd, unsigned long arg);static int tty_fasync(struct inode * inode, struct file * filp, int on);extern void reset_palette(int currcons) ;extern void set_palette(void) ;#ifndef MIN#define MIN(a,b)	((a) < (b) ? (a) : (b))#endif/* * These two routines return the name of tty.  tty_name() should NOT * be used in interrupt drivers, since it's not re-entrant.  Use * _tty_name() instead. */char *_tty_name(struct tty_struct *tty, char *buf){	if (tty)		sprintf(buf, "%s%d", tty->driver.name,			MINOR(tty->device) - tty->driver.minor_start +			tty->driver.name_base);	else		strcpy(buf, "NULL tty");	return buf;}char *tty_name(struct tty_struct *tty){	static char buf[64];	return(_tty_name(tty, buf));}inline int tty_paranoia_check(struct tty_struct *tty, kdev_t device,			      const char *routine){#ifdef TTY_PARANOIA_CHECK	static const char *badmagic =		"Warning: bad magic number for tty struct (%s) in %s\n";	static const char *badtty =		"Warning: null TTY for (%s) in %s\n";	if (!tty) {		printk(badtty, kdevname(device), routine);		return 1;	}	if (tty->magic != TTY_MAGIC) {		printk(badmagic, kdevname(device), routine);		return 1;	}#endif	return 0;}static int check_tty_count(struct tty_struct *tty, const char *routine){#ifdef CHECK_TTY_COUNT	struct file *f;	int i, count = 0;		for (f = first_file, i=0; i<nr_files; i++, f = f->f_next) {		if (!f->f_count)			continue;		if (f->private_data == tty) {			count++;		}	}	if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&	    tty->driver.subtype == PTY_TYPE_SLAVE &&	    tty->link && tty->link->count)		count++;	if (tty->count != count) {		printk("Warning: dev (%s) tty->count(%d) != #fd's(%d) in %s\n",		       kdevname(tty->device), tty->count, count, routine);		return count;       }	#endif	return 0;}int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc){	if (disc < N_TTY || disc >= NR_LDISCS)		return -EINVAL;		if (new_ldisc) {		ldiscs[disc] = *new_ldisc;		ldiscs[disc].flags |= LDISC_FLAG_DEFINED;		ldiscs[disc].num = disc;	} else		memset(&ldiscs[disc], 0, sizeof(struct tty_ldisc));		return 0;}/* Set the discipline of a tty line. */static int tty_set_ldisc(struct tty_struct *tty, int ldisc){	int	retval = 0;	struct	tty_ldisc o_ldisc;	if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS))		return -EINVAL;#ifdef CONFIG_KERNELD	/* Eduardo Blanco <ejbs@cs.cs.com.uy> */	if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) {		char modname [20];		sprintf(modname, "tty-ldisc-%d", ldisc);		request_module (modname);	}#endif	if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED))		return -EINVAL;	if (tty->ldisc.num == ldisc)		return 0;	/* We are already in the desired discipline */	o_ldisc = tty->ldisc;	tty_wait_until_sent(tty, 0);		/* Shutdown the current discipline. */	if (tty->ldisc.close)		(tty->ldisc.close)(tty);	/* Now set up the new line discipline. */	tty->ldisc = ldiscs[ldisc];	tty->termios->c_line = ldisc;	if (tty->ldisc.open)		retval = (tty->ldisc.open)(tty);	if (retval < 0) {		tty->ldisc = o_ldisc;		tty->termios->c_line = tty->ldisc.num;		if (tty->ldisc.open && (tty->ldisc.open(tty) < 0)) {			tty->ldisc = ldiscs[N_TTY];			tty->termios->c_line = N_TTY;			if (tty->ldisc.open) {				int r = tty->ldisc.open(tty);				if (r < 0)					panic("Couldn't open N_TTY ldisc for "					      "%s --- error %d.",					      tty_name(tty), r);			}		}	}	if (tty->ldisc.num != o_ldisc.num && tty->driver.set_ldisc)		tty->driver.set_ldisc(tty);	return retval;}/* * This routine returns a tty driver structure, given a device number */struct tty_driver *get_tty_driver(kdev_t device){	int	major, minor;	struct tty_driver *p;		minor = MINOR(device);	major = MAJOR(device);	for (p = tty_drivers; p; p = p->next) {		if (p->major != major)			continue;		if (minor < p->minor_start)			continue;		if (minor >= p->minor_start + p->num)			continue;		return p;	}	return NULL;}/* * If we try to write to, or set the state of, a terminal and we're * not in the foreground, send a SIGTTOU.  If the signal is blocked or * ignored, go ahead and perform the operation.  (POSIX 7.2) */int tty_check_change(struct tty_struct * tty){	if (current->tty != tty)		return 0;	if (tty->pgrp <= 0) {		printk("tty_check_change: tty->pgrp <= 0!\n");		return 0;	}	if (current->pgrp == tty->pgrp)		return 0;	if (is_ignored(SIGTTOU))		return 0;	if (is_orphaned_pgrp(current->pgrp))		return -EIO;	(void) kill_pg(current->pgrp,SIGTTOU,1);	return -ERESTARTSYS;}static int hung_up_tty_read(struct inode * inode, struct file * file, char * buf, int count){	return 0;}static int hung_up_tty_write(struct inode * inode, struct file * file, const char * buf, int count){	return -EIO;}static int hung_up_tty_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait){	return 1;}static int hung_up_tty_ioctl(struct inode * inode, struct file * file,			     unsigned int cmd, unsigned long arg){	return cmd == TIOCSPGRP ? -ENOTTY : -EIO;}static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int orig){	return -ESPIPE;}static struct file_operations tty_fops = {	tty_lseek,	tty_read,	tty_write,	NULL,		/* tty_readdir */	tty_select,	tty_ioctl,	NULL,		/* tty_mmap */	tty_open,	tty_release,	NULL,		/* tty_fsync */	tty_fasync};static struct file_operations hung_up_tty_fops = {	tty_lseek,	hung_up_tty_read,	hung_up_tty_write,	NULL,		/* hung_up_tty_readdir */	hung_up_tty_select,	hung_up_tty_ioctl,	NULL,		/* hung_up_tty_mmap */	NULL,		/* hung_up_tty_open */	tty_release,	/* hung_up_tty_release */	NULL,		/* hung_up_tty_fsync  */	NULL		/* hung_up_tty_fasync */};void do_tty_hangup(struct tty_struct * tty, struct file_operations *fops){	int i;	struct file * filp;	struct task_struct *p;	if (!tty)		return;	check_tty_count(tty, "do_tty_hangup");	for (filp = first_file, i=0; i<nr_files; i++, filp = filp->f_next) {		if (!filp->f_count)			continue;		if (filp->private_data != tty)			continue;		if (!filp->f_inode)			continue;		if (filp->f_inode->i_rdev == CONSOLE_DEV)			continue;		if (filp->f_op != &tty_fops)			continue;		tty_fasync(filp->f_inode, filp, 0);		filp->f_op = fops;	}		if (tty->ldisc.flush_buffer)		tty->ldisc.flush_buffer(tty);	if (tty->driver.flush_buffer)		tty->driver.flush_buffer(tty);	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&	    tty->ldisc.write_wakeup)		(tty->ldisc.write_wakeup)(tty);	wake_up_interruptible(&tty->write_wait);	wake_up_interruptible(&tty->read_wait);	/*	 * Shutdown the current line discipline, and reset it to	 * N_TTY.	 */	if (tty->ldisc.num != ldiscs[N_TTY].num) {		if (tty->ldisc.close)			(tty->ldisc.close)(tty);		tty->ldisc = ldiscs[N_TTY];		tty->termios->c_line = N_TTY;		if (tty->ldisc.open) {			i = (tty->ldisc.open)(tty);			if (i < 0)				printk("do_tty_hangup: N_TTY open: error %d\n",				       -i);		}	}	 	for_each_task(p) {		if ((tty->session > 0) && (p->session == tty->session) &&		    p->leader) {			send_sig(SIGHUP,p,1);			send_sig(SIGCONT,p,1);			if (tty->pgrp > 0)				p->tty_old_pgrp = tty->pgrp;		}		if (p->tty == tty)			p->tty = NULL;	}	tty->flags = 0;	tty->session = 0;	tty->pgrp = -1;	tty->ctrl_status = 0;	if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS)		*tty->termios = tty->driver.init_termios;	if (tty->driver.hangup)		(tty->driver.hangup)(tty);}void tty_hangup(struct tty_struct * tty){#ifdef TTY_DEBUG_HANGUP	printk("%s hangup...\n", tty_name(tty));#endif	do_tty_hangup(tty, &hung_up_tty_fops);}void tty_vhangup(struct tty_struct * tty){#ifdef TTY_DEBUG_HANGUP	printk("%s vhangup...\n", tty_name(tty));#endif	do_tty_hangup(tty, &hung_up_tty_fops);}int tty_hung_up_p(struct file * filp){	return (filp->f_op == &hung_up_tty_fops);}/* * This function is typically called only by the session leader, when * it wants to disassociate itself from its controlling tty. * * It performs the following functions: * 	(1)  Sends a SIGHUP and SIGCONT to the foreground process group * 	(2)  Clears the tty from being controlling the session * 	(3)  Clears the controlling tty for all processes in the * 		session group. * * The argument on_exit is set to 1 if called when a process is * exiting; it is 0 if called by the ioctl TIOCNOTTY. */void disassociate_ctty(int on_exit){	struct tty_struct *tty = current->tty;	struct task_struct *p;	int tty_pgrp = -1;	if (tty) {		tty_pgrp = tty->pgrp;		if (on_exit && tty->driver.type != TTY_DRIVER_TYPE_PTY)			tty_vhangup(tty);	} else {		if (current->tty_old_pgrp) {			kill_pg(current->tty_old_pgrp, SIGHUP, on_exit);			kill_pg(current->tty_old_pgrp, SIGCONT, on_exit);		}		return;	}	if (tty_pgrp > 0) {		kill_pg(tty_pgrp, SIGHUP, on_exit);		if (!on_exit)			kill_pg(tty_pgrp, SIGCONT, on_exit);	}	current->tty_old_pgrp = 0;	tty->session = 0;	tty->pgrp = -1;	for_each_task(p)	  	if (p->session == current->session)			p->tty = NULL;}/* * Sometimes we want to wait until a particular VT has been activated. We * do it in a very simple manner. Everybody waits on a single queue and * get woken up at once. Those that are satisfied go on with their business, * while those not ready go back to sleep. Seems overkill to add a wait * to each vt just for this - usually this does nothing! */

⌨️ 快捷键说明

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