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

📄 tty_io.c

📁 带中文注释的 linux 0.11 源代码0.11,很好的
💻 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 终端初始化函数。// 初始化串口终端和控制台终端。voidtty_init (void){  rs_init ();			// 初始化串行中断程序和串行接口1 和2。(serial.c, 37)  con_init ();			// 初始化控制台终端。(console.c, 617)}//// tty 键盘终端字符处理函数。// 参数:tty - 相应tty 终端结构指针;mask - 信号屏蔽位。voidtty_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 voidsleep_if_empty (struct tty_queue *queue){  cli ();			// 关中断。// 若当前进程没有信号要处理并且指定的队列缓冲区空,则让进程进入可中断睡眠状态,并让// 队列的进程等待指针指向该进程。  while (!current->signal && EMPTY (*queue))    interruptible_sleep_on (&queue->proc_list);  sti ();			// 开中断。}//// 若队列缓冲区满则让进程进入可中断的睡眠状态。// 参数:queue - 指定队列的指针。// 进程在往队列缓冲区中写入时调用此函数。static voidsleep_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 ();			// 开中断。}//// 等待按键。// 如果控制台的读队列缓冲区空则让进程进入可中断的睡眠状态。voidwait_for_keypress (void){  sleep_if_empty (&tty_table[0].secondary);}//// 复制成规范模式字符序列。// 将指定tty 终端队列缓冲区中的字符复制成规范(熟)模式字符并存放在辅助队列(规范模式队列)中。// 参数:tty - 指定终端的tty 结构。voidcopy_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;	    }

⌨️ 快捷键说明

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