fbcon.c

来自「Linux环境下视频显示卡设备的驱动程序源代码」· C语言 代码 · 共 2,542 行 · 第 1/5 页

C
2,542
字号
			retval = 1;	}	return retval;}static int search_for_mapped_con(void){	int i, retval = 0;	for (i = first_fb_vc; i <= last_fb_vc; i++) {		if (con2fb_map[i] != -1)			retval = 1;	}	return retval;}static int fbcon_takeover(int show_logo){	int err, i;	if (!num_registered_fb)		return -ENODEV;	if (!show_logo)		logo_shown = FBCON_LOGO_DONTSHOW;	for (i = first_fb_vc; i <= last_fb_vc; i++)		con2fb_map[i] = info_idx;	err = take_over_console(&fb_con, first_fb_vc, last_fb_vc,				fbcon_is_default);	if (err) {		for (i = first_fb_vc; i <= last_fb_vc; i++) {			con2fb_map[i] = -1;		}		info_idx = -1;	}	return err;}#ifdef MODULEstatic void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,			       int cols, int rows, int new_cols, int new_rows){	logo_shown = FBCON_LOGO_DONTSHOW;}#elsestatic void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,			       int cols, int rows, int new_cols, int new_rows){	/* Need to make room for the logo */	struct fbcon_ops *ops = info->fbcon_par;	int cnt, erase = vc->vc_video_erase_char, step;	unsigned short *save = NULL, *r, *q;	int logo_height;	if (info->flags & FBINFO_MODULE) {		logo_shown = FBCON_LOGO_DONTSHOW;		return;	}	/*	 * remove underline attribute from erase character	 * if black and white framebuffer.	 */	if (fb_get_color_depth(&info->var, &info->fix) == 1)		erase &= ~0x400;	logo_height = fb_prepare_logo(info, ops->rotate);	logo_lines = DIV_ROUND_UP(logo_height, vc->vc_font.height);	q = (unsigned short *) (vc->vc_origin +				vc->vc_size_row * rows);	step = logo_lines * cols;	for (r = q - logo_lines * cols; r < q; r++)		if (scr_readw(r) != vc->vc_video_erase_char)			break;	if (r != q && new_rows >= rows + logo_lines) {		save = kmalloc(logo_lines * new_cols * 2, GFP_KERNEL);		if (save) {			int i = cols < new_cols ? cols : new_cols;			scr_memsetw(save, erase, logo_lines * new_cols * 2);			r = q - step;			for (cnt = 0; cnt < logo_lines; cnt++, r += i)				scr_memcpyw(save + cnt * new_cols, r, 2 * i);			r = q;		}	}	if (r == q) {		/* We can scroll screen down */		r = q - step - cols;		for (cnt = rows - logo_lines; cnt > 0; cnt--) {			scr_memcpyw(r + step, r, vc->vc_size_row);			r -= cols;		}		if (!save) {			int lines;			if (vc->vc_y + logo_lines >= rows)				lines = rows - vc->vc_y - 1;			else				lines = logo_lines;			vc->vc_y += lines;			vc->vc_pos += lines * vc->vc_size_row;		}	}	scr_memsetw((unsigned short *) vc->vc_origin,		    erase,		    vc->vc_size_row * logo_lines);	if (CON_IS_VISIBLE(vc) && vc->vc_mode == KD_TEXT) {		fbcon_clear_margins(vc, 0);		update_screen(vc);	}	if (save) {		q = (unsigned short *) (vc->vc_origin +					vc->vc_size_row *					rows);		scr_memcpyw(q, save, logo_lines * new_cols * 2);		vc->vc_y += logo_lines;		vc->vc_pos += logo_lines * vc->vc_size_row;		kfree(save);	}	if (logo_lines > vc->vc_bottom) {		logo_shown = FBCON_LOGO_CANSHOW;		printk(KERN_INFO		       "fbcon_init: disable boot-logo (boot-logo bigger than screen).\n");	} else if (logo_shown != FBCON_LOGO_DONTSHOW) {		logo_shown = FBCON_LOGO_DRAW;		vc->vc_top = logo_lines;	}}#endif /* MODULE */#ifdef CONFIG_FB_TILEBLITTINGstatic void set_blitting_type(struct vc_data *vc, struct fb_info *info){	struct fbcon_ops *ops = info->fbcon_par;	ops->p = &fb_display[vc->vc_num];	if ((info->flags & FBINFO_MISC_TILEBLITTING))		fbcon_set_tileops(vc, info);	else {		fbcon_set_rotation(info);		fbcon_set_bitops(ops);	}}static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount){	int err = 0;	if (info->flags & FBINFO_MISC_TILEBLITTING &&	    info->tileops->fb_get_tilemax(info) < charcount)		err = 1;	return err;}#elsestatic void set_blitting_type(struct vc_data *vc, struct fb_info *info){	struct fbcon_ops *ops = info->fbcon_par;	info->flags &= ~FBINFO_MISC_TILEBLITTING;	ops->p = &fb_display[vc->vc_num];	fbcon_set_rotation(info);	fbcon_set_bitops(ops);}static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount){	return 0;}#endif /* CONFIG_MISC_TILEBLITTING */static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info,				  int unit, int oldidx){	struct fbcon_ops *ops = NULL;	int err = 0;	if (!try_module_get(info->fbops->owner))		err = -ENODEV;	if (!err && info->fbops->fb_open &&	    info->fbops->fb_open(info, 0))		err = -ENODEV;	if (!err) {		ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);		if (!ops)			err = -ENOMEM;	}	if (!err) {		info->fbcon_par = ops;		if (vc)			set_blitting_type(vc, info);	}	if (err) {		con2fb_map[unit] = oldidx;		module_put(info->fbops->owner);	}	return err;}static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo,				  struct fb_info *newinfo, int unit,				  int oldidx, int found){	struct fbcon_ops *ops = oldinfo->fbcon_par;	int err = 0;	if (oldinfo->fbops->fb_release &&	    oldinfo->fbops->fb_release(oldinfo, 0)) {		con2fb_map[unit] = oldidx;		if (!found && newinfo->fbops->fb_release)			newinfo->fbops->fb_release(newinfo, 0);		if (!found)			module_put(newinfo->fbops->owner);		err = -ENODEV;	}	if (!err) {		fbcon_del_cursor_timer(oldinfo);		kfree(ops->cursor_state.mask);		kfree(ops->cursor_data);		kfree(ops->fontbuffer);		kfree(oldinfo->fbcon_par);		oldinfo->fbcon_par = NULL;		module_put(oldinfo->fbops->owner);		/*		  If oldinfo and newinfo are driving the same hardware,		  the fb_release() method of oldinfo may attempt to		  restore the hardware state.  This will leave the		  newinfo in an undefined state. Thus, a call to		  fb_set_par() may be needed for the newinfo.		*/		if (newinfo->fbops->fb_set_par)			newinfo->fbops->fb_set_par(newinfo);	}	return err;}static void con2fb_init_display(struct vc_data *vc, struct fb_info *info,				int unit, int show_logo){	struct fbcon_ops *ops = info->fbcon_par;	ops->currcon = fg_console;	if (info->fbops->fb_set_par && !(ops->flags & FBCON_FLAGS_INIT))		info->fbops->fb_set_par(info);	ops->flags |= FBCON_FLAGS_INIT;	ops->graphics = 0;	fbcon_set_disp(info, &info->var, unit);	if (show_logo) {		struct vc_data *fg_vc = vc_cons[fg_console].d;		struct fb_info *fg_info =			registered_fb[con2fb_map[fg_console]];		fbcon_prepare_logo(fg_vc, fg_info, fg_vc->vc_cols,				   fg_vc->vc_rows, fg_vc->vc_cols,				   fg_vc->vc_rows);	}	update_screen(vc_cons[fg_console].d);}/** *	set_con2fb_map - map console to frame buffer device *	@unit: virtual console number to map *	@newidx: frame buffer index to map virtual console to *      @user: user request * *	Maps a virtual console @unit to a frame buffer device *	@newidx. */static int set_con2fb_map(int unit, int newidx, int user){	struct vc_data *vc = vc_cons[unit].d;	int oldidx = con2fb_map[unit];	struct fb_info *info = registered_fb[newidx];	struct fb_info *oldinfo = NULL; 	int found, err = 0;	if (oldidx == newidx)		return 0;	if (!info || fbcon_has_exited)		return -EINVAL; 	if (!err && !search_for_mapped_con()) {		info_idx = newidx;		return fbcon_takeover(0);	}	if (oldidx != -1)		oldinfo = registered_fb[oldidx];	found = search_fb_in_map(newidx);	acquire_console_sem();	con2fb_map[unit] = newidx;	if (!err && !found) 		err = con2fb_acquire_newinfo(vc, info, unit, oldidx);	/*	 * If old fb is not mapped to any of the consoles,	 * fbcon should release it.	 */ 	if (!err && oldinfo && !search_fb_in_map(oldidx)) 		err = con2fb_release_oldinfo(vc, oldinfo, info, unit, oldidx, 					     found); 	if (!err) { 		int show_logo = (fg_console == 0 && !user && 				 logo_shown != FBCON_LOGO_DONTSHOW); 		if (!found) 			fbcon_add_cursor_timer(info); 		con2fb_map_boot[unit] = newidx; 		con2fb_init_display(vc, info, unit, show_logo);	}	if (!search_fb_in_map(info_idx))		info_idx = newidx;	release_console_sem(); 	return err;}/* *  Low Level Operations *//* NOTE: fbcon cannot be __init: it may be called from take_over_console later */static int var_to_display(struct display *disp,			  struct fb_var_screeninfo *var,			  struct fb_info *info){	disp->xres_virtual = var->xres_virtual;	disp->yres_virtual = var->yres_virtual;	disp->bits_per_pixel = var->bits_per_pixel;	disp->grayscale = var->grayscale;	disp->nonstd = var->nonstd;	disp->accel_flags = var->accel_flags;	disp->height = var->height;	disp->width = var->width;	disp->red = var->red;	disp->green = var->green;	disp->blue = var->blue;	disp->transp = var->transp;	disp->rotate = var->rotate;	disp->mode = fb_match_mode(var, &info->modelist);	if (disp->mode == NULL)		/* This should not happen */		return -EINVAL;	return 0;}static void display_to_var(struct fb_var_screeninfo *var,			   struct display *disp){	fb_videomode_to_var(var, disp->mode);	var->xres_virtual = disp->xres_virtual;	var->yres_virtual = disp->yres_virtual;	var->bits_per_pixel = disp->bits_per_pixel;	var->grayscale = disp->grayscale;	var->nonstd = disp->nonstd;	var->accel_flags = disp->accel_flags;	var->height = disp->height;	var->width = disp->width;	var->red = disp->red;	var->green = disp->green;	var->blue = disp->blue;	var->transp = disp->transp;	var->rotate = disp->rotate;}static const char *fbcon_startup(void){	const char *display_desc = "frame buffer device";	struct display *p = &fb_display[fg_console];	struct vc_data *vc = vc_cons[fg_console].d;	const struct font_desc *font = NULL;	struct module *owner;	struct fb_info *info = NULL;	struct fbcon_ops *ops;	int rows, cols;	/*	 *  If num_registered_fb is zero, this is a call for the dummy part.	 *  The frame buffer devices weren't initialized yet.	 */	if (!num_registered_fb || info_idx == -1)		return display_desc;	/*	 * Instead of blindly using registered_fb[0], we use info_idx, set by	 * fb_console_init();	 */	info = registered_fb[info_idx];	if (!info)		return NULL;		owner = info->fbops->owner;	if (!try_module_get(owner))		return NULL;	if (info->fbops->fb_open && info->fbops->fb_open(info, 0)) {		module_put(owner);		return NULL;	}	ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);	if (!ops) {		module_put(owner);		return NULL;	}	ops->currcon = -1;	ops->graphics = 1;	ops->cur_rotate = -1;	info->fbcon_par = ops;	p->con_rotate = initial_rotation;	set_blitting_type(vc, info);	if (info->fix.type != FB_TYPE_TEXT) {		if (fbcon_softback_size) {			if (!softback_buf) {				softback_buf =				    (unsigned long)				    kmalloc(fbcon_softback_size,					    GFP_KERNEL);				if (!softback_buf) {					fbcon_softback_size = 0;					softback_top = 0;				}			}		} else {			if (softback_buf) {				kfree((void *) softback_buf);				softback_buf = 0;				softback_top = 0;			}		}		if (softback_buf)			softback_in = softback_top = softback_curr =			    softback_buf;		softback_lines = 0;	}	/* Setup default font */	if (!p->fontdata) {		if (!fontname[0] || !(font = find_font(fontname)))			font = get_default_font(info->var.xres,						info->var.yres,						info->pixmap.blit_x,						info->pixmap.blit_y);		vc->vc_font.width = font->width;		vc->vc_font.height = font->height;		vc->vc_font.data = (void *)(p->fontdata = font->data);		vc->vc_font.charcount = 256; /* FIXME  Need to support more fonts */	}	cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);	rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);	cols /= vc->vc_font.width;	rows /= vc->vc_font.height;	vc_resize(vc, cols, rows);	DPRINTK("mode:   %s\n", info->fix.id);	DPRINTK("visual: %d\n", info->fix.visual);	DPRINTK("res:    %dx%d-%d\n", info->var.xres,		info->var.yres,		info->var.bits_per_pixel);	fbcon_add_cursor_timer(info);	fbcon_has_exited = 0;	return display_desc;}static void fbcon_init(struct vc_data *vc, int init){	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];	struct fbcon_ops *ops;	struct vc_data **default_mode = vc->vc_display_fg;	struct vc_data *svc = *default_mode;	struct display *t, *p = &fb_display[vc->vc_num];	int logo = 1, new_rows, new_cols, rows, cols, charcnt = 256;	int cap;	if (info_idx == -1 || info == NULL)	    return;	cap = info->flags;	if (vc != svc || logo_shown == FBCON_LOGO_DONTSHOW ||	    (info->fix.type == FB_TYPE_TEXT))		logo = 0;

⌨️ 快捷键说明

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