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

📄 tty_io.c

📁 全中文注释的Linux源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	  		if (c == INTR_CHAR (tty))	    		{	      			tty_intr (tty, INTMASK);	      			continue;	    		}						// 如果该字符是键盘中断符(^\),则向当前进程发送键盘退出信号,并继续处理下一字符。	  		if (c == QUIT_CHAR (tty))	    		{	      			tty_intr (tty, QUITMASK);	      			continue;	    		}		}					// 如果该字符是换行符NL(10),或者是文件结束符EOF(^D),辅助缓冲队列字符数加1。[??]      		if (c == 10 || c == EOF_CHAR (tty))			tty->secondary.data++;					// 如果本地模式标志集中回显标志ECHO 置位,那么,如果字符是换行符NL(10),则将换行符NL(10)		// 和回车符CR(13)放入tty 写队列缓冲区中;如果字符是控制字符(字符值<32)并且回显控制字符标志		// ECHOCTL 置位,则将字符'^'和字符c+64 放入tty 写队列中(也即会显示^C、^H 等);否则将该字符		// 直接放入tty 写缓冲队列中。最后调用该tty 的写操作函数。      		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);}//// tty 读函数。// 参数:channel - 子设备号;buf - 缓冲区指针;nr - 欲读字节数。// 返回已读字节数。int tty_read (unsigned channel, char *buf, int nr){	struct tty_struct *tty;  	char c, *b = buf;  	int minimum, time, flag = 0;  	long oldalarm;	// 本版本linux 内核的终端只有3 个子设备,分别是控制台(0)、串口终端1(1)和串口终端2(2)。	// 所以任何大于2 的子设备号都是非法的。写的字节数当然也不能小于0 的。  	if (channel > 2 || nr < 0)    		return -1;	// tty 指针指向子设备号对应ttb_table 表中的tty 结构。	tty = &tty_table[channel];	// 下面首先保存进程原定时值,然后根据控制字符VTIME 和VMIN 设置读字符操作的超时定时值。	// 在非规范模式下,这两个值是超时定时值。MIN 表示为了满足读操作,需要读取的最少字符数。	// TIME 是一个十分之一秒计数的计时值。	// 首先取进程中的(报警)定时值(滴答数)。  	oldalarm = current->alarm;	// 并设置读操作超时定时值time 和需要最少读取的字符个数minimum。	time = 10L * tty->termios.c_cc[VTIME];  	minimum = tty->termios.c_cc[VMIN];	// 如果设置了读超时定时值time 但没有设置最少读取个数minimum,那么在读到至少一个字符或者	// 定时超时后读操作将立刻返回。所以这里置minimum=1。  	if (time && !minimum)    	{      		minimum = 1;		// 如果进程原定时值是0 或者time+当前系统时间值小于进程原定时值的话,则置重新设置进程定时		// 值为time+当前系统时间,并置flag 标志。	  	if (flag = (!oldalarm || time + jiffies < oldalarm))			current->alarm = time + jiffies;    	}		// 如果设置的最少读取字符数>欲读的字符数,则令其等于此次欲读取的字符数。  	if (minimum > nr)    		minimum = nr;		// 当欲读的字节数>0,则循环执行以下操作。  	while (nr > 0)    	{		// 如果flag 不为0(即进程原定时值是0 或者time+当前系统时间值小于进程原定时值)并且进程有定		// 时信号SIGALRM,则复位进程的定时信号并中断循环。      		if (flag && (current->signal & ALRMMASK))		{	  		current->signal &= ~ALRMMASK;	  		break;		}					// 如果当前进程有信号要处理,则退出,返回0。      		if (current->signal)			break;		// 如果辅助缓冲队列(规范模式队列)为空,或者设置了规范模式标志并且辅助队列中字符数为0 以及		// 辅助模式缓冲队列空闲空间>20,则进入可中断睡眠状态,返回后继续处理。      		if (EMPTY (tty->secondary) || (L_CANON (tty) &&						     !tty->secondary.data						     && LEFT (tty->secondary) > 20))		{	  		sleep_if_empty (&tty->secondary);	  		continue;		}					// 执行以下操作,直到nr=0 或者辅助缓冲队列为空。      		do		{			// 取辅助缓冲队列字符c。	  		GETCH (tty->secondary, c);			// 如果该字符是文件结束符(^D)或者是换行符NL(10),则辅助缓冲队列字符数减1。		  	if (c == EOF_CHAR (tty) || c == 10)			    	tty->secondary.data--;				// 如果该字符是文件结束符(^D)并且规范模式标志置位,则返回已读字符数,并退出。	 		 if (c == EOF_CHAR (tty) && L_CANON (tty))	    			return (b - buf);			 			// 否则将该字符放入用户数据段缓冲区buf 中,欲读字符数减1,如果欲读字符数已为0,则中断循环。	  		else	    		{	      			put_fs_byte (c, b++);	      			if (!--nr)					break;	    		}		}			      		while (nr > 0 && !EMPTY (tty->secondary));		// 如果超时定时值time 不为0 并且规范模式标志没有置位(非规范模式),那么:      		if (time && !L_CANON (tty))			// 如果进程原定时值是0 或者time+当前系统时间值小于进程原定时值的话,则置重新设置进程定时值			// 为time+当前系统时间,并置flag 标志。否则让进程的定时值等于进程原定时值。			if (flag = (!oldalarm || time + jiffies < oldalarm))	  			current->alarm = time + jiffies;			else	  			current->alarm = oldalarm;			// 如果规范模式标志置位,那么若没有读到1 个字符则中断循环。否则若已读取数大于或等于最少要			// 求读取的字符数,则也中断循环。      			if (L_CANON (tty))			{	  			if (b - buf)	    				break;			}      		else if (b - buf >= minimum)			break;    	}	// 让进程的定时值等于进程原定时值。	current->alarm = oldalarm;	// 如果进程有信号并且没有读取任何字符,则返回出错号(超时)。  	if (current->signal && !(b - buf))    		return -EINTR;  	return (b - buf);		/* 返回已读取的字符数*/}//// tty 写函数。// 参数:channel - 子设备号;buf - 缓冲区指针;nr - 写字节数。// 返回已写字节数。int tty_write (unsigned channel, char *buf, int nr){	static cr_flag = 0;  	struct tty_struct *tty;  	char c, *b = buf;	// 本版本linux 内核的终端只有3 个子设备,分别是控制台(0)、串口终端1(1)和串口终端2(2)。	// 所以任何大于2 的子设备号都是非法的。写的字节数当然也不能小于0 的。  	if (channel > 2 || nr < 0)    		return -1;	// tty 指针指向子设备号对应ttb_table 表中的tty 结构。	tty = channel + tty_table;	// 字符设备是一个一个字符进行处理的,所以这里对于nr 大于0 时对每个字符进行循环处理。  	while (nr > 0)    	{		// 如果此时tty 的写队列已满,则当前进程进入可中断的睡眠状态。      		sleep_if_full (&tty->write_q);		// 如果当前进程有信号要处理,则退出,返回0。      		if (current->signal)			break;		// 当要写的字节数>0 并且tty 的写队列不满时,循环执行以下操作。      		while (nr > 0 && !FULL (tty->write_q))		{			// 从用户数据段内存中取一字节c。	  		c = get_fs_byte (b);			// 如果终端输出模式标志集中的执行输出处理标志OPOST 置位,则执行下列输出时处理过程。	  		if (O_POST (tty))	    		{				// 如果该字符是回车符'\r'(CR,13)并且回车符转换行符标志OCRNL 置位,则将该字符换成换行符				// '\n'(NL,10);否则如果该字符是换行符'\n'(NL,10)并且换行转回车功能标志ONLRET 置位的话,				// 则将该字符换成回车符'\r'(CR,13)。	      			if (c == '\r' && O_CRNL (tty))					c = '\n';	      			else if (c == '\n' && O_NLRET (tty))					c = '\r';									// 如果该字符是换行符'\n'并且回车标志cr_flag 没有置位,换行转回车-换行标志ONLCR 置位的话,				// 则将cr_flag 置位,并将一回车符放入写队列中。然后继续处理下一个字符。	      			if (c == '\n' && !cr_flag && O_NLCR (tty))				{		  			cr_flag = 1;		  			PUTCH (13, tty->write_q);		  			continue;				}									// 如果小写转大写标志OLCUC 置位的话,就将该字符转成大写字符。	      			if (O_LCUC (tty))					c = toupper (c);	    		}						// 用户数据缓冲指针b 前进1 字节;欲写字节数减1 字节;复位cr_flag 标志,并将该字节放入tty			// 写队列中。	  		b++;	  		nr--;	  		cr_flag = 0;	  		PUTCH (c, tty->write_q);		}					// 若字节全部写完,或者写队列已满,则程序执行到这里。调用对应tty 的写函数,若还有字节要写,		// 则等待写队列不满,所以调用调度程序,先去执行其它任务。      		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.*//** 呵,有时我是真得很喜欢386。该子程序是从一个中断处理程序中调用的,即使在* 中断处理程序中睡眠也应该绝对没有问题(我希望如此)。当然,如果有人证明我是* 错的,那么我将憎恨intel 一辈子?。但是我们必须小心,在调用该子程序之前需* 要恢复中断。** 我不认为在通常环境下会处在这里睡眠,这样很好,因为任务睡眠是完全任意的。*/// tty 中断处理调用函数 - 执行tty 中断处理。// 参数:tty - 指定的tty 终端号(0,1 或2)。// 将指定tty 终端队列缓冲区中的字符复制成规范(熟)模式字符并存放在辅助队列(规范模式队列)中。// 在串口读字符中断(rs_io.s, 109)和键盘中断(kerboard.S, 69)中调用。void do_tty_interrupt (int tty){	copy_to_cooked(struct tty_struct * tty) (tty_table + tty);}// 字符设备初始化函数。空,为以后扩展做准备。void chr_dev_init (void){}

⌨️ 快捷键说明

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