📄 fbcon.c
字号:
} } else if (w <= 24) { for (i = 0; i < op->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 < op->charcount; i++) { memcpy(p, data, h); data += 128; p += h; } }#endif /* 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) 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++) { if (fb_display[i].userfont && fb_display[i].fontdata && FNTSUM(fb_display[i].fontdata) == k && FNTSIZE(fb_display[i].fontdata) == size && fontwidth(&fb_display[i]) == 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(unit, op, new_data, 1);}static inline int fbcon_set_def_font(int unit, struct console_font_op *op){ char name[MAX_FONT_NAME]; struct fbcon_font_desc *f; struct display *p = &fb_display[unit]; if (!op->data) f = fbcon_get_default_font(p->var.xres, p->var.yres); else if (strncpy_from_user(name, op->data, MAX_FONT_NAME-1) < 0) return -EFAULT; else { name[MAX_FONT_NAME-1] = 0; if (!(f = fbcon_find_font(name))) return -ENOENT; } op->width = f->width; op->height = f->height; return fbcon_do_set_font(unit, op, f->data, 0);}static int fbcon_font_op(struct vc_data *conp, struct console_font_op *op){ int unit = conp->vc_num; switch (op->op) { case KD_FONT_OP_SET: return fbcon_set_font(unit, op); case KD_FONT_OP_GET: return fbcon_get_font(unit, op); case KD_FONT_OP_SET_DEFAULT: return fbcon_set_def_font(unit, op); case KD_FONT_OP_COPY: return fbcon_copy_font(unit, op); default: return -ENOSYS; }}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 *conp, unsigned char *table){ int unit = conp->vc_num; struct display *p = &fb_display[unit]; int i, j, k; u8 val; if (!conp->vc_can_do_color || (!p->can_soft_blank && console_blanked)) return -EINVAL; for (i = j = 0; i < 16; i++) { k = table[i]; val = conp->vc_palette[j++]; palette_red[k] = (val<<8)|val; val = conp->vc_palette[j++]; palette_green[k] = (val<<8)|val; val = conp->vc_palette[j++]; palette_blue[k] = (val<<8)|val; } if (p->var.bits_per_pixel <= 4) palette_cmap.len = 1<<p->var.bits_per_pixel; else palette_cmap.len = 16; palette_cmap.start = 0; return p->fb_info->fbops->fb_set_cmap(&palette_cmap, 1, unit, p->fb_info);}static u16 *fbcon_screen_pos(struct vc_data *conp, int offset){ int line; unsigned long p; if (conp->vc_num != fg_console || !softback_lines) return (u16 *)(conp->vc_origin + offset); line = offset / conp->vc_size_row; if (line >= softback_lines) return (u16 *)(conp->vc_origin + offset - softback_lines * conp->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 *conp, unsigned long pos, int *px, int *py){ int x, y; unsigned long ret; if (pos >= conp->vc_origin && pos < conp->vc_scr_end) { unsigned long offset = (pos - conp->vc_origin) / 2; x = offset % conp->vc_cols; y = offset / conp->vc_cols; if (conp->vc_num == fg_console) y += softback_lines; ret = pos + (conp->vc_cols - x) * 2; } else if (conp->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 % conp->vc_cols; y = offset / conp->vc_cols; ret = pos + (conp->vc_cols - x) * 2; if (ret == softback_end) ret = softback_buf; if (ret == softback_in) ret = conp->vc_origin; } else { /* Should not happen */ x = y = 0; ret = conp->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 *conp, u16 *p, int cnt){ while (cnt--) { u16 a = scr_readw(p); if (!conp->vc_can_do_color) a ^= 0x0800; else if (conp->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 *)conp->vc_origin; }}static int fbcon_scrolldelta(struct vc_data *conp, int lines){ int unit, offset, limit, scrollback_old; struct display *p; unit = fg_console; p = &fb_display[unit]; if (softback_top) { if (conp->vc_num != unit) return 0; if (vt_cons[unit]->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 == unit) { unsigned long p, q; int i; p = softback_in; q = conp->vc_origin + logo_lines * conp->vc_size_row; for (i = 0; i < logo_lines; i++) { if (p == softback_top) break; if (p == softback_buf) p = softback_end; p -= conp->vc_size_row; q -= conp->vc_size_row; scr_memcpyw((u16 *)q, (u16 *)p, conp->vc_size_row); } softback_in = p; update_region(unit, conp->vc_origin, logo_lines * conp->vc_cols); } logo_shown = -1; } fbcon_cursor(conp, CM_ERASE|CM_SOFTBACK); fbcon_redraw_softback(conp, p, lines); fbcon_cursor(conp, CM_DRAW|CM_SOFTBACK); return 0; } if (!scrollback_phys_max) return -ENOSYS; scrollback_old = scrollback_current; scrollback_current -= lines; if (scrollback_current < 0) scrollback_current = 0; else if (scrollback_current > scrollback_max) scrollback_current = scrollback_max; if (scrollback_current == scrollback_old) return 0; if (!p->can_soft_blank && (console_blanked || vt_cons[unit]->vc_mode != KD_TEXT || !lines)) return 0; fbcon_cursor(conp, CM_ERASE); offset = p->yscroll-scrollback_current; limit = p->vrows; switch (p->scrollmode && __SCROLL_YMASK) { case __SCROLL_YWRAP: p->var.vmode |= FB_VMODE_YWRAP; break; case __SCROLL_YPAN: limit -= conp->vc_rows; p->var.vmode &= ~FB_VMODE_YWRAP; break; } if (offset < 0) offset += limit; else if (offset >= limit) offset -= limit; p->var.xoffset = 0; p->var.yoffset = offset*fontheight(p); p->fb_info->updatevar(unit, p->fb_info); if (!scrollback_current) fbcon_cursor(conp, CM_DRAW); return 0;}static int fbcon_set_origin(struct vc_data *conp){ if (softback_lines && !console_blanked) fbcon_scrolldelta(conp, softback_lines); return 0;}static inline unsigned safe_shift(unsigned d,int n){ return n<0 ? d>>-n : d<<n;}static int __init fbcon_show_logo( void ){ struct display *p = &fb_display[fg_console]; /* draw to vt in foreground */ int depth = p->var.bits_per_pixel; int line = p->next_line; unsigned char *fb = p->screen_base; unsigned char *logo; unsigned char *dst, *src; int i, j, n, x1, y1, x; int logo_depth, done = 0; /* Return if the frame buffer is not mapped */ if (!fb) return 0; /* * Set colors if visual is PSEUDOCOLOR and we have enough colors, or for * DIRECTCOLOR * We don't have to set the colors for the 16-color logo, since that logo * uses the standard VGA text console palette */ if ((p->visual == FB_VISUAL_PSEUDOCOLOR && depth >= 8) || (p->visual == FB_VISUAL_DIRECTCOLOR && depth >= 24)) for (i = 0; i < LINUX_LOGO_COLORS; i += n) { n = LINUX_LOGO_COLORS - i; if (n > 16) /* palette_cmap provides space for only 16 colors at once */ n = 16; palette_cmap.start = 32 + i; palette_cmap.len = n; for( j = 0; j < n; ++j ) { palette_cmap.red[j] = (linux_logo_red[i+j] << 8) | linux_logo_red[i+j]; palette_cmap.green[j] = (linux_logo_green[i+j] << 8) | linux_logo_green[i+j]; palette_cmap.blue[j] = (linux_logo_blue[i+j] << 8) | linux_logo_blue[i+j]; } p->fb_info->fbops->fb_set_cmap(&palette_cmap, 1, fg_console, p->fb_info); } if (depth >= 8) { logo = linux_logo; logo_depth = 8; } else if (depth >= 4) { logo = linux_logo16; logo_depth = 4; } else { logo = linux_logo_bw; logo_depth = 1; } if (p->fb_info->fbops->fb_rasterimg) p->fb_info->fbops->fb_rasterimg(p->fb_info, 1); for (x = 0; x < smp_num_cpus * (LOGO_W + 8) && x < p->var.xres - (LOGO_W + 8); x += (LOGO_W + 8)) { #if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || \ defined(CONFIG_FBCON_CFB32) || defined(CONFIG_FB_SBUS) if (p->visual == FB_VISUAL_DIRECTCOLOR) { unsigned int val; /* max. depth 32! */ int bdepth; int redshift, greenshift, blueshift; /* Bug: Doesn't obey msb_right ... (who needs that?) */ redshift = p->var.red.offset; greenshift = p->var.green.offset; blueshift = p->var.blue.offset; if (depth >= 24 && (depth % 8) == 0) { /* have at least 8 bits per color */ src = logo; bdepth = depth/8; for( y1 = 0; y1 < LOGO_H; y1++ ) { dst = fb + y1*line + x*bdepth; for( x1 = 0; x1 < LOGO_W; x1++, src++ ) { val = (*src << redshift) | (*src << greenshift) | (*src << blueshift); if (bdepth == 4 && !((long)dst & 3)) { /* Some cards require 32bit access */ fb_writel (val, dst); dst += 4; } else if (bdepth == 2 && !((long)dst & 1)) { /* others require 16bit access */ fb_writew (val,dst); dst +=2; } else {#ifdef __LITTLE_ENDIAN for( i = 0; i < bdepth; ++i )#else for( i = bdepth-1; i >= 0; --i )#endif fb_writeb (val >> (i*8), dst++); } } } } else if (depth >= 12 && depth <= 23) { /* have 4..7 bits per color, using 16 color image */ unsigned int pix; src = linux_logo16; bdepth = (depth+7)/8; for( y1 = 0; y1 < LOGO_H; y1++ ) { dst = fb + y1*line + x*bdepth; for( x1 = 0; x1 < LOGO_W/2; x1++, src++ ) { pix = *src >> 4; /* upper nibble */ val = (pix << redshift) | (pix << greenshift) | (pix << blueshift);#ifdef __LITTLE_ENDIAN for( i = 0; i < bdepth; ++i )#else for( i = bdepth-1; i >= 0; --i )#endif fb_writeb (val >> (i*8), dst++); pix = *src & 0x0f; /* lower nibble */ val = (pix << redshift) | (pix << greenshift) | (pix << blueshift);#ifdef __LITTLE_ENDIAN for( i = 0; i < bdepth; ++i )#else for( i = bdepth-1; i >= 0; --i )#endif fb_writeb (val >> (i*8), dst++); } } } done = 1; }#endif#if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || \ defined(CONFIG_FBCON_CFB32) || defined(CONFIG_FB_SBUS) if ((depth % 8 == 0) && (p->visual == FB_VISUAL_TRUECOLOR)) { /* Modes without color mapping, needs special data transformation... */ unsigned int val; /* max. depth 32! */ int bdepth = depth/8; unsigned char mask[9] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff }; unsigned char redmask, greenmask, bluemask; int redshift, greenshift, blueshift; /* Bug: Doesn't obey msb_right ... (who needs that?) */ redmask = mask[p->var.red.length < 8 ? p->var.red.length : 8]; greenmask = mask[p->var.green.length < 8 ? p->var.green.length : 8]; bluemask = mask[p->var.blue.length < 8 ? p->var.blue.length : 8]; redshift = p->var.red.offset - (8-p->var.red.length); greenshift = p->var.green.offset - (8-p->var.green.length); blueshift = p->var.blue.offset - (8-p->var.blue.length); src = logo; for( y1 = 0; y1 < LOGO_H; y1++ ) { dst = fb + y1*line + x*bdepth; for( x1 = 0; x1 < LOGO_W; x1++, src++ ) { val = safe_shift((linux_logo_red[*src-32] & redmask), redshift) | safe_shift((linux_logo_green[*src-32] & greenmask), greenshift) | safe_shift((linux_logo_blue[*src-32] & bluemask), blueshift); if (bdepth == 4 && !((long)dst & 3)) { /* Some cards require 32bit access */ fb_writel (val, dst); dst += 4; } else if (bdepth == 2 && !((long)dst & 1)) { /* others require 16bit access */ fb_writew (val,dst); dst +=2; } else {#ifdef __LITTLE_ENDIAN for( i = 0; i < bdepth; ++i )#else for( i = bdepth-1; i >= 0; --i )#endif fb_writeb (val >> (i*8), dst++); } } } done = 1; }#endif#if defined(CONFIG_FBCON_CFB4) if (depth == 4 && p->type == FB_TYPE_PACKED_PIXELS) { src = logo; for( y1 =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -