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

📄 tty_io.c

📁 linux0.02源代码用于研究linux操作系统
💻 C
字号:
/* *  linux/kernel/tty_io.c * *  (C) 1991  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. */#include <ctype.h>#include <errno.h>#include <signal.h>#include <unistd.h>#define ALRMMASK (1<<(SIGALRM-1))#include <linux/sched.h>#include <linux/tty.h>#include <asm/segment.h>#include <asm/system.h>int kill_pg(int pgrp, int sig, int priv);int is_orphaned_pgrp(int pgrp);#define _L_FLAG(tty,f)	((tty)->termios.c_lflag & f)#define _I_FLAG(tty,f)	((tty)->termios.c_iflag & f)#define _O_FLAG(tty,f)	((tty)->termios.c_oflag & f)#define L_CANON(tty)	_L_FLAG((tty),ICANON)#define L_ISIG(tty)	_L_FLAG((tty),ISIG)#define L_ECHO(tty)	_L_FLAG((tty),ECHO)#define L_ECHOE(tty)	_L_FLAG((tty),ECHOE)#define L_ECHOK(tty)	_L_FLAG((tty),ECHOK)#define L_ECHOCTL(tty)	_L_FLAG((tty),ECHOCTL)#define L_ECHOKE(tty)	_L_FLAG((tty),ECHOKE)#define L_TOSTOP(tty)	_L_FLAG((tty),TOSTOP)#define I_UCLC(tty)	_I_FLAG((tty),IUCLC)#define I_NLCR(tty)	_I_FLAG((tty),INLCR)#define I_CRNL(tty)	_I_FLAG((tty),ICRNL)#define I_NOCR(tty)	_I_FLAG((tty),IGNCR)#define I_IXON(tty)	_I_FLAG((tty),IXON)#define O_POST(tty)	_O_FLAG((tty),OPOST)#define O_NLCR(tty)	_O_FLAG((tty),ONLCR)#define O_CRNL(tty)	_O_FLAG((tty),OCRNL)#define O_NLRET(tty)	_O_FLAG((tty),ONLRET)#define O_LCUC(tty)	_O_FLAG((tty),OLCUC)#define C_SPEED(tty)	((tty)->termios.c_cflag & CBAUD)#define C_HUP(tty)	(C_SPEED((tty)) == B0)#ifndef MIN#define MIN(a,b) ((a) < (b) ? (a) : (b))#endif#define QUEUES	(3*(MAX_CONSOLES+NR_SERIALS+2*NR_PTYS))static struct tty_queue tty_queues[QUEUES];struct tty_struct tty_table[256];#define con_queues tty_queues#define rs_queues ((3*MAX_CONSOLES) + tty_queues)#define mpty_queues ((3*(MAX_CONSOLES+NR_SERIALS)) + tty_queues)#define spty_queues ((3*(MAX_CONSOLES+NR_SERIALS+NR_PTYS)) + tty_queues)#define con_table tty_table#define rs_table (64+tty_table)#define mpty_table (128+tty_table)#define spty_table (192+tty_table)int fg_console = 0;/* * these are the tables used by the machine code handlers. * you can implement virtual consoles. */struct tty_queue * table_list[]={	con_queues + 0, con_queues + 1,	rs_queues + 0, rs_queues + 1,	rs_queues + 3, rs_queues + 4	};void change_console(unsigned int new_console){	if (new_console == fg_console || new_console >= NR_CONSOLES)		return;	fg_console = new_console;	table_list[0] = con_queues + 0 + fg_console*3;	table_list[1] = con_queues + 1 + fg_console*3;	update_screen();}static void sleep_if_empty(struct tty_queue * queue){	cli();	while (!(current->signal & ~current->blocked) && EMPTY(queue))		interruptible_sleep_on(&queue->proc_list);	sti();}static void sleep_if_full(struct tty_queue * queue){	if (!FULL(queue))		return;	cli();	while (!(current->signal & ~current->blocked) && LEFT(queue)<128)		interruptible_sleep_on(&queue->proc_list);	sti();}void wait_for_keypress(void){	sleep_if_empty(tty_table[fg_console].secondary);}void copy_to_cooked(struct tty_struct * tty){	signed char c;	if (!(tty->read_q || tty->write_q || tty->secondary)) {		printk("copy_to_cooked: missing queues\n\r");		return;	}	while (1) {		if (EMPTY(tty->read_q))			break;		if (FULL(tty->secondary))			break;		GETCH(tty->read_q,c);		if (c==13) {			if (I_CRNL(tty))				c=10;			else if (I_NOCR(tty))				continue;		} else if (c==10 && I_NLCR(tty))			c=13;		if (I_UCLC(tty))			c=tolower(c);		if (L_CANON(tty)) {			if ((KILL_CHAR(tty) != _POSIX_VDISABLE) &&			    (c==KILL_CHAR(tty))) {				/* deal with killing the input line */				while(!(EMPTY(tty->secondary) ||				        (c=LAST(tty->secondary))==10 ||				        ((EOF_CHAR(tty) != _POSIX_VDISABLE) &&					 (c==EOF_CHAR(tty))))) {					if (L_ECHO(tty)) {						if (c<32)							PUTCH(127,tty->write_q);						PUTCH(127,tty->write_q);						tty->write(tty);					}					DEC(tty->secondary->head);				}				continue;			}			if ((ERASE_CHAR(tty) != _POSIX_VDISABLE) &&			    (c==ERASE_CHAR(tty))) {				if (EMPTY(tty->secondary) ||				   (c=LAST(tty->secondary))==10 ||				   ((EOF_CHAR(tty) != _POSIX_VDISABLE) &&				    (c==EOF_CHAR(tty))))					continue;				if (L_ECHO(tty)) {					if (c<32)						PUTCH(127,tty->write_q);					PUTCH(127,tty->write_q);					tty->write(tty);				}				DEC(tty->secondary->head);				continue;			}		}		if (I_IXON(tty)) {			if ((STOP_CHAR(tty) != _POSIX_VDISABLE) &&			    (c==STOP_CHAR(tty))) {				tty->stopped=1;				tty->write(tty);				continue;			}			if ((START_CHAR(tty) != _POSIX_VDISABLE) &&			    (c==START_CHAR(tty))) {				tty->stopped=0;				tty->write(tty);				continue;			}		}		if (L_ISIG(tty)) {			if ((INTR_CHAR(tty) != _POSIX_VDISABLE) &&			    (c==INTR_CHAR(tty))) {				kill_pg(tty->pgrp, SIGINT, 1);				continue;			}			if ((QUIT_CHAR(tty) != _POSIX_VDISABLE) &&			    (c==QUIT_CHAR(tty))) {				kill_pg(tty->pgrp, SIGQUIT, 1);				continue;			}			if ((SUSPEND_CHAR(tty) != _POSIX_VDISABLE) &&			    (c==SUSPEND_CHAR(tty))) {				if (!is_orphaned_pgrp(tty->pgrp))					kill_pg(tty->pgrp, SIGTSTP, 1);				continue;			}		}		if (c==10 || (EOF_CHAR(tty) != _POSIX_VDISABLE &&			      c==EOF_CHAR(tty)))			tty->secondary->data++;		if (L_ECHO(tty)) {			if (c==10) {				PUTCH(10,tty->write_q);				PUTCH(13,tty->write_q);			} else if (c<32) {				if (L_ECHOCTL(tty)) {					PUTCH('^',tty->write_q);					PUTCH(c+64,tty->write_q);				}			} else				PUTCH(c,tty->write_q);			tty->write(tty);		}		PUTCH(c,tty->secondary);	}	wake_up(&tty->secondary->proc_list);}/* * Called when we need to send a SIGTTIN or SIGTTOU to our process * group *  * We only request that a system call be restarted if there was if the  * default signal handler is being used.  The reason for this is that if * a job is catching SIGTTIN or SIGTTOU, the signal handler may not want  * the system call to be restarted blindly.  If there is no way to reset the * terminal pgrp back to the current pgrp (perhaps because the controlling * tty has been released on logout), we don't want to be in an infinite loop * while restarting the system call, and have it always generate a SIGTTIN * or SIGTTOU.  The default signal handler will cause the process to stop * thus avoiding the infinite loop problem.  Presumably the job-control * cognizant parent will fix things up before continuging its child process. */int tty_signal(int sig, struct tty_struct *tty){	if (is_orphaned_pgrp(current->pgrp))		return -EIO;		/* don't stop an orphaned pgrp */	(void) kill_pg(current->pgrp,sig,1);	if ((current->blocked & (1<<(sig-1))) ||	    ((int) current->sigaction[sig-1].sa_handler == 1)) 		return -EIO;		/* Our signal will be ignored */	else if (current->sigaction[sig-1].sa_handler)		return -EINTR;		/* We _will_ be interrupted :-) */	else		return -ERESTARTSYS;	/* We _will_ be interrupted :-) */					/* (but restart after we continue) */}int tty_read(unsigned channel, char * buf, int nr){	struct tty_struct * tty;	struct tty_struct * other_tty = NULL;	char c, * b=buf;	int minimum,time;	if (channel > 255)		return -EIO;	tty = TTY_TABLE(channel);	if (!(tty->write_q || tty->read_q || tty->secondary))		return -EIO;	if ((current->tty == channel) && (tty->pgrp != current->pgrp)) 		return(tty_signal(SIGTTIN, tty));	if (channel & 0x80)		other_tty = tty_table + (channel ^ 0x40);	time = 10L*tty->termios.c_cc[VTIME];	minimum = tty->termios.c_cc[VMIN];	if (L_CANON(tty)) {		minimum = nr;		current->timeout = 0xffffffff;		time = 0;	} else if (minimum)		current->timeout = 0xffffffff;	else {		minimum = nr;		if (time)			current->timeout = time + jiffies;		time = 0;	}	if (minimum>nr)		minimum = nr;	while (nr>0) {		if (other_tty)			other_tty->write(other_tty);		cli();		if (EMPTY(tty->secondary) || (L_CANON(tty) &&		    !FULL(tty->read_q) && !tty->secondary->data)) {			if (!current->timeout ||			  (current->signal & ~current->blocked)) {			  	sti();				break;			}			if (IS_A_PTY_SLAVE(channel) && C_HUP(other_tty))				break;			interruptible_sleep_on(&tty->secondary->proc_list);			sti();			continue;		}		sti();		do {			GETCH(tty->secondary,c);			if ((EOF_CHAR(tty) != _POSIX_VDISABLE &&			     c==EOF_CHAR(tty)) || c==10)				tty->secondary->data--;			if ((EOF_CHAR(tty) != _POSIX_VDISABLE &&			     c==EOF_CHAR(tty)) && L_CANON(tty))				break;			else {				put_fs_byte(c,b++);				if (!--nr)					break;			}			if (c==10 && L_CANON(tty))				break;		} while (nr>0 && !EMPTY(tty->secondary));		wake_up(&tty->read_q->proc_list);		if (time)			current->timeout = time+jiffies;		if (L_CANON(tty) || b-buf >= minimum)			break;	}	current->timeout = 0;	if ((current->signal & ~current->blocked) && !(b-buf))		return -ERESTARTSYS;	return (b-buf);}int tty_write(unsigned channel, char * buf, int nr){	static cr_flag=0;	struct tty_struct * tty;	char c, *b=buf;	if (channel > 255)		return -EIO;	tty = TTY_TABLE(channel);	if (!(tty->write_q || tty->read_q || tty->secondary))		return -EIO;	if (L_TOSTOP(tty) && 	    (current->tty == channel) && (tty->pgrp != current->pgrp)) 		return(tty_signal(SIGTTOU, tty));	while (nr>0) {		sleep_if_full(tty->write_q);		if (current->signal & ~current->blocked)			break;		while (nr>0 && !FULL(tty->write_q)) {			c=get_fs_byte(b);			if (O_POST(tty)) {				if (c=='\r' && O_CRNL(tty))					c='\n';				else if (c=='\n' && O_NLRET(tty))					c='\r';				if (c=='\n' && !cr_flag && O_NLCR(tty)) {					cr_flag = 1;					PUTCH(13,tty->write_q);					continue;				}				if (O_LCUC(tty))					c=toupper(c);			}			b++; nr--;			cr_flag = 0;			PUTCH(c,tty->write_q);		}		tty->write(tty);		if (nr>0)			schedule();	}	return (b-buf);}/* * Jeh, sometimes I really like the 386. * This routine is called from an interrupt, * and there should be absolutely no problem * with sleeping even in an interrupt (I hope). * Of course, if somebody proves me wrong, I'll * hate intel for all time :-). We'll have to * be careful and see to reinstating the interrupt * chips before calling this, though. * * I don't think we sleep here under normal circumstances * anyway, which is good, as the task sleeping might be * totally innocent. */void do_tty_interrupt(int tty){	copy_to_cooked(TTY_TABLE(tty));}void chr_dev_init(void){}void tty_init(void){	int i;	for (i=0 ; i < QUEUES ; i++)		tty_queues[i] = (struct tty_queue) {0,0,0,0,""};	rs_queues[0] = (struct tty_queue) {0x3f8,0,0,0,""};	rs_queues[1] = (struct tty_queue) {0x3f8,0,0,0,""};	rs_queues[3] = (struct tty_queue) {0x2f8,0,0,0,""};	rs_queues[4] = (struct tty_queue) {0x2f8,0,0,0,""};	for (i=0 ; i<256 ; i++) {		tty_table[i] =  (struct tty_struct) {		 	{0, 0, 0, 0, 0, INIT_C_CC},			0, 0, 0, NULL, NULL, NULL, NULL		};	}	con_init();	for (i = 0 ; i<NR_CONSOLES ; i++) {		con_table[i] = (struct tty_struct) {		 	{ICRNL,		/* change incoming CR to NL */			OPOST|ONLCR,	/* change outgoing NL to CRNL */			0,			IXON | ISIG | ICANON | ECHO | ECHOCTL | ECHOKE,			0,		/* console termio */			INIT_C_CC},			0,			/* initial pgrp */			0,			/* initial session */			0,			/* initial stopped */			con_write,			con_queues+0+i*3,con_queues+1+i*3,con_queues+2+i*3		};	}	for (i = 0 ; i<NR_SERIALS ; i++) {		rs_table[i] = (struct tty_struct) {			{0, /* no translation */			0,  /* no translation */			B2400 | CS8,			0,			0,			INIT_C_CC},			0,			0,			0,			rs_write,			rs_queues+0+i*3,rs_queues+1+i*3,rs_queues+2+i*3		};	}	for (i = 0 ; i<NR_PTYS ; i++) {		mpty_table[i] = (struct tty_struct) {			{0, /* no translation */			0,  /* no translation */			B9600 | CS8,			0,			0,			INIT_C_CC},			0,			0,			0,			mpty_write,			mpty_queues+0+i*3,mpty_queues+1+i*3,mpty_queues+2+i*3		};		spty_table[i] = (struct tty_struct) {			{0, /* no translation */			0,  /* no translation */			B9600 | CS8,			IXON | ISIG | ICANON,			0,			INIT_C_CC},			0,			0,			0,			spty_write,			spty_queues+0+i*3,spty_queues+1+i*3,spty_queues+2+i*3		};	}	rs_init();	printk("%d virtual consoles\n\r",NR_CONSOLES);	printk("%d pty's\n\r",NR_PTYS);}

⌨️ 快捷键说明

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