tty0 显示的过程

xiaoxiao2021-02-27  301

我们知道在调用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(®istration_lock);     ret = do_register_framebuffer(fb_info);     mutex_unlock(®istration_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函数了
转载请注明原文地址: https://www.6miu.com/read-4407.html

最新回复(0)