Chinaunix首页 | 论坛 | 博客
  • 博客访问: 570860
  • 博文数量: 146
  • 博客积分: 5251
  • 博客等级: 大校
  • 技术积分: 1767
  • 用 户 组: 普通用户
  • 注册时间: 2006-11-10 15:58
文章分类
文章存档

2010年(12)

2008年(129)

2007年(5)

我的朋友

分类: LINUX

2008-02-01 11:55:20

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;
}
阅读(2781) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~