📄 fbcon.c
字号:
vc->vc_size_row * rows); step = logo_lines * cols; for (r = q - logo_lines * cols; r < q; r++) if (scr_readw(r) != vc->vc_video_erase_char) break; if (r != q && new_rows >= rows + logo_lines) { save = kmalloc(logo_lines * new_cols * 2, GFP_KERNEL); if (save) { int i = cols < new_cols ? cols : new_cols; scr_memsetw(save, erase, logo_lines * new_cols * 2); r = q - step; for (cnt = 0; cnt < logo_lines; cnt++, r += i) scr_memcpyw(save + cnt * new_cols, r, 2 * i); r = q; } } if (r == q) { /* We can scroll screen down */ r = q - step - cols; for (cnt = rows - logo_lines; cnt > 0; cnt--) { scr_memcpyw(r + step, r, vc->vc_size_row); r -= cols; } if (!save) { int lines; if (vc->vc_y + logo_lines >= rows) lines = rows - vc->vc_y - 1; else lines = logo_lines; vc->vc_y += lines; vc->vc_pos += lines * vc->vc_size_row; } } scr_memsetw((unsigned short *) vc->vc_origin, erase, vc->vc_size_row * logo_lines); if (CON_IS_VISIBLE(vc) && vc->vc_mode == KD_TEXT) { fbcon_clear_margins(vc, 0); update_screen(vc); } if (save) { q = (unsigned short *) (vc->vc_origin + vc->vc_size_row * rows); scr_memcpyw(q, save, logo_lines * new_cols * 2); vc->vc_y += logo_lines; vc->vc_pos += logo_lines * vc->vc_size_row; kfree(save); } if (logo_lines > vc->vc_bottom) { logo_shown = FBCON_LOGO_CANSHOW; printk(KERN_INFO "fbcon_init: disable boot-logo (boot-logo bigger than screen).\n"); } else if (logo_shown != FBCON_LOGO_DONTSHOW) { logo_shown = FBCON_LOGO_DRAW; vc->vc_top = logo_lines; }}static void set_blitting_type(struct vc_data *vc, struct fb_info *info){ struct fbcon_ops *ops = info->fbcon_par; info->flags &= ~FBINFO_MISC_TILEBLITTING; ops->p = &fb_display[vc->vc_num]; fbcon_set_rotation(info); fbcon_set_bitops(ops);}static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount){ return 0;}static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info, int unit, int oldidx){ struct fbcon_ops *ops = NULL; int err = 0; if (!try_module_get(info->fbops->owner)) err = -ENODEV; if (!err && info->fbops->fb_open && info->fbops->fb_open(info, 0)) err = -ENODEV; if (!err) { ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL); if (!ops) err = -ENOMEM; } if (!err) { info->fbcon_par = ops; set_blitting_type(vc, info); } if (err) { con2fb_map[unit] = oldidx; module_put(info->fbops->owner); } return err;}static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo, struct fb_info *newinfo, int unit, int oldidx, int found){ struct fbcon_ops *ops = oldinfo->fbcon_par; int err = 0; if (oldinfo->fbops->fb_release && oldinfo->fbops->fb_release(oldinfo, 0)) { con2fb_map[unit] = oldidx; if (!found && newinfo->fbops->fb_release) newinfo->fbops->fb_release(newinfo, 0); if (!found) module_put(newinfo->fbops->owner); err = -ENODEV; } if (!err) { fbcon_del_cursor_timer(oldinfo); kfree(ops->cursor_state.mask); kfree(ops->cursor_data); kfree(ops->fontbuffer); kfree(oldinfo->fbcon_par); oldinfo->fbcon_par = NULL; module_put(oldinfo->fbops->owner); /* If oldinfo and newinfo are driving the same hardware, the fb_release() method of oldinfo may attempt to restore the hardware state. This will leave the newinfo in an undefined state. Thus, a call to fb_set_par() may be needed for the newinfo. */ if (newinfo->fbops->fb_set_par) newinfo->fbops->fb_set_par(newinfo); } return err;}static void con2fb_init_display(struct vc_data *vc, struct fb_info *info, int unit, int show_logo){ struct fbcon_ops *ops = info->fbcon_par; ops->currcon = fg_console; if (info->fbops->fb_set_par && !(ops->flags & FBCON_FLAGS_INIT)) info->fbops->fb_set_par(info); ops->flags |= FBCON_FLAGS_INIT; ops->graphics = 0; if (vc) fbcon_set_disp(info, &info->var, vc); else fbcon_preset_disp(info, &info->var, unit); if (show_logo) { struct vc_data *fg_vc = vc_cons[fg_console].d; struct fb_info *fg_info = registered_fb[con2fb_map[fg_console]]; fbcon_prepare_logo(fg_vc, fg_info, fg_vc->vc_cols, fg_vc->vc_rows, fg_vc->vc_cols, fg_vc->vc_rows); } update_screen(vc_cons[fg_console].d);}/** * set_con2fb_map - map console to frame buffer device * @unit: virtual console number to map * @newidx: frame buffer index to map virtual console to * @user: user request * * Maps a virtual console @unit to a frame buffer device * @newidx. */static int set_con2fb_map(int unit, int newidx, int user){ struct vc_data *vc = vc_cons[unit].d; int oldidx = con2fb_map[unit]; struct fb_info *info = registered_fb[newidx]; struct fb_info *oldinfo = NULL; int found, err = 0; if (oldidx == newidx) return 0; if (!info || fbcon_has_exited) return -EINVAL; if (!err && !search_for_mapped_con()) { info_idx = newidx; return fbcon_takeover(0); } if (oldidx != -1) oldinfo = registered_fb[oldidx]; found = search_fb_in_map(newidx); acquire_console_sem(); con2fb_map[unit] = newidx; if (!err && !found) err = con2fb_acquire_newinfo(vc, info, unit, oldidx); /* * If old fb is not mapped to any of the consoles, * fbcon should release it. */ if (!err && oldinfo && !search_fb_in_map(oldidx)) err = con2fb_release_oldinfo(vc, oldinfo, info, unit, oldidx, found); if (!err) { int show_logo = (fg_console == 0 && !user && logo_shown != FBCON_LOGO_DONTSHOW); if (!found) fbcon_add_cursor_timer(info); con2fb_map_boot[unit] = newidx; con2fb_init_display(vc, info, unit, show_logo); } if (!search_fb_in_map(info_idx)) info_idx = newidx; release_console_sem(); return err;}/* * Low Level Operations *//* NOTE: fbcon cannot be __init: it may be called from take_over_console later */static int var_to_display(struct display *disp, struct fb_var_screeninfo *var, struct fb_info *info){ disp->xres_virtual = var->xres_virtual; disp->yres_virtual = var->yres_virtual; disp->bits_per_pixel = var->bits_per_pixel; disp->grayscale = var->grayscale; disp->nonstd = var->nonstd; disp->accel_flags = var->accel_flags; disp->height = var->height; disp->width = var->width; disp->red = var->red; disp->green = var->green; disp->blue = var->blue; disp->transp = var->transp; disp->rotate = var->rotate; disp->mode = fb_match_mode(var, &info->modelist); if (disp->mode == NULL) /* This should not happen */ return -EINVAL; return 0;}static void display_to_var(struct fb_var_screeninfo *var, struct display *disp){ fb_videomode_to_var(var, disp->mode); var->xres_virtual = disp->xres_virtual; var->yres_virtual = disp->yres_virtual; var->bits_per_pixel = disp->bits_per_pixel; var->grayscale = disp->grayscale; var->nonstd = disp->nonstd; var->accel_flags = disp->accel_flags; var->height = disp->height; var->width = disp->width; var->red = disp->red; var->green = disp->green; var->blue = disp->blue; var->transp = disp->transp; var->rotate = disp->rotate;}static const char *fbcon_startup(void){ const char *display_desc = "frame buffer device"; struct display *p = &fb_display[fg_console]; struct vc_data *vc = vc_cons[fg_console].d; const struct font_desc *font = NULL; struct module *owner; struct fb_info *info = NULL; struct fbcon_ops *ops; int rows, cols; int irqres; irqres = 1; /* * If num_registered_fb is zero, this is a call for the dummy part. * The frame buffer devices weren't initialized yet. */ if (!num_registered_fb || info_idx == -1) return display_desc; /* * Instead of blindly using registered_fb[0], we use info_idx, set by * fb_console_init(); */ info = registered_fb[info_idx]; if (!info) return NULL; owner = info->fbops->owner; if (!try_module_get(owner)) return NULL; if (info->fbops->fb_open && info->fbops->fb_open(info, 0)) { module_put(owner); return NULL; } ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL); if (!ops) { module_put(owner); return NULL; } ops->currcon = -1; ops->graphics = 1; ops->cur_rotate = -1; info->fbcon_par = ops; p->con_rotate = rotate; set_blitting_type(vc, info); if (info->fix.type != FB_TYPE_TEXT) { if (fbcon_softback_size) { if (!softback_buf) { softback_buf = (unsigned long) kmalloc(fbcon_softback_size, GFP_KERNEL); if (!softback_buf) { fbcon_softback_size = 0; softback_top = 0; } } } else { if (softback_buf) { kfree((void *) softback_buf); softback_buf = 0; softback_top = 0; } } if (softback_buf) softback_in = softback_top = softback_curr = softback_buf; softback_lines = 0; } /* Setup default font */ if (!p->fontdata) { if (!fontname[0] || !(font = find_font(fontname))) font = get_default_font(info->var.xres, info->var.yres, info->pixmap.blit_x, info->pixmap.blit_y); vc->vc_font.width = font->width; vc->vc_font.height = font->height; vc->vc_font.data = (void *)(p->fontdata = font->data); vc->vc_font.charcount = 256; /* FIXME Need to support more fonts */ } cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); cols /= vc->vc_font.width; rows /= vc->vc_font.height; vc_resize(vc, cols, rows); DPRINTK("mode: %s\n", info->fix.id); DPRINTK("visual: %d\n", info->fix.visual); DPRINTK("res: %dx%d-%d\n", info->var.xres, info->var.yres, info->var.bits_per_pixel); fbcon_add_cursor_timer(info); fbcon_has_exited = 0; return display_desc;}static void fbcon_init(struct vc_data *vc, int init){ struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fbcon_ops *ops; struct vc_data **default_mode = vc->vc_display_fg; struct vc_data *svc = *default_mode; struct display *t, *p = &fb_display[vc->vc_num]; int logo = 1, new_rows, new_cols, rows, cols, charcnt = 256; int cap; if (info_idx == -1 || info == NULL) return; cap = info->flags; if (vc != svc || logo_shown == FBCON_LOGO_DONTSHOW || (info->fix.type == FB_TYPE_TEXT)) logo = 0; if (var_to_display(p, &info->var, info)) return; /* If we are not the first console on this fb, copy the font from that console */ t = &fb_display[fg_console]; if (!p->fontdata) { if (t->fontdata) { struct vc_data *fvc = vc_cons[fg_console].d; vc->vc_font.data = (void *)(p->fontdata = fvc->vc_font.data); vc->vc_font.width = fvc->vc_font.width; vc->vc_font.height = fvc->vc_font.height; p->userfont = t->userfont; if (p->userfont) REFCOUNT(p->fontdata)++; } else { const struct font_desc *font = NULL; if (!fontname[0] || !(font = find_font(fontname))) font = get_default_font(info->var.xres, info->var.yres, info->pixmap.blit_x, info->pixmap.blit_y); vc->vc_font.width = font->width; vc->vc_font.height = font->height; vc->vc_font.data = (void *)(p->fontdata = font->data); vc->vc_font.charcount = 256; /* FIXME Need to support more fonts */ } } if (p->userfont) charcnt = FNTCHARCNT(p->fontdata); vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1); vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; if (charcnt == 256) { vc->vc_hi_font_mask = 0; } else { vc->vc_hi_font_mask = 0x100; if (vc->vc_can_do_color) vc->vc_complement_mask <<= 1; } if (!*svc->vc_uni_pagedir_loc) con_set_default_unimap(svc); if (!*vc->vc_uni_pagedir_loc) con_copy_unimap(vc, svc); ops = info->fbcon_par; p->con_rotate = rotate; set_blitting_type(vc, info); cols = vc->vc_cols; rows = vc->vc_rows; new_cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); new_rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); new_cols /= vc->vc_font.width; new_rows /= vc->vc_font.height; vc_resize(vc, new_cols, new_rows); /* * We must always set the mode. The mode of the previous console * driver could be in the same resolution but we are using different * hardware so we have to initialize the hardware. * * We need to do it in fbcon_init() to prevent screen corruption. */ if (CON_IS_VISIBLE(vc) && vc->vc_mode == KD_TEXT) { if (info->fbops->fb_set_par && !(ops->flags & FBCON_FLAGS_INIT)) info->fbops->fb_set_par(info); ops->flags |= FBCON_FLAGS_INIT; } ops->graphics = 0; if ((cap & FBINFO_HWACCEL_COPYAREA) && !(cap & FBINFO_HWACCEL_DISABLED)) p->scrollmode = SCROLL_MOVE; else /* default to something safe */ p->scrollmode = SCROLL_REDRAW;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -