从printk到framebuff

本文详细解析了在Linux环境下,从printk到framebuff及从tty写操作到framebuff的过程。主要介绍了如何通过printk和tty文件操作实现字符输出到屏幕,并最终调用到framebuff显示的方法。
摘要由CSDN通过智能技术生成

转自: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的调用查询


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值