tty0 显示的过程

我们知道在调用prink输出的时候最终都会调用到call_console_drivers
static void call_console_drivers(int level,
                 const char *ext_text, size_t ext_len,
                 const char *text, size_t len)
{
    struct console *con;

    trace_console_rcuidle(text, len);

    if (!console_drivers)
        return;

    for_each_console(con) {
        if (exclusive_console && con != exclusive_console)
            continue;
        if (!(con->flags & CON_ENABLED))
            continue;
        if (!con->write)
            continue;
        if (!cpu_online(smp_processor_id()) &&
            !(con->flags & CON_ANYTIME))
            continue;
        if (con->flags & CON_EXTENDED)
            con->write(con, ext_text, ext_len);
        else
            con->write(con, text, len);
    }
}
而call_console_drivers 又会调用个个注册driver的write函数。
con_init 函数中下面的这段code中的visual_init会调用tty0往下模块的    vc->vc_sw->con_init(vc, init);函数

    for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
        vc_cons[currcons].d = vc = kzalloc(sizeof(struct vc_data), GFP_NOWAIT);
        INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
        tty_port_init(&vc->port);
        visual_init(vc, currcons, 1);
        vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT);
        vc_init(vc, vc->vc_rows, vc->vc_cols,
            currcons || !vc->vc_sw->con_save_screen);
    }
从visual_init 中我们知道vc->vc_sw = conswitchp;所以也就是调用conswitchp的con_init
而在setup_arch 中
#ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE)
    conswitchp = &vga_con;
#elif defined(CONFIG_DUMMY_CONSOLE)
    conswitchp = &dummy_con;
#endif
#endif
我们的系统定义了CONFIG_VT和CONFIG_DUMMY_CONSOLE,因此conswitchp = &dummy_con;
而在drivers/video/console/dummycon.c 中
const struct consw dummy_con = {
    .owner =        THIS_MODULE,
    .con_startup =    dummycon_startup,
    .con_init =        dummycon_init,
    .con_deinit =    DUMMY,
    .con_clear =    DUMMY,
    .con_putc =        DUMMY,
    .con_putcs =    DUMMY,
    .con_cursor =    DUMMY,
    .con_scroll =    DUMMY,
    .con_switch =    DUMMY,
    .con_blank =    DUMMY,
    .con_font_set =    DUMMY,
    .con_font_get =    DUMMY,
    .con_font_default =    DUMMY,
    .con_font_copy =    DUMMY,
};
可以看到con_init和 con_putcs 都是空函数。而显示的话,那这部分是怎么真正的driver对接的呢?这里以fb为例,出列fb还有drm。
不管哪个硬件实现fb,都会调用register_framebuffer。
int
register_framebuffer(struct fb_info *fb_info)
{
    int ret;

    mutex_lock(&registration_lock);
    ret = do_register_framebuffer(fb_info);
    mutex_unlock(&registration_lock);

    return ret;
}

继续调用do_register_framebuffer,其中最重要的code如下:
fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
static int fbcon_event_notify(struct notifier_block *self,
                  unsigned long action, void *data)
{
    struct fb_event *event = data;
    struct fb_info *info = event->info;
    struct fb_videomode *mode;
    struct fb_con2fbmap *con2fb;
    struct fb_blit_caps *caps;
    int idx, ret = 0;

    /*
     * ignore all events except driver registration and deregistration
     * if fbcon is not active
     */
    if (fbcon_has_exited && !(action == FB_EVENT_FB_REGISTERED ||
                  action == FB_EVENT_FB_UNREGISTERED))
        goto done;

    switch(action) {
    case FB_EVENT_SUSPEND:
        fbcon_suspended(info);
        break;

    case FB_EVENT_FB_REGISTERED:
        ret = fbcon_fb_registered(info);
}
可见对应的FB_EVENT_FB_REGISTERED的处理函数为fbcon_fb_registered
/* called with console_lock held */
static int fbcon_fb_registered(struct fb_info *info)
{
    int ret = 0, i, idx;

    idx = info->node;
    fbcon_select_primary(info);

    if (info_idx == -1) {
        for (i = first_fb_vc; i <= last_fb_vc; i++) {
            if (con2fb_map_boot[i] == idx) {
                info_idx = idx;
                break;
            }
        }

        if (info_idx != -1)
            ret = do_fbcon_takeover(1);
    } else {
        for (i = first_fb_vc; i <= last_fb_vc; i++) {
            if (con2fb_map_boot[i] == idx)
                set_con2fb_map(i, idx, 0);
        }
    }

    return ret;
}
在fbcon_fb_registered 中会调用do_fbcon_takeover 来显示
static int do_fbcon_takeover(int show_logo)
{
    int err, i;

    if (!num_registered_fb)
        return -ENODEV;

    if (!show_logo)
        logo_shown = FBCON_LOGO_DONTSHOW;

    for (i = first_fb_vc; i <= last_fb_vc; i++)
        con2fb_map[i] = info_idx;

    err = do_take_over_console(&fb_con, first_fb_vc, last_fb_vc,
                fbcon_is_default);

    if (err) {
        for (i = first_fb_vc; i <= last_fb_vc; i++)
            con2fb_map[i] = -1;
        info_idx = -1;
    } else {
        fbcon_has_console_bind = 1;
    }

    return err;
}
do_fbcon_takeover 有又调用do_take_over_console 来接过console的显示
这样当在call_console_drivers 中调用tty0的write函数vt_console_print会调用
vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
这样当调用do_take_over_console 之后,这里的con_putcs就对应是具体driver的con_putcs函数了



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值