【转载】从printk到framebuff

源地址: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的调用查询

posted on 2012-04-18 20:43  hydah  阅读(1233)  评论(0编辑  收藏  举报