VGA文本显示控制台的初始化过程

VGA文本显示控制台的初始化过程
=============================

1) 终端设备是UNIX中一个非常重要的对象, 内容十分丰富, 它是UNIX人机接口的基础,
它对于UNIX的意义不亚于文件系统对于操作系统的意义,
了解终端设备的工作细节对改善人机接口有很大的帮助.
今后这段时间我准备从VGA文本显示控制台开始, 分析终端驱动, 帧缓冲显示台,
键盘驱动等代码.

2) 应用程序通过终端接口设备使用特定的接口规程与终端进行交互,
与操作系统内核本身交互的终端称为控制台, 它可以是内核本身的内部显示终端,
也可以是通过串口连接的外部哑终端. 由于大多数情况下控制台都是内核显示终端,
因此内核显示终端也常常直接称为控制台. 内核终端对用户来说具有若干个虚拟终端子设备,
它们共享同一物理终端, 但同一时刻只能有一个虚拟终端操作硬件屏幕.

3) 内核终端的主设备号为4(TTY_MAJOR), 1至63号子设备表示不同的虚拟终端,
0号子设备代表当前活动的虚拟终端. 内核终端的物理显示设备接口用consw结构描述,
在配置了VGA文本控制台时(CONFIG_VGA_CONSOLE),
系统的缺省显示设备指针conswitchp指向vga_con设备.

; init/main.c:

asmlinkage void __init start_kernel(void)

{

char * command_line;

unsigned long mempages;

extern char saved_command_line[];

/*

* Interrupts are still disabled. Do necessary setups, then

* enable them

*/

lock_kernel();

printk(linux_banner);

setup_arch(&command_line);

printk("Kernel command line: %s\n", saved_command_line);

parse_options(command_line);

trap_init();

init_IRQ();

sched_init();

time_init();

softirq_init();

/*

* HACK ALERT! This is early. We're enabling the console before

* we've done PCI setups etc, and console_init() must be aware of

* this. But we do want output early, in case something goes wrong.

*/

console_init(); 初始化内核显示终端

#ifdef CONFIG_MODULES

init_modules();

#endif

}

; arch/i386/kernel/setup.c:

void __init setup_arch(char **cmdline_p)

{

#ifdef CONFIG_VT

#if defined(CONFIG_VGA_CONSOLE)

conswitchp = &vga_con; 设置缺省的显示设备接口

#elif defined(CONFIG_DUMMY_CONSOLE)

conswitchp = &dummy_con;

#endif

#endif

}

; drivers/char/tty_io.c:

struct termios tty_std_termios; /* for the benefit of tty drivers */

/*

* Initialize the console device. This is called *early*, so

* we can't necessarily depend on lots of kernel help here.

* Just do some early initializations, and do the complex setup

* later.

*/

void __init console_init(void)

{

/* Setup the default TTY line discipline. */

memset(ldiscs, 0, sizeof(ldiscs));

(void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY); 注册终端规程

/*

* Set up the standard termios. Individual tty drivers may

* deviate from this; this is used as a template.

*/

memset(&tty_std_termios, 0, sizeof(struct termios)); 建立标准终端参数结构

memcpy(tty_std_termios.c_cc, INIT_C_CC, NCCS);

tty_std_termios.c_iflag = ICRNL | IXON;

tty_std_termios.c_oflag = OPOST | ONLCR;

tty_std_termios.c_cflag = B38400 | CS8 | CREAD | HUPCL;

tty_std_termios.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |

ECHOCTL | ECHOKE | IEXTEN;

/*

* set up the console device so that later boot sequences can

* inform about problems etc..

*/

#ifdef CONFIG_VT

con_init(); 初始化内核虚拟终端

#endif

}

; drivers/char/console.c:

struct vc_data { 虚拟控制台的参数结构

unsigned short vc_num; /* Console number */

unsigned int vc_cols; /* [#] Console size */

unsigned int vc_rows;

unsigned int vc_size_row; /* Bytes per row */

const struct consw *vc_sw;

unsigned short *vc_screenbuf; /* In-memory character/attribute buffer */

unsigned int vc_screenbuf_size;

unsigned char vc_attr; /* Current attributes */

unsigned char vc_def_color; /* Default colors */

unsigned char vc_color; /* Foreground & background */

unsigned char vc_s_color; /* Saved foreground & background */

unsigned char vc_ulcolor; /* Color for underline mode */

unsigned char vc_halfcolor; /* Color for half intensity mode */

unsigned short vc_complement_mask; /* [#] Xor mask for mouse pointer */

unsigned short vc_hi_font_mask; /* [#] Attribute set for upper 256 chars of font or 0
if not supported */

unsigned short vc_video_erase_char; /* Background erase character */

unsigned short vc_s_complement_mask; /* Saved mouse pointer mask */

unsigned int vc_x, vc_y; /* Cursor position */

unsigned int vc_top, vc_bottom; /* Scrolling region */

unsigned int vc_state; /* Escape sequence parser state */

unsigned int vc_npar,vc_par[NPAR]; /* Parameters of current escape sequence */

unsigned long vc_origin; /* [!] Start of real screen */

unsigned long vc_scr_end; /* [!] End of real screen */

unsigned long vc_visible_origin; /* [!] Top of visible window */

unsigned long vc_pos; /* Cursor address */

unsigned int vc_saved_x;

unsigned int vc_saved_y;

/* mode flags */

unsigned int vc_charset : 1; /* Character set G0 / G1 */

unsigned int vc_s_charset : 1; /* Saved character set */

unsigned int vc_disp_ctrl : 1; /* Display chars < 32? */

unsigned int vc_toggle_meta : 1; /* Toggle high bit? */

unsigned int vc_decscnm : 1; /* Screen Mode */

unsigned int vc_decom : 1; /* Origin Mode */

unsigned int vc_decawm : 1; /* Autowrap Mode */

unsigned int vc_deccm : 1; /* Cursor Visible */

unsigned int vc_decim : 1; /* Insert Mode */

unsigned int vc_deccolm : 1; /* 80/132 Column Mode */

/* attribute flags */

unsigned int vc_intensity : 2; /* 0=half-bright, 1=normal, 2=bold */

unsigned int vc_underline : 1;

unsigned int vc_blink : 1;

unsigned int vc_reverse : 1;

unsigned int vc_s_intensity : 2; /* saved rendition */

unsigned int vc_s_underline : 1;

unsigned int vc_s_blink : 1;

unsigned int vc_s_reverse : 1;

/* misc */

unsigned int vc_ques : 1;

unsigned int vc_need_wrap : 1;

unsigned int vc_can_do_color : 1;

unsigned int vc_report_mouse : 2;

unsigned int vc_kmalloced : 1;

unsigned char vc_utf : 1; /* Unicode UTF-8 encoding */

unsigned char vc_utf_count;

int vc_utf_char;

unsigned int vc_tab_stop[5]; /* Tab stops. 160 columns. */

unsigned char vc_palette[16*3]; /* Colour palette for VGA+ */

unsigned short * vc_translate;

unsigned char vc_G0_charset;

unsigned char vc_G1_charset;

unsigned char vc_saved_G0;

unsigned char vc_saved_G1;

unsigned int vc_bell_pitch; /* Console bell pitch */

unsigned int vc_bell_duration; /* Console bell duration */

unsigned int vc_cursor_type;

struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this
display */

unsigned long vc_uni_pagedir;

unsigned long *vc_uni_pagedir_loc; /* [!] Location of uni_pagedir variable for this
console */

/* additional information is in vt_kern.h */

};

struct vc {

struct vc_data *d;

/* might add scrmem, vt_struct, kbd at some time,

to have everything in one place - the disadvantage

would be that vc_cons etc can no longer be static */

};

#define cons_num (vc_cons[currcons].d->vc_num)

#define sw (vc_cons[currcons].d->vc_sw)

#define screenbuf (vc_cons[currcons].d->vc_screenbuf)

#define screenbuf_size (vc_cons[currcons].d->vc_screenbuf_size)

#define origin (vc_cons[currcons].d->vc_origin)

#define scr_top (vc_cons[currcons].d->vc_scr_top)

#define visible_origin (vc_cons[currcons].d->vc_visible_origin)

#define scr_end (vc_cons[currcons].d->vc_scr_end)

#define pos (vc_cons[currcons].d->vc_pos)

#define top (vc_cons[currcons].d->vc_top)

#define bottom (vc_cons[currcons].d->vc_bottom)

#define x (vc_cons[currcons].d->vc_x)

#define y (vc_cons[currcons].d->vc_y)

#define vc_state (vc_cons[currcons].d->vc_state)

#define npar (vc_cons[currcons].d->vc_npar)

#define par (vc_cons[currcons].d->vc_par)

#define ques (vc_cons[currcons].d->vc_ques)

#define attr (vc_cons[currcons].d->vc_attr)

#define saved_x (vc_cons[currcons].d->vc_saved_x)

#define saved_y (vc_cons[currcons].d->vc_saved_y)

#define translate (vc_cons[currcons].d->vc_translate)

#define G0_charset (vc_cons[currcons].d->vc_G0_charset)

#define G1_charset (vc_cons[currcons].d->vc_G1_charset)

#define saved_G0 (vc_cons[currcons].d->vc_saved_G0)

#define saved_G1 (vc_cons[currcons].d->vc_saved_G1)

#define utf (vc_cons[currcons].d->vc_utf)

#define utf_count (vc_cons[currcons].d->vc_utf_count)

#define utf_char (vc_cons[currcons].d->vc_utf_char)

#define video_erase_char (vc_cons[currcons].d->vc_video_erase_char)

#define disp_ctrl (vc_cons[currcons].d->vc_disp_ctrl)

#define toggle_meta (vc_cons[currcons].d->vc_toggle_meta)

#define decscnm (vc_cons[currcons].d->vc_decscnm)

#define decom (vc_cons[currcons].d->vc_decom)

#define decawm (vc_cons[currcons].d->vc_decawm)

#define deccm (vc_cons[currcons].d->vc_deccm)

#define decim (vc_cons[currcons].d->vc_decim)

#define deccolm (vc_cons[currcons].d->vc_deccolm)

#define need_wrap (vc_cons[currcons].d->vc_need_wrap)

#define kmalloced (vc_cons[currcons].d->vc_kmalloced)

#define report_mouse (vc_cons[currcons].d->vc_report_mouse)

#define color (vc_cons[currcons].d->vc_color)

#define s_color (vc_cons[currcons].d->vc_s_color)

#define def_color (vc_cons[currcons].d->vc_def_color)

#define foreground (color & 0x0f)

#define background (color & 0xf0)

#define charset (vc_cons[currcons].d->vc_charset)

#define s_charset (vc_cons[currcons].d->vc_s_charset)

#define intensity (vc_cons[currcons].d->vc_intensity)

#define underline (vc_cons[currcons].d->vc_underline)

#define blink (vc_cons[currcons].d->vc_blink)

#define reverse (vc_cons[currcons].d->vc_reverse)

#define s_intensity (vc_cons[currcons].d->vc_s_intensity)

#define s_underline (vc_cons[currcons].d->vc_s_underline)

#define s_blink (vc_cons[currcons].d->vc_s_blink)

#define s_reverse (vc_cons[currcons].d->vc_s_reverse)

#define ulcolor (vc_cons[currcons].d->vc_ulcolor)

#define halfcolor (vc_cons[currcons].d->vc_halfcolor)

#define tab_stop (vc_cons[currcons].d->vc_tab_stop)

#define palette (vc_cons[currcons].d->vc_palette)

#define bell_pitch (vc_cons[currcons].d->vc_bell_pitch)

#define bell_duration (vc_cons[currcons].d->vc_bell_duration)

#define cursor_type (vc_cons[currcons].d->vc_cursor_type)

#define display_fg (vc_cons[currcons].d->vc_display_fg)

#define complement_mask (vc_cons[currcons].d->vc_complement_mask)

#define s_complement_mask (vc_cons[currcons].d->vc_s_complement_mask)

#define hi_font_mask (vc_cons[currcons].d->vc_hi_font_mask)

#define vcmode (vt_cons[currcons]->vc_mode)

#define structsize (sizeof(struct vc_data) + sizeof(struct vt_struct))

#define update_screen(x) redraw_screen(x, 0)

extern struct vt_struct { 虚拟终端的键盘参数结构

int vc_num; /* The console number */

unsigned char vc_mode; /* KD_TEXT, … */

struct vt_mode vt_mode;

int vt_pid;

int vt_newvt;

wait_queue_head_t paste_wait;

} *vt_cons[MAX_NR_CONSOLES];

const struct consw *conswitchp;

static struct tty_struct *console_table[MAX_NR_CONSOLES]; 虚拟终端表

static struct termios *console_termios[MAX_NR_CONSOLES]; 虚拟终端接口参数表

static struct termios *console_termios_locked[MAX_NR_CONSOLES];

struct vc vc_cons [MAX_NR_CONSOLES]; 虚拟终端参数表

/*

* For each existing display, we have a pointer to console currently visible

* on that display, allowing consoles other than fg_console to be refreshed

* appropriately. Unless the low-level driver supplies its own display_fg

* variable, we use this one for the "master display".

*/

static struct vc_data *master_display_fg;

static int printable; /* Is console ready for printing? */

/*

* fg_console is the current virtual console,

* last_console is the last used one,

* want_console is the console we want to switch to,

* kmsg_redirect is the console for kernel messages,

*/

int fg_console;

int last_console;

int want_console = -1;

int kmsg_redirect;

/*

* This routine initializes console interrupts, and does nothing

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

* the appropriate escape-sequence.

*/

struct tty_driver console_driver; 内核终端驱动结构

static int console_refcount;

DECLARE_TASKLET_DISABLED(console_tasklet, console_softint, 0); 内核终端软中断

/* the default colour table, for VGA+ colour systems */

int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa,

0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff};

int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,

0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff};

int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,

0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};

void __init con_init(void)

{

const char *display_desc = NULL;

unsigned int currcons = 0;

if (conswitchp)

display_desc = conswitchp->con_startup(); 启动内核终端的物理显示设备

if (!display_desc) {

fg_console = 0;

return;

}

memset(&console_driver, 0, sizeof(struct tty_driver));

console_driver.magic = TTY_DRIVER_MAGIC;

console_driver.name = "vc/%d";

console_driver.name_base = 1;

console_driver.major = TTY_MAJOR; 主设备号

console_driver.minor_start = 1; 子设备起始编号

console_driver.num = MAX_NR_CONSOLES; 虚拟终端数目

console_driver.type = TTY_DRIVER_TYPE_CONSOLE; 虚拟终端为控制台类型

console_driver.init_termios = tty_std_termios; 标准终端参数块

console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;

/* Tell tty_register_driver() to skip consoles because they are

* registered before kmalloc() is ready. We'll patch them in later.

* See comments at console_init(); see also con_init_devfs().

*/

console_driver.flags |= TTY_DRIVER_NO_DEVFS;

console_driver.refcount = &console_refcount;

console_driver.table = console_table; 终端驱动程序的虚拟终端表

console_driver.termios = console_termios; 终端驱动程序的虚拟终端参数表

console_driver.termios_locked = console_termios_locked;

console_driver.open = con_open; 打开虚拟终端

console_driver.close = con_close; 关闭

console_driver.write = con_write; 写数据块

console_driver.write_room = con_write_room; 取缓冲区尺寸

console_driver.put_char = con_put_char; 写字符

console_driver.flush_chars = con_flush_chars; 冲刷缓冲区

console_driver.chars_in_buffer = con_chars_in_buffer; 取缓冲区内的字符数

console_driver.ioctl = vt_ioctl; 设备控制

console_driver.stop = con_stop; 暂停

console_driver.start = con_start; 启动

console_driver.throttle = con_throttle; 流量控制

console_driver.unthrottle = con_unthrottle;

if (tty_register_driver(&console_driver)) 注册内核终端驱动设备

panic("Couldn't register console driver\n");

init_timer(&console_timer);

console_timer.function = blank_screen; 内核终端屏幕保护定时器

if (blankinterval) {

mod_timer(&console_timer, jiffies + blankinterval);

}

/*

* kmalloc is not running yet - we use the bootmem allocator.

*/

for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
建立初始化时的1个虚拟终端

vc_cons[currcons].d = (struct vc_data *)

alloc_bootmem(sizeof(struct vc_data));

vt_cons[currcons] = (struct vt_struct *)

alloc_bootmem(sizeof(struct vt_struct));

visual_init(currcons, 1); 显示设备初始化

screenbuf = (unsigned short *) alloc_bootmem(screenbuf_size); 分配显示缓冲区

kmalloced = 0;

vc_init(currcons, video_num_lines, video_num_columns,

currcons || !sw->con_save_screen); 终端初始化

}

currcons = fg_console = 0;

master_display_fg = vc_cons[currcons].d; master_display用以识别当前的前景控制台

set_origin(currcons); 设置终端的起始显示点

save_screen(currcons); 保存硬件屏幕到终端屏幕缓冲区

gotoxy(currcons,x,y); 定位光标

csi_J(currcons, 0); 清除光标到屏幕尾部的字符

update_screen(fg_console); 使用终端屏幕缓冲区重新绘制屏幕

printk("Console: %s %s %dx%d",

can_do_color ? "colour" : "mono",

display_desc, video_num_columns, video_num_lines);

printable = 1;

printk("\n");

#ifdef CONFIG_VT_CONSOLE

register_console(&vt_console_driver); 将内核终端注册为内核控制台

#endif

tasklet_enable(&console_tasklet); 允许控制台软中断

tasklet_schedule(&console_tasklet); 激发控制台软中断

}

/*

* This is the console switching tasklet.

*

* Doing console switching in a tasklet allows

* us to do the switches asynchronously (needed when we want

* to switch due to a keyboard interrupt). Synchronization

* with other console code and prevention of re-entrancy is

* ensured with console_lock.

*/

static void console_softint(unsigned long ignored)

{

/* Runs the task queue outside of the console lock. These

* callbacks can come back into the console code and thus

* will perform their own locking.

*/

run_task_queue(&con_task_queue); 运行键盘中断产生的任务队列

spin_lock_irq(&console_lock);

if (want_console >= 0) { 如果切换控制台

if (want_console != fg_console && vc_cons_allocated(want_console)) {

hide_cursor(fg_console);

change_console(want_console); 切换虚拟终端

/* we only changed when the console had already

been allocated - a new console is not created

in an interrupt routine */

}

want_console = -1;

}

if (do_poke_blanked_console) { /* do not unblank for a LED change */

do_poke_blanked_console = 0;

poke_blanked_console(); 取消屏幕保护状态

}

if (scrollback_delta) { 如果屏幕回卷

int currcons = fg_console;

clear_selection(); 清楚鼠标选择状态

if (vcmode == KD_TEXT)

sw->con_scrolldelta(vc_cons[currcons].d, scrollback_delta);

scrollback_delta = 0;

}

spin_unlock_irq(&console_lock);

}

static void visual_init(int currcons, int init)

{

/* ++Geert: sw->con_init determines console size */

sw = conswitchp;

#ifndef VT_SINGLE_DRIVER

if (con_driver_map[currcons])

sw = con_driver_map[currcons];

#endif

cons_num = currcons;

display_fg = &master_display_fg;

vc_cons[currcons].d->vc_uni_pagedir_loc = &vc_cons[currcons].d->vc_uni_pagedir;

vc_cons[currcons].d->vc_uni_pagedir = 0;

hi_font_mask = 0;

complement_mask = 0;

can_do_color = 0;

sw->con_init(vc_cons[currcons].d, init); 建立该虚拟终端的显示参数

if (!complement_mask)

complement_mask = can_do_color ? 0x7700 : 0x0800;

s_complement_mask = complement_mask;

video_size_row = video_num_columns«1; 计算每行字节数

screenbuf_size = video_num_lines*video_size_row; 计算虚拟屏幕缓冲区尺寸

}

static void vc_init(unsigned int currcons, unsigned int rows, unsigned int cols, int
do_clear)

{

int j, k ;

video_num_columns = cols;

video_num_lines = rows;

video_size_row = cols«1;

screenbuf_size = video_num_lines * video_size_row;

set_origin(currcons); 设置起始显示位置

pos = origin;

reset_vc(currcons); 复位终端

for (j=k=0; j<16; j++) { 建立16种字符色彩的颜色表

vc_cons[currcons].d->vc_palette[k++] = default_red[j] ;

vc_cons[currcons].d->vc_palette[k++] = default_grn[j] ;

vc_cons[currcons].d->vc_palette[k++] = default_blu[j] ;

}

def_color = 0x07; /* white */ 缺省字符颜色

ulcolor = 0x0f; /* bold white */ 下划线字符颜色

halfcolor = 0x08; /* grey */ 灰色字符

init_waitqueue_head(&vt_cons[currcons]->paste_wait);

reset_terminal(currcons, do_clear);

}

static void reset_terminal(int currcons, int do_clear)

{

top = 0; 设置屏幕顶部坐标

bottom = video_num_lines; 设置屏幕底部坐标

vc_state = ESnormal; 字符转义状态

ques = 0;

translate = set_translate(LAT1_MAP,currcons); 设置字符映射表类型

G0_charset = LAT1_MAP; 设置缺省的G0字符集

G1_charset = GRAF_MAP; 设置缺省的G1字符集

charset = 0; 设置缺省显示字符集

need_wrap = 0; 清除换行标志

report_mouse = 0; 清除鼠标汇报标志

utf = 0; 清除UNICODE状态

utf_count = 0; 清除UNICODE码长

disp_ctrl = 0; 是否显示控制码

toggle_meta = 0; 字符的最高位是否置位

decscnm = 0; 屏幕显示模式

decom = 0; 屏幕原点模式

decawm = 1; 自动换行模式

deccm = 1; 光标可见模式

decim = 0; 清除插入模式

set_kbd(decarm); 设置键盘为DEC自动重发模式(VC_REPEAT)

clr_kbd(decckm); 设置键盘为DEC光标键编码模式(VC_CKMODE)

clr_kbd(kbdapplic); 设置数字小键盘为光标模式

clr_kbd(lnm); 设置键盘为回车换行模式

kbd_table[currcons].lockstate = 0; 清除修饰键状态

kbd_table[currcons].slockstate = 0; 清除锁定滚动状态

kbd_table[currcons].ledmode = LED_SHOW_FLAGS; 设置键盘灯显示模式

kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate;
设置键盘灯的缺省状态

set_leds(); 设置键盘灯

cursor_type = CUR_DEFAULT; 设置缺省的光标形状为下横线

complement_mask = s_complement_mask; 设置鼠标字符的补码掩模

default_attr(currcons); 设置缺省显示属性

update_attr(currcons); 刷新属性字

tab_stop[0] = 0x01010100; 设置160列的制表站

tab_stop[1] =

tab_stop[2] =

tab_stop[3] =

tab_stop[4] = 0x01010101;

bell_pitch = DEFAULT_BELL_PITCH; 字符响铃频率(750赫兹)

bell_duration = DEFAULT_BELL_DURATION; 字符响铃时间(125毫秒)

gotoxy(currcons,0,0); 定位光标到屏幕原点

save_cur(currcons); 保存显示属性

if (do_clear)

csi_J(currcons,2); 清除全屏幕

}

static void save_cur(int currcons)

{

saved_x = x;

saved_y = y;

s_intensity = intensity;

s_underline = underline;

s_blink = blink;

s_reverse = reverse;

s_charset = charset;

s_color = color;

saved_G0 = G0_charset;

saved_G1 = G1_charset;

}

static void default_attr(int currcons) 缺省的显示属性

{

intensity = 1; 亮度

underline = 0; 下划线

reverse = 0; 反视频

blink = 0; 显烁

color = def_color; 颜色

}

static void update_attr(int currcons)

{

attr = build_attr(currcons, color, intensity, blink, underline, reverse ^ decscnm);

video_erase_char = (build_attr(currcons, color, 1, blink, 0, decscnm) « 8) | ' ';
构造空白字符属性字

}

/* Structure of attributes is hardware-dependent */

static u8 build_attr(int currcons, u8 _color, u8 _intensity, u8 _blink, u8 _underline,
u8 _reverse)

{ 根据显示属性构造属性字

if (sw->con_build_attr)

return sw->con_build_attr(vc_cons[currcons].d, _color, _intensity, _blink,
_underline, _reverse);

#ifndef VT_BUF_VRAM_ONLY

/*

* ++roman: I completely changed the attribute format for monochrome

* mode (!can_do_color). The formerly used MDA (monochrome display

* adapter) format didn't allow the combination of certain effects.

* Now the attribute is just a bit vector:

* Bit 0..1: intensity (0..2)

* Bit 2 : underline

* Bit 3 : reverse

* Bit 7 : blink

*/

{

u8 a = color;

if (!can_do_color)

return _intensity |

(_underline ? 4 : 0) |

(_reverse ? 8 : 0) |

(_blink ? 0x80 : 0);

if (_underline)

a = (a & 0xf0) | ulcolor;

else if (_intensity == 0)

a = (a & 0xf0) | halfcolor;

if (_reverse)

a = ((a) & 0x88) | ((((a) » 4) | ((a) « 4)) & 0x77);

if (_blink)

a ^= 0x80;

if (_intensity == 2)

a ^= 0x08;

if (hi_font_mask == 0x100)

a «= 1;

return a;

}

#else

return 0;

#endif

}

static inline void save_screen(int currcons)

{

if (sw->con_save_screen)

sw->con_save_screen(vc_cons[currcons].d);

}

static void set_origin(int currcons)

{

if (!IS_VISIBLE || 如果是不是当前控制台

!sw->con_set_origin ||

!sw->con_set_origin(vc_cons[currcons].d))

origin = (unsigned long) screenbuf; 取终端缓冲区作为显示原点

visible_origin = origin; 设置显示原点

scr_end = origin + screenbuf_size; 计算屏幕缓冲区终点

pos = origin + video_size_row*y + 2*x; 计算当前字符指针

}

/*

* gotoxy() must verify all boundaries, because the arguments

* might also be negative. If the given position is out of

* bounds, the cursor is placed at the nearest margin.

*/

static void gotoxy(int currcons, int new_x, int new_y)

{

int min_y, max_y;

if (new_x < 0)

x = 0;

else

if (new_x >= video_num_columns)

x = video_num_columns - 1;

else

x = new_x;

if (decom) {

min_y = top;

max_y = bottom;

} else {

min_y = 0;

max_y = video_num_lines;

}

if (new_y < min_y)

y = min_y;

else if (new_y >= max_y)

y = max_y - 1;

else

y = new_y;

pos = origin + y*video_size_row + (x«1);

need_wrap = 0;

}

; drivers/video/vgacon.c:

/*

* The console ‘switch’ structure for the VGA based console

*/

#define DUMMY (void *) vgacon_dummy

const struct consw vga_con = { VGA显示设接驱动接口

con_startup: vgacon_startup, 启动设备

con_init: vgacon_init, 初始化设置

con_deinit: vgacon_deinit, 反初始化

con_clear: DUMMY,

con_putc: DUMMY,

con_putcs: DUMMY,

con_cursor: vgacon_cursor, 设置光标

con_scroll: vgacon_scroll, 滚动屏幕

con_bmove: DUMMY,

con_switch: vgacon_switch, 切换屏幕

con_blank: vgacon_blank, 屏幕黑屏

con_font_op: vgacon_font_op, 设置字模

con_set_palette: vgacon_set_palette, 设置颜色表

con_scrolldelta: vgacon_scrolldelta, 屏幕回卷

con_set_origin: vgacon_set_origin, 设置显示缓冲区起点

con_save_screen: vgacon_save_screen, 保存硬件屏幕

con_build_attr: vgacon_build_attr, 构造属性字

con_invert_region: vgacon_invert_region, 反视频显示区域

};

static const char __init *vgacon_startup(void)

{

const char *display_desc = NULL;

u16 saved1, saved2;

volatile u16 *p;

if (ORIG_VIDEO_ISVGA == VIDEO_TYPE_VLFB) {

no_vga:

#ifdef CONFIG_DUMMY_CONSOLE

conswitchp = &dummy_con;

return conswitchp->con_startup();

#else

return NULL;

#endif

}

vga_video_num_lines = ORIG_VIDEO_LINES;

vga_video_num_columns = ORIG_VIDEO_COLS;

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

{

vga_vram_base = 0xb0000;

vga_video_port_reg = 0x3b4;

vga_video_port_val = 0x3b5;

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

{

static struct resource ega_console_resource = { "ega", 0x3B0, 0x3BF };

vga_video_type = VIDEO_TYPE_EGAM;

vga_vram_end = 0xb8000;

display_desc = "EGA+";

request_resource(&ioport_resource, &ega_console_resource);

}

else

{

static struct resource mda1_console_resource = { "mda", 0x3B0, 0x3BB };

static struct resource mda2_console_resource = { "mda", 0x3BF, 0x3BF };

vga_video_type = VIDEO_TYPE_MDA;

vga_vram_end = 0xb2000;

display_desc = "*MDA";

request_resource(&ioport_resource, &mda1_console_resource);

request_resource(&ioport_resource, &mda2_console_resource);

vga_video_font_height = 14;

}

}

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

{

vga_can_do_color = 1;

vga_vram_base = 0xb8000;

vga_video_port_reg = 0x3d4;

vga_video_port_val = 0x3d5;

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

{

int i;

vga_vram_end = 0xc0000;

if (!ORIG_VIDEO_ISVGA) {

static struct resource ega_console_resource = { "ega", 0x3C0, 0x3DF };

vga_video_type = VIDEO_TYPE_EGAC;

display_desc = "EGA";

request_resource(&ioport_resource, &ega_console_resource);

} else {

static struct resource vga_console_resource = { "vga+", 0x3C0, 0x3DF };

vga_video_type = VIDEO_TYPE_VGAC;

display_desc = "VGA+";

request_resource(&ioport_resource, &vga_console_resource);

#ifdef VGA_CAN_DO_64KB

/*

* get 64K rather than 32K of video RAM.

* This doesn't actually work on all "VGA"

* controllers (it seems like setting MM=01

* and COE=1 isn't necessarily a good idea)

*/

vga_vram_base = 0xa0000;

vga_vram_end = 0xb0000;

outb_p (6, 0x3ce) ;

outb_p (6, 0x3cf) ;

#endif

/*

* Normalise the palette registers, to point

* the 16 screen colours to the first 16

* DAC entries.

*/

for (i=0; i<16; i++) {

inb_p (0x3da) ;

outb_p (i, 0x3c0) ;

outb_p (i, 0x3c0) ;

}

outb_p (0x20, 0x3c0) ;

/* now set the DAC registers back to their

* default values */

for (i=0; i<16; i++) {

outb_p (color_table[ i ], 0x3c8) ;

outb_p (default_red[ i ], 0x3c9) ;

outb_p (default_grn[ i ], 0x3c9) ;

outb_p (default_blu[ i ], 0x3c9) ;

}

}

}

else

{

static struct resource cga_console_resource = { "cga", 0x3D4, 0x3D5 };

vga_video_type = VIDEO_TYPE_CGA;

vga_vram_end = 0xba000;

display_desc = "*CGA";

request_resource(&ioport_resource, &cga_console_resource);

vga_video_font_height = 8;

}

}

vga_vram_base = VGA_MAP_MEM(vga_vram_base);

vga_vram_end = VGA_MAP_MEM(vga_vram_end);

/*

* Find out if there is a graphics card present.

* Are there smarter methods around?

*/

p = (volatile u16 *)vga_vram_base;

saved1 = scr_readw(p);

saved2 = scr_readw(p + 1);

scr_writew(0xAA55, p);

scr_writew(0x55AA, p + 1);

if (scr_readw(p) != 0xAA55 || scr_readw(p + 1) != 0x55AA) {

scr_writew(saved1, p);

scr_writew(saved2, p + 1);

goto no_vga;

}

scr_writew(0x55AA, p);

scr_writew(0xAA55, p + 1);

if (scr_readw(p) != 0x55AA || scr_readw(p + 1) != 0xAA55) {

scr_writew(saved1, p);

scr_writew(saved2, p + 1);

goto no_vga;

}

scr_writew(saved1, p);

scr_writew(saved2, p + 1);

if (vga_video_type == VIDEO_TYPE_EGAC

|| vga_video_type == VIDEO_TYPE_VGAC

|| vga_video_type == VIDEO_TYPE_EGAM) {

vga_hardscroll_enabled = vga_hardscroll_user_enable;

vga_default_font_height = ORIG_VIDEO_POINTS;

vga_video_font_height = ORIG_VIDEO_POINTS;

/* This may be suboptimal but is a safe bet - go with it */

video_scan_lines =

vga_video_font_height * vga_video_num_lines; 文本模式扫描线数目

}

video_font_height = vga_video_font_height;

return display_desc;

}

static void vgacon_init(struct vc_data *c, int init)

{

unsigned long p;

/* We cannot be loaded as a module, therefore init is always 1 */

c->vc_can_do_color = vga_can_do_color;

c->vc_cols = vga_video_num_columns;

c->vc_rows = vga_video_num_lines;

c->vc_complement_mask = 0x7700;

p = *c->vc_uni_pagedir_loc;

if (c->vc_uni_pagedir_loc == &c->vc_uni_pagedir ||

!—c->vc_uni_pagedir_loc[1])

con_free_unimap(c->vc_num);

c->vc_uni_pagedir_loc = vgacon_uni_pagedir;

vgacon_uni_pagedir[1]++;

if (!vgacon_uni_pagedir[0] && p)

con_set_default_unimap(c->vc_num);

}

static void vgacon_deinit(struct vc_data *c)

{

/* When closing the last console, reset video origin */

if (!—vgacon_uni_pagedir[1]) {

c->vc_visible_origin = vga_vram_base;

vga_set_mem_top(c);

con_free_unimap(c->vc_num);

}

c->vc_uni_pagedir_loc = &c->vc_uni_pagedir;

con_set_default_unimap(c->vc_num);

}

static int vgacon_set_origin(struct vc_data *c)

{

if (vga_is_gfx || /* We don't play origin tricks in graphic modes */

(console_blanked && !vga_palette_blanked)) /* Nor we write to blanked screens */

return 0;

c->vc_origin = c->vc_visible_origin = vga_vram_base;

vga_set_mem_top(c);

vga_rolled_over = 0;

return 1;

}

static int vgacon_dummy(struct vc_data *c)

{

return 0;

}

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License