📄 xen-fbfront.c
字号:
/* * 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 + -