📄 fbcon.c
字号:
#elsestatic void set_blitting_type(struct vc_data *vc, struct fb_info *info, struct display *p){ struct fbcon_ops *ops = info->fbcon_par; info->flags &= ~FBINFO_MISC_TILEBLITTING; fbcon_set_bitops(ops);}#endif /* CONFIG_MISC_TILEBLITTING */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 = kmalloc(sizeof(struct fbcon_ops), GFP_KERNEL); if (!ops) err = -ENOMEM; } if (!err) { memset(ops, 0, sizeof(struct fbcon_ops)); info->fbcon_par = ops; set_blitting_type(vc, info, NULL); } 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) { if (oldinfo->queue.func == fb_flashcursor) del_timer_sync(&ops->cursor_timer); kfree(ops->cursor_state.mask); kfree(ops->cursor_data); kfree(oldinfo->fbcon_par); oldinfo->fbcon_par = NULL; module_put(oldinfo->fbops->owner); } return err;}static void con2fb_init_newinfo(struct fb_info *info){ if (!info->queue.func || info->queue.func == fb_flashcursor) { struct fbcon_ops *ops = info->fbcon_par; if (!info->queue.func) INIT_WORK(&info->queue, fb_flashcursor, info); init_timer(&ops->cursor_timer); ops->cursor_timer.function = cursor_timer_handler; ops->cursor_timer.expires = jiffies + HZ / 5; ops->cursor_timer.data = (unsigned long ) info; add_timer(&ops->cursor_timer); }}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) info->fbops->fb_set_par(info); if (vc) fbcon_set_disp(info, vc); else fbcon_preset_disp(info, 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); } switch_screen(fg_console);}/** * 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) err = -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) con2fb_init_newinfo(info); con2fb_map_boot[unit] = newidx; con2fb_init_display(vc, info, unit, show_logo); } 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->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;}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; 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 = kmalloc(sizeof(struct fbcon_ops), GFP_KERNEL); if (!ops) { module_put(owner); return NULL; } memset(ops, 0, sizeof(struct fbcon_ops)); ops->currcon = -1; info->fbcon_par = ops; set_blitting_type(vc, info, NULL); 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); vc->vc_font.width = font->width; vc->vc_font.height = font->height; vc->vc_font.data = p->fontdata = font->data; vc->vc_font.charcount = 256; /* FIXME Need to support more fonts */ } cols = info->var.xres / vc->vc_font.width; rows = info->var.yres / vc->vc_font.height; vc_resize(vc->vc_num, 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);#ifdef CONFIG_ATARI if (MACH_IS_ATARI) { cursor_blink_rate = ATARI_CURSOR_BLINK_RATE; irqres = request_irq(IRQ_AUTO_4, fb_vbl_handler, IRQ_TYPE_PRIO, "framebuffer vbl", info); }#endif /* CONFIG_ATARI */#ifdef CONFIG_MAC /* * On a Macintoy, the VBL interrupt may or may not be active. * As interrupt based cursor is more reliable and race free, we * probe for VBL interrupts. */ if (MACH_IS_MAC) { int ct = 0; /* * Probe for VBL: set temp. handler ... */ irqres = request_irq(IRQ_MAC_VBL, fb_vbl_detect, 0, "framebuffer vbl", info); vbl_detected = 0; /* * ... and spin for 20 ms ... */ while (!vbl_detected && ++ct < 1000) udelay(20); if (ct == 1000) printk ("fbcon_startup: No VBL detected, using timer based cursor.\n"); free_irq(IRQ_MAC_VBL, fb_vbl_detect); if (vbl_detected) { /* * interrupt based cursor ok */ cursor_blink_rate = MAC_CURSOR_BLINK_RATE; irqres = request_irq(IRQ_MAC_VBL, fb_vbl_handler, 0, "framebuffer vbl", info); } else { /* * VBL not detected: fall through, use timer based cursor */ irqres = 1; } }#endif /* CONFIG_MAC */#if defined(__arm__) && defined(IRQ_VSYNCPULSE) cursor_blink_rate = ARM_CURSOR_BLINK_RATE; irqres = request_irq(IRQ_VSYNCPULSE, fb_vbl_handler, SA_SHIRQ, "framebuffer vbl", info);#endif /* Initialize the work queue. If the driver provides its * own work queue this means it will use something besides * default timer to flash the cursor. */ if (!info->queue.func) { INIT_WORK(&info->queue, fb_flashcursor, info); init_timer(&ops->cursor_timer); ops->cursor_timer.function = cursor_timer_handler; ops->cursor_timer.expires = jiffies + HZ / 5; ops->cursor_timer.data = (unsigned long ) info; add_timer(&ops->cursor_timer); } 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 vc_data **default_mode = vc->vc_display_fg; struct vc_data *svc = *default_mode; struct display *t, *p = &fb_display[vc->vc_num]; int display_fg = (*default_mode)->vc_num; int logo = 1, new_rows, new_cols, rows, cols, charcnt = 256; int cap = info->flags; if (info_idx == -1 || info == NULL) return; if (vc->vc_num != display_fg || logo_shown == FBCON_LOGO_DONTSHOW || (info->fix.type == FB_TYPE_TEXT)) logo = 0; info->var.xoffset = info->var.yoffset = p->yscroll = 0; /* reset wrap/pan */ 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[display_fg]; if (!vc->vc_font.data) { vc->vc_font.data = p->fontdata = t->fontdata; vc->vc_font.width = (*default_mode)->vc_font.width; vc->vc_font.height = (*default_mode)->vc_font.height; p->userfont = t->userfont; if (p->userfont) REFCOUNT(p->fontdata)++; } if (p->userfont) charcnt = FNTCHARCNT(p->fontdata); vc->vc_can_do_color = (fb_get_color_depth(info) != 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(display_fg); if (!*vc->vc_uni_pagedir_loc) con_copy_unimap(vc->vc_num, display_fg); cols = vc->vc_cols; rows = vc->vc_rows; new_cols = info->var.xres / vc->vc_font.width; new_rows = info->var.yres / vc->vc_font.height; vc_resize(vc->vc_num, 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) && info->fbops->fb_set_par) info->fbops->fb_set_par(info); if ((cap & FBINFO_HWACCEL_COPYAREA) && !(cap & FBINFO_HWACCEL_DISABLED)) p->scrollmode = SCROLL_MOVE; else /* default to something safe */ p->scrollmode = SCROLL_REDRAW; /* * ++guenther: console.c:vc_allocate() relies on initializing * vc_{cols,rows}, but we must not set those if we are only * resizing the console. */ if (!init) { vc->vc_cols = new_cols; vc->vc_rows = new_rows; } if (logo) fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows); if (vc->vc_num == display_fg && softback_buf) { int l = fbcon_softback_size / vc->vc_size_row; if (l > 5) softback_end = softback_buf + l * vc->vc_size_row; else { /* Smaller scrollback makes no sense, and 0 would screw the operation totally */ softback_top = 0; } }}static void fbcon_deinit(struct vc_data *vc){ struct display *p = &fb_display[vc->vc_num]; if (info_idx != -1) return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -