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

📄 tty_io.c

📁 全中文注释的Linux源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/** 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.*//** 'tty_io.c'给tty 一种非相关的感觉,是控制台还是串行通道。该程序同样* 实现了回显、规范(熟)模式等。** Kill-line,谢谢John T Kahl。*/#include <ctype.h>							/* 字符类型头文件。定义了一些有关字符类型判断和转换的宏*/#include <errno.h>							/* 错误号头文件。包含系统中各种出错号。(Linus 从minix 中引进的) */#include <signal.h>							/* 信号头文件。定义信号符号常量,信号结构以及信号操作函数原型*/// 下面给出相应信号在信号位图中的对应比特位。#define ALRMMASK (1<<(SIGALRM-1))			/* 警告(alarm)信号屏蔽位*/#define KILLMASK (1<<(SIGKILL-1))				/* 终止(kill)信号屏蔽位*/#define INTMASK (1<<(SIGINT-1))				/* 键盘中断(int)信号屏蔽位*/#define QUITMASK (1<<(SIGQUIT-1))			/* 键盘退出(quit)信号屏蔽位*/#define TSTPMASK (1<<(SIGTSTP-1))			/* tty 发出的停止进程(tty stop)信号屏蔽位*/#include <linux/sched.h>						/* 调度程序头文件,定义了任务结构task_struct、初始任务0 的数据*/											// 还有一些有关描述符参数设置和获取的嵌入式汇编函数宏语句。#include <linux/tty.h>							/* tty 头文件,定义了有关tty_io,串行通信方面的参数、常数*/#include <asm/segment.h>						/* 段操作头文件。定义了有关段寄存器操作的嵌入式汇编函数*/#include <asm/system.h>						/* 系统头文件。定义了设置或修改描述符/中断门等的嵌入式汇编宏*/#define _L_FLAG(tty,f) ((tty)->termios.c_lflag & f)	/* 取termios 结构中的本地模式标志*/#define _I_FLAG(tty,f) ((tty)->termios.c_iflag & f)	/* 取termios 结构中的输入模式标志*/#define _O_FLAG(tty,f) ((tty)->termios.c_oflag & f)/* 取termios 结构中的输出模式标志*/// 取termios 结构中本地模式标志集中的一个标志位。#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)		/* 规范模式时,取KILL 擦除当前行标志位*/#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL)	/* 取回显控制字符标志位*/#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE)	/* 规范模式时,取KILL 擦除行并回显标志位*/// 取termios 结构中输入模式标志中的一个标志位。#define I_UCLC(tty) _I_FLAG((tty),IUCLC)		/* 取输入模式标志集中大写到小写转换标志位*/#define I_NLCR(tty) _I_FLAG((tty),INLCR)		/* 取换行符NL 转回车符CR 标志位*/#define I_CRNL(tty) _I_FLAG((tty),ICRNL)		/* 取回车符CR 转换行符NL 标志位*/#define I_NOCR(tty) _I_FLAG((tty),IGNCR)		/* 取忽略回车符CR 标志位*/// 取termios 结构中输出模式标志中的一个标志位。#define O_POST(tty) _O_FLAG((tty),OPOST)		/* 取输出模式标志集中执行输出处理标志*/#define O_NLCR(tty) _O_FLAG((tty),ONLCR)		/* 取换行符NL 转回车换行符CR-NL 标志*/#define O_CRNL(tty) _O_FLAG((tty),OCRNL)		/* 取回车符CR 转换行符NL 标志*/#define O_NLRET(tty) _O_FLAG((tty),ONLRET)	/* 取换行符NL 执行回车功能的标志*/#define O_LCUC(tty) _O_FLAG((tty),OLCUC)		/* 取小写转大写字符标志*/// tty 数据结构的tty_table 数组。其中包含三个初始化项数据,分别对应控制台、串口终端1 和// 串口终端2 的初始化数据。struct tty_struct tty_table[] = {{	{ICRNL,			/* change incoming CR to NL *//* 将输入的CR 转换为NL */         OPOST | ONLCR,		/* change outgoing NL to CRNL *//* 将输出的NL 转CRNL */         0,				// 控制模式标志初始化为0。         ISIG | ICANON | ECHO | ECHOCTL | ECHOKE,	// 本地模式标志。         0,				/* console termio */// 控制台termio。         INIT_C_CC},			// 控制字符数组。     	  0,				/* initial pgrp */// 所属初始进程组。         0,				/* initial stopped */// 初始停止标志。        con_write,			// tty 写函数指针。        {0, 0, 0, 0, ""},		/* console read-queue */// tty 控制台读队列。        {0, 0, 0, 0, ""},		/* console write-queue */// tty 控制台写队列。        {0, 0, 0, 0, ""}		/* console secondary queue */// tty 控制台辅助(第二)队列。       },        {       {0,			/* no translation */// 输入模式标志。0,无须转换。	0,			/* no translation */// 输出模式标志。0,无须转换。	B2400 | CS8,		// 控制模式标志。波特率2400bps,8 位数据位。	0,			// 本地模式标志0。	0,			// 行规程0。	INIT_C_CC},		// 控制字符数组。       0,			// 所属初始进程组。       0,			// 初始停止标志。       rs_write,		// 串口1 tty 写函数指针。       {0x3f8, 0, 0, 0, ""},	/* rs 1 */// 串行终端1 读缓冲队列。       {0x3f8, 0, 0, 0, ""},	// 串行终端1 写缓冲队列。       {0, 0, 0, 0, ""}		// 串行终端1 辅助缓冲队列。       }, {	   {0,			/* no translation */// 输入模式标志。0,无须转换。	    0,			/* no translation */// 输出模式标志。0,无须转换。	    B2400 | CS8,	// 控制模式标志。波特率2400bps,8 位数据位。	    0,			// 本地模式标志0。	    0,			// 行规程0。	    INIT_C_CC},		// 控制字符数组。	   0,			// 所属初始进程组。	   0,			// 初始停止标志。	   rs_write,		// 串口2 tty 写函数指针。	   {0x2f8, 0, 0, 0, ""},	/* rs 2 */// 串行终端2 读缓冲队列。	   {0x2f8, 0, 0, 0, ""},	// 串行终端2 写缓冲队列。	   {0, 0, 0, 0, ""}	// 串行终端2 辅助缓冲队列。	   }};/** these are the tables used by the machine code handlers.* you can implement pseudo-tty's or something by changing* them. Currently not done.*//** 下面是汇编程序使用的缓冲队列地址表。通过修改你可以实现* 伪tty 终端或其它终端类型。目前还没有这样做。*/// tty 缓冲队列地址表。rs_io.s 汇编程序使用,用于取得读写缓冲队列地址。struct tty_queue *table_list[] = {  	&tty_table[0].read_q, &tty_table[0].write_q,	/* 控制台终端读、写缓冲队列地址*/  	&tty_table[1].read_q, &tty_table[1].write_q,	/* 串行口1 终端读、写缓冲队列地址*/  	&tty_table[2].read_q, &tty_table[2].write_q	/* 串行口2 终端读、写缓冲队列地址*/};//// tty 终端初始化函数。// 初始化串口终端和控制台终端。void	tty_init (void){	rs_init ();	/* 初始化串行中断程序和串行接口1 和2。(serial.c, 37)*/ 	con_init ();	/* 初始化控制台终端。(console.c, 617)*/}//// tty 键盘终端字符处理函数。// 参数:tty - 相应tty 终端结构指针;mask - 信号屏蔽位。void tty_intr (struct tty_struct *tty, int mask){	int i;	// 如果tty 所属组号小于等于0,则退出。  	if (tty->pgrp <= 0)    		return;	// 扫描任务数组,向tty 相应组的所有任务发送指定的信号。  	for (i = 0; i < NR_TASKS; i++)		// 如果该项任务指针不为空,并且其组号等于tty 组号,则设置该任务指定的信号mask。    		if (task[i] && task[i]->pgrp == tty->pgrp)      			task[i]->signal |= mask;}//// 如果队列缓冲区空则让进程进入可中断的睡眠状态。// 参数:queue - 指定队列的指针。// 进程在取队列缓冲区中字符时调用此函数。static void sleep_if_empty (struct tty_queue *queue){	cli ();			/* 关中断*/	// 若当前进程没有信号要处理并且指定的队列缓冲区空,则让进程进入可中断睡眠状态,并让	// 队列的进程等待指针指向该进程。  	while (!current->signal && EMPTY (*queue))    		interruptible_sleep_on (&queue->proc_list);  	sti ();			/* 开中断*/}//// 若队列缓冲区满则让进程进入可中断的睡眠状态。// 参数:queue - 指定队列的指针。// 进程在往队列缓冲区中写入时调用此函数。static void sleep_if_full (struct tty_queue *queue){	// 若队列缓冲区不满,则返回退出。  	if (!FULL (*queue))    		return;  	cli ();			/* 关中断*/	// 如果进程没有信号需要处理并且队列缓冲区中空闲剩余区长度<128,则让进程进入可中断睡眠状态,	// 并让该队列的进程等待指针指向该进程。 	while (!current->signal && LEFT (*queue) < 128)    		interruptible_sleep_on (&queue->proc_list);  	sti ();			/* 开中断*/}//// 等待按键。// 如果控制台的读队列缓冲区空则让进程进入可中断的睡眠状态。void wait_for_keypress (void){  	sleep_if_empty (&tty_table[0].secondary);}//// 复制成规范模式字符序列。// 将指定tty 终端队列缓冲区中的字符复制成规范(熟)模式字符并存放在辅助队列(规范模式队列)中。// 参数:tty - 指定终端的tty 结构。void copy_to_cooked (struct tty_struct *tty){	signed char c;	// 如果tty 的读队列缓冲区不空并且辅助队列缓冲区为空,则循环执行下列代码。  	while (!EMPTY (tty->read_q) && !FULL (tty->secondary))    	{		// 从队列尾处取一字符到c,并前移尾指针。      		GETCH (tty->read_q, c);		// 下面对输入字符,利用输入模式标志集进行处理。		// 如果该字符是回车符CR(13),则:若回车转换行标志CRNL 置位则将该字符转换为换行符NL(10);		// 否则若忽略回车标志NOCR 置位,则忽略该字符,继续处理其它字符。      		if (c == 13)			if (I_CRNL (tty))	  			c = 10;			else if (I_NOCR (tty))	  			continue;			else;		// 如果该字符是换行符NL(10)并且换行转回车标志NLCR 置位,则将其转换为回车符CR(13)。      		else if (c == 10 && I_NLCR (tty))			c = 13;		// 如果大写转小写标志UCLC 置位,则将该字符转换为小写字符。	      	if (I_UCLC (tty))			c = tolower (c);		// 如果本地模式标志集中规范(熟)模式标志CANON 置位,则进行以下处理。      		if (L_CANON (tty))		{			// 如果该字符是键盘终止控制字符KILL(^U),则进行删除输入行处理。	  		if (c == KILL_CHAR (tty))	    		{				/* deal with killing the input line *//* 删除输入行处理 */				// 如果tty 辅助队列不空,或者辅助队列中最后一个字符是换行NL(10),或者该字符是文件结束字符				// (^D),则循环执行下列代码。	      			while (!(EMPTY (tty->secondary) ||		       			(c = LAST (tty->secondary)) == 10 ||		       			c == EOF_CHAR (tty)))				{					// 如果本地回显标志ECHO 置位,那么:若字符是控制字符(值<32),则往tty 的写队列中放入擦除					// 字符ERASE。再放入一个擦除字符ERASE,并且调用该tty 的写函数。		  			if (L_ECHO (tty))		    			{		      				if (c < 32)							PUTCH (127, tty->write_q);									      				PUTCH (127, tty->write_q);		      				tty->write (tty);		    			}					// 将tty 辅助队列头指针后退1 字节。		  			DEC (tty->secondary.head);				}		  		continue;		// 继续读取并处理其它字符。	    		}			// 如果该字符是删除控制字符ERASE(^H),那么:	  		if (c == ERASE_CHAR (tty))	    		{				// 若tty 的辅助队列为空,或者其最后一个字符是换行符NL(10),或者是文件结束符,继续处理				// 其它字符。	      			if (EMPTY (tty->secondary) ||(c = LAST (tty->secondary)) == 10 || c == EOF_CHAR (tty))					continue;				// 如果本地回显标志ECHO 置位,那么:若字符是控制字符(值<32),则往tty 的写队列中放入擦除				// 字符ERASE。再放入一个擦除字符ERASE,并且调用该tty 的写函数。	      			if (L_ECHO (tty))				{		  			if (c < 32)		    				PUTCH (127, tty->write_q);		  			PUTCH (127, tty->write_q);		  			tty->write (tty);				}									// 将tty 辅助队列头指针后退1 字节,继续处理其它字符。	      			DEC (tty->secondary.head);	      			continue;	    		}			//如果该字符是停止字符(^S),则置tty 停止标志,继续处理其它字符。	  		if (c == STOP_CHAR (tty))	    		{	      			tty->stopped = 1;	      			continue;	    		}						// 如果该字符是停止字符(^Q),则复位tty 停止标志,继续处理其它字符。	  		if (c == START_CHAR (tty))	    		{	      			tty->stopped = 0;	      			continue;	    		}		}					// 若输入模式标志集中ISIG 标志置位,则在收到INTR、QUIT、SUSP 或DSUSP 字符时,需要为进程		// 产生相应的信号。      		if (L_ISIG (tty))		{			// 如果该字符是键盘中断符(^C),则向当前进程发送键盘中断信号,并继续处理下一字符。

⌨️ 快捷键说明

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