转自:http://blog.sina.com.cn/s/blog_633f46290100k4yw.html
在linux内核的使用framebuff的vga显示中,有两种方式(可能不止,但笔者能力所限,仅知道两种)向屏幕输出,一种是通过printk向>屏幕输出,一种是通过向tty文件使用文件操作书写。1。从printk到vc_cons
printk --------------------------------------kernel/printk.c
printk处理完参数后调用vprintk
vprintk --------------------------------------kernel/printk.c
vprintk调用emit_log_char 将字符填充进log_buff中,并调用release_console_sem()将字符打印出
release_console_sem --------------------------kernel/printk.c
函数的本意是释放信号量,但同时调用了call_console_drivers(_con_start, _log_end)将log_buff中的字符打印出。
call_console_drivers ------------------------kernel/printk.c
调用_call_console_drivers打印字符
_call_console_drivers-------------------------kernel/printk.c
调用__call_console_drivers打印字符
__call_console_drivers------------------------kernel/printk.c
__call_console_drivers中语句如下:
436 for (con = console_drivers; con; con = con->next) {
437 if ((con->flags & CON_ENABLED) && con->write &&
438 (cpu_online(smp_processor_id()) ||
439 (con->flags & CON_ANYTIME)))
440 con->write(con, &LOG_BUF(start), end - start);
441 }
可见其以此调用的是注册的console中的write函数。
不妨以driver/char/vt.c中注册的vt_console_driver,其对应的write函数是vt_console_print
vt_console_print --------------------------driver/char/vt.c
vt_console_print 最终调用的是vc_cons[fg_console].d->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x)显示字符。
因此由printk可以追溯到vc_data结构体数组vc_cons中某个的成员vc_sw->con_putcs函数。
2。从tty到vc_cons
在写入tty设备文件时调用的操作是tty_fops(drivers/char/tty_io.c)
810 static const struct file_operations tty_fops = {
811 .llseek = no_llseek,
812 .read = tty_read,
813 .write = tty_write,
814 .poll = tty_poll,
815 .unlocked_ioctl = tty_ioctl,
816 .compat_ioctl = tty_compat_ioctl,
817 .open = tty_open,
818 .release = tty_release,
819 .fasync = tty_fasync,
820 };
在tty_open中选择tty_driver (具体请见偶以前书写的 console,tty,keyboard关系的分析)
2234 retval = init_dev(driver, index, &tty);
的语句,使得tty_driver于tty相关联。
通过一个具体的tty_driver的注册例子来表示
在drivers/char/vt.c的vty_init函数中
2965 console_driver->owner = THIS_MODULE;
2966 console_driver->name = "tty";
2967 console_driver->name_base = 1;
2968 console_driver->major = TTY_MAJOR;
2969 console_driver->minor_start = 1;
2970 console_driver->type = TTY_DRIVER_TYPE_CONSOLE;
2971 console_driver->init_termios = tty_std_termios;
2972 if (default_utf8)
2973 console_driver->init_termios.c_iflag |= IUTF8;
2974 console_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
2975 tty_set_operations(console_driver, &con_ops);
2976 if (tty_register_driver(console_driver))
2977 panic("Couldn't register console driver\n");
其中tty_set_operations(console_driver, &con_ops);是设置tty_driver使用的一系列操作,con_ops是tty_operations类型,tty_register_driver(console_driver)即是注册tty_driver
其中注册的con_ops如下所示
2939 static const struct tty_operations con_ops = {
2940 .open = con_open,
2941 .close = con_close,
2942 .write = con_write,
2943 .write_room = con_write_room,
2944 .put_char = con_put_char,
2945 .flush_chars = con_flush_chars,
2946 .chars_in_buffer = con_chars_in_buffer,
2947 .ioctl = vt_ioctl,
2948 .stop = con_stop,
2949 .start = con_start,
2950 .throttle = con_throttle,
2951 .unthrottle = con_unthrottle,
2952 .resize = vt_resize,
2953 };
因此对tty设备文件写操作使用的是con_write
con_write -----------------------------------------------driver/char/vt.c
con_write调用do_con_write
do_con_write --------------------------------------------driver/char/vt.c
do_con_write中定义的有宏
2096 #define FLUSH if (draw_x >= 0) { \
2097 vc->vc_sw->con_putcs(vc, (u16 *)draw_from, (u16 *)draw_to - (u16 *)draw_from, vc->vc_y, draw_x); \
2098 draw_x = -1; \
2099 }
2100 #endif
因此其调用的也是vc_data结构体数组vc_cons中某个的成员vc_sw->con_putcs函数。
综上可知,使用printk和对tty文件写最后均调用到vc_cons中某个的成员vc_sw->con_putcs函数。
3。从vc_cons 到framebuff
vc_cons[]是在con_init中初始化
con_init -----------------------------------------------drivers/char/vt.c
2908 for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
2909 vc_cons[currcons].d = vc = alloc_bootmem(sizeof(struct vc_data));
2910 INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
2911 visual_init(vc, currcons, 1);
2912 vc->vc_screenbuf = (unsigned short *)alloc_bootmem(vc->vc_screenbuf_size);
2913 vc->vc_kmalloced = 0;
2914 vc_init(vc, vc->vc_rows, vc->vc_cols,
2915 currcons || !vc->vc_sw->con_save_screen);
2916 }
其中visual_init 包含对vc_sw的初始化
visual_init -------------------------------------------drivers/char/vt.c
函数中有
724 vc->vc_sw = conswitchp;
可见vc_sw来自conswitchp全局变量。
bind_con_driver中有对conswitchp的赋值
bind_con_driver----------------------------------------drivers/char/vt.c
2992 static int bind_con_driver(const struct consw *csw, int first, int last,
2993 int deflt)
3029 conswitchp = csw;
故conswitchp的值与其调用者有关
bind_con_driver 被vt_bind调用
vt_bind -------------------------------------------------driver/char/vt.c
vt_bind被store_bind调用
store_bind ----------------------------------------------driver/char/vt.c
其中有
3317 struct con_driver *con = dev_get_drvdata(dev);
3320 if (bind)
3321 vt_bind(con);
故conswitchp来自dev_get_drvdata(dev)
而在vtconsole_init_device有
3359 dev_set_drvdata(con->dev, con);
因此conswitchp来自vtconsole_init_device的调用者
vtconsole_init_device虽有两处调用 但归根揭底是到register_con_driver调用
register_con_driver -----------------------------------driver/char/vt.c
其中有语句
3420 int register_con_driver(const struct consw *csw, int first, int last)
故conswitchp来自register_con_driver调用者
register_con_driver由take_over_console调用
take_over_console-------------------drivers/char/vt.c
在drivers/video/console/fbcon.c中fb_takeover调用了take_over_console
fb_takeover -------------------------------------------drivers/char/vt.c
其中语句:
581 err = take_over_console(&fb_con, first_fb_vc, last_fb_vc,
582 fbcon_is_default);
因此conswitchp来自fb_con.
fbcon 定义如下
3320 static const struct consw fb_con = { -----------------drivers/char/vt.c
3321 .owner = THIS_MODULE,
3322 .con_startup = fbcon_startup,
3323 .con_init = fbcon_init,
3324 .con_deinit = fbcon_deinit,
3325 .con_clear = fbcon_clear,
3326 .con_putc = fbcon_putc,
3327 .con_putcs = fbcon_putcs,
3328 .con_cursor = fbcon_cursor,
3329 .con_scroll = fbcon_scroll,
3330 .con_bmove = fbcon_bmove,
3331 .con_switch = fbcon_switch,
3332 .con_blank = fbcon_blank,
3333 .con_font_set = fbcon_set_font,
3334 .con_font_get = fbcon_get_font,
3335 .con_font_default = fbcon_set_def_font,
3336 .con_font_copy = fbcon_copy_font,
3337 .con_set_palette = fbcon_set_palette,
3338 .con_scrolldelta = fbcon_scrolldelta,
3339 .con_set_origin = fbcon_set_origin,
3340 .con_invert_region = fbcon_invert_region,
3341 .con_screen_pos = fbcon_screen_pos,
3342 .con_getxy = fbcon_getxy,
3343 .con_resize = fbcon_resize,
3344 };
因此vc_con[]中变量的成员变量vc_sw->con_putcs 在framebuff中对应的是fbcon_putcs
fbcon_putcs ------------------------------------------drivers/video/console/fbcon.c
代码如下:
1332 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
1333 struct display *p = &fb_display[vc->vc_num];
1334 struct fbcon_ops *ops = info->fbcon_par;
1335
1336 if (!fbcon_is_inactive(vc, info))
1337 ops->putcs(vc, info, s, count, real_y(p, ypos), xpos,
1338 get_color(vc, info, scr_readw(s), 1),
1339 get_color(vc, info, scr_readw(s), 0));
可见其具体调用的是其注册的register_fb中的putcs
由此完成了从printk到framebuff 从tty到framebuff的调用查询