📄 fbcon.c
字号:
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--) { if (!conp->vc_can_do_color) *p++ ^= 0x0800; else if (conp->vc_hi_font_mask == 0x100) { u16 a = *p; a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4); *p++ = a; } else { u16 a = *p; a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4); *p++ = a; } 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 */ if ((p->visual == FB_VISUAL_PSEUDOCOLOR && depth >= 4) || p->visual == FB_VISUAL_DIRECTCOLOR) { int is_truecolor = (p->visual == FB_VISUAL_DIRECTCOLOR); int use_256 = (!is_truecolor && depth >= 8) || (is_truecolor && depth >= 24); int first_col = use_256 ? 32 : depth > 4 ? 16 : 0; int num_cols = use_256 ? LINUX_LOGO_COLORS : 16; unsigned char *red, *green, *blue; if (use_256) { red = linux_logo_red; green = linux_logo_green; blue = linux_logo_blue; } else { red = linux_logo16_red; green = linux_logo16_green; blue = linux_logo16_blue; } for( i = 0; i < num_cols; i += n ) { n = num_cols - i; if (n > 16) /* palette_cmap provides space for only 16 colors at once */ n = 16; palette_cmap.start = first_col + i; palette_cmap.len = n; for( j = 0; j < n; ++j ) { palette_cmap.red[j] = (red[i+j] << 8) | red[i+j]; palette_cmap.green[j] = (green[i+j] << 8) | green[i+j]; palette_cmap.blue[j] = (blue[i+j] << 8) | 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 {#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 >= 15 && depth <= 23) { /* have 5..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) | 0x10; /* 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) | 0x10; /* 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 {#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 = 0; y1 < LOGO_H; y1++) { dst = fb + y1*line + x/2; for( x1 = 0; x1 < LOGO_W/2; x1++) { u8 q = *src++; q = (q << 4) | (q >> 4); fb_writeb (q, dst++); } } done = 1; }#endif#if defined(CONFIG_FBCON_CFB8) || defined(CONFIG_FB_SBUS) if (depth == 8 && p->type == FB_TYPE_PACKED_PIXELS) { /* depth 8 or more, packed, with color registers */ src = logo; for( y1 = 0; y1 < LOGO_H; y1++ ) { dst = fb + y1*line + x; for( x1 = 0; x1 < LOGO_W; x1++ ) fb_writeb (*src++, dst++); } done = 1; }#endif#if defined(CONFIG_FBCON_AFB) || defined(CONFIG_FBCON_ILBM) || \ defined(CONFIG_FBCON_IPLAN2P2) || defined(CONFIG_FBCON_IPLAN2P4) || \ defined(CONFIG_FBCON_IPLAN2P8) if (depth >= 2 && (p->type == FB_TYPE_PLANES || p->type == FB_TYPE_INTERLEAVED_PLANES)) { /* planes (normal or interleaved), with color registers */ int bit; unsigned char val, mask; int plane = p->next_plane;#if defined(CONFIG_FBCON_IPLAN2P2) || defined(CONFIG_FBCON_IPLAN2P4) || \ defined(CONFIG_FBCON_IPLAN2P8) int line_length = p->line_length; /* for support of Atari interleaved planes */#define MAP_X(x) (line_length ? (x) : ((x) & ~1)*depth + ((x) & 1))#else#define MAP_X(x) (x)#endif /* extract a bit from the source image */#define BIT(p,pix,bit) (p[pix*logo_depth/8] & \ (1 << ((8-((pix*logo_depth)&7)-logo_depth) + bit))) src = logo; for( y1 = 0; y1 < LOGO_H; y1++ ) { for( x1 = 0; x1 < LOGO_LINE; x1++, src += logo_depth ) { dst = fb + y1*line + MAP_X(x/8+x1); for( bit = 0; bit < logo_depth; bit++ ) { val = 0; for( mask = 0x80, i = 0; i < 8; mask >>= 1, i++ ) { if (BIT( src, i, bit )) val |= mask; } *dst = val; dst += plane; } } } /* fill remaining planes * special case for logo_depth == 4: we used color registers 16..31, * so fill plane 4 with 1 bits instead of 0 */ if (depth > logo_depth) { for( y1 = 0; y1 < LOGO_H; y1++ ) { for( x1 = 0; x1 < LOGO_LINE; x1++ ) { dst = fb + y1*line + MAP_X(x/8+x1) + logo_depth*plane; for( i = logo_depth; i < depth; i++, dst += plane ) *dst = (i == logo_depth && logo_depth == 4) ? 0xff : 0x00; } } } done = 1; break; }#endif#if defined(CONFIG_FBCON_MFB) || defined(CONFIG_FBCON_AFB) || \ defined(CONFIG_FBCON
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -