📄 fbcon.c
字号:
}#endif /* CONFIG_MAC */#if defined(__arm__) && defined(IRQ_VSYNCPULSE) cursor_blink_rate = ARM_CURSOR_BLINK_RATE; irqres = request_irq(IRQ_VSYNCPULSE, fbcon_vbl_handler, SA_SHIRQ, "console/cursor", fbcon_vbl_handler);#endif if (irqres) { use_timer_cursor = 1; cursor_blink_rate = DEFAULT_CURSOR_BLINK_RATE; cursor_timer.expires = jiffies+HZ/50; add_timer(&cursor_timer); }#ifdef CONFIG_PM pm_fbcon = pm_register(PM_SYS_DEV, PM_SYS_VGA, pm_fbcon_request);#endif return display_desc;}static void fbcon_init(struct vc_data *conp, int init){ int unit = conp->vc_num; struct fb_info *info; /* on which frame buffer will we open this console? */ info = registered_fb[(int)con2fb_map[unit]]; info->changevar = &fbcon_changevar; fb_display[unit] = *(info->disp); /* copy from default */ DPRINTK("mode: %s\n",info->modename); DPRINTK("visual: %d\n",fb_display[unit].visual); DPRINTK("res: %dx%d-%d\n",fb_display[unit].var.xres, fb_display[unit].var.yres, fb_display[unit].var.bits_per_pixel); fb_display[unit].conp = conp; fb_display[unit].fb_info = info; /* clear out the cmap so we don't have dangling pointers */ fb_display[unit].cmap.len = 0; fb_display[unit].cmap.red = 0; fb_display[unit].cmap.green = 0; fb_display[unit].cmap.blue = 0; fb_display[unit].cmap.transp = 0; fbcon_setup(unit, init, !init); /* Must be done after fbcon_setup to prevent excess updates */ conp->vc_display_fg = &info->display_fg; if (!info->display_fg) info->display_fg = conp;}static void fbcon_deinit(struct vc_data *conp){ int unit = conp->vc_num; struct display *p = &fb_display[unit]; fbcon_free_font(p); p->dispsw = &fbcon_dummy; p->conp = 0;}static int fbcon_changevar(int con){ if (fb_display[con].conp) fbcon_setup(con, 0, 0); return 0;}static __inline__ void updatescrollmode(struct display *p){ int m; if (p->scrollmode & __SCROLL_YFIXED) return; if (divides(p->ywrapstep, fontheight(p)) && divides(fontheight(p), p->var.yres_virtual)) m = __SCROLL_YWRAP; else if (divides(p->ypanstep, fontheight(p)) && p->var.yres_virtual >= p->var.yres+fontheight(p)) m = __SCROLL_YPAN; else if (p->scrollmode & __SCROLL_YNOMOVE) m = __SCROLL_YREDRAW; else m = __SCROLL_YMOVE; p->scrollmode = (p->scrollmode & ~__SCROLL_YMASK) | m;}static void fbcon_font_widths(struct display *p){ int i; p->_fontwidthlog = 0; for (i = 2; i <= 6; i++) if (fontwidth(p) == (1 << i)) p->_fontwidthlog = i; p->_fontheightlog = 0; for (i = 2; i <= 6; i++) if (fontheight(p) == (1 << i)) p->_fontheightlog = i;}#define fontwidthvalid(p,w) ((p)->dispsw->fontwidthmask & FONTWIDTH(w))static void fbcon_setup(int con, int init, int logo){ struct display *p = &fb_display[con]; struct vc_data *conp = p->conp; int nr_rows, nr_cols; int old_rows, old_cols; unsigned short *save = NULL, *r, *q; int i, charcnt = 256; struct fbcon_font_desc *font; if (con != fg_console || (p->fb_info->flags & FBINFO_FLAG_MODULE) || p->type == FB_TYPE_TEXT) logo = 0; p->var.xoffset = p->var.yoffset = p->yscroll = 0; /* reset wrap/pan */ if (con == fg_console && p->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; } for (i = 0; i < MAX_NR_CONSOLES; i++) if (i != con && fb_display[i].fb_info == p->fb_info && fb_display[i].conp && fb_display[i].fontdata) break; fbcon_free_font(p); if (i < MAX_NR_CONSOLES) { struct display *q = &fb_display[i]; if (fontwidthvalid(p,fontwidth(q))) { /* If we are not the first console on this fb, copy the font from that console */ p->_fontwidth = q->_fontwidth; p->_fontheight = q->_fontheight; p->_fontwidthlog = q->_fontwidthlog; p->_fontheightlog = q->_fontheightlog; p->fontdata = q->fontdata; p->userfont = q->userfont; if (p->userfont) { REFCOUNT(p->fontdata)++; charcnt = FNTCHARCNT(p->fontdata); } con_copy_unimap(con, i); } } if (!p->fontdata) { if (!p->fb_info->fontname[0] || !(font = fbcon_find_font(p->fb_info->fontname))) font = fbcon_get_default_font(p->var.xres, p->var.yres); p->_fontwidth = font->width; p->_fontheight = font->height; p->fontdata = font->data; fbcon_font_widths(p); } if (!fontwidthvalid(p,fontwidth(p))) {#if defined(CONFIG_FBCON_MAC) && defined(CONFIG_MAC) if (MACH_IS_MAC) /* ++Geert: hack to make 6x11 fonts work on mac */ p->dispsw = &fbcon_mac; else#endif { /* ++Geert: changed from panic() to `correct and continue' */ printk(KERN_ERR "fbcon_setup: No support for fontwidth %d\n", fontwidth(p)); p->dispsw = &fbcon_dummy; } } if (p->dispsw->set_font) p->dispsw->set_font(p, fontwidth(p), fontheight(p)); updatescrollmode(p); old_cols = conp->vc_cols; old_rows = conp->vc_rows; nr_cols = p->var.xres/fontwidth(p); nr_rows = p->var.yres/fontheight(p); if (logo) { /* Need to make room for the logo */ int cnt; int step; logo_lines = (LOGO_H + fontheight(p) - 1) / fontheight(p); q = (unsigned short *)(conp->vc_origin + conp->vc_size_row * old_rows); step = logo_lines * old_cols; for (r = q - logo_lines * old_cols; r < q; r++) if (scr_readw(r) != conp->vc_video_erase_char) break; if (r != q && nr_rows >= old_rows + logo_lines) { save = kmalloc(logo_lines * nr_cols * 2, GFP_KERNEL); if (save) { int i = old_cols < nr_cols ? old_cols : nr_cols; scr_memsetw(save, conp->vc_video_erase_char, logo_lines * nr_cols * 2); r = q - step; for (cnt = 0; cnt < logo_lines; cnt++, r += i) scr_memcpyw(save + cnt * nr_cols, r, 2 * i); r = q; } } if (r == q) { /* We can scroll screen down */ r = q - step - old_cols; for (cnt = old_rows - logo_lines; cnt > 0; cnt--) { scr_memcpyw(r + step, r, conp->vc_size_row); r -= old_cols; } if (!save) { conp->vc_y += logo_lines; conp->vc_pos += logo_lines * conp->vc_size_row; } } scr_memsetw((unsigned short *)conp->vc_origin, conp->vc_video_erase_char, conp->vc_size_row * logo_lines); } /* * ++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) { conp->vc_cols = nr_cols; conp->vc_rows = nr_rows; } p->vrows = p->var.yres_virtual/fontheight(p); if ((p->var.yres % fontheight(p)) && (p->var.yres_virtual % fontheight(p) < p->var.yres % fontheight(p))) p->vrows--; conp->vc_can_do_color = p->var.bits_per_pixel != 1; conp->vc_complement_mask = conp->vc_can_do_color ? 0x7700 : 0x0800; if (charcnt == 256) { conp->vc_hi_font_mask = 0; p->fgshift = 8; p->bgshift = 12; p->charmask = 0xff; } else { conp->vc_hi_font_mask = 0x100; if (conp->vc_can_do_color) conp->vc_complement_mask <<= 1; p->fgshift = 9; p->bgshift = 13; p->charmask = 0x1ff; } if (p->dispsw == &fbcon_dummy) printk(KERN_WARNING "fbcon_setup: type %d (aux %d, depth %d) not " "supported\n", p->type, p->type_aux, p->var.bits_per_pixel); p->dispsw->setup(p); p->fgcol = p->var.bits_per_pixel > 2 ? 7 : (1<<p->var.bits_per_pixel)-1; p->bgcol = 0; if (!init) { if (conp->vc_cols != nr_cols || conp->vc_rows != nr_rows) vc_resize_con(nr_rows, nr_cols, con); else if (CON_IS_VISIBLE(conp) && vt_cons[conp->vc_num]->vc_mode == KD_TEXT) { if (p->dispsw->clear_margins) p->dispsw->clear_margins(conp, p, 0); update_screen(con); } if (save) { q = (unsigned short *)(conp->vc_origin + conp->vc_size_row * old_rows); scr_memcpyw(q, save, logo_lines * nr_cols * 2); conp->vc_y += logo_lines; conp->vc_pos += logo_lines * conp->vc_size_row; kfree(save); } } if (logo) { logo_shown = -2; conp->vc_top = logo_lines; } if (con == fg_console && softback_buf) { int l = fbcon_softback_size / conp->vc_size_row; if (l > 5) softback_end = softback_buf + l * conp->vc_size_row; else { /* Smaller scrollback makes no sense, and 0 would screw the operation totally */ softback_top = 0; } }}/* ====================================================================== *//* fbcon_XXX routines - interface used by the world * * This system is now divided into two levels because of complications * caused by hardware scrolling. Top level functions: * * fbcon_bmove(), fbcon_clear(), fbcon_putc() * * handles y values in range [0, scr_height-1] that correspond to real * screen positions. y_wrap shift means that first line of bitmap may be * anywhere on this display. These functions convert lineoffsets to * bitmap offsets and deal with the wrap-around case by splitting blits. * * fbcon_bmove_physical_8() -- These functions fast implementations * fbcon_clear_physical_8() -- of original fbcon_XXX fns. * fbcon_putc_physical_8() -- (fontwidth != 8) may be added later * * WARNING: * * At the moment fbcon_putc() cannot blit across vertical wrap boundary * Implies should only really hardware scroll in rows. Only reason for * restriction is simplicity & efficiency at the moment. */static __inline__ int real_y(struct display *p, int ypos){ int rows = p->vrows; ypos += p->yscroll; return ypos < rows ? ypos : ypos-rows;}static void fbcon_clear(struct vc_data *conp, int sy, int sx, int height, int width){ int unit = conp->vc_num; struct display *p = &fb_display[unit]; u_int y_break; int redraw_cursor = 0; if (!p->can_soft_blank && console_blanked) return; if (!height || !width) return; if ((sy <= p->cursor_y) && (p->cursor_y < sy+height) && (sx <= p->cursor_x) && (p->cursor_x < sx+width)) { cursor_undrawn(); redraw_cursor = 1; } /* Split blits that cross physical y_wrap boundary */ y_break = p->vrows-p->yscroll; if (sy < y_break && sy+height-1 >= y_break) { u_int b = y_break-sy; p->dispsw->clear(conp, p, real_y(p, sy), sx, b, width); p->dispsw->clear(conp, p, real_y(p, sy+b), sx, height-b, width); } else p->dispsw->clear(conp, p, real_y(p, sy), sx, height, width); if (redraw_cursor) vbl_cursor_cnt = CURSOR_DRAW_DELAY;}static void fbcon_putc(struct vc_data *conp, int c, int ypos, int xpos){ int unit = conp->vc_num; struct display *p = &fb_display[unit]; int redraw_cursor = 0; if (!p->can_soft_blank && console_blanked) return; if (vt_cons[unit]->vc_mode != KD_TEXT) return; if ((p->cursor_x == xpos) && (p->cursor_y == ypos)) { cursor_undrawn(); redraw_cursor = 1; } p->dispsw->putc(conp, p, c, real_y(p, ypos), xpos); if (redraw_cursor) vbl_cursor_cnt = CURSOR_DRAW_DELAY;}static void fbcon_putcs(struct vc_data *conp, const unsigned short *s, int count, int ypos, int xpos){ int unit = conp->vc_num; struct display *p = &fb_display[unit]; int redraw_cursor = 0; if (!p->can_soft_blank && console_blanked) return; if (vt_cons[unit]->vc_mode != KD_TEXT) return; if ((p->cursor_y == ypos) && (xpos <= p->cursor_x) && (p->cursor_x < (xpos + count))) { cursor_undrawn(); redraw_cursor = 1; } p->dispsw->putcs(conp, p, s, count, real_y(p, ypos), xpos); if (redraw_cursor) vbl_cursor_cnt = CURSOR_DRAW_DELAY;}static void fbcon_cursor(struct vc_data *conp, int mode){ int unit = conp->vc_num; struct display *p = &fb_display[unit]; int y = conp->vc_y; if (mode & CM_SOFTBACK) { mode &= ~CM_SOFTBACK; if (softback_lines) { if (y + softback_lines >= conp->vc_rows) mode = CM_ERASE; else y += softback_lines; } } else if (softback_lines) fbcon_set_origin(conp); /* do we have a hardware cursor ? */ if (p->dispsw->cursor) { p->cursor_x = conp->vc_x; p->cursor_y = y; p->dispsw->cursor(p, mode, p->cursor_x, real_y(p, p->cursor_y)); return; } /* Avoid flickering if there's no real change. */ if (p->cursor_x == conp->vc_x && p->cursor_y == y && (mode == CM_ERASE) == !cursor_on) return; cursor_on = 0; if (cursor_drawn && p->cursor_x < conp->vc_cols && p->cursor_y < conp->vc_rows)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -