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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

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

發(fā)布時(shí)間:2024/7/19 linux 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux 0.11 内核学习 -- console.c,控制台 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

參考《linux內(nèi)核完全注釋》和網(wǎng)上相關(guān)文章

/*

?* 控制臺(tái)顯示操作

?*/

/*

?* ?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結(jié)構(gòu),串行通信方面的參數(shù)和常量

#include <asm/io.h> // 硬件對(duì)應(yīng)的匯編io指令

#include <asm/system.h>

/*

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

?*/

#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ù)

#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); // 鍵盤中斷處理程序

/* 全局變量,指示顯示器的相關(guān)信息 */

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,每行使用的字節(jié)數(shù) */

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

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

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 */ // 滾屏起始內(nèi)存地址

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

static unsigned long pos; // 當(dāng)前光標(biāo)位置相對(duì)于顯存的位置

static unsigned long x,y; // 當(dāng)前光標(biāo)

static unsigned long top,bottom; // 滾動(dòng)時(shí)頂行行號(hào)和底行行號(hào)

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

static unsigned long state=0; // 處理ESC 轉(zhuǎn)義序列時(shí)的當(dāng)前進(jìn)行到哪

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

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

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

/* 更新當(dāng)前光標(biāo)位置 */

/*

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

?* | ? ? ? ? ? ? video_size_row

?* |--------------------------------------| -|------> top頂行行號(hào)

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

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

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

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

?* |--------------------------------------| -|------> button底行行號(hào)

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

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

?* | ? ? ? ? ? ? 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; // 錯(cuò)誤檢查

x=new_x; // 更新x,y

y=new_y;

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

}

/* 設(shè)置滾屏起始顯示內(nèi)存地址 */

static inline void set_origin(void)

{

cli();

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

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

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

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

sti();

}

/* 向上卷動(dòng)一行 */

static void scrup(void)

{

/*

?* 我們可以認(rèn)為的是顯存就是一片內(nèi)存區(qū)域,顯示器在決定顯示部分時(shí),根據(jù)的是

?* 顯示控制器的的內(nèi)存起始位置值。但是在實(shí)際的操作系統(tǒng)中,顯存是固定在一個(gè)

?* 區(qū)域內(nèi)的。

?*

?* 將屏幕看作是顯示內(nèi)存上對(duì)應(yīng)屏幕內(nèi)容的一個(gè)窗口

?*/

/* EGA/VGA */

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)

{

// 更新數(shù)據(jù)

origin += video_size_row;

pos += video_size_row;

scr_end += video_size_row;

// 如果屏幕末端最后一個(gè)顯示字符所對(duì)應(yīng)的顯示內(nèi)存指針scr_end?

// 超出了實(shí)際顯示內(nèi)存的末端。保證所有當(dāng)前屏幕數(shù)據(jù)都落在顯示

// 內(nèi)存范圍內(nèi)

if (scr_end > video_mem_end)

{

// 屏幕內(nèi)容內(nèi)存數(shù)據(jù)移動(dòng)到顯示內(nèi)存的起始位置video_mem_start

// 處,并在出現(xiàn)的新行上填入空格字符

__asm__("cld\n\t"

"rep\n\t"

"movsl\n\t" // 移動(dòng)到顯示內(nèi)存起始處

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

// 更新數(shù)據(jù)

scr_end -= origin-video_mem_start;

pos -= origin-video_mem_start;

origin = video_mem_start;

}

else // scr_end 沒(méi)有超出顯示內(nèi)存的末端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(); // 向顯示控制器中寫入新的屏幕內(nèi)容對(duì)應(yīng)的內(nèi)存起始位置值

}?

else // 表示不是整屏移動(dòng)

{

__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 */

{

// 因?yàn)镸DA 顯示控制卡會(huì)自動(dòng)調(diào)整超出顯示范圍的情況,也即會(huì)自動(dòng)

// 翻卷指針,所以這里不對(duì)屏幕內(nèi)容對(duì)應(yīng)內(nèi)存超出顯示內(nèi)存的情況單獨(dú)處理

__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)一行,該函數(shù)只是根據(jù)top和button來(lái)實(shí)現(xiàn)的卷屏 */

static void scrdown(void)

{

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

{

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

"rep\n\t" // 重復(fù)操作,向下移動(dòng)從top 行到bottom-1 行

"movsl\n\t" // 對(duì)應(yīng)的內(nèi)存數(shù)據(jù)

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

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

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

}

}

/* 光標(biāo)位置下移一行 */

static void lf(void)

{

if (y+1<bottom)?

{

y++;

pos += video_size_row;

return;

}

scrup(); // 函數(shù)還沒(méi)有退出,將屏幕內(nèi)容上移一行

}

/* 光標(biāo)上移一行,同上lf */

static void ri(void)

{

if (y>top) {

y--;

pos -= video_size_row;

return;

}

scrdown();

}

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

static void cr(void)

{

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

x=0;

}

/* 擦除光標(biāo)前一字符 */

static void del(void)

{

if (x) //如果光標(biāo)沒(méi)有處在0 列

{

pos -= 2; // 光標(biāo)對(duì)應(yīng)內(nèi)存位置指針pos 后退2 字節(jié)

x--; // 當(dāng)前光標(biāo)變量列值減1

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

}

}

/* 刪除屏幕上的相關(guān)區(qū)域 */

static void csi_J(int par)

{

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

long start __asm__("di");

switch (par)?

{

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

/* 擦除光標(biāo)到屏幕底端 */

count = (scr_end-pos)>>1;

start = pos;

break;

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

/* 刪除從屏幕開(kāi)始到光標(biāo)處的字符 */

count = (pos-origin)>>1;

start = origin;

break;

case 2: /* erase whole display */

/* 刪除整個(gè)屏幕上的字符 */

count = video_num_columns * video_num_lines;

start = origin;

break;

default:

return;

}

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

// %0 - ecx(要?jiǎng)h除的字符數(shù)count);%1 - edi(刪除操作開(kāi)始地址);

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

__asm__("cld\n\t"

"rep\n\t"

"stosw\n\t"

::"c" (count),

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

:"cx","di");

}

/* 根據(jù)par的不同,刪除與行相關(guān)的字符,并填充其他字符 */

static void csi_K(int par)

{

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

long start __asm__("di");

/* 計(jì)算count和start的值,以便在下面實(shí)現(xiàn)字符的擦除 */

switch (par)?

{

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

/* 刪除光標(biāo)到行尾字符 */

if (x>=video_num_columns)

return;

count = video_num_columns-x;

start = pos;

break;

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

/* 刪除從行開(kāi)始到光標(biāo)處 */

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

}

/* 重新設(shè)置字符顯示方式 */

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 正常顯示

}

}

/* 根據(jù)顯示內(nèi)存光標(biāo)對(duì)應(yīng)位置pos,設(shè)置顯示控制器光標(biāo)的顯示位置 */

static inline void set_cursor(void)

{

cli();

// 使用索引寄存器端口選擇顯示控制數(shù)據(jù)寄存器r14(光標(biāo)當(dāng)前顯示位置高字節(jié))

outb_p(14, video_port_reg);

// 當(dāng)前位置高字節(jié)

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

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

outb_p(15, video_port_reg);

// 光標(biāo)當(dāng)前位置低字節(jié)寫入其中

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

sti();

}

/* ,終端相應(yīng)外部命令,將響應(yīng)序列放入讀緩沖隊(duì)列中 */

/*?

?* console (tty同時(shí)對(duì)應(yīng)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); // 轉(zhuǎn)換成規(guī)范模式(放入輔助隊(duì)列中)

}

/* 在光標(biāo)處插入一空格字符 */

static void insert_char(void)

{

int i=x;

unsigned short tmp, old = video_erase_char;

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

/*

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

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

* 光標(biāo)開(kāi)始的所有字符右移一格,并將擦除字符插入在光標(biāo)所在處

*/

while (i++<video_num_columns)

{

tmp=*p;

*p=old;

old=tmp;

p++;

}

}

/* 在光標(biāo)處插入一行,并且光標(biāo)將處在新的空行上 */

static void insert_line(void)

{

int oldtop,oldbottom;

oldtop=top;

oldbottom=bottom;

top=y; // 設(shè)置屏幕卷動(dòng)開(kāi)始行

bottom = video_num_lines; // 設(shè)置屏幕卷動(dòng)最后行

scrdown();

top=oldtop;

bottom=oldbottom;

}

/* 刪除光標(biāo)處的一個(gè)字符 */

static void delete_char(void)

{

int i;

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

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

return;

i = x;

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

{

*p = *(p+1);

p++;

}

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

}

/* 刪除光標(biāo)所在行,同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;

}

/* 在光標(biāo)處插入nr 個(gè)字符 */

static void csi_at(unsigned int nr)

{

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

nr = video_num_columns; // 截為一行字符數(shù)

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

nr = 1; // nr = 1,插入1 個(gè)字符

while (nr--) // 循環(huán)插入指定的字符數(shù)

insert_char();

}

/* 在光標(biāo)位置處插入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();

}

/* 刪除光標(biāo)處的nr 個(gè)字符,調(diào)用函數(shù)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();

}

/* 刪除光標(biāo)處的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; // 保存光標(biāo)列號(hào)

static int saved_y=0; // 保存光標(biāo)行號(hào)

static void save_cur(void)

{

saved_x=x;

saved_y=y;

}

static void restore_cur(void)

{

gotoxy(saved_x, saved_y);

}

/* 從終端對(duì)應(yīng)的tty 寫緩沖隊(duì)列中取字符,并顯示在屏幕上 */

void con_write(struct tty_struct * tty)

{

int nr;

char c;

nr = CHARS(tty->write_q); // 首先取得寫緩沖隊(duì)列中現(xiàn)有字符數(shù)nr

while (nr--) // 針對(duì)每個(gè)字符進(jìn)行處理

{

// 從寫隊(duì)列中取一字符c,根據(jù)前面所處理字符的狀態(tài)state 分別處理

GETCH(tty->write_q,c);

switch(state)?

{

case 0:

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

{

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

if (x>=video_num_columns)

{

// 若當(dāng)前光標(biāo)處在行末端或末端以外,則將光標(biāo)移到下行頭列。

// 并調(diào)整光標(biāo)位置對(duì)應(yīng)的內(nèi)存指針pos

x -= video_num_columns;

pos -= video_size_row;

lf();

}

// 將字符c 寫到顯示內(nèi)存中pos 處,并將光標(biāo)右移1 列,

// 同時(shí)也將pos 對(duì)應(yīng)地移動(dòng)2 個(gè)字節(jié)。

__asm__("movb _attr,%%ah\n\t"

"movw %%ax,%1\n\t"

::"a" (c),"m" (*(short *)pos)

:"ax");

pos += 2;

x++;

}?

// // 如果字符c 是轉(zhuǎn)義字符ESC,則轉(zhuǎn)換狀態(tài)state 到1

else if (c==27)

state=1;

// 如果字符c 是換行符(10),或是垂直制表符VT(11),或者是

// 換頁(yè)符FF(12),則移動(dòng)光標(biāo)到下一行

else if (c==10 || c==11 || c==12)

lf();

// 如果字符c 是回車符CR(13),則將光標(biāo)移動(dòng)到頭列(0 列)

else if (c==13)

cr();

// 如果字符c 是DEL(127),則將光標(biāo)右邊一字符擦除(用空格

// 字符替代),并將光標(biāo)移到被擦除位置

else if (c==ERASE_CHAR(tty))

del();

// 如果字符c 是BS(backspace,8),則將光標(biāo)右移1 格,并相應(yīng)

// 調(diào)整光標(biāo)對(duì)應(yīng)內(nèi)存位置指針pos

else if (c==8)

{

if (x)?

{

x--;

pos -= 2;

}

}?

// 如果字符c 是水平制表符TAB(9),則將光標(biāo)移到8 的倍數(shù)列上

else if (c==9)

{

c=8-(x&7);

x += c;

pos += c<<1;

if (x>video_num_columns)

{

// 若此時(shí)光標(biāo)列數(shù)超出屏幕最大列數(shù),

// 則將光標(biāo)移到下一行上

x -= video_num_columns;

pos -= video_size_row;

lf();

}

c=9;

}

// 如果字符c 是響鈴符BEL(7),則調(diào)用蜂鳴函數(shù),是揚(yáng)聲器發(fā)聲

else if (c==7)

sysbeep();

break;

// 如果原狀態(tài)是0,并且字符是轉(zhuǎn)義字符ESC(0x1b = 033 = 27),則轉(zhuǎn)到狀態(tài)1 處理

case 1:

state=0;

if (c=='[') // 如果字符c 是'[',則將狀態(tài)state 轉(zhuǎn)到2

state=2;

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

gotoxy(0,y+1);

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

ri();

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

lf();

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

respond(tty);

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

save_cur();

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

restore_cur();

break;

// 如果原狀態(tài)是1,并且上一字符是'[',則轉(zhuǎn)到狀態(tài)2 來(lái)處理

case 2:

// 首先對(duì)ESC 轉(zhuǎn)義字符序列參數(shù)使用的處理數(shù)組par[]清零

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

par[npar]=0;

npar=0; // 索引變量npar 指向首項(xiàng)

state=3; // 設(shè)置狀態(tài)3

if (ques=(c=='?')) // 若此時(shí)字符不是'?',則直接轉(zhuǎn)到狀態(tài)3 去處理

break;

// 如果原來(lái)是狀態(tài)2;或者原來(lái)就是狀態(tài)3,但原字符是';'或數(shù)字,則在下面處理

case 3:

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

{ // 如果字符c 是分號(hào)';',并且數(shù)組par 未滿,則索引值加1

npar++;

break;

}?

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

{

// 如果字符c 是數(shù)字字符'0'-'9',則將該字符轉(zhuǎn)換成數(shù)值并與npar

// 所索引的項(xiàng)組成10 進(jìn)制數(shù)

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

break;

}?

else // 否則轉(zhuǎn)到狀態(tài)4

state=4;

// 如果原狀態(tài)是狀態(tài)3,并且字符不是';'或數(shù)字,則轉(zhuǎn)到狀態(tài)4 處理

case 4:

state=0; // 首先復(fù)位狀態(tài)state=0

switch(c)

{

// 如果字符c 是'G'或'`',則par[]中第一個(gè)參數(shù)代表列號(hào)。若列

// 號(hào)不為零,則將光標(biāo)右移一格

case 'G': case '`':

if (par[0]) par[0]--;

gotoxy(par[0],y);

break;

// 如果字符c 是'A',則第一個(gè)參數(shù)代表光標(biāo)上移的行數(shù)。若參數(shù)

// 為0 則上移一行

case 'A':

if (!par[0]) par[0]++;

gotoxy(x,y-par[0]);

break;

// 如果字符c 是'B'或'e',則第一個(gè)參數(shù)代表光標(biāo)下移的行數(shù)。若

// 參數(shù)為0 則下移一行

case 'B': case 'e':

if (!par[0]) par[0]++;

gotoxy(x,y+par[0]);

break;

// 如果字符c 是'C'或'a',則第一個(gè)參數(shù)代表光標(biāo)右移的格數(shù)。若

// 參數(shù)為0 則右移一格

case 'C': case 'a':

if (!par[0]) par[0]++;

gotoxy(x+par[0],y);

break;

// 如果字符c 是'D',則第一個(gè)參數(shù)代表光標(biāo)左移的格數(shù)。若參數(shù)為

// 0 則左移一格

case 'D':

if (!par[0]) par[0]++;

gotoxy(x-par[0],y);

break;

// 如果字符c 是'E',則第一個(gè)參數(shù)代表光標(biāo)向下移動(dòng)的行數(shù),并回

// 到0 列。若參數(shù)為0 則下移一行

case 'E':

if (!par[0]) par[0]++;

gotoxy(0,y+par[0]);

break;

// 如果字符c 是'F',則第一個(gè)參數(shù)代表光標(biāo)向上移動(dòng)的行數(shù),并回

// 到0 列。若參數(shù)為0 則上移一行

case 'F':

if (!par[0]) par[0]++;

gotoxy(0,y-par[0]);

break;

// 如果字符c 是'd',則第一個(gè)參數(shù)代表光標(biāo)所需在的行號(hào)(從0 計(jì)數(shù))

case 'd':

if (par[0]) par[0]--;

gotoxy(x,par[0]);

break;

// 如果字符c 是'H'或'f',則第一個(gè)參數(shù)代表光標(biāo)移到的行號(hào),第二

// 個(gè)參數(shù)代表光標(biāo)移到的列號(hào)

case 'H': case 'f':

if (par[0]) par[0]--;

if (par[1]) par[1]--;

gotoxy(par[1],par[0]);

break;

// 如果字符c 是'J',則第一個(gè)參數(shù)代表以光標(biāo)所處位置清屏的方式

case 'J':

csi_J(par[0]);

break;

// 如果字符c 是'K',則第一個(gè)參數(shù)代表以光標(biāo)所在位置對(duì)行中字符進(jìn)行

// 刪除處理的方式

case 'K':

csi_K(par[0]);

break;

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

case 'L':

csi_L(par[0]);

break;

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

case 'M':

csi_M(par[0]);

break;

// 如果字符c 是'P',表示在光標(biāo)位置處刪除n 個(gè)字符

case 'P':

csi_P(par[0]);

break;

// 如果字符c 是'@',表示在光標(biāo)位置處插入n 個(gè)字符

case '@':

csi_at(par[0]);

break;

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

case 'm':

csi_m();

break;

// 如果字符c 是'r',則表示用兩個(gè)參數(shù)設(shè)置滾屏的起始行號(hào)和終止行號(hào)

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',則表示保存當(dāng)前光標(biāo)所在位置

case 's':

save_cur();

break;

// 如果字符c 是'u',則表示恢復(fù)光標(biāo)到原保存的位置處

case 'u':

restore_cur();

break;

}

}

}

// 最后根據(jù)上面設(shè)置的光標(biāo)位置,向顯示控制器發(fā)送光標(biāo)顯示位置

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 程序保存的信息,用以確定當(dāng)前顯示器類型,并且設(shè)置所有相關(guān)參數(shù)

?*/

void con_init(void)

{

register unsigned char a;

char *display_desc = "????";

char *display_ptr;

video_num_columns = ORIG_VIDEO_COLS; // 顯示器顯示字符列數(shù)

video_size_row = video_num_columns * 2; // 每行需使用字節(jié)數(shù)

video_num_lines = ORIG_VIDEO_LINES; // 顯示器顯示字符行數(shù)

video_page = ORIG_VIDEO_PAGE; // 當(dāng)前顯示頁(yè)面

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

// 是單色顯示器?

if (ORIG_VIDEO_MODE == 7) /* Is this a monochrome display? */

{

video_mem_start = 0xb0000; // 設(shè)置單顯映象內(nèi)存起始地址

video_port_reg = 0x3b4; // 設(shè)置單顯索引寄存器端口

video_port_val = 0x3b5; // 設(shè)置單顯數(shù)據(jù)寄存器端口

/*

* 根據(jù)BIOS 中斷int 0x10 功能0x12 獲得的顯示模式信息,判斷

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

*/

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

{

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

video_mem_end = 0xb8000; // 設(shè)置顯示內(nèi)存末端地址

display_desc = "EGAm"; // 設(shè)置顯示描述字符串

}

else

{

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

video_mem_end = 0xb2000; // 設(shè)置顯示內(nèi)存末端地址

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

}

}

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

{

video_mem_start = 0xb8000; // 顯示內(nèi)存起始地址

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

video_port_val = 0x3d5; // 設(shè)置彩色顯示數(shù)據(jù)寄存器端口

// 再判斷顯示卡類別

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

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

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

while (*display_desc)

{

*display_ptr++ = *display_desc++; // 復(fù)制字符

display_ptr++; // 空開(kāi)屬性字節(jié)位置

}

/* Initialize the variables used for scrolling (mostly EGA/VGA) */

origin = video_mem_start; // 滾屏起始顯示內(nèi)存地址

scr_end = video_mem_start + video_num_lines * video_size_row; // // 滾屏結(jié)束內(nèi)存地址

top = 0; // 最頂行號(hào)

bottom = video_num_lines; // 最底行號(hào)

gotoxy(ORIG_X,ORIG_Y); // 初始化光標(biāo)位置x,y 和對(duì)應(yīng)的內(nèi)存位置pos

set_trap_gate(0x21,&keyboard_interrupt); // 設(shè)置鍵盤中斷陷阱門

outb_p(inb_p(0x21)&0xfd,0x21); // // 取消8259A 中對(duì)鍵盤中斷的屏蔽

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

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

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

}

/* from bsd-net-2: */

/* 停止蜂鳴 */

void sysbeepstop(void)

{

/* disable counter 2 */

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

}

int beepcount = 0;

/* 開(kāi)通蜂鳴 */

static void sysbeep(void)

{

/* enable counter 2 */

/* 開(kāi)啟定時(shí)器2 */

outb_p(inb_p(0x61)|3, 0x61);

/* set command for counter 2, 2 byte write */

/* 送設(shè)置定時(shí)器2 命令 */

outb_p(0xB6, 0x43);

/* send 0x637 for 750 HZ */

/* 設(shè)置頻率為750HZ,因此送定時(shí)值0x637 */

outb_p(0x37, 0x42);

outb(0x06, 0x42);

/* 1/8 second */

beepcount = HZ/8;

}

轉(zhuǎn)載于:https://www.cnblogs.com/xuqiang/archive/2010/02/01/1953774.html

總結(jié)

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

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。