⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fbcon.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	int good_pan = (cap & FBINFO_HWACCEL_YPAN) &&		divides(ypan, vc->vc_font.height) && vyres > yres;	int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) &&		divides(ywrap, vc->vc_font.height) &&		divides(vc->vc_font.height, vyres) &&		divides(vc->vc_font.height, yres);	int reading_fast = cap & FBINFO_READS_FAST;	int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) &&		!(cap & FBINFO_HWACCEL_DISABLED);	int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) &&		!(cap & FBINFO_HWACCEL_DISABLED);	p->vrows = vyres/fh;	if (yres > (fh * (vc->vc_rows + 1)))		p->vrows -= (yres - (fh * vc->vc_rows)) / fh;	if ((yres % fh) && (vyres % fh < yres % fh))		p->vrows--;	if (good_wrap || good_pan) {		if (reading_fast || fast_copyarea)			p->scrollmode = good_wrap ?				SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE;		else			p->scrollmode = good_wrap ? SCROLL_REDRAW :				SCROLL_PAN_REDRAW;	} else {		if (reading_fast || (fast_copyarea && !fast_imageblit))			p->scrollmode = SCROLL_MOVE;		else			p->scrollmode = SCROLL_REDRAW;	}}static int fbcon_resize(struct vc_data *vc, unsigned int width, 			unsigned int height, unsigned int user){	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];	struct fbcon_ops *ops = info->fbcon_par;	struct display *p = &fb_display[vc->vc_num];	struct fb_var_screeninfo var = info->var;	int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh;	virt_w = FBCON_SWAP(ops->rotate, width, height);	virt_h = FBCON_SWAP(ops->rotate, height, width);	virt_fw = FBCON_SWAP(ops->rotate, vc->vc_font.width,				 vc->vc_font.height);	virt_fh = FBCON_SWAP(ops->rotate, vc->vc_font.height,				 vc->vc_font.width);	var.xres = virt_w * virt_fw;	var.yres = virt_h * virt_fh;	x_diff = info->var.xres - var.xres;	y_diff = info->var.yres - var.yres;	if (x_diff < 0 || x_diff > virt_fw ||	    y_diff < 0 || y_diff > virt_fh) {		const struct fb_videomode *mode;		DPRINTK("attempting resize %ix%i\n", var.xres, var.yres);		mode = fb_find_best_mode(&var, &info->modelist);		if (mode == NULL)			return -EINVAL;		display_to_var(&var, p);		fb_videomode_to_var(&var, mode);		if (virt_w > var.xres/virt_fw || virt_h > var.yres/virt_fh)			return -EINVAL;		DPRINTK("resize now %ix%i\n", var.xres, var.yres);		if (CON_IS_VISIBLE(vc)) {			var.activate = FB_ACTIVATE_NOW |				FB_ACTIVATE_FORCE;			fb_set_var(info, &var);		}		var_to_display(p, &info->var, info);		ops->var = info->var;	}	updatescrollmode(p, info, vc);	return 0;}static int fbcon_switch(struct vc_data *vc){	struct fb_info *info, *old_info = NULL;	struct fbcon_ops *ops;	struct display *p = &fb_display[vc->vc_num];	struct fb_var_screeninfo var;	int i, prev_console, charcnt = 256;	info = registered_fb[con2fb_map[vc->vc_num]];	ops = info->fbcon_par;	if (softback_top) {		if (softback_lines)			fbcon_set_origin(vc);		softback_top = softback_curr = softback_in = softback_buf;		softback_lines = 0;		fbcon_update_softback(vc);	}	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;		logo_shown = FBCON_LOGO_CANSHOW;	}	prev_console = ops->currcon;	if (prev_console != -1)		old_info = registered_fb[con2fb_map[prev_console]];	/*	 * FIXME: If we have multiple fbdev's loaded, we need to	 * update all info->currcon.  Perhaps, we can place this	 * in a centralized structure, but this might break some	 * drivers.	 *	 * info->currcon = vc->vc_num;	 */	for (i = 0; i < FB_MAX; i++) {		if (registered_fb[i] != NULL && registered_fb[i]->fbcon_par) {			struct fbcon_ops *o = registered_fb[i]->fbcon_par;			o->currcon = vc->vc_num;		}	}	memset(&var, 0, sizeof(struct fb_var_screeninfo));	display_to_var(&var, p);	var.activate = FB_ACTIVATE_NOW;	/*	 * make sure we don't unnecessarily trip the memcmp()	 * in fb_set_var()	 */	info->var.activate = var.activate;	var.vmode |= info->var.vmode & ~FB_VMODE_MASK;	fb_set_var(info, &var);	ops->var = info->var;	if (old_info != NULL && (old_info != info ||				 info->flags & FBINFO_MISC_ALWAYS_SETPAR)) {		if (info->fbops->fb_set_par)			info->fbops->fb_set_par(info);		if (old_info != info)			fbcon_del_cursor_timer(old_info);	}	if (fbcon_is_inactive(vc, info) ||	    ops->blank_state != FB_BLANK_UNBLANK)		fbcon_del_cursor_timer(info);	else		fbcon_add_cursor_timer(info);	set_blitting_type(vc, info);	ops->cursor_reset = 1;	if (ops->rotate_font && ops->rotate_font(info, vc)) {		ops->rotate = FB_ROTATE_UR;		set_blitting_type(vc, info);	}	vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1);	vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;	if (p->userfont)		charcnt = FNTCHARCNT(vc->vc_font.data);	if (charcnt > 256)		vc->vc_complement_mask <<= 1;	updatescrollmode(p, info, vc);	switch (p->scrollmode) {	case SCROLL_WRAP_MOVE:		scrollback_phys_max = p->vrows - vc->vc_rows;		break;	case SCROLL_PAN_MOVE:	case SCROLL_PAN_REDRAW:		scrollback_phys_max = p->vrows - 2 * vc->vc_rows;		if (scrollback_phys_max < 0)			scrollback_phys_max = 0;		break;	default:		scrollback_phys_max = 0;		break;	}	scrollback_max = 0;	scrollback_current = 0;	if (!fbcon_is_inactive(vc, info)) {	    ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;	    ops->update_start(info);	}	fbcon_set_palette(vc, color_table); 		fbcon_clear_margins(vc, 0);	if (logo_shown == FBCON_LOGO_DRAW) {		logo_shown = fg_console;		/* This is protected above by initmem_freed */		fb_show_logo(info, ops->rotate);		update_region(vc,			      vc->vc_origin + vc->vc_size_row * vc->vc_top,			      vc->vc_size_row * (vc->vc_bottom -						 vc->vc_top) / 2);		return 0;	}	return 1;}static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info,				int blank){	struct fb_event event;	if (blank) {		unsigned short charmask = vc->vc_hi_font_mask ?			0x1ff : 0xff;		unsigned short oldc;		oldc = vc->vc_video_erase_char;		vc->vc_video_erase_char &= charmask;		fbcon_clear(vc, 0, 0, vc->vc_rows, vc->vc_cols);		vc->vc_video_erase_char = oldc;	}	event.info = info;	event.data = &blank;	fb_notifier_call_chain(FB_EVENT_CONBLANK, &event);}static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch){	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];	struct fbcon_ops *ops = info->fbcon_par;	if (mode_switch) {		struct fb_var_screeninfo var = info->var;		ops->graphics = 1;		if (!blank) {			if (info->fbops->fb_save_state)				info->fbops->fb_save_state(info);			var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;			fb_set_var(info, &var);			ops->graphics = 0;			ops->var = info->var;		} else if (info->fbops->fb_restore_state)			info->fbops->fb_restore_state(info);	} 	if (!fbcon_is_inactive(vc, info)) {		if (ops->blank_state != blank) {			ops->blank_state = blank;			fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW);			ops->cursor_flash = (!blank);			if (!(info->flags & FBINFO_MISC_USEREVENT))				if (fb_blank(info, blank))					fbcon_generic_blank(vc, info, blank);		}		if (!blank)			update_screen(vc);	}	if (mode_switch || fbcon_is_inactive(vc, info) ||	    ops->blank_state != FB_BLANK_UNBLANK)		fbcon_del_cursor_timer(info);	else		fbcon_add_cursor_timer(info);	return 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,			     const u8 * data, int userfont){	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];	struct fbcon_ops *ops = info->fbcon_par;	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 = (void *)(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) {		int cols, rows;		cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);		rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);		cols /= w;		rows /= h;		vc_resize(vc, cols, rows);		if (CON_IS_VISIBLE(vc) && softback_buf)			fbcon_update_softback(vc);	} else if (CON_IS_VISIBLE(vc)		   && vc->vc_mode == KD_TEXT) {		fbcon_clear_margins(vc, 0);		update_screen(vc);	}	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 *  but lets not assume that, since someone might someday want to use larger *  fonts. And charcount of 512 is small for unicode support. * *  However, user space gives the font in 32 rows , regardless of *  actual font height. So a new API is needed if support for larger fonts *  is ever implemented. */static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigned flags){	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];	unsigned charcount = font->charcount;	int w = font->width;	int h = font->height;	int size;	int i, csum;	u8 *new_data, *data = font->data;	int pitch = (font->width+7) >> 3;	/* Is there a reason why fbconsole couldn't handle any charcount >256?	 * If not this check should be changed to charcount < 256 */	if (charcount != 256 && charcount != 512)		return -EINVAL;	/* Make sure drawing engine can handle the font */	if (!(info->pixmap.blit_x & (1 << (font->width - 1))) ||	    !(info->pixmap.blit_y & (1 << (font->height - 1))))		return -EINVAL;	/* Make sure driver can handle the font length */	if (fbcon_invalid_charcount(info, charcount))		return -EINVAL;	size = h * pitch * 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 */	for (i=0; i< charcount; i++) {		memcpy(new_data + i*h*pitch, data +  i*32*pitch, h*pitch);	}	/* Since linux has a nice crc32 function use it for counting font	 * checksums. */	csum = crc32(0, new_data, size);	FNTSUM(new_data) = csum;	/* Check if the same font is on some other console already */	for (i = first_fb_vc; i <= last_fb_vc; i++) {		struct vc_data *tmp = vc_cons[i].d;				if (fb_display[i].userfont

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -