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

📄 xen-fbfront.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Xen para-virtual frame buffer device * * Copyright (C) 2005-2006 Anthony Liguori <aliguori@us.ibm.com> * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> * *  Based on linux/drivers/video/q40fb.c * *  This file is subject to the terms and conditions of the GNU General Public *  License. See the file COPYING in the main directory of this archive for *  more details. *//* * TODO: * * Switch to grant tables when they become capable of dealing with the * frame buffer. */#include <linux/console.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/fb.h>#include <linux/module.h>#include <linux/vmalloc.h>#include <linux/mm.h>#include <asm/xen/hypervisor.h>#include <xen/events.h>#include <xen/page.h>#include <xen/interface/io/fbif.h>#include <xen/interface/io/protocols.h>#include <xen/xenbus.h>struct xenfb_info {	unsigned char		*fb;	struct fb_info		*fb_info;	int			x1, y1, x2, y2;	/* dirty rectangle,						   protected by dirty_lock */	spinlock_t		dirty_lock;	int			nr_pages;	int			irq;	struct xenfb_page	*page;	unsigned long 		*mfns;	int			update_wanted; /* XENFB_TYPE_UPDATE wanted */	int			feature_resize; /* XENFB_TYPE_RESIZE ok */	struct xenfb_resize	resize;		/* protected by resize_lock */	int			resize_dpy;	/* ditto */	spinlock_t		resize_lock;	struct xenbus_device	*xbdev;};#define XENFB_DEFAULT_FB_LEN (XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8)enum { KPARAM_MEM, KPARAM_WIDTH, KPARAM_HEIGHT, KPARAM_CNT };static int video[KPARAM_CNT] = { 2, XENFB_WIDTH, XENFB_HEIGHT };module_param_array(video, int, NULL, 0);MODULE_PARM_DESC(video,	"Video memory size in MB, width, height in pixels (default 2,800,600)");static void xenfb_make_preferred_console(void);static int xenfb_remove(struct xenbus_device *);static void xenfb_init_shared_page(struct xenfb_info *, struct fb_info *);static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info *);static void xenfb_disconnect_backend(struct xenfb_info *);static void xenfb_send_event(struct xenfb_info *info,			     union xenfb_out_event *event){	u32 prod;	prod = info->page->out_prod;	/* caller ensures !xenfb_queue_full() */	mb();			/* ensure ring space available */	XENFB_OUT_RING_REF(info->page, prod) = *event;	wmb();			/* ensure ring contents visible */	info->page->out_prod = prod + 1;	notify_remote_via_irq(info->irq);}static void xenfb_do_update(struct xenfb_info *info,			    int x, int y, int w, int h){	union xenfb_out_event event;	memset(&event, 0, sizeof(event));	event.type = XENFB_TYPE_UPDATE;	event.update.x = x;	event.update.y = y;	event.update.width = w;	event.update.height = h;	/* caller ensures !xenfb_queue_full() */	xenfb_send_event(info, &event);}static void xenfb_do_resize(struct xenfb_info *info){	union xenfb_out_event event;	memset(&event, 0, sizeof(event));	event.resize = info->resize;	/* caller ensures !xenfb_queue_full() */	xenfb_send_event(info, &event);}static int xenfb_queue_full(struct xenfb_info *info){	u32 cons, prod;	prod = info->page->out_prod;	cons = info->page->out_cons;	return prod - cons == XENFB_OUT_RING_LEN;}static void xenfb_handle_resize_dpy(struct xenfb_info *info){	unsigned long flags;	spin_lock_irqsave(&info->resize_lock, flags);	if (info->resize_dpy) {		if (!xenfb_queue_full(info)) {			info->resize_dpy = 0;			xenfb_do_resize(info);		}	}	spin_unlock_irqrestore(&info->resize_lock, flags);}static void xenfb_refresh(struct xenfb_info *info,			  int x1, int y1, int w, int h){	unsigned long flags;	int x2 = x1 + w - 1;	int y2 = y1 + h - 1;	xenfb_handle_resize_dpy(info);	if (!info->update_wanted)		return;	spin_lock_irqsave(&info->dirty_lock, flags);	/* Combine with dirty rectangle: */	if (info->y1 < y1)		y1 = info->y1;	if (info->y2 > y2)		y2 = info->y2;	if (info->x1 < x1)		x1 = info->x1;	if (info->x2 > x2)		x2 = info->x2;	if (xenfb_queue_full(info)) {		/* Can't send right now, stash it in the dirty rectangle */		info->x1 = x1;		info->x2 = x2;		info->y1 = y1;		info->y2 = y2;		spin_unlock_irqrestore(&info->dirty_lock, flags);		return;	}	/* Clear dirty rectangle: */	info->x1 = info->y1 = INT_MAX;	info->x2 = info->y2 = 0;	spin_unlock_irqrestore(&info->dirty_lock, flags);	if (x1 <= x2 && y1 <= y2)		xenfb_do_update(info, x1, y1, x2 - x1 + 1, y2 - y1 + 1);}static void xenfb_deferred_io(struct fb_info *fb_info,			      struct list_head *pagelist){	struct xenfb_info *info = fb_info->par;	struct page *page;	unsigned long beg, end;	int y1, y2, miny, maxy;	miny = INT_MAX;	maxy = 0;	list_for_each_entry(page, pagelist, lru) {		beg = page->index << PAGE_SHIFT;		end = beg + PAGE_SIZE - 1;		y1 = beg / fb_info->fix.line_length;		y2 = end / fb_info->fix.line_length;		if (y2 >= fb_info->var.yres)			y2 = fb_info->var.yres - 1;		if (miny > y1)			miny = y1;		if (maxy < y2)			maxy = y2;	}	xenfb_refresh(info, 0, miny, fb_info->var.xres, maxy - miny + 1);}static struct fb_deferred_io xenfb_defio = {	.delay		= HZ / 20,	.deferred_io	= xenfb_deferred_io,};static int xenfb_setcolreg(unsigned regno, unsigned red, unsigned green,			   unsigned blue, unsigned transp,			   struct fb_info *info){	u32 v;	if (regno > info->cmap.len)		return 1;#define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16)	red = CNVT_TOHW(red, info->var.red.length);	green = CNVT_TOHW(green, info->var.green.length);	blue = CNVT_TOHW(blue, info->var.blue.length);	transp = CNVT_TOHW(transp, info->var.transp.length);#undef CNVT_TOHW	v = (red << info->var.red.offset) |	    (green << info->var.green.offset) |	    (blue << info->var.blue.offset);	switch (info->var.bits_per_pixel) {	case 16:	case 24:	case 32:		((u32 *)info->pseudo_palette)[regno] = v;		break;	}	return 0;}static void xenfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect){	struct xenfb_info *info = p->par;	sys_fillrect(p, rect);	xenfb_refresh(info, rect->dx, rect->dy, rect->width, rect->height);}static void xenfb_imageblit(struct fb_info *p, const struct fb_image *image){	struct xenfb_info *info = p->par;	sys_imageblit(p, image);	xenfb_refresh(info, image->dx, image->dy, image->width, image->height);}static void xenfb_copyarea(struct fb_info *p, const struct fb_copyarea *area){	struct xenfb_info *info = p->par;	sys_copyarea(p, area);	xenfb_refresh(info, area->dx, area->dy, area->width, area->height);}static ssize_t xenfb_write(struct fb_info *p, const char __user *buf,			size_t count, loff_t *ppos){	struct xenfb_info *info = p->par;	ssize_t res;	res = fb_sys_write(p, buf, count, ppos);	xenfb_refresh(info, 0, 0, info->page->width, info->page->height);	return res;}static intxenfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info){	struct xenfb_info *xenfb_info;	int required_mem_len;	xenfb_info = info->par;	if (!xenfb_info->feature_resize) {		if (var->xres == video[KPARAM_WIDTH] &&		    var->yres == video[KPARAM_HEIGHT] &&		    var->bits_per_pixel == xenfb_info->page->depth) {			return 0;		}		return -EINVAL;	}	/* Can't resize past initial width and height */	if (var->xres > video[KPARAM_WIDTH] || var->yres > video[KPARAM_HEIGHT])		return -EINVAL;	required_mem_len = var->xres * var->yres * xenfb_info->page->depth / 8;	if (var->bits_per_pixel == xenfb_info->page->depth &&	    var->xres <= info->fix.line_length / (XENFB_DEPTH / 8) &&	    required_mem_len <= info->fix.smem_len) {		var->xres_virtual = var->xres;		var->yres_virtual = var->yres;		return 0;	}	return -EINVAL;}static int xenfb_set_par(struct fb_info *info){	struct xenfb_info *xenfb_info;	unsigned long flags;	xenfb_info = info->par;	spin_lock_irqsave(&xenfb_info->resize_lock, flags);	xenfb_info->resize.type = XENFB_TYPE_RESIZE;	xenfb_info->resize.width = info->var.xres;	xenfb_info->resize.height = info->var.yres;	xenfb_info->resize.stride = info->fix.line_length;	xenfb_info->resize.depth = info->var.bits_per_pixel;	xenfb_info->resize.offset = 0;	xenfb_info->resize_dpy = 1;	spin_unlock_irqrestore(&xenfb_info->resize_lock, flags);	return 0;}static struct fb_ops xenfb_fb_ops = {	.owner		= THIS_MODULE,	.fb_read	= fb_sys_read,	.fb_write	= xenfb_write,	.fb_setcolreg	= xenfb_setcolreg,	.fb_fillrect	= xenfb_fillrect,	.fb_copyarea	= xenfb_copyarea,	.fb_imageblit	= xenfb_imageblit,	.fb_check_var	= xenfb_check_var,	.fb_set_par     = xenfb_set_par,};static irqreturn_t xenfb_event_handler(int rq, void *dev_id){	/*	 * No in events recognized, simply ignore them all.	 * If you need to recognize some, see xen-kbdfront's	 * input_handler() for how to do that.	 */	struct xenfb_info *info = dev_id;	struct xenfb_page *page = info->page;	if (page->in_cons != page->in_prod) {		info->page->in_cons = info->page->in_prod;		notify_remote_via_irq(info->irq);	}	/* Flush dirty rectangle: */	xenfb_refresh(info, INT_MAX, INT_MAX, -INT_MAX, -INT_MAX);

⌨️ 快捷键说明

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