?? console.c.bak
字號(hào):
/** linux/kernel/console.c** (C) 1991 Linus Torvalds*/#include <set_seg.h>
/** console.c** 該模塊實(shí)現(xiàn)控制臺(tái)輸入輸出功能* 'void con_init(void)'* 'void con_write(struct tty_queue * queue)'* 希望這是一個(gè)非常完整的VT102 實(shí)現(xiàn)。** 感謝John T Kohl 實(shí)現(xiàn)了蜂鳴指示。*//** 注意!!! 我們有時(shí)短暫地禁止和允許中斷(在將一個(gè)字(word)放到視頻IO),但即使* 對(duì)于鍵盤(pán)中斷這也是可以工作的。因?yàn)槲覀兪褂孟葳彘T,所以我們知道在獲得一個(gè)* 鍵盤(pán)中斷時(shí)中斷是不允許的。希望一切均正常。*//** 檢測(cè)不同顯示卡的代碼大多數(shù)是Galen Hunt 編寫(xiě)的,* <g-hunt@ee.utah.edu>*/#include <linux/sched.h> // 調(diào)度程序頭文件,定義了任務(wù)結(jié)構(gòu)task_struct、初始任務(wù)0 的數(shù)據(jù), // 還有一些有關(guān)描述符參數(shù)設(shè)置和獲取的嵌入式匯編函數(shù)宏語(yǔ)句。#include <linux/tty.h> // tty 頭文件,定義了有關(guān)tty_io,串行通信方面的參數(shù)、常數(shù)。#include <asm/io.h> // io 頭文件。定義硬件端口輸入/輸出宏匯編語(yǔ)句。#include <asm/system.h> // 系統(tǒng)頭文件。定義了設(shè)置或修改描述符/中斷門等的嵌入式匯編宏。/** 這些是設(shè)置子程序setup 在引導(dǎo)啟動(dòng)系統(tǒng)時(shí)設(shè)置的參數(shù):*/// 參見(jiàn)對(duì)boot/setup.s 的注釋,和setup 程序讀取并保留的參數(shù)表。#define ORIG_X (*(unsigned char *)0x90000) // 光標(biāo)列號(hào)。#define ORIG_Y (*(unsigned char *)0x90001) // 光標(biāo)行號(hào)。#define ORIG_VIDEO_PAGE (*(unsigned short *)0x90004) // 顯示頁(yè)面。#define ORIG_VIDEO_MODE ((*(unsigned short *)0x90006) & 0xff) // 顯示模式。#define ORIG_VIDEO_COLS (((*(unsigned short *)0x90006) & 0xff00) >> 8) // 字符列數(shù)。#define ORIG_VIDEO_LINES (25) // 顯示行數(shù)。#define ORIG_VIDEO_EGA_AX (*(unsigned short *)0x90008) // [??]#define ORIG_VIDEO_EGA_BX (*(unsigned short *)0x9000a) // 顯示內(nèi)存大小和色彩模式。#define ORIG_VIDEO_EGA_CX (*(unsigned short *)0x9000c) // 顯示卡特性參數(shù)。// 定義顯示器單色/彩色顯示模式類型符號(hào)常數(shù)。#define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */ /* 單色文本 */#define VIDEO_TYPE_CGA 0x11 /* CGA Display */ /* CGA 顯示器 */#define VIDEO_TYPE_EGAM 0x20 /* EGA/VGA in Monochrome Mode */ /* EGA/VGA 單色 */#define VIDEO_TYPE_EGAC 0x21 /* EGA/VGA in Color Mode */ /* EGA/VGA 彩色 */#define NPAR 16extern void keyboard_interrupt (void); // 鍵盤(pán)中斷處理程序(keyboard.S)。static unsigned char video_type = 0; /* Type of display being used *//* 使用的顯示類型 */static unsigned long video_num_columns = 0; /* Number of text columns *//* 屏幕文本列數(shù) */static unsigned long video_size_row = 0; /* Bytes per row *//* 每行使用的字節(jié)數(shù) */static unsigned long video_num_lines = 0; /* Number of test lines *//* 屏幕文本行數(shù) */static unsigned char video_page = 0; /* Initial video page *//* 初始顯示頁(yè)面 */static unsigned long video_mem_start = 0; /* Start of video RAM *//* 顯示內(nèi)存起始地址 */static unsigned long video_mem_end = 0; /* End of video RAM (sort of) *//* 顯示內(nèi)存結(jié)束(末端)地址 */static unsigned short video_port_reg = 0; /* Video register select port *//* 顯示控制索引寄存器端口 */static unsigned short video_port_val = 0; /* Video register value port *//* 顯示控制數(shù)據(jù)寄存器端口 */static unsigned short video_erase_char = 0; /* Char+Attrib to erase with *//* 擦除字符屬性與字符(0x0720) */// 以下這些變量用于屏幕卷屏操作。static unsigned long origin = 0; /* Used for EGA/VGA fast scroll */// scr_start。/* 用于EGA/VGA 快速滾屏 */// 滾屏起始內(nèi)存地址。static unsigned long scr_end = 0; /* Used for EGA/VGA fast scroll *//* 用于EGA/VGA 快速滾屏 */// 滾屏末端內(nèi)存地址。static unsigned long pos = 0; // 當(dāng)前光標(biāo)對(duì)應(yīng)的顯示內(nèi)存位置。static unsigned long x = 0, y = 0; // 當(dāng)前光標(biāo)位置。static unsigned long top = 0, bottom = 0; // 滾動(dòng)時(shí)頂行行號(hào);底行行號(hào)。// state 用于標(biāo)明處理ESC 轉(zhuǎn)義序列時(shí)的當(dāng)前步驟。npar,par[]用于存放ESC 序列的中間處理參數(shù)。static unsigned long state = 0; // ANSI 轉(zhuǎn)義字符序列處理狀態(tài)。static unsigned long npar = 0, par[NPAR] = {0}; // ANSI 轉(zhuǎn)義字符序列參數(shù)個(gè)數(shù)和參數(shù)數(shù)組。static unsigned long ques = 0;static unsigned char attr = 0x07; // 字符屬性(黑底白字)。static void sysbeep (void); // 系統(tǒng)蜂鳴函數(shù)。/** this is what the terminal answers to a ESC-Z or csi0c* query (= vt100 response).*//** 下面是終端回應(yīng)ESC-Z 或csi0c 請(qǐng)求的應(yīng)答(=vt100 響應(yīng))。*/// csi - 控制序列引導(dǎo)碼(Control Sequence Introducer)。#define RESPONSE "\033[?1;2c"/* NOTE! gotoxy thinks x==video_num_columns is ok *//* 注意!gotoxy 函數(shù)認(rèn)為x==video_num_columns,這是正確的 *///// 跟蹤光標(biāo)當(dāng)前位置。// 參數(shù):new_x - 光標(biāo)所在列號(hào);new_y - 光標(biāo)所在行號(hào)。// 更新當(dāng)前光標(biāo)位置變量x,y,并修正pos 指向光標(biāo)在顯示內(nèi)存中的對(duì)應(yīng)位置。static _inline voidgotoxy (unsigned int new_x, unsigned int new_y){// 如果輸入的光標(biāo)行號(hào)超出顯示器列數(shù),或者光標(biāo)行號(hào)超出顯示的最大行數(shù),則退出。 if (new_x > video_num_columns || new_y >= video_num_lines) return;// 更新當(dāng)前光標(biāo)變量;更新光標(biāo)位置對(duì)應(yīng)的在顯示內(nèi)存中位置變量pos。 x = new_x; y = new_y; pos = origin + y * video_size_row + (x << 1);}//// 設(shè)置滾屏起始顯示內(nèi)存地址。static _inline voidset_origin (void){ cli ();// 首先選擇顯示控制數(shù)據(jù)寄存器r12,然后寫(xiě)入卷屏起始地址高字節(jié)。向右移動(dòng)9 位,表示向右移動(dòng)// 8 位,再除以2(2 字節(jié)代表屏幕上1 字符)。是相對(duì)于默認(rèn)顯示內(nèi)存操作的。 outb_p (12, video_port_reg); outb_p ((unsigned char)(0xff & ((origin - video_mem_start) >> 9)), video_port_val);// 再選擇顯示控制數(shù)據(jù)寄存器r13,然后寫(xiě)入卷屏起始地址底字節(jié)。向右移動(dòng)1 位表示除以2。 outb_p (13, video_port_reg); outb_p ((unsigned char)(0xff & ((origin - video_mem_start) >> 1)), video_port_val); sti ();}//// 向上卷動(dòng)一行(屏幕窗口向下移動(dòng))。// 將屏幕窗口向下移動(dòng)一行。參見(jiàn)程序列表后說(shuō)明。static voidscrup (void){
unsigned long t1,t2,t3;
// 如果顯示類型是EGA,則執(zhí)行以下操作。 if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM) {// 如果移動(dòng)起始行top=0,移動(dòng)最底行bottom=video_num_lines=25,則表示整屏窗口向下移動(dòng)。 if (!top && bottom == video_num_lines) {// 調(diào)整屏幕顯示對(duì)應(yīng)內(nèi)存的起始位置指針origin 為向下移一行屏幕字符對(duì)應(yīng)的內(nèi)存位置,同時(shí)也調(diào)整// 當(dāng)前光標(biāo)對(duì)應(yīng)的內(nèi)存位置以及屏幕末行末端字符指針scr_end 的位置。 origin += video_size_row; pos += video_size_row; scr_end += video_size_row;// 如果屏幕末端最后一個(gè)顯示字符所對(duì)應(yīng)的顯示內(nèi)存指針scr_end 超出了實(shí)際顯示內(nèi)存的末端,則將// 屏幕內(nèi)容內(nèi)存數(shù)據(jù)移動(dòng)到顯示內(nèi)存的起始位置video_mem_start 處,并在出現(xiàn)的新行上填入空格字符。 if (scr_end > video_mem_end) {// %0 - eax(擦除字符+屬性);%1 - ecx((顯示器字符行數(shù)-1)所對(duì)應(yīng)的字符數(shù)/2,是以長(zhǎng)字移動(dòng));// %2 - edi(顯示內(nèi)存起始位置video_mem_start);%3 - esi(屏幕內(nèi)容對(duì)應(yīng)的內(nèi)存起始位置origin)。// 移動(dòng)方向:[edi]->[esi],移動(dòng)ecx 個(gè)長(zhǎng)字。
t1 = (video_num_lines - 1) * video_num_columns >> 1;
_asm { pushf
mov ecx,t1;
// mov ecx,((video_num_lines - 1) * video_num_columns >> 1);
mov ax,video_erase_char;
mov edi,video_mem_start;
mov esi,origin;
cld; // 清方向位。
rep movsd; // 重復(fù)操作,將當(dāng)前屏幕內(nèi)存數(shù)據(jù)移動(dòng)到顯示內(nèi)存起始處。
mov ecx,video_num_columns; // ecx=1 行字符數(shù)。
rep stosw; // 在新行上填入空格字符。 popf
}/* __asm__ ("cld\n\t" "rep\n\t" "movsl\n\t" // "movl _video_num_columns,%1\n\t" "rep\n\t" "stosw"::"a" (video_erase_char), "c" ((video_num_lines - 1) * video_num_columns >> 1), "D" (video_mem_start), "S" (origin):"cx", "di", "si"); */// 根據(jù)屏幕內(nèi)存數(shù)據(jù)移動(dòng)后的情況,重新調(diào)整當(dāng)前屏幕對(duì)應(yīng)內(nèi)存的起始指針、光標(biāo)位置指針和屏幕末端// 對(duì)應(yīng)內(nèi)存指針scr_end。 scr_end -= origin - video_mem_start; pos -= origin - video_mem_start; origin = video_mem_start; } else {// 如果調(diào)整后的屏幕末端對(duì)應(yīng)的內(nèi)存指針scr_end 沒(méi)有超出顯示內(nèi)存的末端video_mem_end,則只需在// 新行上填入擦除字符(空格字符)。// %0 - eax(擦除字符+屬性);%1 - ecx(顯示器字符行數(shù));%2 - edi(屏幕對(duì)應(yīng)內(nèi)存最后一行開(kāi)始處); t1 = scr_end - video_size_row;
_asm { pushf
mov ax,video_erase_char;
mov ecx,video_num_columns;
mov edi,t1;
// mov edi,(scr_end - video_size_row);
cld; // 清方向位。
rep stosw; // 重復(fù)操作,在新出現(xiàn)行上填入擦除字符(空格字符)。 popf
}
/* __asm__ ("cld\n\t" "rep\n\t" "stosw" // ::"a" (video_erase_char), "c" (video_num_columns), "D" (scr_end - video_size_row):"cx", "di");*/ } // 向顯示控制器中寫(xiě)入新的屏幕內(nèi)容對(duì)應(yīng)的內(nèi)存起始位置值。 set_origin ();// 否則表示不是整屏移動(dòng)。也即表示從指定行top 開(kāi)始的所有行向上移動(dòng)1 行(刪除1 行)。此時(shí)直接// 將屏幕從指定行top 到屏幕末端所有行對(duì)應(yīng)的顯示內(nèi)存數(shù)據(jù)向上移動(dòng)1 行,并在新出現(xiàn)的行上填入擦// 除字符。// %0-eax(擦除字符+屬性);%1-ecx(top 行下1 行開(kāi)始到屏幕末行的行數(shù)所對(duì)應(yīng)的內(nèi)存長(zhǎng)字?jǐn)?shù));// %2-edi(top 行所處的內(nèi)存位置);%3-esi(top+1 行所處的內(nèi)存位置)。 } else {
t1 = (bottom - top - 1) * video_num_columns >> 1;
t2 = origin + video_size_row * top;
t3 = origin + video_size_row * (top + 1);
_asm { pushf
mov ecx,t1;
// mov ecx,((bottom - top - 1) * video_num_columns >> 1);
mov edi,t2;
// mov edi,(origin + video_size_row * top);
mov esi,t3;
// mov esi,(origin + video_size_row * (top + 1));
mov ax,video_erase_char;
cld; // 清方向位。
rep movsd; // 循環(huán)操作,將top+1 到bottom 行 所對(duì)應(yīng)的內(nèi)存塊移到top 行開(kāi)始處。
mov ecx,video_num_columns; // ecx = 1 行字符數(shù)。
rep stosw; // 在新行上填入擦除字符。 popf
}
/* __asm__ ("cld\n\t" "rep\n\t" "movsl\n\t" // "movl _video_num_columns,%%ecx\n\t" "rep\n\t" "stosw"::"a" (video_erase_char), "c" ((bottom - top - 1) * video_num_columns >> 1), "D" (origin + video_size_row * top), "S" (origin + video_size_row * (top + 1)):"cx", "di", "si");*/ } }// 如果顯示類型不是EGA(是MDA),則執(zhí)行下面移動(dòng)操作。因?yàn)镸DA 顯示控制卡會(huì)自動(dòng)調(diào)整超出顯示范圍// 的情況,也即會(huì)自動(dòng)翻卷指針,所以這里不對(duì)屏幕內(nèi)容對(duì)應(yīng)內(nèi)存超出顯示內(nèi)存的情況單獨(dú)處理。處理// 方法與EGA 非整屏移動(dòng)情況完全一樣。 else /* Not EGA/VGA */ {
t1 = (bottom - top - 1) * video_num_columns >> 1;
t2 = origin + video_size_row * top;
t3 = origin + video_size_row * (top + 1);
_asm { pushf
mov ecx,t1;
// mov ecx,((bottom - top - 1) * video_num_columns >> 1);
mov edi,t2;
// mov edi,(origin + video_size_row * top);
mov esi,t3;
// mov esi,(origin + video_size_row * (top + 1));
mov ax,video_erase_char;
cld;
rep movsd;
mov ecx,video_num_columns;
rep stosw; popf
}/* __asm__ ("cld\n\t" "rep\n\t" "movsl\n\t" "movl _video_num_columns,%%ecx\n\t" "rep\n\t" "stosw"::"a" (video_erase_char), "c" ((bottom - top - 1) * video_num_columns >> 1), "D" (origin + video_size_row * top), "S" (origin + video_size_row * (top + 1)):"cx", "di","si");*/ }}//// 向下卷動(dòng)一行(屏幕窗口向上移動(dòng))。// 將屏幕窗口向上移動(dòng)一行,屏幕顯示的內(nèi)容向下移動(dòng)1 行,在被移動(dòng)開(kāi)始行的上方出現(xiàn)一新行。參見(jiàn)// 程序列表后說(shuō)明。處理方法與scrup()相似,只是為了在移動(dòng)顯示內(nèi)存數(shù)據(jù)時(shí)不出現(xiàn)數(shù)據(jù)覆蓋錯(cuò)誤情// 況,復(fù)制是以反方向進(jìn)行的,也即從屏幕倒數(shù)第2 行的最后一個(gè)字符開(kāi)始復(fù)制static voidscrdown (void){
unsigned long t1,t2,t3;// 如果顯示類型是EGA,則執(zhí)行下列操作。// [??好象if 和else 的操作完全一樣啊!為什么還要分別處理呢?難道與任務(wù)切換有關(guān)?] if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM) {// %0-eax(擦除字符+屬性);%1-ecx(top 行開(kāi)始到屏幕末行-1 行的行數(shù)所對(duì)應(yīng)的內(nèi)存長(zhǎng)字?jǐn)?shù));// %2-edi(屏幕右下角最后一個(gè)長(zhǎng)字位置);%3-esi(屏幕倒數(shù)第2 行最后一個(gè)長(zhǎng)字位置)。// 移動(dòng)方向:[esi]??[edi],移動(dòng)ecx 個(gè)長(zhǎng)字。
t1 = (bottom - top - 1) * video_num_columns >> 1;
t2 = origin + video_size_row * bottom - 4;
t3 = origin + video_size_row * (bottom - 1) - 4;
_asm {
mov ecx,t1;
// mov ecx,((bottom - top - 1) * video_num_columns >> 1);
mov edi,t2;
// mov edi,(origin + video_size_row * bottom - 4);
mov esi,t3;
// mov esi,(origin + video_size_row * (bottom - 1) - 4);
mov ax,video_erase_char;
std; // 置方向位。
rep movsd; // 重復(fù)操作,向下移動(dòng)從top 行到bottom-1 行對(duì)應(yīng)的內(nèi)存數(shù)據(jù)。
add edi,2; /* %edi 已經(jīng)減4,因?yàn)橐彩欠较蛱畈脸址?*/
mov ecx,video_num_columns; // 置ecx=1 行字符數(shù)。
rep stosw; // 將擦除字符填入上方新行中。
}/* __asm__ ("std\n\t" "rep\n\t" "movsl\n\t" // "addl $2,%%edi\n\t" "movl _video_num_columns,%%ecx\n\t" "rep\n\t" "stosw"::"a" (video_erase_char), "c" ((bottom - top - 1) * video_num_columns >> 1), "D" (origin + video_size_row * bottom - 4), "S" (origin + video_size_row * (bottom - 1) - 4):"ax", "cx", "di", "si");*/ }// 如果不是EGA 顯示類型,則執(zhí)行以下操作(目前與上面完全一樣)。 else /* Not EGA/VGA */ {
t1 = (bottom - top - 1) * video_num_columns >> 1;
t2 = origin + video_size_row * bottom - 4;
t3 = origin + video_size_row * (bottom - 1) - 4;
_asm {
mov ecx,t1;
// mov ecx,((bottom - top - 1) * video_num_columns >> 1);
mov edi,t2;
// mov edi,(origin + video_size_row * bottom - 4);
mov esi,t3;
// mov esi,(origin + video_size_row * (bottom - 1) - 4);
mov ax,video_erase_char;
std;
rep movsd;
add edi,2;/* %edi has been decremented by 4 */
mov ecx,video_num_columns;
rep stosw;
} /* __asm__ ("std\n\t" "rep\n\t" "movsl\n\t" "addl $2,%%edi\n\t" "movl _video_num_columns,%%ecx\n\t" "rep\n\t" "stosw"::"a" (video_erase_char), "c" ((bottom - top - 1) * video_num_columns >> 1), "D" (origin + video_size_row * bottom - 4), "S" (origin + video_size_row * (bottom - 1) - 4):"ax", "cx", "di", "si");*/ }}//// 光標(biāo)位置下移一行(lf - line feed 換行)。static voidlf (void){// 如果光標(biāo)沒(méi)有處在倒數(shù)第2 行之后,則直接修改光標(biāo)當(dāng)前行變量y++,并調(diào)整光標(biāo)對(duì)應(yīng)顯示內(nèi)存位置// pos(加上屏幕一行字符所對(duì)應(yīng)的內(nèi)存長(zhǎng)度)。 if (y + 1 < bottom) { y++; pos += video_size_row; return; }// 否則需要將屏幕內(nèi)容上移一行。 scrup ();}
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -