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

📄 console.c

📁 linux完全注释的源代码。内核版本为0.11的linux kernel。
💻 C
📖 第 1 页 / 共 3 页
字号:
			{// 若当前光标处在行末端或末端以外,则将光标移到下行头列。并调整光标位置对应的内存指针pos。				if (x >= video_num_columns)				{					x -= video_num_columns;					pos -= video_size_row;					lf ();				}// 将字符c 写到显示内存中pos 处,并将光标右移1 列,同时也将pos 对应地移动2 个字节。//__asm__ ("movb _attr,%%ah\n\t" "movw %%ax,%1\n\t"::"a" (c), "m" (*(short *) pos):"ax");
				_asm {
					mov al,c;
					mov ah,attr;
					mov ebx,pos
					mov [ebx],ax;
				}
				pos += 2;				x++;// 如果字符c 是转义字符ESC,则转换状态state 到1。			}			else if (c == 27)				state = 1;// 如果字符c 是换行符(10),或是垂直制表符VT(11),或者是换页符FF(12),则移动光标到下一行。			else if (c == 10 || c == 11 || c == 12)				lf ();// 如果字符c 是回车符CR(13),则将光标移动到头列(0 列)。			else if (c == 13)				cr ();// 如果字符c 是DEL(127),则将光标右边一字符擦除(用空格字符替代),并将光标移到被擦除位置。			else if (c == ERASE_CHAR (tty))				del ();// 如果字符c 是BS(backspace,8),则将光标右移1 格,并相应调整光标对应内存位置指针pos。			else if (c == 8)			{				if (x)				{					x--;					pos -= 2;				}// 如果字符c 是水平制表符TAB(9),则将光标移到8 的倍数列上。若此时光标列数超出屏幕最大列数,// 则将光标移到下一行上。			}			else if (c == 9)			{				c = (char)(8 - (x & 7));				x += c;				pos += c << 1;				if (x > video_num_columns)				{					x -= video_num_columns;					pos -= video_size_row;					lf ();				}				c = 9;// 如果字符c 是响铃符BEL(7),则调用蜂鸣函数,是扬声器发声。			}			else if (c == 7)				sysbeep ();			break;// 如果原状态是0,并且字符是转义字符ESC(0x1b = 033 = 27),则转到状态1 处理。		case 1:			state = 0;// 如果字符c 是'[',则将状态state 转到2。			if (c == '[')				state = 2;// 如果字符c 是'E',则光标移到下一行开始处(0 列)。			else if (c == 'E')				gotoxy (0, y + 1);// 如果字符c 是'M',则光标上移一行。			else if (c == 'M')				ri ();// 如果字符c 是'D',则光标下移一行。			else if (c == 'D')				lf ();// 如果字符c 是'Z',则发送终端应答字符序列。			else if (c == 'Z')				respond (tty);// 如果字符c 是'7',则保存当前光标位置。注意这里代码写错!应该是(c=='7')。			else if (x == '7')				save_cur ();// 如果字符c 是'8',则恢复到原保存的光标位置。注意这里代码写错!应该是(c=='8')。			else if (x == '8')				restore_cur ();			break;// 如果原状态是1,并且上一字符是'[',则转到状态2 来处理。		case 2:// 首先对ESC 转义字符序列参数使用的处理数组par[]清零,索引变量npar 指向首项,并且设置状态// 为3。若此时字符不是'?',则直接转到状态3 去处理,否则去读一字符,再到状态3 处理代码处。			for (npar = 0; npar < NPAR; npar++)				par[npar] = 0;			npar = 0;			state = 3;			if (ques = (c == '?'))				break;// 如果原来是状态2;或者原来就是状态3,但原字符是';'或数字,则在下面处理。		case 3:// 如果字符c 是分号';',并且数组par 未满,则索引值加1。			if (c == ';' && npar < NPAR - 1)			{				npar++;				break;// 如果字符c 是数字字符'0'-'9',则将该字符转换成数值并与npar 所索引的项组成10 进制数。			}			else if (c >= '0' && c <= '9')			{				par[npar] = 10 * par[npar] + c - '0';				break;// 否则转到状态4。			}			else				state = 4;// 如果原状态是状态3,并且字符不是';'或数字,则转到状态4 处理。首先复位状态state=0。		case 4:			state = 0;			switch (c)			{// 如果字符c 是'G'或'`',则par[]中第一个参数代表列号。若列号不为零,则将光标右移一格。			case 'G':			case '`':				if (par[0])					par[0]--;				gotoxy (par[0], y);				break;// 如果字符c 是'A',则第一个参数代表光标上移的行数。若参数为0 则上移一行。			case 'A':				if (!par[0])					par[0]++;				gotoxy (x, y - par[0]);				break;// 如果字符c 是'B'或'e',则第一个参数代表光标下移的行数。若参数为0 则下移一行。			case 'B':			case 'e':				if (!par[0])					par[0]++;				gotoxy (x, y + par[0]);				break;// 如果字符c 是'C'或'a',则第一个参数代表光标右移的格数。若参数为0 则右移一格。			case 'C':			case 'a':				if (!par[0])					par[0]++;				gotoxy (x + par[0], y);				break;// 如果字符c 是'D',则第一个参数代表光标左移的格数。若参数为0 则左移一格。			case 'D':				if (!par[0])					par[0]++;				gotoxy (x - par[0], y);				break;// 如果字符c 是'E',则第一个参数代表光标向下移动的行数,并回到0 列。若参数为0 则下移一行。			case 'E':				if (!par[0])					par[0]++;				gotoxy (0, y + par[0]);				break;// 如果字符c 是'F',则第一个参数代表光标向上移动的行数,并回到0 列。若参数为0 则上移一行。			case 'F':				if (!par[0])					par[0]++;				gotoxy (0, y - par[0]);				break;// 如果字符c 是'd',则第一个参数代表光标所需在的行号(从0 计数)。			case 'd':				if (par[0])					par[0]--;				gotoxy (x, par[0]);				break;// 如果字符c 是'H'或'f',则第一个参数代表光标移到的行号,第二个参数代表光标移到的列号。			case 'H':			case 'f':				if (par[0])					par[0]--;				if (par[1])					par[1]--;				gotoxy (par[1], par[0]);				break;// 如果字符c 是'J',则第一个参数代表以光标所处位置清屏的方式:// ANSI 转义序列:'ESC [sJ'(s = 0 删除光标到屏幕底端;1 删除屏幕开始到光标处;2 整屏删除)。			case 'J':				csi_J (par[0]);				break;// 如果字符c 是'K',则第一个参数代表以光标所在位置对行中字符进行删除处理的方式。// ANSI 转义字符序列:'ESC [sK'(s = 0 删除到行尾;1 从开始删除;2 整行都删除)。			case 'K':				csi_K (par[0]);				break;// 如果字符c 是'L',表示在光标位置处插入n 行(ANSI 转义字符序列'ESC [nL')。			case 'L':				csi_L (par[0]);				break;// 如果字符c 是'M',表示在光标位置处删除n 行(ANSI 转义字符序列'ESC [nM')。			case 'M':				csi_M (par[0]);				break;// 如果字符c 是'P',表示在光标位置处删除n 个字符(ANSI 转义字符序列'ESC [nP')。			case 'P':				csi_P (par[0]);				break;// 如果字符c 是'@',表示在光标位置处插入n 个字符(ANSI 转义字符序列'ESC [n@')。			case '@':				csi_at (par[0]);				break;// 如果字符c 是'm',表示改变光标处字符的显示属性,比如加粗、加下划线、闪烁、反显等。// ANSI 转义字符序列:'ESC [nm'。n = 0 正常显示;1 加粗;4 加下划线;7 反显;27 正常显示。			case 'm':				csi_m ();				break;// 如果字符c 是'r',则表示用两个参数设置滚屏的起始行号和终止行号。			case 'r':				if (par[0])					par[0]--;				if (!par[1])					par[1] = video_num_lines;				if (par[0] < par[1] && par[1] <= video_num_lines)				{					top = par[0];					bottom = par[1];				}				break;// 如果字符c 是's',则表示保存当前光标所在位置。			case 's':				save_cur ();				break;// 如果字符c 是'u',则表示恢复光标到原保存的位置处。			case 'u':				restore_cur ();				break;			}		}	}// 最后根据上面设置的光标位置,向显示控制器发送光标显示位置。	set_cursor ();}/** void con_init(void);* 这个子程序初始化控制台中断,其它什么都不做。如果你想让屏幕干净的话,就使用* 适当的转义字符序列调用tty_write()函数。** 读取setup.s 程序保存的信息,用以确定当前显示器类型,并且设置所有相关参数。*/voidcon_init (void){	register unsigned char a;	char *display_desc = "????";	char *display_ptr;	video_num_columns = ORIG_VIDEO_COLS;	// 显示器显示字符列数。	video_size_row = video_num_columns * 2;	// 每行需使用字节数。	video_num_lines = ORIG_VIDEO_LINES;	// 显示器显示字符行数。	video_page = (unsigned char)ORIG_VIDEO_PAGE;	// 当前显示页面。	video_erase_char = 0x0720;	// 擦除字符(0x20 显示字符, 0x07 是属性)。// 如果原始显示模式等于7,则表示是单色显示器。	if (ORIG_VIDEO_MODE == 7)	/* Is this a monochrome display? */	{		video_mem_start = 0xb0000;	// 设置单显映象内存起始地址。		video_port_reg = 0x3b4;	// 设置单显索引寄存器端口。		video_port_val = 0x3b5;	// 设置单显数据寄存器端口。// 根据BIOS 中断int 0x10 功能0x12 获得的显示模式信息,判断显示卡单色显示卡还是彩色显示卡。// 如果使用上述中断功能所得到的BX 寄存器返回值不等于0x10,则说明是EGA 卡。因此初始// 显示类型为EGA 单色;所使用映象内存末端地址为0xb8000;并置显示器描述字符串为'EGAm'。// 在系统初始化期间显示器描述字符串将显示在屏幕的右上角。		if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)		{			video_type = VIDEO_TYPE_EGAM;	// 设置显示类型(EGA 单色)。			video_mem_end = 0xb8000;	// 设置显示内存末端地址。			display_desc = "EGAm";	// 设置显示描述字符串。		}// 如果BX 寄存器的值等于0x10,则说明是单色显示卡MDA。则设置相应参数。		else		{			video_type = VIDEO_TYPE_MDA;	// 设置显示类型(MDA 单色)。			video_mem_end = 0xb2000;	// 设置显示内存末端地址。			display_desc = "*MDA";	// 设置显示描述字符串。		}	}// 如果显示模式不为7,则为彩色模式。此时所用的显示内存起始地址为0xb800;显示控制索引寄存// 器端口地址为0x3d4;数据寄存器端口地址为0x3d5。	else				/* If not, it is color. */	{		video_mem_start = 0xb8000;	// 显示内存起始地址。		video_port_reg = 0x3d4;	// 设置彩色显示索引寄存器端口。		video_port_val = 0x3d5;	// 设置彩色显示数据寄存器端口。// 再判断显示卡类别。如果BX 不等于0x10,则说明是EGA 显示卡。		if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)		{			video_type = VIDEO_TYPE_EGAC;	// 设置显示类型(EGA 彩色)。			video_mem_end = 0xbc000;	// 设置显示内存末端地址。			display_desc = "EGAc";	// 设置显示描述字符串。		}// 如果BX 寄存器的值等于0x10,则说明是CGA 显示卡。则设置相应参数。		else		{			video_type = VIDEO_TYPE_CGA;	// 设置显示类型(CGA)。			video_mem_end = 0xba000;	// 设置显示内存末端地址。			display_desc = "*CGA";	// 设置显示描述字符串。		}	}/* Let the user known what kind of display driver we are using *//* 让用户知道我们正在使用哪一类显示驱动程序 */// 在屏幕的右上角显示显示描述字符串。采用的方法是直接将字符串写到显示内存的相应位置处。// 首先将显示指针display_ptr 指到屏幕第一行右端差4 个字符处(每个字符需2 个字节,因此减8)。	display_ptr = ((char *) video_mem_start) + video_size_row - 8;// 然后循环复制字符串中的字符,并且每复制一个字符都空开一个属性字节。	while (*display_desc)	{		*display_ptr++ = *display_desc++;	// 复制字符。		display_ptr++;		// 空开属性字节位置。	}/* 初始化用于滚屏的变量(主要用于EGA/VGA) */	origin = video_mem_start;	// 滚屏起始显示内存地址。	scr_end = video_mem_start + video_num_lines * video_size_row;	// 滚屏结束内存地址。	top = 0;			// 最顶行号。	bottom = video_num_lines;	// 最底行号。	gotoxy (ORIG_X, ORIG_Y);	// 初始化光标位置x,y 和对应的内存位置pos。	set_trap_gate (0x21, &keyboard_interrupt);	// 设置键盘中断陷阱门。	outb_p ((unsigned char)(inb_p (0x21) & 0xfd), 0x21);	// 取消8259A 中对键盘中断的屏蔽,允许IRQ1。	a = inb_p (0x61);		// 延迟读取键盘端口0x61(8255A 端口PB)。	outb_p ((unsigned char)(a | 0x80), 0x61);	// 设置禁止键盘工作(位7 置位),	outb (a, 0x61);		// 再允许键盘工作,用以复位键盘操作。}/* from bsd-net-2: *///// 停止蜂鸣。// 复位8255A PB 端口的位1 和位0。voidsysbeepstop (void){/* disable counter 2 *//* 禁止定时器2 */	outb ((unsigned char)(inb_p (0x61) & 0xFC), 0x61);}int beepcount = 0;// 开通蜂鸣。// 8255A 芯片PB 端口的位1 用作扬声器的开门信号;位0 用作8253 定时器2 的门信号,该定时器的// 输出脉冲送往扬声器,作为扬声器发声的频率。因此要使扬声器蜂鸣,需要两步:首先开启PB 端口// 位1 和位0(置位),然后设置定时器发送一定的定时频率即可。static voidsysbeep (void){/* enable counter 2 *//* 开启定时器2 */	outb_p ((unsigned char)(inb_p (0x61) | 3), 0x61);/* set command for counter 2, 2 byte write *//* 送设置定时器2 命令 */	outb_p (0xB6, 0x43);/* send 0x637 for 750 HZ *//* 设置频率为750HZ,因此送定时值0x637 */	outb_p (0x37, 0x42);	outb (0x06, 0x42);/* 1/8 second *//* 蜂鸣时间为1/8 秒 */	beepcount = HZ / 8;}

⌨️ 快捷键说明

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