日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux 0.11 内核学习 -- console.c,控制台

發布時間:2024/7/19 linux 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux 0.11 内核学习 -- console.c,控制台 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

參考《linux內核完全注釋》和網上相關文章

/*

?* 控制臺顯示操作

?*/

/*

?* ?linux/kernel/console.c

?*

?* ?(C) 1991 ?Linus Torvalds

?*/

/*

?* console.c

?*

?* This module implements the console io functions

?* 'void con_init(void)'

?* 'void con_write(struct tty_queue * queue)'

?* Hopefully this will be a rather complete VT102 implementation.

?*

?* Beeping thanks to John T Kohl.

?*/

/**********************

?* con_init con_write *

?**********************/

/*

?* ?NOTE!!! We sometimes disable and enable interrupts for a short while

?* (to put a word in video IO), but this will work even for keyboard

?* interrupts. We know interrupts aren't enabled when getting a keyboard

?* interrupt, as we use trap-gates. Hopefully all is well.

?*/

/*

?* Code to check for different video-cards mostly by Galen Hunt,

?* <g-hunt@ee.utah.edu>

?*/

#include <linux/sched.h>

#include <linux/tty.h> // 定義tty_struct結構,串行通信方面的參數和常量

#include <asm/io.h> // 硬件對應的匯編io指令

#include <asm/system.h>

/*

?* These are set up by the setup-routine at boot-time:

?*/

#define ORIG_X (*(unsigned char *)0x90000) // 光標列號

#define ORIG_Y (*(unsigned char *)0x90001) // 光標行號

#define ORIG_VIDEO_PAGE (*(unsigned short *)0x90004) // 顯示頁面

#define ORIG_VIDEO_MODE ((*(unsigned short *)0x90006) & 0xff) // 顯示模式

#define ORIG_VIDEO_COLS (((*(unsigned short *)0x90006) & 0xff00) >> 8) // 字符列數

#define ORIG_VIDEO_LINES (25) // 字符行數

#define ORIG_VIDEO_EGA_AX (*(unsigned short *)0x90008) // ??

#define ORIG_VIDEO_EGA_BX (*(unsigned short *)0x9000a) // 顯示內存大小和色彩模式

#define ORIG_VIDEO_EGA_CX (*(unsigned short *)0x9000c) // 顯示卡特性參數

#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 16

extern void keyboard_interrupt(void); // 鍵盤中斷處理程序

/* 全局變量,指示顯示器的相關信息 */

static unsigned char video_type; /* Type of display being used */

static unsigned long video_num_columns; /* Number of text columns */

static unsigned long video_size_row; /* Bytes per row,每行使用的字節數 */

static unsigned long video_num_lines; /* Number of test lines,屏幕文本行數 */

static unsigned char video_page; /* Initial video page,初始顯示頁面 */

static unsigned long video_mem_start; /* Start of video RAM */

static unsigned long video_mem_end; /* End of video RAM (sort of) */

static unsigned short video_port_reg; /* Video register select port */

/* 顯示控制索引寄存器端口 */

static unsigned short video_port_val; /* Video register value port */

static unsigned short video_erase_char; /* Char+Attrib to erase with,擦除字符屬性與字符 */

/* 下面的全局變量是屏幕卷屏操作所使用 */

static unsigned long origin; /* Used for EGA/VGA fast scroll */ // 滾屏起始內存地址

static unsigned long scr_end; /* Used for EGA/VGA fast scroll */ // 滾屏末端內存地址

static unsigned long pos; // 當前光標位置相對于顯存的位置

static unsigned long x,y; // 當前光標

static unsigned long top,bottom; // 滾動時頂行行號和底行行號

/**************************************************************/

static unsigned long state=0; // 處理ESC 轉義序列時的當前進行到哪

static unsigned long npar,par[NPAR]; // 放ESC 序列的中間處理參數

/************************************************************/

static unsigned long ques=0;

static unsigned char attr=0x07; // char

static void sysbeep(void);

/*

?* this is what the terminal answers to a ESC-Z or csi0c

?* query (= vt100 response).

?*/

#define RESPONSE "\033[?1;2c"

/* NOTE! gotoxy thinks x==video_num_columns is ok */

/* 更新當前光標位置 */

/*

?* |----------------------------------------------------------> x

?* | ? ? ? ? ? ? video_size_row

?* |--------------------------------------| -|------> top頂行行號

?* |--------------------------------------| ?|

?* | ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| ?|

?* | ? ? ? ?* ? ? * ? ? ? ? * ? ? ? ? ? ? | ?| --> video_num_row

?* ? ? ? ? ? ?P(x, y) ? ? ? ? ? ? ? ? ? ? ? ?|?

?* |--------------------------------------| -|------> button底行行號

?* |--------------------------------------|

?* | ? ? ? ? ? ? ? ? ?|

?* | ? ? ? ? ? ? video_num_columns

?* |

?* | y

?* ??

?* all video memory = video_size_row * video_num_row

?* the screen point P(x, y) is mapping the main memory?

?* video_mem_start + y * video_size_row + (x << 1)

?*/

static inline void gotoxy(unsigned int new_x,unsigned int new_y)

{

if (new_x > video_num_columns || new_y >= video_num_lines)

return; // 錯誤檢查

x=new_x; // 更新x,y

y=new_y;

pos=origin + y*video_size_row + (x<<1); // 重新計算全局變量pos值

}

/* 設置滾屏起始顯示內存地址 */

static inline void set_origin(void)

{

cli();

outb_p(12, video_port_reg); // 向擇顯示控制數據寄存器r12寫入卷屏起始地址高字節

outb_p(0xff&((origin-video_mem_start)>>9), video_port_val);

outb_p(13, video_port_reg); // 向顯示控制數據寄存器r13寫入卷屏起始地址底字節

outb_p(0xff&((origin-video_mem_start)>>1), video_port_val);

sti();

}

/* 向上卷動一行 */

static void scrup(void)

{

/*

?* 我們可以認為的是顯存就是一片內存區域,顯示器在決定顯示部分時,根據的是

?* 顯示控制器的的內存起始位置值。但是在實際的操作系統中,顯存是固定在一個

?* 區域內的。

?*

?* 將屏幕看作是顯示內存上對應屏幕內容的一個窗口

?*/

/* EGA/VGA */

if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM)

{

// 如果移動起始行top=0,移動最底行bottom=video_num_lines=25,則

// 表示整屏窗口向下移動

if (!top && bottom == video_num_lines)

{

// 更新數據

origin += video_size_row;

pos += video_size_row;

scr_end += video_size_row;

// 如果屏幕末端最后一個顯示字符所對應的顯示內存指針scr_end?

// 超出了實際顯示內存的末端。保證所有當前屏幕數據都落在顯示

// 內存范圍內

if (scr_end > video_mem_end)

{

// 屏幕內容內存數據移動到顯示內存的起始位置video_mem_start

// 處,并在出現的新行上填入空格字符

__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");

// 更新數據

scr_end -= origin-video_mem_start;

pos -= origin-video_mem_start;

origin = video_mem_start;

}

else // scr_end 沒有超出顯示內存的末端video_mem_end?

{

// 新行上填入擦除字符(空格字符)

__asm__("cld\n\t"

"rep\n\t"

"stosw"

::"a" (video_erase_char),

"c" (video_num_columns),

"D" (scr_end-video_size_row)

:"cx","di");

}

set_origin(); // 向顯示控制器中寫入新的屏幕內容對應的內存起始位置值

}?

else // 表示不是整屏移動

{

__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");

}

}

else /* Not EGA/VGA */

{

// 因為MDA 顯示控制卡會自動調整超出顯示范圍的情況,也即會自動

// 翻卷指針,所以這里不對屏幕內容對應內存超出顯示內存的情況單獨處理

__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");

}

}

/* 向下卷動一行,該函數只是根據top和button來實現的卷屏 */

static void scrdown(void)

{

if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM)

{

__asm__("std\n\t" // 置方向位

"rep\n\t" // 重復操作,向下移動從top 行到bottom-1 行

"movsl\n\t" // 對應的內存數據

"addl $2,%%edi\n\t" /* %edi has been decremented by 4 */

"movl _video_num_columns,%%ecx\n\t" // 置ecx=1 行字符數

"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");

}

else /* Not EGA/VGA */

{

__asm__("std\n\t"

"rep\n\t"

"movsl\n\t"

"addl $2,%%edi\n\t" /* %edi has been decremented by 4 */

"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");

}

}

/* 光標位置下移一行 */

static void lf(void)

{

if (y+1<bottom)?

{

y++;

pos += video_size_row;

return;

}

scrup(); // 函數還沒有退出,將屏幕內容上移一行

}

/* 光標上移一行,同上lf */

static void ri(void)

{

if (y>top) {

y--;

pos -= video_size_row;

return;

}

scrdown();

}

/* 光標回到第1 列(0 列)左端 */

static void cr(void)

{

pos -= x<<1; // x / 2

x=0;

}

/* 擦除光標前一字符 */

static void del(void)

{

if (x) //如果光標沒有處在0 列

{

pos -= 2; // 光標對應內存位置指針pos 后退2 字節

x--; // 當前光標變量列值減1

*(unsigned short *)pos = video_erase_char; // 光標所在位置字符擦除

}

}

/* 刪除屏幕上的相關區域 */

static void csi_J(int par)

{

long count __asm__("cx"); // // 設為寄存器變量

long start __asm__("di");

switch (par)?

{

case 0: /* erase from cursor to end of display */

/* 擦除光標到屏幕底端 */

count = (scr_end-pos)>>1;

start = pos;

break;

case 1: /* erase from start to cursor */

/* 刪除從屏幕開始到光標處的字符 */

count = (pos-origin)>>1;

start = origin;

break;

case 2: /* erase whole display */

/* 刪除整個屏幕上的字符 */

count = video_num_columns * video_num_lines;

start = origin;

break;

default:

return;

}

// 使用擦除字符填寫刪除字符的地方

// %0 - ecx(要刪除的字符數count);%1 - edi(刪除操作開始地址);

// %2 - eax(填入的擦除字符)

__asm__("cld\n\t"

"rep\n\t"

"stosw\n\t"

::"c" (count),

"D" (start),"a" (video_erase_char)

:"cx","di");

}

/* 根據par的不同,刪除與行相關的字符,并填充其他字符 */

static void csi_K(int par)

{

long count __asm__("cx"); // 設置寄存器變量

long start __asm__("di");

/* 計算count和start的值,以便在下面實現字符的擦除 */

switch (par)?

{

case 0: /* erase from cursor to end of line */

/* 刪除光標到行尾字符 */

if (x>=video_num_columns)

return;

count = video_num_columns-x;

start = pos;

break;

case 1: /* erase from start of line to cursor */

/* 刪除從行開始到光標處 */

start = pos - (x<<1);

count = (x<video_num_columns)?x:video_num_columns;

break;

case 2: /* erase whole line */

start = pos - (x<<1);

count = video_num_columns;

break;

default:

return;

}

// 使用擦除字符填寫刪除字符的地方

__asm__("cld\n\t"

"rep\n\t"

"stosw\n\t"

::"c" (count),

"D" (start),"a" (video_erase_char)

:"cx","di");

}

/* 重新設置字符顯示方式 */

void csi_m(void)

{

int i;

for (i=0;i<=npar;i++)

switch (par[i])

{

case 0:attr=0x07;break; // n = 0 正常顯示

case 1:attr=0x0f;break; // 1 加粗

case 4:attr=0x0f;break; // 4 加下劃線

case 7:attr=0x70;break; // 7 反顯

case 27:attr=0x07;break; // 27 正常顯示

}

}

/* 根據顯示內存光標對應位置pos,設置顯示控制器光標的顯示位置 */

static inline void set_cursor(void)

{

cli();

// 使用索引寄存器端口選擇顯示控制數據寄存器r14(光標當前顯示位置高字節)

outb_p(14, video_port_reg);

// 當前位置高字節

outb_p(0xff&((pos-video_mem_start)>>9), video_port_val);

// 再使用索引寄存器選擇r15

outb_p(15, video_port_reg);

// 光標當前位置低字節寫入其中

outb_p(0xff&((pos-video_mem_start)>>1), video_port_val);

sti();

}

/* ,終端相應外部命令,將響應序列放入讀緩沖隊列中 */

/*?

?* console (tty同時對應screen)

?*

?* ? ? ? ? ? ? ? ? ? ? ? ? |---struct tty_queue read_q

?* console --> tty_struct -|

?* ? ? ? ? ? ? ? ? ? ? ? ? |---struct tty_queue write_q

?*

?*/

static void respond(struct tty_struct * tty)

{

char * p = RESPONSE; // "\033[?1;2c"

cli();

while (*p)

{

PUTCH(*p,tty->read_q);

p++;

}

sti();

copy_to_cooked(tty); // 轉換成規范模式(放入輔助隊列中)

}

/* 在光標處插入一空格字符 */

static void insert_char(void)

{

int i=x;

unsigned short tmp, old = video_erase_char;

unsigned short * p = (unsigned short *) pos;

/*

* |----------|-|----------------------------|

* ? ? ? ? ? ? |-----swap---->|

* 光標開始的所有字符右移一格,并將擦除字符插入在光標所在處

*/

while (i++<video_num_columns)

{

tmp=*p;

*p=old;

old=tmp;

p++;

}

}

/* 在光標處插入一行,并且光標將處在新的空行上 */

static void insert_line(void)

{

int oldtop,oldbottom;

oldtop=top;

oldbottom=bottom;

top=y; // 設置屏幕卷動開始行

bottom = video_num_lines; // 設置屏幕卷動最后行

scrdown();

top=oldtop;

bottom=oldbottom;

}

/* 刪除光標處的一個字符 */

static void delete_char(void)

{

int i;

unsigned short * p = (unsigned short *) pos;

if (x>=video_num_columns) // 如果光標超出屏幕最右列

return;

i = x;

while (++i < video_num_columns) // 從光標右一個字符開始到行末所有字符左移一格

{

*p = *(p+1);

p++;

}

*p = video_erase_char; // 最后一個字符處填入擦除字符(空格字符)

}

/* 刪除光標所在行,同insert_line */

static void delete_line(void)

{

int oldtop,oldbottom;

oldtop=top;

oldbottom=bottom;

top=y;

bottom = video_num_lines;

scrup();

top=oldtop;

bottom=oldbottom;

}

/* 在光標處插入nr 個字符 */

static void csi_at(unsigned int nr)

{

if (nr > video_num_columns) // 如果插入的字符數大于一行字符數

nr = video_num_columns; // 截為一行字符數

else if (!nr) // nr == 0 ?

nr = 1; // nr = 1,插入1 個字符

while (nr--) // 循環插入指定的字符數

insert_char();

}

/* 在光標位置處插入nr 行 */

static void csi_L(unsigned int nr)

{

if (nr > video_num_lines)

nr = video_num_lines;

else if (!nr)

nr = 1;

while (nr--)

insert_line();

}

/* 刪除光標處的nr 個字符,調用函數delete_char */

static void csi_P(unsigned int nr)

{

if (nr > video_num_columns)

nr = video_num_columns;

else if (!nr)

nr = 1;

while (nr--)

delete_char();

}

/* 刪除光標處的nr 行 */

static void csi_M(unsigned int nr)

{

if (nr > video_num_lines)

nr = video_num_lines;

else if (!nr)

nr=1;

while (nr--)

delete_line();

}

static int saved_x=0; // 保存光標列號

static int saved_y=0; // 保存光標行號

static void save_cur(void)

{

saved_x=x;

saved_y=y;

}

static void restore_cur(void)

{

gotoxy(saved_x, saved_y);

}

/* 從終端對應的tty 寫緩沖隊列中取字符,并顯示在屏幕上 */

void con_write(struct tty_struct * tty)

{

int nr;

char c;

nr = CHARS(tty->write_q); // 首先取得寫緩沖隊列中現有字符數nr

while (nr--) // 針對每個字符進行處理

{

// 從寫隊列中取一字符c,根據前面所處理字符的狀態state 分別處理

GETCH(tty->write_q,c);

switch(state)?

{

case 0:

if (c>31 && c<127)?

{

// 符不是控制字符(c>31),并且也不是擴展字符(c<127)

if (x>=video_num_columns)

{

// 若當前光標處在行末端或末端以外,則將光標移到下行頭列。

// 并調整光標位置對應的內存指針pos

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");

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=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;

if (c=='[') // 如果字符c 是'[',則將狀態state 轉到2

state=2;

else if (c=='E') // 如果字符c 是'E',則光標移到下一行開始處(0 列)

gotoxy(0,y+1);

else if (c=='M') // 如果字符c 是'M',則光標上移一行

ri();

else if (c=='D') // 如果字符c 是'D',則光標下移一行

lf();

else if (c=='Z') // 如果字符c 是'Z',則發送終端應答字符序列

respond(tty);

else if (x=='7') // 如果字符c 是'7',則保存當前光標位置

save_cur();

else if (x=='8') // 如果字符c 是'8',則恢復到原保存的光標位置

restore_cur();

break;

// 如果原狀態是1,并且上一字符是'[',則轉到狀態2 來處理

case 2:

// 首先對ESC 轉義字符序列參數使用的處理數組par[]清零

for(npar=0;npar<NPAR;npar++)

par[npar]=0;

npar=0; // 索引變量npar 指向首項

state=3; // 設置狀態3

if (ques=(c=='?')) // 若此時字符不是'?',則直接轉到狀態3 去處理

break;

// 如果原來是狀態2;或者原來就是狀態3,但原字符是';'或數字,則在下面處理

case 3:

if (c==';' && npar<NPAR-1)

{ // 如果字符c 是分號';',并且數組par 未滿,則索引值加1

npar++;

break;

}?

else if (c>='0' && c<='9')?

{

// 如果字符c 是數字字符'0'-'9',則將該字符轉換成數值并與npar

// 所索引的項組成10 進制數

par[npar]=10*par[npar]+c-'0';

break;

}?

else // 否則轉到狀態4

state=4;

// 如果原狀態是狀態3,并且字符不是';'或數字,則轉到狀態4 處理

case 4:

state=0; // 首先復位狀態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',則第一個參數代表以光標所處位置清屏的方式

case 'J':

csi_J(par[0]);

break;

// 如果字符c 是'K',則第一個參數代表以光標所在位置對行中字符進行

// 刪除處理的方式

case 'K':

csi_K(par[0]);

break;

// 如果字符c 是'L',表示在光標位置處插入n 行

case 'L':

csi_L(par[0]);

break;

// 如果字符c 是'M',表示在光標位置處刪除n 行

case 'M':

csi_M(par[0]);

break;

// 如果字符c 是'P',表示在光標位置處刪除n 個字符

case 'P':

csi_P(par[0]);

break;

// 如果字符c 是'@',表示在光標位置處插入n 個字符

case '@':

csi_at(par[0]);

break;

// 如果字符c 是'm',表示改變光標處字符的顯示屬性

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);

?*

?* This routine initalizes console interrupts, and does nothing

?* else. If you want the screen to clear, call tty_write with

?* the appropriate escape-sequece.

?*

?* Reads the information preserved by setup.s to determine the current display

?* type and sets everything accordingly.

?*/

/*

?* 讀取setup.s 程序保存的信息,用以確定當前顯示器類型,并且設置所有相關參數

?*/

void con_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 = ORIG_VIDEO_PAGE; // 當前顯示頁面

video_erase_char = 0x0720; // 擦除字符(0x20 顯示字符, 0x07 是屬性)

// 是單色顯示器?

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 獲得的顯示模式信息,判斷

* 顯示卡單色顯示卡還是彩色顯示卡

*/

if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)

{

video_type = VIDEO_TYPE_EGAM; // 設置顯示類型(EGA 單色)

video_mem_end = 0xb8000; // 設置顯示內存末端地址

display_desc = "EGAm"; // 設置顯示描述字符串

}

else

{

video_type = VIDEO_TYPE_MDA; // 設置顯示類型(MDA 單色)

video_mem_end = 0xb2000; // 設置顯示內存末端地址

display_desc = "*MDA"; // 設置顯示描述字符串

}

}

else /* If not, it is color. */

{

video_mem_start = 0xb8000; // 顯示內存起始地址

video_port_reg = 0x3d4; // 設置彩色顯示索引寄存器端口

video_port_val = 0x3d5; // 設置彩色顯示數據寄存器端口

// 再判斷顯示卡類別

if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)

{

video_type = VIDEO_TYPE_EGAC;

video_mem_end = 0xbc000;

display_desc = "EGAc";

}

else

{

video_type = VIDEO_TYPE_CGA;

video_mem_end = 0xba000;

display_desc = "*CGA";

}

}

/* Let the user known what kind of display driver we are using */

/* 在屏幕的右上角顯示顯示描述字符串。采用的方法是直接將字符串寫到顯示內存的相應位置處 */

display_ptr = ((char *)video_mem_start) + video_size_row - 8;

while (*display_desc)

{

*display_ptr++ = *display_desc++; // 復制字符

display_ptr++; // 空開屬性字節位置

}

/* Initialize the variables used for scrolling (mostly 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(inb_p(0x21)&0xfd,0x21); // // 取消8259A 中對鍵盤中斷的屏蔽

a=inb_p(0x61); // // 延遲讀取鍵盤端口0x61

outb_p(a|0x80,0x61); // 設置禁止鍵盤工作

outb(a,0x61); // 再允許鍵盤工作,用以復位鍵盤操作

}

/* from bsd-net-2: */

/* 停止蜂鳴 */

void sysbeepstop(void)

{

/* disable counter 2 */

outb(inb_p(0x61)&0xFC, 0x61);

}

int beepcount = 0;

/* 開通蜂鳴 */

static void sysbeep(void)

{

/* enable counter 2 */

/* 開啟定時器2 */

outb_p(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 */

beepcount = HZ/8;

}

轉載于:https://www.cnblogs.com/xuqiang/archive/2010/02/01/1953774.html

總結

以上是生活随笔為你收集整理的linux 0.11 内核学习 -- console.c,控制台的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。