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 + -
显示快捷键?