【转载】从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的调用查询