fbcon.c
来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 2,412 行 · 第 1/5 页
C
2,412 行
static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch){ unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; struct display *p = &fb_display[vc->vc_num]; if (mode_switch) { struct fb_var_screeninfo var = info->var;/* * HACK ALERT: Some hardware will require reinitializion at this stage, * others will require it to be done as late as possible. * For now, we differentiate this with the * FBINFO_MISC_MODESWITCHLATE bitflag. Worst case will be * hardware that requires it here and another one later. * A definitive solution may require fixing X or the VT * system. */ if (info->flags & FBINFO_MISC_MODESWITCHLATE) info->flags |= FBINFO_MISC_MODESWITCH; if (blank) { fbcon_cursor(vc, CM_ERASE); return 0; } if (!(info->flags & FBINFO_MISC_MODESWITCHLATE)) { var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; fb_set_var(info, &var); } } fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW); if (!info->fbops->fb_blank) { if (blank) { unsigned short oldc; u_int height; u_int y_break; oldc = vc->vc_video_erase_char; vc->vc_video_erase_char &= charmask; height = vc->vc_rows; y_break = p->vrows - p->yscroll; if (height > y_break) { accel_clear(vc, info, real_y(p, 0), 0, y_break, vc->vc_cols); accel_clear(vc, info, real_y(p, y_break), 0, height - y_break, vc->vc_cols); } else accel_clear(vc, info, real_y(p, 0), 0, height, vc->vc_cols); vc->vc_video_erase_char = oldc; } else update_screen(vc->vc_num); return 0; } else return fb_blank(info, blank);}static void fbcon_free_font(struct display *p){ if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0)) kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int)); p->fontdata = NULL; p->userfont = 0;}static int fbcon_get_font(struct vc_data *vc, struct console_font *font){ u8 *fontdata = vc->vc_font.data; u8 *data = font->data; int i, j; font->width = vc->vc_font.width; font->height = vc->vc_font.height; font->charcount = vc->vc_hi_font_mask ? 512 : 256; if (!font->data) return 0; if (font->width <= 8) { j = vc->vc_font.height; for (i = 0; i < font->charcount; i++) { memcpy(data, fontdata, j); memset(data + j, 0, 32 - j); data += 32; fontdata += j; } } else if (font->width <= 16) { j = vc->vc_font.height * 2; for (i = 0; i < font->charcount; i++) { memcpy(data, fontdata, j); memset(data + j, 0, 64 - j); data += 64; fontdata += j; } } else if (font->width <= 24) { for (i = 0; i < font->charcount; i++) { for (j = 0; j < vc->vc_font.height; j++) { *data++ = fontdata[0]; *data++ = fontdata[1]; *data++ = fontdata[2]; fontdata += sizeof(u32); } memset(data, 0, 3 * (32 - j)); data += 3 * (32 - j); } } else { j = vc->vc_font.height * 4; for (i = 0; i < font->charcount; i++) { memcpy(data, fontdata, j); memset(data + j, 0, 128 - j); data += 128; fontdata += j; } } return 0;}static int fbcon_do_set_font(struct vc_data *vc, int w, int h, u8 * data, int userfont){ struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; struct display *p = &fb_display[vc->vc_num]; int resize; int cnt; char *old_data = NULL; if (CON_IS_VISIBLE(vc) && softback_lines) fbcon_set_origin(vc); resize = (w != vc->vc_font.width) || (h != vc->vc_font.height); if (p->userfont) old_data = vc->vc_font.data; if (userfont) cnt = FNTCHARCNT(data); else cnt = 256; vc->vc_font.data = p->fontdata = data; if ((p->userfont = userfont)) REFCOUNT(data)++; vc->vc_font.width = w; vc->vc_font.height = h; if (vc->vc_hi_font_mask && cnt == 256) { vc->vc_hi_font_mask = 0; if (vc->vc_can_do_color) { vc->vc_complement_mask >>= 1; vc->vc_s_complement_mask >>= 1; } /* ++Edmund: reorder the attribute bits */ if (vc->vc_can_do_color) { unsigned short *cp = (unsigned short *) vc->vc_origin; int count = vc->vc_screenbuf_size / 2; unsigned short c; for (; count > 0; count--, cp++) { c = scr_readw(cp); scr_writew(((c & 0xfe00) >> 1) | (c & 0xff), cp); } c = vc->vc_video_erase_char; vc->vc_video_erase_char = ((c & 0xfe00) >> 1) | (c & 0xff); vc->vc_attr >>= 1; } } else if (!vc->vc_hi_font_mask && cnt == 512) { vc->vc_hi_font_mask = 0x100; if (vc->vc_can_do_color) { vc->vc_complement_mask <<= 1; vc->vc_s_complement_mask <<= 1; } /* ++Edmund: reorder the attribute bits */ { unsigned short *cp = (unsigned short *) vc->vc_origin; int count = vc->vc_screenbuf_size / 2; unsigned short c; for (; count > 0; count--, cp++) { unsigned short newc; c = scr_readw(cp); if (vc->vc_can_do_color) newc = ((c & 0xff00) << 1) | (c & 0xff); else newc = c & ~0x100; scr_writew(newc, cp); } c = vc->vc_video_erase_char; if (vc->vc_can_do_color) { vc->vc_video_erase_char = ((c & 0xff00) << 1) | (c & 0xff); vc->vc_attr <<= 1; } else vc->vc_video_erase_char = c & ~0x100; } } if (resize) { /* reset wrap/pan */ info->var.xoffset = info->var.yoffset = p->yscroll = 0; vc_resize(vc->vc_num, info->var.xres / w, info->var.yres / h); if (CON_IS_VISIBLE(vc) && 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; } } } else if (CON_IS_VISIBLE(vc) && vt_cons[vc->vc_num]->vc_mode == KD_TEXT) { accel_clear_margins(vc, info, 0); update_screen(vc->vc_num); } if (old_data && (--REFCOUNT(old_data) == 0)) kfree(old_data - FONT_EXTRA_WORDS * sizeof(int)); return 0;}static int fbcon_copy_font(struct vc_data *vc, int con){ struct display *od = &fb_display[con]; struct console_font *f = &vc->vc_font; if (od->fontdata == f->data) return 0; /* already the same font... */ return fbcon_do_set_font(vc, f->width, f->height, od->fontdata, od->userfont);}/* * User asked to set font; we are guaranteed that * a) width and height are in range 1..32 * b) charcount does not exceed 512 */static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigned flags){ unsigned charcount = font->charcount; int w = font->width; int h = font->height; int size = h; int i, k; u8 *new_data, *data = font->data, *p; if (charcount != 256 && charcount != 512) return -EINVAL; if (w > 8) { if (w <= 16) size *= 2; else size *= 4; } size *= charcount; new_data = kmalloc(FONT_EXTRA_WORDS * sizeof(int) + size, GFP_USER); if (!new_data) return -ENOMEM; new_data += FONT_EXTRA_WORDS * sizeof(int); FNTSIZE(new_data) = size; FNTCHARCNT(new_data) = charcount; REFCOUNT(new_data) = 0; /* usage counter */ p = new_data; if (w <= 8) { for (i = 0; i < charcount; i++) { memcpy(p, data, h); data += 32; p += h; } } else if (w <= 16) { h *= 2; for (i = 0; i < charcount; i++) { memcpy(p, data, h); data += 64; p += h; } } else if (w <= 24) { for (i = 0; i < charcount; i++) { int j; for (j = 0; j < h; j++) { memcpy(p, data, 3); p[3] = 0; data += 3; p += sizeof(u32); } data += 3 * (32 - h); } } else { h *= 4; for (i = 0; i < charcount; i++) { memcpy(p, data, h); data += 128; p += h; } } /* we can do it in u32 chunks because of charcount is 256 or 512, so font length must be multiple of 256, at least. And 256 is multiple of 4 */ k = 0; while (p > new_data) { p = (u8 *)((u32 *)p - 1); k += *(u32 *) p; } FNTSUM(new_data) = k; /* Check if the same font is on some other console already */ for (i = 0; i < MAX_NR_CONSOLES; i++) { struct vc_data *tmp = vc_cons[i].d; if (fb_display[i].userfont && fb_display[i].fontdata && FNTSUM(fb_display[i].fontdata) == k && FNTSIZE(fb_display[i].fontdata) == size && tmp->vc_font.width == w && !memcmp(fb_display[i].fontdata, new_data, size)) { kfree(new_data - FONT_EXTRA_WORDS * sizeof(int)); new_data = fb_display[i].fontdata; break; } } return fbcon_do_set_font(vc, font->width, font->height, new_data, 1);}static int fbcon_set_def_font(struct vc_data *vc, struct console_font *font, char *name){ struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; struct font_desc *f; if (!name) f = get_default_font(info->var.xres, info->var.yres); else if (!(f = find_font(name))) return -ENOENT; font->width = f->width; font->height = f->height; return fbcon_do_set_font(vc, f->width, f->height, f->data, 0);}static u16 palette_red[16];static u16 palette_green[16];static u16 palette_blue[16];static struct fb_cmap palette_cmap = { 0, 16, palette_red, palette_green, palette_blue, NULL};static int fbcon_set_palette(struct vc_data *vc, unsigned char *table){ struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; int i, j, k; u8 val; if (!vc->vc_can_do_color || (!info->fbops->fb_blank && console_blanked)) return -EINVAL; for (i = j = 0; i < 16; i++) { k = table[i]; val = vc->vc_palette[j++]; palette_red[k] = (val << 8) | val; val = vc->vc_palette[j++]; palette_green[k] = (val << 8) | val; val = vc->vc_palette[j++]; palette_blue[k] = (val << 8) | val; } if (info->var.bits_per_pixel <= 4) palette_cmap.len = 1 << info->var.bits_per_pixel; else palette_cmap.len = 16; palette_cmap.start = 0; return fb_set_cmap(&palette_cmap, info);}static u16 *fbcon_screen_pos(struct vc_data *vc, int offset){ unsigned long p; int line; if (vc->vc_num != fg_console || !softback_lines) return (u16 *) (vc->vc_origin + offset); line = offset / vc->vc_size_row; if (line >= softback_lines) return (u16 *) (vc->vc_origin + offset - softback_lines * vc->vc_size_row); p = softback_curr + offset; if (p >= softback_end) p += softback_buf - softback_end; return (u16 *) p;}static unsigned long fbcon_getxy(struct vc_data *vc, unsigned long pos, int *px, int *py){ unsigned long ret; int x, y; if (pos >= vc->vc_origin && pos < vc->vc_scr_end) { unsigned long offset = (pos - vc->vc_origin) / 2; x = offset % vc->vc_cols; y = offset / vc->vc_cols; if (vc->vc_num == fg_console) y += softback_lines; ret = pos + (vc->vc_cols - x) * 2; } else if (vc->vc_num == fg_console && softback_lines) { unsigned long offset = pos - softback_curr; if (pos < softback_curr) offset += softback_end - softback_buf; offset /= 2; x = offset % vc->vc_cols; y = offset / vc->vc_cols; ret = pos + (vc->vc_cols - x) * 2; if (ret == softback_end) ret = softback_buf; if (ret == softback_in) ret = vc->vc_origin; } else { /* Should not happen */ x = y = 0; ret = vc->vc_origin; } if (px) *px = x; if (py) *py = y; return ret;}/* As we might be inside of softback, we may work with non-contiguous buffer, that's why we have to use a separate routine. */static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt){ while (cnt--) { u16 a = scr_readw(p); if (!vc->vc_can_do_color) a ^= 0x0800; else if (vc->vc_hi_font_mask == 0x100) a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4); else a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4); scr_writew(a, p++); if (p == (u16 *) softback_end) p = (u16 *) softback_buf; if (p == (u16 *) softback_in) p = (u16 *) vc->vc_origin; }}static int fbcon_scrolldelta(struct vc_data *vc, int lines){ struct fb_info *info = registered_fb[(int) con2fb_map[fg_console]]; struct display *p = &fb_display[fg_console]; int offset, limit, scrollback_old; if (softback_top) { if (vc->vc_num != fg_console) return 0; if (vt_cons[vc->vc_num]->vc_mode != KD_TEXT || !lines) return 0; if (logo_shown >= 0) { struct vc_data *conp2 = vc_cons[logo_shown].d; if (conp2->vc_top == logo_lines && conp2->vc_bottom == conp2->vc_rows) conp2->vc_top = 0; if (logo_shown == vc->vc_num) { unsigned long p,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?