PV framebuffer frontend. Derived from http://www.cs.utexas.edu/users/aliguori/vfb-20060124.bundle Extensive changes based on feedback from xen-devel. Signed-off-by: Markus Armbruster <armbru@redhat.com> --- arch/i386/kernel/setup-xen.c | 5 arch/ia64/kernel/setup.c | 4 arch/x86_64/kernel/setup-xen.c | 7 drivers/char/tty_io.c | 6 drivers/xen/Kconfig | 23 + drivers/xen/Makefile | 2 drivers/xen/console/console.c | 56 +++ drivers/xen/xenfb/Makefile | 1 drivers/xen/xenfb/xenfb.c | 638 ++++++++++++++++++++++++++++++++++++++ drivers/xen/xenkbd/Makefile | 1 drivers/xen/xenkbd/xenkbd.c | 271 ++++++++++++++++ include/xen/interface/io/xenfb.h | 116 ++++++ include/xen/interface/io/xenkbd.h | 108 ++++++ 13 files changed, 1221 insertions(+), 17 deletions(-) diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/arch/i386/kernel/setup-xen.c linux-2.6.16.29-xen-vfb/arch/i386/kernel/setup-xen.c --- linux-2.6.16.29-xen/arch/i386/kernel/setup-xen.c 2006-09-29 16:11:51.000000000 +0200 +++ linux-2.6.16.29-xen-vfb/arch/i386/kernel/setup-xen.c 2006-11-10 09:43:37.000000000 +0100 @@ -1850,8 +1850,9 @@ void __init setup_arch(char **cmdline_p) #endif #endif } else { - extern int console_use_vt; - console_use_vt = 0; +#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE) + conswitchp = &dummy_con; +#endif } } diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/arch/ia64/kernel/setup.c linux-2.6.16.29-xen-vfb/arch/ia64/kernel/setup.c --- linux-2.6.16.29-xen/arch/ia64/kernel/setup.c 2006-11-09 17:54:47.000000000 +0100 +++ linux-2.6.16.29-xen-vfb/arch/ia64/kernel/setup.c 2006-11-10 09:43:37.000000000 +0100 @@ -550,9 +550,9 @@ setup_arch (char **cmdline_p) xen_start_info->nr_pages, xen_start_info->flags); if (!is_initial_xendomain()) { - extern int console_use_vt; +#if !defined(CONFIG_VT) || !defined(CONFIG_DUMMY_CONSOLE) conswitchp = NULL; - console_use_vt = 0; +#endif } } #endif diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/arch/x86_64/kernel/setup-xen.c linux-2.6.16.29-xen-vfb/arch/x86_64/kernel/setup-xen.c --- linux-2.6.16.29-xen/arch/x86_64/kernel/setup-xen.c 2006-09-29 16:11:51.000000000 +0200 +++ linux-2.6.16.29-xen-vfb/arch/x86_64/kernel/setup-xen.c 2006-11-10 09:43:37.000000000 +0100 @@ -970,9 +970,10 @@ void __init setup_arch(char **cmdline_p) #endif #endif } else { - extern int console_use_vt; - console_use_vt = 0; - } +#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE) + conswitchp = &dummy_con; +#endif + } } #else /* CONFIG_XEN */ diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/char/tty_io.c linux-2.6.16.29-xen-vfb/drivers/char/tty_io.c --- linux-2.6.16.29-xen/drivers/char/tty_io.c 2006-09-29 16:11:51.000000000 +0200 +++ linux-2.6.16.29-xen-vfb/drivers/char/tty_io.c 2006-11-10 09:43:37.000000000 +0100 @@ -132,8 +132,6 @@ LIST_HEAD(tty_drivers); /* linked list vt.c for deeply disgusting hack reasons */ DECLARE_MUTEX(tty_sem); -int console_use_vt = 1; - #ifdef CONFIG_UNIX98_PTYS extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */ extern int pty_limit; /* Config limit on Unix98 ptys */ @@ -2056,7 +2054,7 @@ retry_open: goto got_driver; } #ifdef CONFIG_VT - if (console_use_vt && (device == MKDEV(TTY_MAJOR,0))) { + if (device == MKDEV(TTY_MAJOR,0)) { extern struct tty_driver *console_driver; driver = console_driver; index = fg_console; @@ -3247,8 +3245,6 @@ static int __init tty_init(void) #endif #ifdef CONFIG_VT - if (!console_use_vt) - goto out_vt; cdev_init(&vc0_cdev, &console_fops); if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) || register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/Kconfig linux-2.6.16.29-xen-vfb/drivers/xen/Kconfig --- linux-2.6.16.29-xen/drivers/xen/Kconfig 2006-08-16 09:20:03.000000000 +0200 +++ linux-2.6.16.29-xen-vfb/drivers/xen/Kconfig 2006-11-10 09:43:37.000000000 +0100 @@ -172,6 +172,29 @@ config XEN_NETDEV_FRONTEND dedicated device-driver domain, or your master control domain (domain 0), then you almost certainly want to say Y here. +config XEN_FRAMEBUFFER + tristate "Framebuffer-device frontend driver" + depends on XEN && FB + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + default y + help + The framebuffer-device frontend drivers allows the kernel to create a + virtual framebuffer. This framebuffer can be viewed in another + domain. Unless this domain has access to a real video card, you + probably want to say Y here. + +config XEN_KEYBOARD + tristate "Keyboard-device frontend driver" + depends on XEN + default y + help + The keyboard-device frontend driver allows the kernel to create a + virtual keyboard. This keyboard can then be driven by another + domain. If you''ve said Y to CONFIG_XEN_FRAMEBUFFER, you probably + want to say Y here. + config XEN_SCRUB_PAGES bool "Scrub memory before freeing it to Xen" default y diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/Makefile linux-2.6.16.29-xen-vfb/drivers/xen/Makefile --- linux-2.6.16.29-xen/drivers/xen/Makefile 2006-07-20 14:12:19.000000000 +0200 +++ linux-2.6.16.29-xen-vfb/drivers/xen/Makefile 2006-11-10 09:43:37.000000000 +0100 @@ -15,3 +15,5 @@ obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += blk obj-$(CONFIG_XEN_NETDEV_FRONTEND) += netfront/ obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback/ obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += pcifront/ +obj-$(CONFIG_XEN_FRAMEBUFFER) += xenfb/ +obj-$(CONFIG_XEN_KEYBOARD) += xenkbd/ diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/console/console.c linux-2.6.16.29-xen-vfb/drivers/xen/console/console.c --- linux-2.6.16.29-xen/drivers/xen/console/console.c 2006-09-29 16:11:51.000000000 +0200 +++ linux-2.6.16.29-xen-vfb/drivers/xen/console/console.c 2006-11-10 09:43:37.000000000 +0100 @@ -58,20 +58,28 @@ #include <asm/hypervisor.h> #include <xen/evtchn.h> #include <xen/xencons.h> +#include <xen/xenbus.h> /* * Modes: * ''xencons=off'' [XC_OFF]: Console is disabled. * ''xencons=tty'' [XC_TTY]: Console attached to ''/dev/tty[0-9]+''. * ''xencons=ttyS'' [XC_SERIAL]: Console attached to ''/dev/ttyS[0-9]+''. + * ''xencons=xvc'' [XC_XVC]: Console attached to ''/dev/xvc[0-9]+''. * [XC_DEFAULT]: DOM0 -> XC_SERIAL ; all others -> XC_TTY. * * NB. In mode XC_TTY, we create dummy consoles for tty2-63. This suppresses * warnings from standard distro startup scripts. */ -static enum { XC_OFF, XC_DEFAULT, XC_TTY, XC_SERIAL } xc_mode = XC_DEFAULT; +static enum { XC_OFF, XC_DEFAULT, XC_TTY, XC_SERIAL, XC_XVC } + xc_mode = XC_DEFAULT; static int xc_num = -1; +/* If we are in XC_XVC mode (a virtual console at /dev/xvcX), we need to + * comply with Lanana and use a minor under the low density serial major. + */ +#define XEN_XVC_MINOR 187 + #ifdef CONFIG_MAGIC_SYSRQ static unsigned long sysrq_requested; extern int sysrq_enabled; @@ -86,6 +94,8 @@ static int __init xencons_setup(char *st xc_mode = XC_SERIAL; else if (!strncmp(str, "tty", 3)) xc_mode = XC_TTY; + else if (!strncmp(str, "xvc", 3)) + xc_mode = XC_XVC; else if (!strncmp(str, "off", 3)) xc_mode = XC_OFF; @@ -100,6 +110,11 @@ static int __init xencons_setup(char *st if (q > (str + 3)) xc_num = n; break; + case XC_XVC: + n = simple_strtol(str+3, &q, 10); + if (q > (str + 3)) + xc_num = n; + break; default: break; } @@ -195,12 +210,23 @@ static int __init xen_console_init(void) } else { if (!xen_start_info->console.domU.evtchn) goto out; - if (xc_mode == XC_DEFAULT) - xc_mode = XC_TTY; + if (xc_mode == XC_DEFAULT) { +#ifdef CONFIG_XEN_FRAMEBUFFER + xc_mode = XC_XVC; +#else + xc_mode = XC_TTY; +#endif + } kcons_info.write = kcons_write; } switch (xc_mode) { + case XC_XVC: + strcpy(kcons_info.name, "xvc"); + if (xc_num == -1) + xc_num = 0; + break; + case XC_SERIAL: strcpy(kcons_info.name, "ttyS"); if (xc_num == -1) @@ -305,7 +331,7 @@ void dom0_init_screen_info(const struct /******************** User-space console driver (/dev/console) ************/ #define DRV(_d) (_d) -#define DUMMY_TTY(_tty) ((xc_mode != XC_SERIAL) && \ +#define DUMMY_TTY(_tty) ((xc_mode != XC_SERIAL) && (xc_mode != XC_XVC) && \ ((_tty)->index != (xc_num - 1))) static struct termios *xencons_termios[MAX_NR_CONSOLES]; @@ -628,7 +654,8 @@ static int __init xencons_init(void) return rc; } - xencons_driver = alloc_tty_driver((xc_mode == XC_SERIAL) ? + xencons_driver = alloc_tty_driver(((xc_mode == XC_SERIAL) || + (xc_mode == XC_XVC)) ? 1 : MAX_NR_CONSOLES); if (xencons_driver == NULL) return -ENOMEM; @@ -648,6 +675,11 @@ static int __init xencons_init(void) DRV(xencons_driver)->name = "ttyS"; DRV(xencons_driver)->minor_start = 64 + xc_num; DRV(xencons_driver)->name_base = 0 + xc_num; + } else if (xc_mode == XC_XVC) { + DRV(xencons_driver)->name = "xvc"; + DRV(xencons_driver)->major = 250; /* FIXME: until lanana approves for 204:187 */ + DRV(xencons_driver)->minor_start = XEN_XVC_MINOR; + DRV(xencons_driver)->name_base = xc_num; } else { DRV(xencons_driver)->name = "tty"; DRV(xencons_driver)->minor_start = 1; @@ -680,6 +712,20 @@ static int __init xencons_init(void) printk("Xen virtual console successfully installed as %s%d\n", DRV(xencons_driver)->name, xc_num); + /* Don''t need to check about graphical fb for domain 0 */ + if (is_initial_xendomain()) + return 0; + + rc = 0; + if (xenbus_scanf(XBT_NIL, "console", "use_graphics", "%d", &rc) < 0) + printk(KERN_ERR "Unable to read console/use_graphics\n"); + if (rc == 0) { + /* FIXME: this is ugly */ + unregister_console(&kcons_info); + kcons_info.flags |= CON_CONSDEV; + register_console(&kcons_info); + } + return 0; } diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/xenfb/Makefile linux-2.6.16.29-xen-vfb/drivers/xen/xenfb/Makefile --- linux-2.6.16.29-xen/drivers/xen/xenfb/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.29-xen-vfb/drivers/xen/xenfb/Makefile 2006-11-10 09:43:37.000000000 +0100 @@ -0,0 +1 @@ +obj-$(CONFIG_XEN_FRAMEBUFFER) := xenfb.o diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/xenfb/xenfb.c linux-2.6.16.29-xen-vfb/drivers/xen/xenfb/xenfb.c --- linux-2.6.16.29-xen/drivers/xen/xenfb/xenfb.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.29-xen-vfb/drivers/xen/xenfb/xenfb.c 2006-11-10 09:43:37.000000000 +0100 @@ -0,0 +1,638 @@ +/* + * linux/drivers/video/xenfb.c -- Xen para-virtual frame buffer device + * + * Copyright (C) 2005-2006 Anthony Liguori <aliguori@us.ibm.com> + * Copyright (C) 2006 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/kernel.h> +#include <linux/errno.h> +#include <linux/fb.h> +#include <linux/module.h> +#include <linux/vmalloc.h> +#include <linux/mm.h> +#include <asm/hypervisor.h> +#include <xen/evtchn.h> +#include <xen/interface/io/xenfb.h> +#include <xen/xenbus.h> +#include <linux/kthread.h> + +struct xenfb_mapping +{ + struct list_head link; + struct vm_area_struct *vma; + atomic_t map_refs; + int faults; + struct xenfb_info *info; +}; + +struct xenfb_info +{ + struct task_struct *kthread; + wait_queue_head_t wq; + + unsigned char *fb; + struct fb_info *fb_info; + struct timer_list refresh; + int dirty; + int x1, y1, x2, y2; /* dirty rectangle, + protected by mm_lock */ + spinlock_t mm_lock; + int nr_pages; + struct page **pages; + struct list_head mappings; /* protected by mm_lock */ + + unsigned evtchn; + int irq; + struct xenfb_page *page; + unsigned long *mfns; + int update_wanted; /* XENFB_TYPE_UPDATE wanted */ + + struct xenbus_device *xbdev; +}; + +static int xenfb_fps = 20; +static unsigned long xenfb_mem_len = XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8; + +static int __devexit xenfb_remove(struct xenbus_device *); + +static void xenfb_do_update(struct xenfb_info *info, + int x, int y, int w, int h) +{ + union xenfb_out_event event; + __u32 prod; + + event.type = XENFB_TYPE_UPDATE; + event.update.x = x; + event.update.y = y; + event.update.width = w; + event.update.height = h; + + 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_evtchn(info->evtchn); +} + +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_update_screen(struct xenfb_info *info) +{ + unsigned long flags; + int y1, y2, x1, x2; + struct xenfb_mapping *map; + + if (!info->update_wanted) + return; + if (xenfb_queue_full(info)) + return; + + spin_lock_irqsave(&info->mm_lock, flags); + + y1 = info->y1; + y2 = info->y2; + x1 = info->x1; + x2 = info->x2; + info->x1 = info->y1 = INT_MAX; + info->x2 = info->y2 = 0; + + list_for_each_entry(map, &info->mappings, link) { + if (!map->faults) + continue; + zap_page_range(map->vma, map->vma->vm_start, + map->vma->vm_end - map->vma->vm_start, NULL); + map->faults = 0; + } + + spin_unlock_irqrestore(&info->mm_lock, flags); + + xenfb_do_update(info, x1, y1, x2 - x1, y2 - y1); +} + +static int xenfb_thread(void *data) +{ + struct xenfb_info *info = data; + + for (;;) { + if (kthread_should_stop()) + break; + if (info->dirty) { + info->dirty = 0; + xenfb_update_screen(info); + } + wait_event_interruptible(info->wq, + kthread_should_stop() || info->dirty); + } + return 0; +} + +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; + + red >>= (16 - info->var.red.length); + green >>= (16 - info->var.green.length); + blue >>= (16 - info->var.blue.length); + + v = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + + /* FIXME is this sane? check against xxxfb_setcolreg()! */ + switch (info->var.bits_per_pixel) { + case 16: + case 24: + case 32: + ((u32 *)info->pseudo_palette)[regno] = v; + break; + } + + return 0; +} + +static void xenfb_timer(unsigned long data) +{ + struct xenfb_info *info = (struct xenfb_info *)data; + info->dirty = 1; + wake_up(&info->wq); +} + +static void __xenfb_refresh(struct xenfb_info *info, + int x1, int y1, int w, int h) +{ + int y2, x2; + + y2 = y1 + h; + x2 = x1 + w; + + if (info->y1 > y1) + info->y1 = y1; + if (info->y2 < y2) + info->y2 = y2; + if (info->x1 > x1) + info->x1 = x1; + if (info->x2 < x2) + info->x2 = x2; + + if (timer_pending(&info->refresh)) + return; + + mod_timer(&info->refresh, jiffies + HZ/xenfb_fps); +} + +static void xenfb_refresh(struct xenfb_info *info, + int x1, int y1, int w, int h) +{ + unsigned long flags; + + spin_lock_irqsave(&info->mm_lock, flags); + __xenfb_refresh(info, x1, y1, w, h); + spin_unlock_irqrestore(&info->mm_lock, flags); +} + +static void xenfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) +{ + struct xenfb_info *info = p->par; + + cfb_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; + + cfb_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; + + cfb_copyarea(p, area); + xenfb_refresh(info, area->dx, area->dy, area->width, area->height); +} + +static void xenfb_vm_open(struct vm_area_struct *vma) +{ + struct xenfb_mapping *map = vma->vm_private_data; + atomic_inc(&map->map_refs); +} + +static void xenfb_vm_close(struct vm_area_struct *vma) +{ + struct xenfb_mapping *map = vma->vm_private_data; + struct xenfb_info *info = map->info; + unsigned long flags; + + spin_lock_irqsave(&info->mm_lock, flags); + if (atomic_dec_and_test(&map->map_refs)) { + list_del(&map->link); + kfree(map); + } + spin_unlock_irqrestore(&info->mm_lock, flags); +} + +static struct page *xenfb_vm_nopage(struct vm_area_struct *vma, + unsigned long vaddr, int *type) +{ + struct xenfb_mapping *map = vma->vm_private_data; + struct xenfb_info *info = map->info; + int pgnr = (vaddr - vma->vm_start) >> PAGE_SHIFT; + unsigned long flags; + struct page *page; + int y1, y2; + + if (pgnr >= info->nr_pages) + return NOPAGE_SIGBUS; + + spin_lock_irqsave(&info->mm_lock, flags); + page = info->pages[pgnr]; + get_page(page); + map->faults++; + + y1 = pgnr * PAGE_SIZE / info->fb_info->fix.line_length; + y2 = (pgnr * PAGE_SIZE + PAGE_SIZE - 1) / info->fb_info->fix.line_length; + if (y2 > info->fb_info->var.yres) + y2 = info->fb_info->var.yres; + __xenfb_refresh(info, 0, y1, info->fb_info->var.xres, y2 - y1); + spin_unlock_irqrestore(&info->mm_lock, flags); + + if (type) + *type = VM_FAULT_MINOR; + + return page; +} + +static struct vm_operations_struct xenfb_vm_ops = { + .open = xenfb_vm_open, + .close = xenfb_vm_close, + .nopage = xenfb_vm_nopage, +}; + +static int xenfb_mmap(struct fb_info *fb_info, struct vm_area_struct *vma) +{ + struct xenfb_info *info = fb_info->par; + unsigned long flags; + struct xenfb_mapping *map; + int map_pages; + + if (!(vma->vm_flags & VM_WRITE)) + return -EINVAL; + if (!(vma->vm_flags & VM_SHARED)) + return -EINVAL; + if (vma->vm_pgoff != 0) + return -EINVAL; + + map_pages = (vma->vm_end - vma->vm_start + PAGE_SIZE-1) >> PAGE_SHIFT; + if (map_pages > info->nr_pages) + return -EINVAL; + + map = kzalloc(sizeof(*map), GFP_KERNEL); + if (map == NULL) + return -ENOMEM; + + map->vma = vma; + map->faults = 0; + map->info = info; + atomic_set(&map->map_refs, 1); + + spin_lock_irqsave(&info->mm_lock, flags); + list_add(&map->link, &info->mappings); + spin_unlock_irqrestore(&info->mm_lock, flags); + + vma->vm_ops = &xenfb_vm_ops; + vma->vm_flags |= (VM_DONTEXPAND | VM_RESERVED); + vma->vm_private_data = map; + + return 0; +} + +static struct fb_ops xenfb_fb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = xenfb_setcolreg, + .fb_fillrect = xenfb_fillrect, + .fb_copyarea = xenfb_copyarea, + .fb_imageblit = xenfb_imageblit, + .fb_mmap = xenfb_mmap, +}; + +static irqreturn_t xenfb_event_handler(int rq, void *dev_id, + struct pt_regs *regs) +{ + /* + * No in events recognized, simply ignore them all. + * If you need to recognize some, see xenbkd''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_evtchn(info->evtchn); + } + return IRQ_HANDLED; +} + +static unsigned long vmalloc_to_mfn(void *address) +{ + return pfn_to_mfn(vmalloc_to_pfn(address)); +} + +static int __devinit xenfb_probe(struct xenbus_device *dev, + const struct xenbus_device_id *id) +{ + struct xenfb_info *info; + int i, ret; + struct fb_info *fb_info; + struct xenbus_transaction xbt; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (info == NULL) { + xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); + return -ENOMEM; + } + dev->dev.driver_data = info; + info->xbdev = dev; + info->irq = -1; + info->x1 = info->y1 = INT_MAX; + spin_lock_init(&info->mm_lock); + init_waitqueue_head(&info->wq); + init_timer(&info->refresh); + info->refresh.function = xenfb_timer; + info->refresh.data = (unsigned long)info; + INIT_LIST_HEAD(&info->mappings); + + info->fb = vmalloc(xenfb_mem_len); + if (info->fb == NULL) + goto error_nomem; + memset(info->fb, 0, xenfb_mem_len); + + info->nr_pages = (xenfb_mem_len + PAGE_SIZE - 1) >> PAGE_SHIFT; + + info->pages = kmalloc(sizeof(struct page *) * info->nr_pages, + GFP_KERNEL); + if (info->pages == NULL) + goto error_nomem; + for (i = 0; i < info->nr_pages; i++) + info->pages[i] = vmalloc_to_page(info->fb + i * PAGE_SIZE); + + info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages); + if (!info->mfns) + goto error_nomem; + for (i = 0; i < info->nr_pages; i++) + info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE); + + /* set up shared page */ + info->page = (void *)__get_free_page(GFP_KERNEL); + if (!info->page) + goto error_nomem; + + info->page->pd[0] = vmalloc_to_mfn(info->mfns); + info->page->pd[1] = 0; + info->page->width = XENFB_WIDTH; + info->page->height = XENFB_HEIGHT; + info->page->depth = XENFB_DEPTH; + info->page->line_length = (info->page->depth / 8) * info->page->width; + info->page->mem_length = xenfb_mem_len; + info->page->in_cons = info->page->in_prod = 0; + info->page->out_cons = info->page->out_prod = 0; + + ret = xenbus_alloc_evtchn(dev, &info->evtchn); + if (ret) + goto error; + ret = bind_evtchn_to_irqhandler(info->evtchn, xenfb_event_handler, + 0, "xenfb", info); + if (ret < 0) { + xenbus_free_evtchn(dev, info->evtchn); + goto error; + } + info->irq = ret; + + fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL); + /* see fishy hackery below */ + if (fb_info == NULL) + goto error_nomem; + + /* FIXME fishy hackery */ + fb_info->pseudo_palette = fb_info->par; + fb_info->par = info; + /* /FIXME */ + fb_info->screen_base = info->fb; + + fb_info->fbops = &xenfb_fb_ops; + fb_info->var.xres_virtual = fb_info->var.xres = info->page->width; + fb_info->var.yres_virtual = fb_info->var.yres = info->page->height; + fb_info->var.bits_per_pixel = info->page->depth; + + fb_info->var.red = (struct fb_bitfield){16, 8, 0}; + fb_info->var.green = (struct fb_bitfield){8, 8, 0}; + fb_info->var.blue = (struct fb_bitfield){0, 8, 0}; + + fb_info->var.activate = FB_ACTIVATE_NOW; + fb_info->var.height = -1; + fb_info->var.width = -1; + fb_info->var.vmode = FB_VMODE_NONINTERLACED; + + fb_info->fix.visual = FB_VISUAL_TRUECOLOR; + fb_info->fix.line_length = info->page->line_length; + fb_info->fix.smem_start = 0; + fb_info->fix.smem_len = xenfb_mem_len; + strcpy(fb_info->fix.id, "xen"); + fb_info->fix.type = FB_TYPE_PACKED_PIXELS; + fb_info->fix.accel = FB_ACCEL_NONE; + + fb_info->flags = FBINFO_FLAG_DEFAULT; + + ret = fb_alloc_cmap(&fb_info->cmap, 256, 0); + if (ret < 0) { + framebuffer_release(fb_info); + xenbus_dev_fatal(dev, ret, "fb_alloc_cmap"); + goto error; + } + + /* FIXME should this be delayed until backend XenbusStateConnected? */ + ret = register_framebuffer(fb_info); + if (ret) { + fb_dealloc_cmap(&info->fb_info->cmap); + framebuffer_release(fb_info); + xenbus_dev_fatal(dev, ret, "register_framebuffer"); + goto error; + } + info->fb_info = fb_info; + + info->kthread = kthread_run(xenfb_thread, info, "xenfb thread"); + if (IS_ERR(info->kthread)) { + ret = PTR_ERR(info->kthread); + xenbus_dev_fatal(dev, ret, "register_framebuffer"); + goto error; + } + + again: + ret = xenbus_transaction_start(&xbt); + if (ret) { + xenbus_dev_fatal(dev, ret, "starting transaction"); + goto error; + } + ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", + virt_to_mfn(info->page)); + if (ret) + goto error_xenbus; + ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", + info->evtchn); + if (ret) + goto error_xenbus; + ret = xenbus_printf(xbt, dev->nodename, "feature-update", "1"); + if (ret) + goto error_xenbus; + ret = xenbus_transaction_end(xbt, 0); + if (ret) { + if (ret == -EAGAIN) + goto again; + xenbus_dev_fatal(dev, ret, "completing transaction"); + goto error; + } + + xenbus_switch_state(dev, XenbusStateInitialised); + return 0; + + error_xenbus: + xenbus_transaction_end(xbt, 1); + xenbus_dev_fatal(dev, ret, "writing xenstore"); + goto error; + error_nomem: + ret = -ENOMEM; + xenbus_dev_fatal(dev, ret, "allocating device memory"); + error: + xenfb_remove(dev); + return ret; +} + +static void xenfb_backend_changed(struct xenbus_device *dev, + enum xenbus_state backend_state) +{ + struct xenfb_info *info = dev->dev.driver_data; + int val; + + switch (backend_state) { + case XenbusStateInitialising: + case XenbusStateInitialised: + case XenbusStateUnknown: + case XenbusStateClosed: + break; + + case XenbusStateInitWait: + xenbus_switch_state(dev, XenbusStateConnected); + break; + + case XenbusStateConnected: + if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, + "request-update", "%d", &val) < 0) + val = 0; + if (val) + info->update_wanted = 1; + break; + + case XenbusStateClosing: + xenbus_frontend_closed(dev); + break; + } +} + +static int __devexit xenfb_remove(struct xenbus_device *dev) +{ + struct xenfb_info *info = dev->dev.driver_data; + + del_timer(&info->refresh); + if (info->kthread) + kthread_stop(info->kthread); + if (info->irq >= 0) + unbind_from_irqhandler(info->irq, info); + if (info->fb_info) { + unregister_framebuffer(info->fb_info); + fb_dealloc_cmap(&info->fb_info->cmap); + framebuffer_release(info->fb_info); + } + free_page((unsigned long)info->page); + vfree(info->mfns); + kfree(info->pages); + vfree(info->fb); + kfree(info); + + return 0; +} + +static struct xenbus_device_id xenfb_ids[] = { + { "vfb" }, + { "" } +}; + +static struct xenbus_driver xenfb = { + .name = "vfb", + .owner = THIS_MODULE, + .ids = xenfb_ids, + .probe = xenfb_probe, + .remove = xenfb_remove, + /* TODO .resume = xenfb_resume, */ + .otherend_changed = xenfb_backend_changed, +}; + +static int __init xenfb_init(void) +{ + int ret; + + if (!is_running_on_xen()) + return -ENODEV; + + /* Nothing to do if running in dom0. */ + if (is_initial_xendomain()) + return -ENODEV; + /* if we''re not set up to use graphics mode, then don''t initialize */ + if (xenbus_scanf(XBT_NIL, "console", "use_graphics", "%d", &ret) < 0) + return -ENODEV; + if (ret == 0) + return -ENODEV; + + return xenbus_register_frontend(&xenfb); +} + +static void __exit xenfb_cleanup(void) +{ + return xenbus_unregister_driver(&xenfb); +} + +module_init(xenfb_init); +module_exit(xenfb_cleanup); + +MODULE_LICENSE("GPL"); diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/xenkbd/Makefile linux-2.6.16.29-xen-vfb/drivers/xen/xenkbd/Makefile --- linux-2.6.16.29-xen/drivers/xen/xenkbd/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.29-xen-vfb/drivers/xen/xenkbd/Makefile 2006-11-10 09:43:37.000000000 +0100 @@ -0,0 +1 @@ +obj-$(CONFIG_XEN_KEYBOARD) += xenkbd.o diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/xenkbd/xenkbd.c linux-2.6.16.29-xen-vfb/drivers/xen/xenkbd/xenkbd.c --- linux-2.6.16.29-xen/drivers/xen/xenkbd/xenkbd.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.29-xen-vfb/drivers/xen/xenkbd/xenkbd.c 2006-11-10 09:43:37.000000000 +0100 @@ -0,0 +1,271 @@ +/* + * linux/drivers/input/keyboard/xenkbd.c -- Xen para-virtual input device + * + * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com> + * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> + * + * Based on linux/drivers/input/mouse/sermouse.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 together with xenfb.c. + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/module.h> +#include <linux/input.h> +#include <asm/hypervisor.h> +#include <xen/evtchn.h> +#include <xen/interface/io/xenfb.h> +#include <xen/interface/io/xenkbd.h> +#include <xen/xenbus.h> + +struct xenkbd_info +{ + struct input_dev *dev; + struct xenkbd_page *page; + unsigned evtchn; + int irq; + struct xenbus_device *xbdev; +}; + +static int __devexit xenkbd_remove(struct xenbus_device *); + +/* + * Note: if you need to send out events, see xenfb_do_update() for how + * to do that. + */ + +static irqreturn_t input_handler(int rq, void *dev_id, struct pt_regs *regs) +{ + struct xenkbd_info *info = dev_id; + struct xenkbd_page *page = info->page; + __u32 cons, prod; + + prod = page->in_prod; + if (prod == page->out_cons) + return IRQ_HANDLED; + rmb(); /* ensure we see ring contents up to prod */ + for (cons = page->in_cons; cons != prod; cons++) { + union xenkbd_in_event *event; + event = &XENKBD_IN_RING_REF(page, cons); + + switch (event->type) { + case XENKBD_TYPE_MOTION: + input_report_rel(info->dev, REL_X, event->motion.rel_x); + input_report_rel(info->dev, REL_Y, event->motion.rel_y); + break; + case XENKBD_TYPE_KEY: + input_report_key(info->dev, event->key.keycode, event->key.pressed); + break; + case XENKBD_TYPE_POS: + input_report_abs(info->dev, ABS_X, event->pos.abs_x); + input_report_abs(info->dev, ABS_Y, event->pos.abs_y); + break; + } + } + input_sync(info->dev); + mb(); /* ensure we got ring contents */ + page->in_cons = cons; + notify_remote_via_evtchn(info->evtchn); + + return IRQ_HANDLED; +} + +int __devinit xenkbd_probe(struct xenbus_device *dev, + const struct xenbus_device_id *id) +{ + int ret, i; + struct xenkbd_info *info; + struct input_dev *input_dev; + struct xenbus_transaction xbt; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); + return -ENOMEM; + } + dev->dev.driver_data = info; + info->xbdev = dev; + + info->page = (void *)__get_free_page(GFP_KERNEL); + if (!info->page) + goto error_nomem; + info->page->in_cons = info->page->in_prod = 0; + info->page->out_cons = info->page->out_prod = 0; + + input_dev = input_allocate_device(); + if (!input_dev) + goto error_nomem; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_MOUSE)] + = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + /* FIXME more buttons? */ + input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); + + /* FIXME not sure this is quite right */ + for (i = 0; i < 256; i++) + set_bit(i, input_dev->keybit); + + input_dev->name = "Xen Virtual Keyboard/Mouse"; + + input_set_abs_params(input_dev, ABS_X, 0, XENFB_WIDTH, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, XENFB_HEIGHT, 0, 0); + + /* FIXME should this be delayed until backend XenbusStateConnected? */ + ret = input_register_device(input_dev); + if (ret) { + input_free_device(input_dev); + xenbus_dev_fatal(dev, ret, "input_register_device"); + goto error; + } + info->dev = input_dev; + + ret = xenbus_alloc_evtchn(dev, &info->evtchn); + if (ret) + goto error; + ret = bind_evtchn_to_irqhandler(info->evtchn, input_handler, 0, + "xenkbd", info); + if (ret < 0) { + xenbus_free_evtchn(dev, info->evtchn); + goto error; + } + info->irq = ret; + + again: + ret = xenbus_transaction_start(&xbt); + if (ret) { + xenbus_dev_fatal(dev, ret, "starting transaction"); + goto error; + } + ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", + virt_to_mfn(info->page)); + if (ret) + goto error_xenbus; + ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", + info->evtchn); + if (ret) + goto error_xenbus; + ret = xenbus_transaction_end(xbt, 0); + if (ret) { + if (ret == -EAGAIN) + goto again; + xenbus_dev_fatal(dev, ret, "completing transaction"); + goto error; + } + + xenbus_switch_state(dev, XenbusStateInitialised); + return 0; + + error_xenbus: + xenbus_transaction_end(xbt, 1); + xenbus_dev_fatal(dev, ret, "writing xenstore"); + goto error; + error_nomem: + ret = -ENOMEM; + xenbus_dev_fatal(dev, ret, "allocating device memory"); + error: + xenkbd_remove(dev); + return ret; +} + +static void xenkbd_backend_changed(struct xenbus_device *dev, + enum xenbus_state backend_state) +{ + struct xenkbd_info *info = dev->dev.driver_data; + int ret, val; + + switch (backend_state) { + case XenbusStateInitialising: + case XenbusStateInitialised: + case XenbusStateUnknown: + case XenbusStateClosed: + break; + + case XenbusStateInitWait: + ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend, + "feature-abs-pointer", "%d", &val); + if (ret < 0) + val = 0; + if (val) { + ret = xenbus_printf(XBT_NIL, info->xbdev->nodename, + "request-abs-pointer", "1"); + if (ret) + ; /* FIXME */ + } + xenbus_switch_state(dev, XenbusStateConnected); + break; + + case XenbusStateConnected: + break; + + case XenbusStateClosing: + xenbus_frontend_closed(dev); + break; + } +} + +static int __devexit xenkbd_remove(struct xenbus_device *dev) +{ + struct xenkbd_info *info = dev->dev.driver_data; + + if (info->irq >= 0) + unbind_from_irqhandler(info->irq, info); + input_unregister_device(info->dev); + free_page((unsigned long)info->page); + kfree(info); + return 0; +} + +static struct xenbus_device_id xenkbd_ids[] = { + { "vkbd" }, + { "" } +}; + +static struct xenbus_driver xenkbd = { + .name = "vkbd", + .owner = THIS_MODULE, + .ids = xenkbd_ids, + .probe = xenkbd_probe, + .remove = xenkbd_remove, + //.resume = xenkbd_resume, + .otherend_changed = xenkbd_backend_changed, +}; + +static int __init xenkbd_init(void) +{ + int ret; + + if (!is_running_on_xen()) + return -ENODEV; + + /* Nothing to do if running in dom0. */ + if (is_initial_xendomain()) + return -ENODEV; + /* if we''re not set up to use graphics mode, then don''t initialize */ + if (xenbus_scanf(XBT_NIL, "console", "use_graphics", "%d", &ret) < 0) + return -ENODEV; + if (ret == 0) + return -ENODEV; + + + return xenbus_register_frontend(&xenkbd); +} + +static void __exit xenkbd_cleanup(void) +{ + return xenbus_unregister_driver(&xenkbd); +} + +module_init(xenkbd_init); +module_exit(xenkbd_cleanup); + +MODULE_LICENSE("GPL"); diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/include/xen/interface/io/xenfb.h linux-2.6.16.29-xen-vfb/include/xen/interface/io/xenfb.h --- linux-2.6.16.29-xen/include/xen/interface/io/xenfb.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.29-xen-vfb/include/xen/interface/io/xenfb.h 2006-11-10 09:43:37.000000000 +0100 @@ -0,0 +1,116 @@ +/* + * linux/include/linux/xenfb.h -- Xen virtual frame buffer device + * + * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com> + * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> + * + * 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. + */ + +#ifndef _LINUX_XENFB_H +#define _LINUX_XENFB_H + +#include <asm/types.h> + +/* Out events (frontend -> backend) */ + +/* + * Out events may be sent only when requested by backend, and receipt + * of an unknown out event is an error. + */ + +/* Event type 1 currently not used */ +/* + * Framebuffer update notification event + * Capable frontend sets feature-update in xenstore. + * Backend requests it by setting request-update in xenstore. + */ +#define XENFB_TYPE_UPDATE 2 + +struct xenfb_update +{ + __u8 type; /* XENFB_TYPE_UPDATE */ + __s32 x; /* source x */ + __s32 y; /* source y */ + __s32 width; /* rect width */ + __s32 height; /* rect height */ +}; + +#define XENFB_OUT_EVENT_SIZE 40 + +union xenfb_out_event +{ + __u8 type; + struct xenfb_update update; + char pad[XENFB_OUT_EVENT_SIZE]; +}; + +/* In events (backend -> frontend) */ + +/* + * Frontends should ignore unknown in events. + * No in events currently defined. + */ + +#define XENFB_IN_EVENT_SIZE 40 + +union xenfb_in_event +{ + __u8 type; + char pad[XENFB_OUT_EVENT_SIZE]; +}; + +/* shared page */ + +#define XENFB_IN_RING_SIZE 1024 +#define XENFB_IN_RING_LEN (XENFB_IN_RING_SIZE / XENFB_IN_EVENT_SIZE) +#define XENFB_IN_RING_OFFS 1024 +#define XENFB_IN_RING(page) \ + ((union xenfb_in_event *)((char *)(page) + XENFB_IN_RING_OFFS)) +#define XENFB_IN_RING_REF(page, idx) \ + (XENFB_IN_RING((page))[(idx) % XENFB_IN_RING_LEN]) + +#define XENFB_OUT_RING_SIZE 2048 +#define XENFB_OUT_RING_LEN (XENFB_OUT_RING_SIZE / XENFB_OUT_EVENT_SIZE) +#define XENFB_OUT_RING_OFFS (XENFB_IN_RING_OFFS + XENFB_IN_RING_SIZE) +#define XENFB_OUT_RING(page) \ + ((union xenfb_out_event *)((char *)(page) + XENFB_OUT_RING_OFFS)) +#define XENFB_OUT_RING_REF(page, idx) \ + (XENFB_OUT_RING((page))[(idx) % XENFB_OUT_RING_LEN]) + +struct xenfb_page +{ + __u32 in_cons, in_prod; + __u32 out_cons, out_prod; + + __s32 width; /* the width of the framebuffer (in pixels) */ + __s32 height; /* the height of the framebuffer (in pixels) */ + __u32 line_length; /* the length of a row of pixels (in bytes) */ + __u32 mem_length; /* the length of the framebuffer (in bytes) */ + __u8 depth; /* the depth of a pixel (in bits) */ + + /* + * Framebuffer page directory + * + * Each directory page holds PAGE_SIZE / sizeof(*pd) + * framebuffer pages, and can thus map up to PAGE_SIZE * + * PAGE_SIZE / sizeof(*pd) bytes. With PAGE_SIZE == 4096 and + * sizeof(unsigned long) == 4, that''s 4 Megs. Two directory + * pages should be enough for a while. + */ + unsigned long pd[2]; +}; + +/* + * Wart: xenkbd needs to know resolution. Put it here until a better + * solution is found, but don''t leak it to the backend. + */ +#ifdef __KERNEL__ +#define XENFB_WIDTH 800 +#define XENFB_HEIGHT 600 +#define XENFB_DEPTH 32 +#endif + +#endif diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/include/xen/interface/io/xenkbd.h linux-2.6.16.29-xen-vfb/include/xen/interface/io/xenkbd.h --- linux-2.6.16.29-xen/include/xen/interface/io/xenkbd.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.29-xen-vfb/include/xen/interface/io/xenkbd.h 2006-11-10 09:43:37.000000000 +0100 @@ -0,0 +1,108 @@ +/* + * linux/include/linux/xenkbd.h -- Xen virtual keyboard/mouse + * + * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com> + * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> + * + * 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. + */ + +#ifndef _LINUX_XENKBD_H +#define _LINUX_XENKBD_H + +#include <asm/types.h> + +/* In events (backend -> frontend) */ + +/* + * Frontends should ignore unknown in events. + */ + +/* Pointer movement event */ +#define XENKBD_TYPE_MOTION 1 +/* Event type 2 currently not used */ +/* Key event (includes pointer buttons) */ +#define XENKBD_TYPE_KEY 3 +/* + * Pointer position event + * Capable backend sets feature-abs-pointer in xenstore. + * Frontend requests ot instead of XENKBD_TYPE_MOTION by setting + * request-abs-update in xenstore. + */ +#define XENKBD_TYPE_POS 4 + +struct xenkbd_motion +{ + __u8 type; /* XENKBD_TYPE_MOTION */ + __s32 rel_x; /* relative X motion */ + __s32 rel_y; /* relative Y motion */ +}; + +struct xenkbd_key +{ + __u8 type; /* XENKBD_TYPE_KEY */ + __u8 pressed; /* 1 if pressed; 0 otherwise */ + __u32 keycode; /* KEY_* from linux/input.h */ +}; + +struct xenkbd_position +{ + __u8 type; /* XENKBD_TYPE_POS */ + __s32 abs_x; /* absolute X position (in FB pixels) */ + __s32 abs_y; /* absolute Y position (in FB pixels) */ +}; + +#define XENKBD_IN_EVENT_SIZE 40 + +union xenkbd_in_event +{ + __u8 type; + struct xenkbd_motion motion; + struct xenkbd_key key; + struct xenkbd_position pos; + char pad[XENKBD_IN_EVENT_SIZE]; +}; + +/* Out events (frontend -> backend) */ + +/* + * Out events may be sent only when requested by backend, and receipt + * of an unknown out event is an error. + * No out events currently defined. + */ + +#define XENKBD_OUT_EVENT_SIZE 40 + +union xenkbd_out_event +{ + __u8 type; + char pad[XENKBD_OUT_EVENT_SIZE]; +}; + +/* shared page */ + +#define XENKBD_IN_RING_SIZE 2048 +#define XENKBD_IN_RING_LEN (XENKBD_IN_RING_SIZE / XENKBD_IN_EVENT_SIZE) +#define XENKBD_IN_RING_OFFS 1024 +#define XENKBD_IN_RING(page) \ + ((union xenkbd_in_event *)((char *)(page) + XENKBD_IN_RING_OFFS)) +#define XENKBD_IN_RING_REF(page, idx) \ + (XENKBD_IN_RING((page))[(idx) % XENKBD_IN_RING_LEN]) + +#define XENKBD_OUT_RING_SIZE 1024 +#define XENKBD_OUT_RING_LEN (XENKBD_OUT_RING_SIZE / XENKBD_OUT_EVENT_SIZE) +#define XENKBD_OUT_RING_OFFS (XENKBD_IN_RING_OFFS + XENKBD_IN_RING_SIZE) +#define XENKBD_OUT_RING(page) \ + ((union xenkbd_out_event *)((char *)(page) + XENKBD_OUT_RING_OFFS)) +#define XENKBD_OUT_RING_REF(page, idx) \ + (XENKBD_OUT_RING((page))[(idx) % XENKBD_OUT_RING_LEN]) + +struct xenkbd_page +{ + __u32 in_cons, in_prod; + __u32 out_cons, out_prod; +}; + +#endif _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
> diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/console/console.c linux-2.6.16.29-xen-vfb/drivers/xen/console/console.c > --- linux-2.6.16.29-xen/drivers/xen/console/console.c 2006-09-29 16:11:51.000000000 +0200 > +++ linux-2.6.16.29-xen-vfb/drivers/xen/console/console.c 2006-11-10 09:43:37.000000000 +0100 > @@ -195,12 +210,23 @@ static int __init xen_console_init(void) > } else { > if (!xen_start_info->console.domU.evtchn) > goto out; > - if (xc_mode == XC_DEFAULT) > - xc_mode = XC_TTY; > + if (xc_mode == XC_DEFAULT) { > +#ifdef CONFIG_XEN_FRAMEBUFFER > + xc_mode = XC_XVC; > +#else > + xc_mode = XC_TTY; > +#endif > + }This hunk is changing the default behaviour of xencons in domU from registering as tty{0...} to registering as xvc{0...}, yes? That''s going to confuse a lot of people with existing domUs which have gettys etc. set up on /dev/ttyX but not /dev/xvcX. Or am I confused again?> kcons_info.write = kcons_write; > } > > switch (xc_mode) { > > diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/Kconfig linux-2.6.16.29-xen-vfb/drivers/xen/Kconfig > --- linux-2.6.16.29-xen/drivers/xen/Kconfig 2006-08-16 09:20:03.000000000 +0200 > +++ linux-2.6.16.29-xen-vfb/drivers/xen/Kconfig 2006-11-10 09:43:37.000000000 +0100 > @@ -172,3 +172,19 @@ config XEN_NETDEV_FRONTEND > dedicated device-driver domain, or your master control domain > (domain 0), then you almost certainly want to say Y here. > > +config XEN_FRAMEBUFFER > + tristate "Framebuffer-device frontend driver" > + depends on XEN && FB > + select FB_CFB_FILLRECT > + select FB_CFB_COPYAREA > + select FB_CFB_IMAGEBLIT > + default y > + help > + The framebuffer-device frontend drivers allows the kernel to create a > + virtual framebuffer. This framebuffer can be viewed in another > + domain. Unless this domain has access to a real video card, you > + probably want to say Y here. > + > +config XEN_KEYBOARD > + tristate "Keyboard-device frontend driver" > + depends on XENDoes this want to depend on XEN_FRAMEBUFFER and INPUT?> + default y > + help > + The keyboard-device frontend driver allows the kernel to create a > + virtual keyboard. This keyboard can then be driven by another > + domain. If you''ve said Y to CONFIG_XEN_FRAMEBUFFER, you probably > + want to say Y here. > + > config XEN_SCRUB_PAGES > bool "Scrub memory before freeing it to Xen" > default y > diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/console/console.c linux-2.6.16.29-xen-vfb/drivers/xen/console/console.c > --- linux-2.6.16.29-xen/drivers/xen/console/console.c 2006-09-29 16:11:51.000000000 +0200 > +++ linux-2.6.16.29-xen-vfb/drivers/xen/console/console.c 2006-11-10 09:43:37.000000000 +0100 > @@ -680,3 +712,17 @@ static int __init xencons_init(void) > printk("Xen virtual console successfully installed as %s%d\n", > DRV(xencons_driver)->name, xc_num); > > + /* Don''t need to check about graphical fb for domain 0 */ > + if (is_initial_xendomain()) > + return 0; > + > + rc = 0; > + if (xenbus_scanf(XBT_NIL, "console", "use_graphics", "%d", &rc) < 0) > + printk(KERN_ERR "Unable to read console/use_graphics\n"); > + if (rc == 0) { > + /* FIXME: this is ugly */ > + unregister_console(&kcons_info); > + kcons_info.flags |= CON_CONSDEV; > + register_console(&kcons_info); > + }I''m still not entirely sure I understand why this bit is necessary. From talking to katz@redhat.com last time:> > > > > Also, why do you need to set CON_CONSDEV at all? > > > > Otherwise, you don''t get kernel console messages. > > > Why not? None of the other console drivers seem to need to set it > > > explicitly, and it seems like it would break setting console=blah on > > > the kernel command line. > > Nothing else sets it explicitly because it happens implicitly in the > > console registration code for the first thing registered with > > register_console(). Alternately, if you have a console=, then > > register_console ensures that your console device has CON_CONSDEV set. > > kernel/printk.c if you want to read all the gory details > The intent of this code seems to be to make sure that CON_CONSDEV is > definitely set on xenconsole if use_graphics is not set, yes? But as > far as I can see, if use_graphics is not set, xenfb should never call > register_console(), and so this is all redundant.I''m still just as unenlightened as I was then. Plus, xen_console_init should be called before any of the pvfb stuff anyway, since it''s a console_initcall and pvfb starts from a module_init, so it''s doubly redundant.> return 0; > } > > diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/xenfb/xenfb.c linux-2.6.16.29-xen-vfb/drivers/xen/xenfb/xenfb.c > --- linux-2.6.16.29-xen/drivers/xen/xenfb/xenfb.c 1970-01-01 01:00:00.000000000 +0100 > +++ linux-2.6.16.29-xen-vfb/drivers/xen/xenfb/xenfb.c 2006-11-10 09:43:37.000000000 +0100 > > +static int __devinit xenfb_probe(struct xenbus_device *dev, > + const struct xenbus_device_id *id) > +{...> + ret = fb_alloc_cmap(&fb_info->cmap, 256, 0); > + if (ret < 0) { > + framebuffer_release(fb_info); > + xenbus_dev_fatal(dev, ret, "fb_alloc_cmap"); > + goto error; > + } > + > + /* FIXME should this be delayed until backend XenbusStateConnected? */I would, but I''m not sure it matters too much. You have a potentially slightly confusing situation where someone starts using the framebuffer before the backend connects, so the backend has to be able to handle there being events on the ring when it starts, but I think it probably works as it is.> + ret = register_framebuffer(fb_info); > + if (ret) { > + fb_dealloc_cmap(&info->fb_info->cmap); > + framebuffer_release(fb_info); > + xenbus_dev_fatal(dev, ret, "register_framebuffer"); > + goto error; > + } > + info->fb_info = fb_info; > + > + info->kthread = kthread_run(xenfb_thread, info, "xenfb thread"); > + if (IS_ERR(info->kthread)) { > + ret = PTR_ERR(info->kthread); > + xenbus_dev_fatal(dev, ret, "register_framebuffer"); > + goto error;goto error will end up calling xenfb_remove, which will notice that info->kthread is non-NULL and try to kthread_stop it. That strikes me as a bad idea. ...> +static int __devexit xenfb_remove(struct xenbus_device *dev)This gets called from some error paths even when the driver is remaining loaded. Is __devexit safe? I''m thinking particularly of the case where the kernel is compiled without module unloading and discards exit text segments.> +{ > + struct xenfb_info *info = dev->dev.driver_data; > + > + del_timer(&info->refresh); > + if (info->kthread) > + kthread_stop(info->kthread); > + if (info->irq >= 0) > + unbind_from_irqhandler(info->irq, info); > + if (info->fb_info) { > + unregister_framebuffer(info->fb_info); > + fb_dealloc_cmap(&info->fb_info->cmap); > + framebuffer_release(info->fb_info); > + } > + free_page((unsigned long)info->page); > + vfree(info->mfns); > + kfree(info->pages); > + vfree(info->fb); > + kfree(info); > + > + return 0; > +} > + > +static struct xenbus_driver xenfb = { > + .name = "vfb", > + .owner = THIS_MODULE, > + .ids = xenfb_ids, > + .probe = xenfb_probe, > + .remove = xenfb_remove,I think this wants to be __devexit_p.> + /* TODO .resume = xenfb_resume, */ > + .otherend_changed = xenfb_backend_changed, > +}; > + > +static int __init xenfb_init(void) > +{ > + int ret; > + > + if (!is_running_on_xen()) > + return -ENODEV; > + > + /* Nothing to do if running in dom0. */ > + if (is_initial_xendomain()) > + return -ENODEV; > + /* if we''re not set up to use graphics mode, then don''t initialize */ > + if (xenbus_scanf(XBT_NIL, "console", "use_graphics", "%d", &ret) < 0) > + return -ENODEV; > + if (ret == 0) > + return -ENODEV;Not sure about this. It seems to me like it might be useful to sometimes have domains which have a PVFB but still use xencons for kernel printks etc. Perhaps I''m just confused.> + > + return xenbus_register_frontend(&xenfb); > +} > + > +static void __exit xenfb_cleanup(void) > +{ > + return xenbus_unregister_driver(&xenfb); > +} > + > +module_init(xenfb_init); > +module_exit(xenfb_cleanup); > + > +MODULE_LICENSE("GPL"); > diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/xenkbd/xenkbd.c linux-2.6.16.29-xen-vfb/drivers/xen/xenkbd/xenkbd.c > --- linux-2.6.16.29-xen/drivers/xen/xenkbd/xenkbd.c 1970-01-01 01:00:00.000000000 +0100 > +++ linux-2.6.16.29-xen-vfb/drivers/xen/xenkbd/xenkbd.c 2006-11-10 09:43:37.000000000 +0100 > @@ -0,0 +1,123 @@ > +int __devinit xenkbd_probe(struct xenbus_device *dev, > + const struct xenbus_device_id *id) > +{...> + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); > + input_dev->keybit[LONG(BTN_MOUSE)] > + = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); > + /* FIXME more buttons? */ > + input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);Do you need to set some bits in absbit, as well, since you can generate absolute coordinate messages?> + input_dev->name = "Xen Virtual Keyboard/Mouse"; > + > + input_set_abs_params(input_dev, ABS_X, 0, XENFB_WIDTH, 0, 0); > + input_set_abs_params(input_dev, ABS_Y, 0, XENFB_HEIGHT, 0, 0); > + > + /* FIXME should this be delayed until backend XenbusStateConnected? */Again, I would move it if I were doing this, but it makes even less difference here than it did before.> + ret = register_framebuffer(fb_info); > + if (ret) { > + fb_dealloc_cmap(&info->fb_info->cmap); > + framebuffer_release(fb_info); > + xenbus_dev_fatal(dev, ret, "register_framebuffer"); > + goto error; > + }...> +static int __devexit xenkbd_remove(struct xenbus_device *dev)Again, not convinced __devexit is entirely valid here.> +{ > + struct xenkbd_info *info = dev->dev.driver_data; > + > + if (info->irq >= 0) > + unbind_from_irqhandler(info->irq, info); > + input_unregister_device(info->dev); > + free_page((unsigned long)info->page); > + kfree(info); > + return 0; > +} > > +static struct xenbus_driver xenkbd = { > + .name = "vkbd", > + .owner = THIS_MODULE, > + .ids = xenkbd_ids, > + .probe = xenkbd_probe, > + .remove = xenkbd_remove,Again, might want to be __devexit_p.> + //.resume = xenkbd_resume, > + .otherend_changed = xenkbd_backend_changed, > +}; > + > +static int __init xenkbd_init(void) > +{ > + int ret; > + > + if (!is_running_on_xen()) > + return -ENODEV; > + > + /* Nothing to do if running in dom0. */ > + if (is_initial_xendomain()) > + return -ENODEV; > + /* if we''re not set up to use graphics mode, then don''t initialize */ > + if (xenbus_scanf(XBT_NIL, "console", "use_graphics", "%d", &ret) < 0) > + return -ENODEV; > + if (ret == 0) > + return -ENODEV;This test obviously wants to be kept in sync with the corresponding test in xenfb_init, so the same comments apply here as there.> + return xenbus_register_frontend(&xenkbd); > +}> diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/include/xen/interface/io/xenfb.h linux-2.6.16.29-xen-vfb/include/xen/interface/io/xenfb.h > --- linux-2.6.16.29-xen/include/xen/interface/io/xenfb.h 1970-01-01 01:00:00.000000000 +0100 > +++ linux-2.6.16.29-xen-vfb/include/xen/interface/io/xenfb.h 2006-11-10 09:43:37.000000000 +0100I think this really wants to be in xen/include/public/io, but I''d guess this is just an artifact of the diff.> +struct xenfb_update > +{ > + __u8 type; /* XENFB_TYPE_UPDATE */ > + __s32 x; /* source x */ > + __s32 y; /* source y */ > + __s32 width; /* rect width */ > + __s32 height; /* rect height */ > +}; > + > +#define XENFB_OUT_EVENT_SIZE 40 > + > +union xenfb_out_event > +{ > + __u8 type; > + struct xenfb_update update; > + char pad[XENFB_OUT_EVENT_SIZE]; > +};I still think you''d be better off doing tagged unions the usual way, but your funeral.> +/* > + * Wart: xenkbd needs to know resolution. Put it here until a better > + * solution is found, but don''t leak it to the backend. > + */Why does xenkbd need to know the resolution? Do you mean xenfb? As far as I can see, these only get used in xenfb.c, so the #defines could go there rather than in the IO description header.> +#ifdef __KERNEL__ > +#define XENFB_WIDTH 800 > +#define XENFB_HEIGHT 600 > +#define XENFB_DEPTH 32 > +#endif > + > +#endifSteven. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
On 12/11/06 2:20 pm, "Steven Smith" <sos22-xen@srcf.ucam.org> wrote:>> +#ifdef CONFIG_XEN_FRAMEBUFFER >> + xc_mode = XC_XVC; >> +#else >> + xc_mode = XC_TTY; >> +#endif >> + } > This hunk is changing the default behaviour of xencons in domU from > registering as tty{0...} to registering as xvc{0...}, yes? That''s > going to confuse a lot of people with existing domUs which have gettys > etc. set up on /dev/ttyX but not /dev/xvcX.We''re waiting to hear from lanana before switching to xvc. I re-submitted the allocation request two weeks ago (31st October). I haven''t heard anything yet. I suppose since static device nodes in /dev are rare these days (since everyone moved to udev) we can just squat on some device number for the time being, or settle for requesting a dynamic one at boot time and require use of udev for anyone who cares about the device node. We already settled for that with /dev/xen/evtchn, for example. -- Keir _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
[A bit of context restored] Keir Fraser <Keir.Fraser@cl.cam.ac.uk> writes:> On 12/11/06 2:20 pm, "Steven Smith" <sos22-xen@srcf.ucam.org> wrote: >diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/console/console.c linux-2.6.16.29-xen-vfb/drivers/xen/console/console.c --- linux-2.6.16.29-xen/drivers/xen/console/console.c 2006-09-29 16:11:51.000000000 +0200 +++ linux-2.6.16.29-xen-vfb/drivers/xen/console/console.c 2006-11-10 09:43:37.000000000 +0100 @@ -195,12 +210,23 @@ static int __init xen_console_init(void) } else { if (!xen_start_info->console.domU.evtchn) goto out; - if (xc_mode == XC_DEFAULT) - xc_mode = XC_TTY;>>> +#ifdef CONFIG_XEN_FRAMEBUFFER >>> + xc_mode = XC_XVC; >>> +#else >>> + xc_mode = XC_TTY; >>> +#endif >>> + } >> This hunk is changing the default behaviour of xencons in domU from >> registering as tty{0...} to registering as xvc{0...}, yes? That''s >> going to confuse a lot of people with existing domUs which have gettys >> etc. set up on /dev/ttyX but not /dev/xvcX. > > We''re waiting to hear from lanana before switching to xvc. I re-submitted > the allocation request two weeks ago (31st October). I haven''t heard > anything yet. I suppose since static device nodes in /dev are rare these > days (since everyone moved to udev) we can just squat on some device number > for the time being, or settle for requesting a dynamic one at boot time and > require use of udev for anyone who cares about the device node. We already > settled for that with /dev/xen/evtchn, for example.What do you want me to do here for the short term? Drop the patch hunk and let you sort it out? Please mind the discussion we had some time ago, most relevant message appended. From: Steven Smith <sos22-xen@srcf.ucam.org> Subject: Re: [Xen-devel] [PATCH] Paravirt framebuffer use xvc as console [4/5] To: Jeremy Katz <katzj@redhat.com> Cc: xen-devel <xen-devel@lists.xensource.com>, Markus Armbruster <armbru@redhat.com>, sos22@srcf.ucam.org, Amos Waterland <apw@us.ibm.com> Date: Wed, 6 Sep 2006 22:17:13 +0100> > > > > This is the patch from Amos Waterland for the xenconsole to > > > > > use /dev/xvc0 instead of taking over ttys. I''ve fixed a few places > > > > > which needed to check for XVC mode in addition to serial mode. Also, > > > > > until LANANA responds with an official minor, I''ve adjusted it to use > > > > > char 250/187 (in the experimental range) as opposed to 204/187. > > > > > > > > > > (Should be identical to this patch from last time) > > > > Does this have anything to do with the virtual framebuffer work, or > > > > does it stand alone? > > > It stands alone, but without it, the framebuffer bits get a little > > > confusing to actually try to have used as the console. > > What goes wrong? > xenconsole takes over ttys and although you can see the framebuffer with > the penguin and X will start, you can''t actually use the framebuffer as > a console :-)Ack, got it now. Forgive me for being a little slow.> > > > > @@ -194,11 +209,17 @@ static int __init xen_console_init(void) > > > > > kcons_info.write = kcons_write_dom0; > > > > > } else { > > > > > if (xc_mode == XC_DEFAULT) > > > > > - xc_mode = XC_TTY; > > > > > + xc_mode = XC_XVC; > > > > Not convinced we want to change the default until a little while after > > > > the rest of the patch gets merged. > > > The default *HAS* to be changed -- otherwise, the xvc console tries to > > > take over ttys (which is really really really wrong in the guest) > > So why have we survived this far without it? If XC_TTY is completely > > broken, why not remove it completely? > We''ve survived this far because there isn''t anything else which is > trying to use the console and this hack let people pretend they had > multiple vcs[1].Perhaps make this part #ifdef on CONFIG_XENFB at first? It''ll be easier to merge if it obviously doesn''t break any existing setup. Steven. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
On 13/11/06 13:09, "Markus Armbruster" <armbru@redhat.com> wrote:>> We''re waiting to hear from lanana before switching to xvc. I re-submitted >> the allocation request two weeks ago (31st October). I haven''t heard >> anything yet. I suppose since static device nodes in /dev are rare these >> days (since everyone moved to udev) we can just squat on some device number >> for the time being, or settle for requesting a dynamic one at boot time and >> require use of udev for anyone who cares about the device node. We already >> settled for that with /dev/xen/evtchn, for example. > > What do you want me to do here for the short term? Drop the patch > hunk and let you sort it out?It doesn''t seem to have much to do with the paravirt fb patch, so probably it should be dropped. -- Keir _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Steven Smith <sos22-xen@srcf.ucam.org> writes:>> diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/console/console.c linux-2.6.16.29-xen-vfb/drivers/xen/console/console.c >> --- linux-2.6.16.29-xen/drivers/xen/console/console.c 2006-09-29 16:11:51.000000000 +0200 >> +++ linux-2.6.16.29-xen-vfb/drivers/xen/console/console.c 2006-11-10 09:43:37.000000000 +0100 >> @@ -195,12 +210,23 @@ static int __init xen_console_init(void) >> } else { >> if (!xen_start_info->console.domU.evtchn) >> goto out; >> - if (xc_mode == XC_DEFAULT) >> - xc_mode = XC_TTY; >> + if (xc_mode == XC_DEFAULT) { >> +#ifdef CONFIG_XEN_FRAMEBUFFER >> + xc_mode = XC_XVC; >> +#else >> + xc_mode = XC_TTY; >> +#endif >> + } > This hunk is changing the default behaviour of xencons in domU from > registering as tty{0...} to registering as xvc{0...}, yes? That''s > going to confuse a lot of people with existing domUs which have gettys > etc. set up on /dev/ttyX but not /dev/xvcX. > > Or am I confused again?Already discussed elsewhere.>> kcons_info.write = kcons_write; >> } >> >> switch (xc_mode) { >> >> diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/Kconfig linux-2.6.16.29-xen-vfb/drivers/xen/Kconfig >> --- linux-2.6.16.29-xen/drivers/xen/Kconfig 2006-08-16 09:20:03.000000000 +0200 >> +++ linux-2.6.16.29-xen-vfb/drivers/xen/Kconfig 2006-11-10 09:43:37.000000000 +0100 >> @@ -172,3 +172,19 @@ config XEN_NETDEV_FRONTEND >> dedicated device-driver domain, or your master control domain >> (domain 0), then you almost certainly want to say Y here. >> >> +config XEN_FRAMEBUFFER >> + tristate "Framebuffer-device frontend driver" >> + depends on XEN && FB >> + select FB_CFB_FILLRECT >> + select FB_CFB_COPYAREA >> + select FB_CFB_IMAGEBLIT >> + default y >> + help >> + The framebuffer-device frontend drivers allows the kernel to create a >> + virtual framebuffer. This framebuffer can be viewed in another >> + domain. Unless this domain has access to a real video card, you >> + probably want to say Y here. >> + >> +config XEN_KEYBOARD >> + tristate "Keyboard-device frontend driver" >> + depends on XEN > Does this want to depend on XEN_FRAMEBUFFER and INPUT?XEN_FRAMEBUFFER: yes. Jeremy fixed that, but I mismerged. INPUT: I missed that.>> + default y >> + help >> + The keyboard-device frontend driver allows the kernel to create a >> + virtual keyboard. This keyboard can then be driven by another >> + domain. If you''ve said Y to CONFIG_XEN_FRAMEBUFFER, you probably >> + want to say Y here. >> + >> config XEN_SCRUB_PAGES >> bool "Scrub memory before freeing it to Xen" >> default y >> diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/console/console.c linux-2.6.16.29-xen-vfb/drivers/xen/console/console.c >> --- linux-2.6.16.29-xen/drivers/xen/console/console.c 2006-09-29 16:11:51.000000000 +0200 >> +++ linux-2.6.16.29-xen-vfb/drivers/xen/console/console.c 2006-11-10 09:43:37.000000000 +0100 >> @@ -680,3 +712,17 @@ static int __init xencons_init(void) >> printk("Xen virtual console successfully installed as %s%d\n", >> DRV(xencons_driver)->name, xc_num); >> >> + /* Don''t need to check about graphical fb for domain 0 */ >> + if (is_initial_xendomain()) >> + return 0; >> + >> + rc = 0; >> + if (xenbus_scanf(XBT_NIL, "console", "use_graphics", "%d", &rc) < 0) >> + printk(KERN_ERR "Unable to read console/use_graphics\n"); >> + if (rc == 0) { >> + /* FIXME: this is ugly */ >> + unregister_console(&kcons_info); >> + kcons_info.flags |= CON_CONSDEV; >> + register_console(&kcons_info); >> + } > I''m still not entirely sure I understand why this bit is necessary. > > From talking to katz@redhat.com last time: > >> > > > > Also, why do you need to set CON_CONSDEV at all? >> > > > Otherwise, you don''t get kernel console messages. >> > > Why not? None of the other console drivers seem to need to set it >> > > explicitly, and it seems like it would break setting console=blah on >> > > the kernel command line. >> > Nothing else sets it explicitly because it happens implicitly in the >> > console registration code for the first thing registered with >> > register_console(). Alternately, if you have a console=, then >> > register_console ensures that your console device has CON_CONSDEV set. >> > kernel/printk.c if you want to read all the gory details >> The intent of this code seems to be to make sure that CON_CONSDEV is >> definitely set on xenconsole if use_graphics is not set, yes? But as >> far as I can see, if use_graphics is not set, xenfb should never call >> register_console(), and so this is all redundant. > > > I''m still just as unenlightened as I was then. Plus, xen_console_init > should be called before any of the pvfb stuff anyway, since it''s a > console_initcall and pvfb starts from a module_init, so it''s doubly > redundant.Jeremy, could you elaborate?>> return 0; >> } >> >> diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/xenfb/xenfb.c linux-2.6.16.29-xen-vfb/drivers/xen/xenfb/xenfb.c >> --- linux-2.6.16.29-xen/drivers/xen/xenfb/xenfb.c 1970-01-01 01:00:00.000000000 +0100 >> +++ linux-2.6.16.29-xen-vfb/drivers/xen/xenfb/xenfb.c 2006-11-10 09:43:37.000000000 +0100 >> >> +static int __devinit xenfb_probe(struct xenbus_device *dev, >> + const struct xenbus_device_id *id) >> +{ > ... >> + ret = fb_alloc_cmap(&fb_info->cmap, 256, 0); >> + if (ret < 0) { >> + framebuffer_release(fb_info); >> + xenbus_dev_fatal(dev, ret, "fb_alloc_cmap"); >> + goto error; >> + } >> + >> + /* FIXME should this be delayed until backend XenbusStateConnected? */ > I would, but I''m not sure it matters too much. You have a potentially > slightly confusing situation where someone starts using the > framebuffer before the backend connects, so the backend has to be able > to handle there being events on the ring when it starts, but I think > it probably works as it is.Yes, it works. I might move it eventually just for cleanliness.>> + ret = register_framebuffer(fb_info); >> + if (ret) { >> + fb_dealloc_cmap(&info->fb_info->cmap); >> + framebuffer_release(fb_info); >> + xenbus_dev_fatal(dev, ret, "register_framebuffer"); >> + goto error; >> + } >> + info->fb_info = fb_info; >> + >> + info->kthread = kthread_run(xenfb_thread, info, "xenfb thread"); >> + if (IS_ERR(info->kthread)) { >> + ret = PTR_ERR(info->kthread); >> + xenbus_dev_fatal(dev, ret, "register_framebuffer"); >> + goto error; > goto error will end up calling xenfb_remove, which will notice that > info->kthread is non-NULL and try to kthread_stop it. That strikes me > as a bad idea. > ...Oops. Thanks for catching.>> +static int __devexit xenfb_remove(struct xenbus_device *dev) > This gets called from some error paths even when the driver is > remaining loaded. Is __devexit safe? I''m thinking particularly of > the case where the kernel is compiled without module unloading and > discards exit text segments.Insufficient understanding of __devexit on my part. Fixing.>> +{ >> + struct xenfb_info *info = dev->dev.driver_data; >> + >> + del_timer(&info->refresh); >> + if (info->kthread) >> + kthread_stop(info->kthread); >> + if (info->irq >= 0) >> + unbind_from_irqhandler(info->irq, info); >> + if (info->fb_info) { >> + unregister_framebuffer(info->fb_info); >> + fb_dealloc_cmap(&info->fb_info->cmap); >> + framebuffer_release(info->fb_info); >> + } >> + free_page((unsigned long)info->page); >> + vfree(info->mfns); >> + kfree(info->pages); >> + vfree(info->fb); >> + kfree(info); >> + >> + return 0; >> +} >> + >> +static struct xenbus_driver xenfb = { >> + .name = "vfb", >> + .owner = THIS_MODULE, >> + .ids = xenfb_ids, >> + .probe = xenfb_probe, >> + .remove = xenfb_remove, > I think this wants to be __devexit_p.Only if xenfb is __devexit, right?>> + /* TODO .resume = xenfb_resume, */ >> + .otherend_changed = xenfb_backend_changed, >> +}; >> + >> +static int __init xenfb_init(void) >> +{ >> + int ret; >> + >> + if (!is_running_on_xen()) >> + return -ENODEV; >> + >> + /* Nothing to do if running in dom0. */ >> + if (is_initial_xendomain()) >> + return -ENODEV; >> + /* if we''re not set up to use graphics mode, then don''t initialize */ >> + if (xenbus_scanf(XBT_NIL, "console", "use_graphics", "%d", &ret) < 0) >> + return -ENODEV; >> + if (ret == 0) >> + return -ENODEV; > Not sure about this. It seems to me like it might be useful to > sometimes have domains which have a PVFB but still use xencons for > kernel printks etc. Perhaps I''m just confused.I guess you''re right.>> + >> + return xenbus_register_frontend(&xenfb); >> +} >> + >> +static void __exit xenfb_cleanup(void) >> +{ >> + return xenbus_unregister_driver(&xenfb); >> +} >> + >> +module_init(xenfb_init); >> +module_exit(xenfb_cleanup); >> + >> +MODULE_LICENSE("GPL"); >> diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/xenkbd/xenkbd.c linux-2.6.16.29-xen-vfb/drivers/xen/xenkbd/xenkbd.c >> --- linux-2.6.16.29-xen/drivers/xen/xenkbd/xenkbd.c 1970-01-01 01:00:00.000000000 +0100 >> +++ linux-2.6.16.29-xen-vfb/drivers/xen/xenkbd/xenkbd.c 2006-11-10 09:43:37.000000000 +0100 >> @@ -0,0 +1,123 @@ >> +int __devinit xenkbd_probe(struct xenbus_device *dev, >> + const struct xenbus_device_id *id) >> +{ > ... >> + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); >> + input_dev->keybit[LONG(BTN_MOUSE)] >> + = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); >> + /* FIXME more buttons? */ >> + input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); > Do you need to set some bits in absbit, as well, since you can > generate absolute coordinate messages?We missed that. Curiously, everything seems to work all the same (as tested with evdev). Apparently, no consumer actually tests the bits correctly. Fixing anyway.>> + input_dev->name = "Xen Virtual Keyboard/Mouse"; >> + >> + input_set_abs_params(input_dev, ABS_X, 0, XENFB_WIDTH, 0, 0); >> + input_set_abs_params(input_dev, ABS_Y, 0, XENFB_HEIGHT, 0, 0); >> + >> + /* FIXME should this be delayed until backend XenbusStateConnected? */ > Again, I would move it if I were doing this, but it makes even less > difference here than it did before.Understood.>> + ret = register_framebuffer(fb_info); >> + if (ret) { >> + fb_dealloc_cmap(&info->fb_info->cmap); >> + framebuffer_release(fb_info); >> + xenbus_dev_fatal(dev, ret, "register_framebuffer"); >> + goto error; >> + } > ... > >> +static int __devexit xenkbd_remove(struct xenbus_device *dev) > Again, not convinced __devexit is entirely valid here.Same as above.>> +{ >> + struct xenkbd_info *info = dev->dev.driver_data; >> + >> + if (info->irq >= 0) >> + unbind_from_irqhandler(info->irq, info); >> + input_unregister_device(info->dev); >> + free_page((unsigned long)info->page); >> + kfree(info); >> + return 0; >> +} >> >> +static struct xenbus_driver xenkbd = { >> + .name = "vkbd", >> + .owner = THIS_MODULE, >> + .ids = xenkbd_ids, >> + .probe = xenkbd_probe, >> + .remove = xenkbd_remove, > Again, might want to be __devexit_p.Same as above.>> + //.resume = xenkbd_resume, >> + .otherend_changed = xenkbd_backend_changed, >> +}; >> + >> +static int __init xenkbd_init(void) >> +{ >> + int ret; >> + >> + if (!is_running_on_xen()) >> + return -ENODEV; >> + >> + /* Nothing to do if running in dom0. */ >> + if (is_initial_xendomain()) >> + return -ENODEV; >> + /* if we''re not set up to use graphics mode, then don''t initialize */ >> + if (xenbus_scanf(XBT_NIL, "console", "use_graphics", "%d", &ret) < 0) >> + return -ENODEV; >> + if (ret == 0) >> + return -ENODEV; > This test obviously wants to be kept in sync with the corresponding > test in xenfb_init, so the same comments apply here as there.Agreed.>> + return xenbus_register_frontend(&xenkbd); >> +} > >> diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/include/xen/interface/io/xenfb.h linux-2.6.16.29-xen-vfb/include/xen/interface/io/xenfb.h >> --- linux-2.6.16.29-xen/include/xen/interface/io/xenfb.h 1970-01-01 01:00:00.000000000 +0100 >> +++ linux-2.6.16.29-xen-vfb/include/xen/interface/io/xenfb.h 2006-11-10 09:43:37.000000000 +0100 > I think this really wants to be in xen/include/public/io, but I''d > guess this is just an artifact of the diff.Where in the *Linux* tree you want it? include/xen/interface or include/xen/public or somewhere else?>> +struct xenfb_update >> +{ >> + __u8 type; /* XENFB_TYPE_UPDATE */ >> + __s32 x; /* source x */ >> + __s32 y; /* source y */ >> + __s32 width; /* rect width */ >> + __s32 height; /* rect height */ >> +}; >> + >> +#define XENFB_OUT_EVENT_SIZE 40 >> + >> +union xenfb_out_event >> +{ >> + __u8 type; >> + struct xenfb_update update; >> + char pad[XENFB_OUT_EVENT_SIZE]; >> +}; > I still think you''d be better off doing tagged unions the usual way, > but your funeral.While I personally prefer Anthony''s way to do it, I''d convert to yours if I could ensure the type''s size remains exactly XENFB_OUT_EVENT_SIZE portably and without undue ugliness. Alternatively, if I could ensure the ring memory layout remains the same even when the type size changes.>> +/* >> + * Wart: xenkbd needs to know resolution. Put it here until a better >> + * solution is found, but don''t leak it to the backend. >> + */ > Why does xenkbd need to know the resolution? Do you mean xenfb? > > As far as I can see, these only get used in xenfb.c, so the #defines > could go there rather than in the IO description header.That''s where they used to be. But xenkbd needs to tell the input layer about the resolution to make absolute pointer work.>> +#ifdef __KERNEL__ >> +#define XENFB_WIDTH 800 >> +#define XENFB_HEIGHT 600 >> +#define XENFB_DEPTH 32 >> +#endif >> + >> +#endif > > Steven._______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
> >> + ret = fb_alloc_cmap(&fb_info->cmap, 256, 0); > >> + if (ret < 0) { > >> + framebuffer_release(fb_info); > >> + xenbus_dev_fatal(dev, ret, "fb_alloc_cmap"); > >> + goto error; > >> + } > >> + > >> + /* FIXME should this be delayed until backend XenbusStateConnected? */ > > I would, but I''m not sure it matters too much. You have a potentially > > slightly confusing situation where someone starts using the > > framebuffer before the backend connects, so the backend has to be able > > to handle there being events on the ring when it starts, but I think > > it probably works as it is. > > Yes, it works. > > I might move it eventually just for cleanliness.Actually, thinking about it, it probably does want to stay where it is, at least if you want to support backend disconnect/reconnect cleanly. If you kill the backend and restart it, _probe shouldn''t get run a second time, whereas the state machine transitions probably will be. You probably want to present the same device to Linux, so re-registering might not be a good idea.> >> + info->kthread = kthread_run(xenfb_thread, info, "xenfb thread"); > >> + if (IS_ERR(info->kthread)) { > >> + ret = PTR_ERR(info->kthread); > >> + xenbus_dev_fatal(dev, ret, "register_framebuffer"); > >> + goto error; > > goto error will end up calling xenfb_remove, which will notice that > > info->kthread is non-NULL and try to kthread_stop it. That strikes me > > as a bad idea. > > ... > Oops. Thanks for catching.np.> >> +static int __devexit xenfb_remove(struct xenbus_device *dev) > > This gets called from some error paths even when the driver is > > remaining loaded. Is __devexit safe? I''m thinking particularly of > > the case where the kernel is compiled without module unloading and > > discards exit text segments. > Insufficient understanding of __devexit on my part. Fixing.Yeah, I had to go and look it up.> >> +{ > >> + struct xenfb_info *info = dev->dev.driver_data; > >> + > >> + del_timer(&info->refresh); > >> + if (info->kthread) > >> + kthread_stop(info->kthread); > >> + if (info->irq >= 0) > >> + unbind_from_irqhandler(info->irq, info); > >> + if (info->fb_info) { > >> + unregister_framebuffer(info->fb_info); > >> + fb_dealloc_cmap(&info->fb_info->cmap); > >> + framebuffer_release(info->fb_info); > >> + } > >> + free_page((unsigned long)info->page); > >> + vfree(info->mfns); > >> + kfree(info->pages); > >> + vfree(info->fb); > >> + kfree(info); > >> + > >> + return 0; > >> +} > >> + > >> +static struct xenbus_driver xenfb = { > >> + .name = "vfb", > >> + .owner = THIS_MODULE, > >> + .ids = xenfb_ids, > >> + .probe = xenfb_probe, > >> + .remove = xenfb_remove, > > I think this wants to be __devexit_p. > Only if xenfb is __devexit, right?Yes, so if xenfb_remove loses __devexit this is correct.> >> + /* TODO .resume = xenfb_resume, */ > >> + .otherend_changed = xenfb_backend_changed, > >> +}; > >> + > >> +static int __init xenfb_init(void) > >> +{ > >> + int ret; > >> + > >> + if (!is_running_on_xen()) > >> + return -ENODEV; > >> + > >> + /* Nothing to do if running in dom0. */ > >> + if (is_initial_xendomain()) > >> + return -ENODEV; > >> + /* if we''re not set up to use graphics mode, then don''t initialize */ > >> + if (xenbus_scanf(XBT_NIL, "console", "use_graphics", "%d", &ret) < 0) > >> + return -ENODEV; > >> + if (ret == 0) > >> + return -ENODEV; > > Not sure about this. It seems to me like it might be useful to > > sometimes have domains which have a PVFB but still use xencons for > > kernel printks etc. Perhaps I''m just confused. > I guess you''re right.Thanks.> >> +int __devinit xenkbd_probe(struct xenbus_device *dev, > >> + const struct xenbus_device_id *id) > >> +{ > > ... > >> + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); > >> + input_dev->keybit[LONG(BTN_MOUSE)] > >> + = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); > >> + /* FIXME more buttons? */ > >> + input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); > > Do you need to set some bits in absbit, as well, since you can > > generate absolute coordinate messages? > We missed that. Curiously, everything seems to work all the same (as > tested with evdev). Apparently, no consumer actually tests the bits > correctly.Figures.> Fixing anyway.Thanks.> >> diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/include/xen/interface/io/xenfb.h linux-2.6.16.29-xen-vfb/include/xen/interface/io/xenfb.h > >> --- linux-2.6.16.29-xen/include/xen/interface/io/xenfb.h 1970-01-01 01:00:00.000000000 +0100 > >> +++ linux-2.6.16.29-xen-vfb/include/xen/interface/io/xenfb.h 2006-11-10 09:43:37.000000000 +0100 > > I think this really wants to be in xen/include/public/io, but I''d > > guess this is just an artifact of the diff. > Where in the *Linux* tree you want it? include/xen/interface or > include/xen/public or somewhere else?The IO header files all go in xen/include/public/io, with symlinks from linux/include/xen/interface/io. Your tree may be different due to de-sparseification. If that''s all it is then I''ll just ignore this from now on.> >> +struct xenfb_update > >> +{ > >> + __u8 type; /* XENFB_TYPE_UPDATE */ > >> + __s32 x; /* source x */ > >> + __s32 y; /* source y */ > >> + __s32 width; /* rect width */ > >> + __s32 height; /* rect height */ > >> +}; > >> + > >> +#define XENFB_OUT_EVENT_SIZE 40 > >> + > >> +union xenfb_out_event > >> +{ > >> + __u8 type; > >> + struct xenfb_update update; > >> + char pad[XENFB_OUT_EVENT_SIZE]; > >> +}; > > I still think you''d be better off doing tagged unions the usual way, > > but your funeral. > While I personally prefer Anthony''s way to do it, I''d convert to yours > if I could ensure the type''s size remains exactly XENFB_OUT_EVENT_SIZE > portably and without undue ugliness. Alternatively, if I could ensure > the ring memory layout remains the same even when the type size > changes.How about something like this: struct xenfb_out_event { __u8 type; __u8 pad1[7]; union { struct xenfb_update update; __u8 pad[XENFB_OUT_SIZE-8]; } u; }; Does this satisfy your requirements? Admittedly, I''ve had to move some padding around to get good alignment, which I''d forgotten about before and makes it look a bit uglier than I was hoping, but I''d still say this is a little nicer.> >> +/* > >> + * Wart: xenkbd needs to know resolution. Put it here until a better > >> + * solution is found, but don''t leak it to the backend. > >> + */ > > Why does xenkbd need to know the resolution? Do you mean xenfb? > > > > As far as I can see, these only get used in xenfb.c, so the #defines > > could go there rather than in the IO description header. > That''s where they used to be. But xenkbd needs to tell the input > layer about the resolution to make absolute pointer work.That''s really quite unfortunate, and is going to cause problems when you start supporting changes in resolution. Does the resolution reported by xenkbd actually need to match the resolution of the framebuffer? Could you report a resolution of 65536x65536 and then have the backend scale it? Presumably, a real tablet won''t scale its output to match the display resolution. Steven. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Steven Smith <sos22-xen@srcf.ucam.org> writes:>> >> + ret = fb_alloc_cmap(&fb_info->cmap, 256, 0); >> >> + if (ret < 0) { >> >> + framebuffer_release(fb_info); >> >> + xenbus_dev_fatal(dev, ret, "fb_alloc_cmap"); >> >> + goto error; >> >> + } >> >> + >> >> + /* FIXME should this be delayed until backend XenbusStateConnected? */ >> > I would, but I''m not sure it matters too much. You have a potentially >> > slightly confusing situation where someone starts using the >> > framebuffer before the backend connects, so the backend has to be able >> > to handle there being events on the ring when it starts, but I think >> > it probably works as it is. >> >> Yes, it works. >> >> I might move it eventually just for cleanliness. > Actually, thinking about it, it probably does want to stay where it > is, at least if you want to support backend disconnect/reconnect > cleanly. If you kill the backend and restart it, _probe shouldn''t get > run a second time, whereas the state machine transitions probably will > be. You probably want to present the same device to Linux, so > re-registering might not be a good idea.Yeah, that makes sense. What about the kernel thread? I figure letting it run only while a backend is connected would make some sense. Anyway, no flawless diamond needed here for the initial merge.>> >> + info->kthread = kthread_run(xenfb_thread, info, "xenfb thread"); >> >> + if (IS_ERR(info->kthread)) { >> >> + ret = PTR_ERR(info->kthread); >> >> + xenbus_dev_fatal(dev, ret, "register_framebuffer"); >> >> + goto error;[...]>> >> +int __devinit xenkbd_probe(struct xenbus_device *dev, >> >> + const struct xenbus_device_id *id) >> >> +{ >> > ... >> >> + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); >> >> + input_dev->keybit[LONG(BTN_MOUSE)] >> >> + = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); >> >> + /* FIXME more buttons? */ >> >> + input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); >> > Do you need to set some bits in absbit, as well, since you can >> > generate absolute coordinate messages? >> We missed that. Curiously, everything seems to work all the same (as >> tested with evdev). Apparently, no consumer actually tests the bits >> correctly. > Figures. > >> Fixing anyway. > Thanks.Haha, I found it: input_set_abs_params() takes care of absbit[] [...] automatically.>> >> diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/include/xen/interface/io/xenfb.h linux-2.6.16.29-xen-vfb/include/xen/interface/io/xenfb.h >> >> --- linux-2.6.16.29-xen/include/xen/interface/io/xenfb.h 1970-01-01 01:00:00.000000000 +0100 >> >> +++ linux-2.6.16.29-xen-vfb/include/xen/interface/io/xenfb.h 2006-11-10 09:43:37.000000000 +0100 >> > I think this really wants to be in xen/include/public/io, but I''d >> > guess this is just an artifact of the diff. >> Where in the *Linux* tree you want it? include/xen/interface or >> include/xen/public or somewhere else? > The IO header files all go in xen/include/public/io, with symlinks > from linux/include/xen/interface/io. Your tree may be different due > to de-sparseification. If that''s all it is then I''ll just ignore this > from now on.Yes, that''s all it is.>> >> +struct xenfb_update >> >> +{ >> >> + __u8 type; /* XENFB_TYPE_UPDATE */ >> >> + __s32 x; /* source x */ >> >> + __s32 y; /* source y */ >> >> + __s32 width; /* rect width */ >> >> + __s32 height; /* rect height */ >> >> +}; >> >> + >> >> +#define XENFB_OUT_EVENT_SIZE 40 >> >> + >> >> +union xenfb_out_event >> >> +{ >> >> + __u8 type; >> >> + struct xenfb_update update; >> >> + char pad[XENFB_OUT_EVENT_SIZE]; >> >> +}; >> > I still think you''d be better off doing tagged unions the usual way, >> > but your funeral. >> While I personally prefer Anthony''s way to do it, I''d convert to yours >> if I could ensure the type''s size remains exactly XENFB_OUT_EVENT_SIZE >> portably and without undue ugliness. Alternatively, if I could ensure >> the ring memory layout remains the same even when the type size >> changes. > How about something like this: > > struct xenfb_out_event { > __u8 type; > __u8 pad1[7]; > union { > struct xenfb_update update; > __u8 pad[XENFB_OUT_SIZE-8]; > } u; > }; > > Does this satisfy your requirements? Admittedly, I''ve had to move > some padding around to get good alignment, which I''d forgotten about > before and makes it look a bit uglier than I was hoping, but I''d still > say this is a little nicer.Umm, doesn''t this make non-portable assumptions? What if __alignof(update) > 8? What if __alignof__(pad1) != 1? I admit I''d be surprised by the latter. Even if we dismiss the portability problem as theoretical: isn''t this padding game too clever by half?>> >> +/* >> >> + * Wart: xenkbd needs to know resolution. Put it here until a better >> >> + * solution is found, but don''t leak it to the backend. >> >> + */ >> > Why does xenkbd need to know the resolution? Do you mean xenfb? >> > >> > As far as I can see, these only get used in xenfb.c, so the #defines >> > could go there rather than in the IO description header. >> That''s where they used to be. But xenkbd needs to tell the input >> layer about the resolution to make absolute pointer work. > That''s really quite unfortunate, and is going to cause problems when > you start supporting changes in resolution. > > Does the resolution reported by xenkbd actually need to match the > resolution of the framebuffer? Could you report a resolution of > 65536x65536 and then have the backend scale it? Presumably, a real > tablet won''t scale its output to match the display resolution.I''m not worried about this right now. When we start supporting resolution change, we can figure out whether lying about the resolution works. If it doesn''t, I''m sure we''ll find a reasonable way to communicate the real resolution to xenkbd. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
> >> >> + /* FIXME should this be delayed until backend XenbusStateConnected? */ > >> > I would, but I''m not sure it matters too much. You have a potentially > >> > slightly confusing situation where someone starts using the > >> > framebuffer before the backend connects, so the backend has to be able > >> > to handle there being events on the ring when it starts, but I think > >> > it probably works as it is. > >> Yes, it works. > >> > >> I might move it eventually just for cleanliness. > > Actually, thinking about it, it probably does want to stay where it > > is, at least if you want to support backend disconnect/reconnect > > cleanly. If you kill the backend and restart it, _probe shouldn''t get > > run a second time, whereas the state machine transitions probably will > > be. You probably want to present the same device to Linux, so > > re-registering might not be a good idea. > Yeah, that makes sense. > > What about the kernel thread? I figure letting it run only while a > backend is connected would make some sense. Anyway, no flawless > diamond needed here for the initial merge.I''m not bothered. Just do whatever''s easier.> >> >> + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); > >> >> + input_dev->keybit[LONG(BTN_MOUSE)] > >> >> + = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); > >> >> + /* FIXME more buttons? */ > >> >> + input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); > >> > Do you need to set some bits in absbit, as well, since you can > >> > generate absolute coordinate messages? > >> We missed that. Curiously, everything seems to work all the same (as > >> tested with evdev). Apparently, no consumer actually tests the bits > >> correctly. > > Figures. > > > >> Fixing anyway. > > Thanks. > Haha, I found it: input_set_abs_params() takes care of absbit[] [...] > automatically.Ah, okay. Thanks for clearing that up for me.> >> > I still think you''d be better off doing tagged unions the usual way, > >> > but your funeral. > >> While I personally prefer Anthony''s way to do it, I''d convert to yours > >> if I could ensure the type''s size remains exactly XENFB_OUT_EVENT_SIZE > >> portably and without undue ugliness. Alternatively, if I could ensure > >> the ring memory layout remains the same even when the type size > >> changes. > > How about something like this: > > > > struct xenfb_out_event { > > __u8 type; > > __u8 pad1[7]; > > union { > > struct xenfb_update update; > > __u8 pad[XENFB_OUT_SIZE-8]; > > } u; > > }; > > > > Does this satisfy your requirements? Admittedly, I''ve had to move > > some padding around to get good alignment, which I''d forgotten about > > before and makes it look a bit uglier than I was hoping, but I''d still > > say this is a little nicer. > Umm, doesn''t this make non-portable assumptions? What if > __alignof(update) > 8? What if __alignof__(pad1) != 1? I admit I''d > be surprised by the latter.I''m quite happy to ignore this problem. Certainly 8 bit types which need more than 8 bit alignment are pretty unexpected, and I''d be amazed if we any of the standard integer types need more than 8 byte alignment on any reasonable architecture. If you''re planning on sending weird SSE types across or something like that then you might have problems, but frankly at that point you deserve everything you get.> Even if we dismiss the portability problem as theoretical: isn''t this > padding game too clever by half?You do need to think about padding to some extent when doing this sort of thing. One of the things which we''d like for new IO protocols is to have the same byte layout between 32 and 64 bit guests, so that you don''t sabotage the ongoing work to get 32 bit guests working on 64 bit hosts. In the past, we''ve screwed up by relying on the compiler to insert implicit padding in e.g. the block request structure, and then discovered later on that it does it differently in 32 and 64 bit mode. Making the padding explicit also makes it more obviously where you can insert fields if we decide that we want e.g. per-request flags in a few months'' time. Anyway, this whole issue is a bikeshed. Do whichever you prefer.> >> >> +/* > >> >> + * Wart: xenkbd needs to know resolution. Put it here until a better > >> >> + * solution is found, but don''t leak it to the backend. > >> >> + */ > >> > Why does xenkbd need to know the resolution? Do you mean xenfb? > >> > > >> > As far as I can see, these only get used in xenfb.c, so the #defines > >> > could go there rather than in the IO description header. > >> That''s where they used to be. But xenkbd needs to tell the input > >> layer about the resolution to make absolute pointer work. > > That''s really quite unfortunate, and is going to cause problems when > > you start supporting changes in resolution. > > > > Does the resolution reported by xenkbd actually need to match the > > resolution of the framebuffer? Could you report a resolution of > > 65536x65536 and then have the backend scale it? Presumably, a real > > tablet won''t scale its output to match the display resolution. > I''m not worried about this right now. When we start supporting > resolution change, we can figure out whether lying about the > resolution works. If it doesn''t, I''m sure we''ll find a reasonable way > to communicate the real resolution to xenkbd.Okay. Steven. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
PV framebuffer frontend. Derived from http://www.cs.utexas.edu/users/aliguori/vfb-20060124.bundle Extensive changes based on feedback from xen-devel. Signed-off-by: Markus Armbruster <armbru@redhat.com> --- arch/i386/kernel/setup-xen.c | 5 arch/ia64/kernel/setup.c | 4 arch/x86_64/kernel/setup-xen.c | 7 drivers/char/tty_io.c | 6 drivers/xen/Kconfig | 23 + drivers/xen/Makefile | 2 drivers/xen/console/console.c | 51 ++- drivers/xen/xenfb/Makefile | 1 drivers/xen/xenfb/xenfb.c | 642 ++++++++++++++++++++++++++++++++++++++ drivers/xen/xenkbd/Makefile | 1 drivers/xen/xenkbd/xenkbd.c | 271 ++++++++++++++++ include/xen/interface/io/xenfb.h | 116 ++++++ include/xen/interface/io/xenkbd.h | 108 ++++++ mm/memory.c | 1 14 files changed, 1221 insertions(+), 17 deletions(-) diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/arch/i386/kernel/setup-xen.c linux-2.6.16.29-xen-pvfb/arch/i386/kernel/setup-xen.c --- linux-2.6.16.29-xen/arch/i386/kernel/setup-xen.c 2006-09-29 16:11:51.000000000 +0200 +++ linux-2.6.16.29-xen-pvfb/arch/i386/kernel/setup-xen.c 2006-11-17 13:38:02.000000000 +0100 @@ -1850,8 +1850,9 @@ void __init setup_arch(char **cmdline_p) #endif #endif } else { - extern int console_use_vt; - console_use_vt = 0; +#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE) + conswitchp = &dummy_con; +#endif } } diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/arch/ia64/kernel/setup.c linux-2.6.16.29-xen-pvfb/arch/ia64/kernel/setup.c --- linux-2.6.16.29-xen/arch/ia64/kernel/setup.c 2006-11-09 17:54:47.000000000 +0100 +++ linux-2.6.16.29-xen-pvfb/arch/ia64/kernel/setup.c 2006-11-17 13:38:02.000000000 +0100 @@ -550,9 +550,9 @@ setup_arch (char **cmdline_p) xen_start_info->nr_pages, xen_start_info->flags); if (!is_initial_xendomain()) { - extern int console_use_vt; +#if !defined(CONFIG_VT) || !defined(CONFIG_DUMMY_CONSOLE) conswitchp = NULL; - console_use_vt = 0; +#endif } } #endif diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/arch/x86_64/kernel/setup-xen.c linux-2.6.16.29-xen-pvfb/arch/x86_64/kernel/setup-xen.c --- linux-2.6.16.29-xen/arch/x86_64/kernel/setup-xen.c 2006-09-29 16:11:51.000000000 +0200 +++ linux-2.6.16.29-xen-pvfb/arch/x86_64/kernel/setup-xen.c 2006-11-17 13:38:02.000000000 +0100 @@ -970,9 +970,10 @@ void __init setup_arch(char **cmdline_p) #endif #endif } else { - extern int console_use_vt; - console_use_vt = 0; - } +#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE) + conswitchp = &dummy_con; +#endif + } } #else /* CONFIG_XEN */ diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/char/tty_io.c linux-2.6.16.29-xen-pvfb/drivers/char/tty_io.c --- linux-2.6.16.29-xen/drivers/char/tty_io.c 2006-09-29 16:11:51.000000000 +0200 +++ linux-2.6.16.29-xen-pvfb/drivers/char/tty_io.c 2006-11-17 13:38:02.000000000 +0100 @@ -132,8 +132,6 @@ LIST_HEAD(tty_drivers); /* linked list vt.c for deeply disgusting hack reasons */ DECLARE_MUTEX(tty_sem); -int console_use_vt = 1; - #ifdef CONFIG_UNIX98_PTYS extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */ extern int pty_limit; /* Config limit on Unix98 ptys */ @@ -2056,7 +2054,7 @@ retry_open: goto got_driver; } #ifdef CONFIG_VT - if (console_use_vt && (device == MKDEV(TTY_MAJOR,0))) { + if (device == MKDEV(TTY_MAJOR,0)) { extern struct tty_driver *console_driver; driver = console_driver; index = fg_console; @@ -3247,8 +3245,6 @@ static int __init tty_init(void) #endif #ifdef CONFIG_VT - if (!console_use_vt) - goto out_vt; cdev_init(&vc0_cdev, &console_fops); if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) || register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/console/console.c linux-2.6.16.29-xen-pvfb/drivers/xen/console/console.c --- linux-2.6.16.29-xen/drivers/xen/console/console.c 2006-09-29 16:11:51.000000000 +0200 +++ linux-2.6.16.29-xen-pvfb/drivers/xen/console/console.c 2006-11-17 13:38:02.000000000 +0100 @@ -58,20 +58,28 @@ #include <asm/hypervisor.h> #include <xen/evtchn.h> #include <xen/xencons.h> +#include <xen/xenbus.h> /* * Modes: * ''xencons=off'' [XC_OFF]: Console is disabled. * ''xencons=tty'' [XC_TTY]: Console attached to ''/dev/tty[0-9]+''. * ''xencons=ttyS'' [XC_SERIAL]: Console attached to ''/dev/ttyS[0-9]+''. + * ''xencons=xvc'' [XC_XVC]: Console attached to ''/dev/xvc[0-9]+''. * [XC_DEFAULT]: DOM0 -> XC_SERIAL ; all others -> XC_TTY. * * NB. In mode XC_TTY, we create dummy consoles for tty2-63. This suppresses * warnings from standard distro startup scripts. */ -static enum { XC_OFF, XC_DEFAULT, XC_TTY, XC_SERIAL } xc_mode = XC_DEFAULT; +static enum { XC_OFF, XC_DEFAULT, XC_TTY, XC_SERIAL, XC_XVC } + xc_mode = XC_DEFAULT; static int xc_num = -1; +/* If we are in XC_XVC mode (a virtual console at /dev/xvcX), we need to + * comply with Lanana and use a minor under the low density serial major. + */ +#define XEN_XVC_MINOR 187 + #ifdef CONFIG_MAGIC_SYSRQ static unsigned long sysrq_requested; extern int sysrq_enabled; @@ -86,6 +94,8 @@ static int __init xencons_setup(char *st xc_mode = XC_SERIAL; else if (!strncmp(str, "tty", 3)) xc_mode = XC_TTY; + else if (!strncmp(str, "xvc", 3)) + xc_mode = XC_XVC; else if (!strncmp(str, "off", 3)) xc_mode = XC_OFF; @@ -100,6 +110,11 @@ static int __init xencons_setup(char *st if (q > (str + 3)) xc_num = n; break; + case XC_XVC: + n = simple_strtol(str+3, &q, 10); + if (q > (str + 3)) + xc_num = n; + break; default: break; } @@ -195,12 +210,23 @@ static int __init xen_console_init(void) } else { if (!xen_start_info->console.domU.evtchn) goto out; - if (xc_mode == XC_DEFAULT) - xc_mode = XC_TTY; + if (xc_mode == XC_DEFAULT) { +#ifdef CONFIG_XEN_FRAMEBUFFER + xc_mode = XC_XVC; +#else + xc_mode = XC_TTY; +#endif + } kcons_info.write = kcons_write; } switch (xc_mode) { + case XC_XVC: + strcpy(kcons_info.name, "xvc"); + if (xc_num == -1) + xc_num = 0; + break; + case XC_SERIAL: strcpy(kcons_info.name, "ttyS"); if (xc_num == -1) @@ -305,7 +331,7 @@ void dom0_init_screen_info(const struct /******************** User-space console driver (/dev/console) ************/ #define DRV(_d) (_d) -#define DUMMY_TTY(_tty) ((xc_mode != XC_SERIAL) && \ +#define DUMMY_TTY(_tty) ((xc_mode != XC_SERIAL) && (xc_mode != XC_XVC) && \ ((_tty)->index != (xc_num - 1))) static struct termios *xencons_termios[MAX_NR_CONSOLES]; @@ -628,7 +654,8 @@ static int __init xencons_init(void) return rc; } - xencons_driver = alloc_tty_driver((xc_mode == XC_SERIAL) ? + xencons_driver = alloc_tty_driver(((xc_mode == XC_SERIAL) || + (xc_mode == XC_XVC)) ? 1 : MAX_NR_CONSOLES); if (xencons_driver == NULL) return -ENOMEM; @@ -648,6 +675,11 @@ static int __init xencons_init(void) DRV(xencons_driver)->name = "ttyS"; DRV(xencons_driver)->minor_start = 64 + xc_num; DRV(xencons_driver)->name_base = 0 + xc_num; + } else if (xc_mode == XC_XVC) { + DRV(xencons_driver)->name = "xvc"; + DRV(xencons_driver)->major = 250; /* FIXME: until lanana approves for 204:187 */ + DRV(xencons_driver)->minor_start = XEN_XVC_MINOR; + DRV(xencons_driver)->name_base = xc_num; } else { DRV(xencons_driver)->name = "tty"; DRV(xencons_driver)->minor_start = 1; @@ -680,6 +712,15 @@ static int __init xencons_init(void) printk("Xen virtual console successfully installed as %s%d\n", DRV(xencons_driver)->name, xc_num); + /* Check about framebuffer messing up the console */ + if (!is_initial_xendomain() && + !xenbus_exists(XBT_NIL, "device", "vfb")) { + /* FIXME: this is ugly */ + unregister_console(&kcons_info); + kcons_info.flags |= CON_CONSDEV; + register_console(&kcons_info); + } + return 0; } diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/Kconfig linux-2.6.16.29-xen-pvfb/drivers/xen/Kconfig --- linux-2.6.16.29-xen/drivers/xen/Kconfig 2006-08-16 09:20:03.000000000 +0200 +++ linux-2.6.16.29-xen-pvfb/drivers/xen/Kconfig 2006-11-17 13:38:02.000000000 +0100 @@ -172,6 +172,29 @@ config XEN_NETDEV_FRONTEND dedicated device-driver domain, or your master control domain (domain 0), then you almost certainly want to say Y here. +config XEN_FRAMEBUFFER + tristate "Framebuffer-device frontend driver" + depends on XEN && FB + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + default y + help + The framebuffer-device frontend drivers allows the kernel to create a + virtual framebuffer. This framebuffer can be viewed in another + domain. Unless this domain has access to a real video card, you + probably want to say Y here. + +config XEN_KEYBOARD + tristate "Keyboard-device frontend driver" + depends on XEN && XEN_FRAMEBUFFER && INPUT + default y + help + The keyboard-device frontend driver allows the kernel to create a + virtual keyboard. This keyboard can then be driven by another + domain. If you''ve said Y to CONFIG_XEN_FRAMEBUFFER, you probably + want to say Y here. + config XEN_SCRUB_PAGES bool "Scrub memory before freeing it to Xen" default y diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/Makefile linux-2.6.16.29-xen-pvfb/drivers/xen/Makefile --- linux-2.6.16.29-xen/drivers/xen/Makefile 2006-07-20 14:12:19.000000000 +0200 +++ linux-2.6.16.29-xen-pvfb/drivers/xen/Makefile 2006-11-17 13:38:02.000000000 +0100 @@ -15,3 +15,5 @@ obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += blk obj-$(CONFIG_XEN_NETDEV_FRONTEND) += netfront/ obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback/ obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += pcifront/ +obj-$(CONFIG_XEN_FRAMEBUFFER) += xenfb/ +obj-$(CONFIG_XEN_KEYBOARD) += xenkbd/ diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/xenfb/Makefile linux-2.6.16.29-xen-pvfb/drivers/xen/xenfb/Makefile --- linux-2.6.16.29-xen/drivers/xen/xenfb/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.29-xen-pvfb/drivers/xen/xenfb/Makefile 2006-11-17 13:38:02.000000000 +0100 @@ -0,0 +1 @@ +obj-$(CONFIG_XEN_FRAMEBUFFER) := xenfb.o diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/xenfb/xenfb.c linux-2.6.16.29-xen-pvfb/drivers/xen/xenfb/xenfb.c --- linux-2.6.16.29-xen/drivers/xen/xenfb/xenfb.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.29-xen-pvfb/drivers/xen/xenfb/xenfb.c 2006-11-17 13:38:02.000000000 +0100 @@ -0,0 +1,642 @@ +/* + * linux/drivers/video/xenfb.c -- Xen para-virtual frame buffer device + * + * Copyright (C) 2005-2006 Anthony Liguori <aliguori@us.ibm.com> + * Copyright (C) 2006 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/kernel.h> +#include <linux/errno.h> +#include <linux/fb.h> +#include <linux/module.h> +#include <linux/vmalloc.h> +#include <linux/mm.h> +#include <asm/hypervisor.h> +#include <xen/evtchn.h> +#include <xen/interface/io/xenfb.h> +#include <xen/xenbus.h> +#include <linux/kthread.h> + +struct xenfb_mapping +{ + struct list_head link; + struct vm_area_struct *vma; + atomic_t map_refs; + int faults; + struct xenfb_info *info; +}; + +struct xenfb_info +{ + struct task_struct *kthread; + wait_queue_head_t wq; + + unsigned char *fb; + struct fb_info *fb_info; + struct timer_list refresh; + int dirty; + int x1, y1, x2, y2; /* dirty rectangle, + protected by mm_lock */ + spinlock_t mm_lock; + int nr_pages; + struct page **pages; + struct list_head mappings; /* protected by mm_lock */ + + unsigned evtchn; + int irq; + struct xenfb_page *page; + unsigned long *mfns; + int update_wanted; /* XENFB_TYPE_UPDATE wanted */ + + struct xenbus_device *xbdev; +}; + +static int xenfb_fps = 20; +static unsigned long xenfb_mem_len = XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8; + +static int xenfb_remove(struct xenbus_device *); + +static void xenfb_do_update(struct xenfb_info *info, + int x, int y, int w, int h) +{ + union xenfb_out_event event; + __u32 prod; + + event.type = XENFB_TYPE_UPDATE; + event.update.x = x; + event.update.y = y; + event.update.width = w; + event.update.height = h; + + 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_evtchn(info->evtchn); +} + +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_update_screen(struct xenfb_info *info) +{ + unsigned long flags; + int y1, y2, x1, x2; + struct xenfb_mapping *map; + + if (!info->update_wanted) + return; + if (xenfb_queue_full(info)) + return; + + spin_lock_irqsave(&info->mm_lock, flags); + + y1 = info->y1; + y2 = info->y2; + x1 = info->x1; + x2 = info->x2; + info->x1 = info->y1 = INT_MAX; + info->x2 = info->y2 = 0; + + list_for_each_entry(map, &info->mappings, link) { + if (!map->faults) + continue; + zap_page_range(map->vma, map->vma->vm_start, + map->vma->vm_end - map->vma->vm_start, NULL); + map->faults = 0; + } + + spin_unlock_irqrestore(&info->mm_lock, flags); + + xenfb_do_update(info, x1, y1, x2 - x1, y2 - y1); +} + +static int xenfb_thread(void *data) +{ + struct xenfb_info *info = data; + + for (;;) { + if (kthread_should_stop()) + break; + if (info->dirty) { + info->dirty = 0; + xenfb_update_screen(info); + } + wait_event_interruptible(info->wq, + kthread_should_stop() || info->dirty); + } + return 0; +} + +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; + + red >>= (16 - info->var.red.length); + green >>= (16 - info->var.green.length); + blue >>= (16 - info->var.blue.length); + + v = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + + /* FIXME is this sane? check against xxxfb_setcolreg()! */ + switch (info->var.bits_per_pixel) { + case 16: + case 24: + case 32: + ((u32 *)info->pseudo_palette)[regno] = v; + break; + } + + return 0; +} + +static void xenfb_timer(unsigned long data) +{ + struct xenfb_info *info = (struct xenfb_info *)data; + info->dirty = 1; + wake_up(&info->wq); +} + +static void __xenfb_refresh(struct xenfb_info *info, + int x1, int y1, int w, int h) +{ + int y2, x2; + + y2 = y1 + h; + x2 = x1 + w; + + if (info->y1 > y1) + info->y1 = y1; + if (info->y2 < y2) + info->y2 = y2; + if (info->x1 > x1) + info->x1 = x1; + if (info->x2 < x2) + info->x2 = x2; + + if (timer_pending(&info->refresh)) + return; + + mod_timer(&info->refresh, jiffies + HZ/xenfb_fps); +} + +static void xenfb_refresh(struct xenfb_info *info, + int x1, int y1, int w, int h) +{ + unsigned long flags; + + spin_lock_irqsave(&info->mm_lock, flags); + __xenfb_refresh(info, x1, y1, w, h); + spin_unlock_irqrestore(&info->mm_lock, flags); +} + +static void xenfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) +{ + struct xenfb_info *info = p->par; + + cfb_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; + + cfb_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; + + cfb_copyarea(p, area); + xenfb_refresh(info, area->dx, area->dy, area->width, area->height); +} + +static void xenfb_vm_open(struct vm_area_struct *vma) +{ + struct xenfb_mapping *map = vma->vm_private_data; + atomic_inc(&map->map_refs); +} + +static void xenfb_vm_close(struct vm_area_struct *vma) +{ + struct xenfb_mapping *map = vma->vm_private_data; + struct xenfb_info *info = map->info; + unsigned long flags; + + spin_lock_irqsave(&info->mm_lock, flags); + if (atomic_dec_and_test(&map->map_refs)) { + list_del(&map->link); + kfree(map); + } + spin_unlock_irqrestore(&info->mm_lock, flags); +} + +static struct page *xenfb_vm_nopage(struct vm_area_struct *vma, + unsigned long vaddr, int *type) +{ + struct xenfb_mapping *map = vma->vm_private_data; + struct xenfb_info *info = map->info; + int pgnr = (vaddr - vma->vm_start) >> PAGE_SHIFT; + unsigned long flags; + struct page *page; + int y1, y2; + + if (pgnr >= info->nr_pages) + return NOPAGE_SIGBUS; + + spin_lock_irqsave(&info->mm_lock, flags); + page = info->pages[pgnr]; + get_page(page); + map->faults++; + + y1 = pgnr * PAGE_SIZE / info->fb_info->fix.line_length; + y2 = (pgnr * PAGE_SIZE + PAGE_SIZE - 1) / info->fb_info->fix.line_length; + if (y2 > info->fb_info->var.yres) + y2 = info->fb_info->var.yres; + __xenfb_refresh(info, 0, y1, info->fb_info->var.xres, y2 - y1); + spin_unlock_irqrestore(&info->mm_lock, flags); + + if (type) + *type = VM_FAULT_MINOR; + + return page; +} + +static struct vm_operations_struct xenfb_vm_ops = { + .open = xenfb_vm_open, + .close = xenfb_vm_close, + .nopage = xenfb_vm_nopage, +}; + +static int xenfb_mmap(struct fb_info *fb_info, struct vm_area_struct *vma) +{ + struct xenfb_info *info = fb_info->par; + unsigned long flags; + struct xenfb_mapping *map; + int map_pages; + + if (!(vma->vm_flags & VM_WRITE)) + return -EINVAL; + if (!(vma->vm_flags & VM_SHARED)) + return -EINVAL; + if (vma->vm_pgoff != 0) + return -EINVAL; + + map_pages = (vma->vm_end - vma->vm_start + PAGE_SIZE-1) >> PAGE_SHIFT; + if (map_pages > info->nr_pages) + return -EINVAL; + + map = kzalloc(sizeof(*map), GFP_KERNEL); + if (map == NULL) + return -ENOMEM; + + map->vma = vma; + map->faults = 0; + map->info = info; + atomic_set(&map->map_refs, 1); + + spin_lock_irqsave(&info->mm_lock, flags); + list_add(&map->link, &info->mappings); + spin_unlock_irqrestore(&info->mm_lock, flags); + + vma->vm_ops = &xenfb_vm_ops; + vma->vm_flags |= (VM_DONTEXPAND | VM_RESERVED); + vma->vm_private_data = map; + + return 0; +} + +static struct fb_ops xenfb_fb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = xenfb_setcolreg, + .fb_fillrect = xenfb_fillrect, + .fb_copyarea = xenfb_copyarea, + .fb_imageblit = xenfb_imageblit, + .fb_mmap = xenfb_mmap, +}; + +static irqreturn_t xenfb_event_handler(int rq, void *dev_id, + struct pt_regs *regs) +{ + /* + * No in events recognized, simply ignore them all. + * If you need to recognize some, see xenbkd''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_evtchn(info->evtchn); + } + return IRQ_HANDLED; +} + +static unsigned long vmalloc_to_mfn(void *address) +{ + return pfn_to_mfn(vmalloc_to_pfn(address)); +} + +static int __devinit xenfb_probe(struct xenbus_device *dev, + const struct xenbus_device_id *id) +{ + struct xenfb_info *info; + int i, ret; + struct fb_info *fb_info; + struct xenbus_transaction xbt; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (info == NULL) { + xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); + return -ENOMEM; + } + dev->dev.driver_data = info; + info->xbdev = dev; + info->irq = -1; + info->x1 = info->y1 = INT_MAX; + spin_lock_init(&info->mm_lock); + init_waitqueue_head(&info->wq); + init_timer(&info->refresh); + info->refresh.function = xenfb_timer; + info->refresh.data = (unsigned long)info; + INIT_LIST_HEAD(&info->mappings); + + info->fb = vmalloc(xenfb_mem_len); + if (info->fb == NULL) + goto error_nomem; + memset(info->fb, 0, xenfb_mem_len); + + info->nr_pages = (xenfb_mem_len + PAGE_SIZE - 1) >> PAGE_SHIFT; + + info->pages = kmalloc(sizeof(struct page *) * info->nr_pages, + GFP_KERNEL); + if (info->pages == NULL) + goto error_nomem; + for (i = 0; i < info->nr_pages; i++) + info->pages[i] = vmalloc_to_page(info->fb + i * PAGE_SIZE); + + info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages); + if (!info->mfns) + goto error_nomem; + for (i = 0; i < info->nr_pages; i++) + info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE); + + /* set up shared page */ + info->page = (void *)__get_free_page(GFP_KERNEL); + if (!info->page) + goto error_nomem; + + info->page->pd[0] = vmalloc_to_mfn(info->mfns); + info->page->pd[1] = 0; + info->page->width = XENFB_WIDTH; + info->page->height = XENFB_HEIGHT; + info->page->depth = XENFB_DEPTH; + info->page->line_length = (info->page->depth / 8) * info->page->width; + info->page->mem_length = xenfb_mem_len; + info->page->in_cons = info->page->in_prod = 0; + info->page->out_cons = info->page->out_prod = 0; + + ret = xenbus_alloc_evtchn(dev, &info->evtchn); + if (ret) + goto error; + ret = bind_evtchn_to_irqhandler(info->evtchn, xenfb_event_handler, + 0, "xenfb", info); + if (ret < 0) { + xenbus_free_evtchn(dev, info->evtchn); + goto error; + } + info->irq = ret; + + fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL); + /* see fishy hackery below */ + if (fb_info == NULL) + goto error_nomem; + + /* FIXME fishy hackery */ + fb_info->pseudo_palette = fb_info->par; + fb_info->par = info; + /* /FIXME */ + fb_info->screen_base = info->fb; + + fb_info->fbops = &xenfb_fb_ops; + fb_info->var.xres_virtual = fb_info->var.xres = info->page->width; + fb_info->var.yres_virtual = fb_info->var.yres = info->page->height; + fb_info->var.bits_per_pixel = info->page->depth; + + fb_info->var.red = (struct fb_bitfield){16, 8, 0}; + fb_info->var.green = (struct fb_bitfield){8, 8, 0}; + fb_info->var.blue = (struct fb_bitfield){0, 8, 0}; + + fb_info->var.activate = FB_ACTIVATE_NOW; + fb_info->var.height = -1; + fb_info->var.width = -1; + fb_info->var.vmode = FB_VMODE_NONINTERLACED; + + fb_info->fix.visual = FB_VISUAL_TRUECOLOR; + fb_info->fix.line_length = info->page->line_length; + fb_info->fix.smem_start = 0; + fb_info->fix.smem_len = xenfb_mem_len; + strcpy(fb_info->fix.id, "xen"); + fb_info->fix.type = FB_TYPE_PACKED_PIXELS; + fb_info->fix.accel = FB_ACCEL_NONE; + + fb_info->flags = FBINFO_FLAG_DEFAULT; + + ret = fb_alloc_cmap(&fb_info->cmap, 256, 0); + if (ret < 0) { + framebuffer_release(fb_info); + xenbus_dev_fatal(dev, ret, "fb_alloc_cmap"); + goto error; + } + + ret = register_framebuffer(fb_info); + if (ret) { + fb_dealloc_cmap(&info->fb_info->cmap); + framebuffer_release(fb_info); + xenbus_dev_fatal(dev, ret, "register_framebuffer"); + goto error; + } + info->fb_info = fb_info; + + /* FIXME should this be delayed until backend XenbusStateConnected? */ + info->kthread = kthread_run(xenfb_thread, info, "xenfb thread"); + if (IS_ERR(info->kthread)) { + ret = PTR_ERR(info->kthread); + info->kthread = NULL; + xenbus_dev_fatal(dev, ret, "register_framebuffer"); + goto error; + } + + again: + ret = xenbus_transaction_start(&xbt); + if (ret) { + xenbus_dev_fatal(dev, ret, "starting transaction"); + goto error; + } + ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", + virt_to_mfn(info->page)); + if (ret) + goto error_xenbus; + ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", + info->evtchn); + if (ret) + goto error_xenbus; + ret = xenbus_printf(xbt, dev->nodename, "feature-update", "1"); + if (ret) + goto error_xenbus; + ret = xenbus_transaction_end(xbt, 0); + if (ret) { + if (ret == -EAGAIN) + goto again; + xenbus_dev_fatal(dev, ret, "completing transaction"); + goto error; + } + + xenbus_switch_state(dev, XenbusStateInitialised); + return 0; + + error_xenbus: + xenbus_transaction_end(xbt, 1); + xenbus_dev_fatal(dev, ret, "writing xenstore"); + goto error; + error_nomem: + ret = -ENOMEM; + xenbus_dev_fatal(dev, ret, "allocating device memory"); + error: + xenfb_remove(dev); + return ret; +} + +static void xenfb_backend_changed(struct xenbus_device *dev, + enum xenbus_state backend_state) +{ + struct xenfb_info *info = dev->dev.driver_data; + int val; + + switch (backend_state) { + case XenbusStateInitialising: + case XenbusStateInitialised: + case XenbusStateUnknown: + case XenbusStateClosed: + break; + + case XenbusStateInitWait: + InitWait: + xenbus_switch_state(dev, XenbusStateConnected); + break; + + case XenbusStateConnected: + /* + * Work around xenbus race condition: If backend goes + * through InitWait to Connected fast enough, we can + * get Connected twice here. + */ + if (dev->state != XenbusStateConnected) + goto InitWait; /* no InitWait seen yet, fudge it */ + + if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, + "request-update", "%d", &val) < 0) + val = 0; + if (val) + info->update_wanted = 1; + break; + + case XenbusStateClosing: + // FIXME is this safe in any dev->state? + xenbus_frontend_closed(dev); + break; + } +} + +static int xenfb_remove(struct xenbus_device *dev) +{ + struct xenfb_info *info = dev->dev.driver_data; + + del_timer(&info->refresh); + if (info->kthread) + kthread_stop(info->kthread); + if (info->irq >= 0) + unbind_from_irqhandler(info->irq, info); + if (info->fb_info) { + unregister_framebuffer(info->fb_info); + fb_dealloc_cmap(&info->fb_info->cmap); + framebuffer_release(info->fb_info); + } + free_page((unsigned long)info->page); + vfree(info->mfns); + kfree(info->pages); + vfree(info->fb); + kfree(info); + + return 0; +} + +static struct xenbus_device_id xenfb_ids[] = { + { "vfb" }, + { "" } +}; + +static struct xenbus_driver xenfb = { + .name = "vfb", + .owner = THIS_MODULE, + .ids = xenfb_ids, + .probe = xenfb_probe, + .remove = xenfb_remove, + /* TODO .resume = xenfb_resume, */ + .otherend_changed = xenfb_backend_changed, +}; + +static int __init xenfb_init(void) +{ + if (!is_running_on_xen()) + return -ENODEV; + + /* Nothing to do if running in dom0. */ + if (is_initial_xendomain()) + return -ENODEV; + + return xenbus_register_frontend(&xenfb); +} + +static void __exit xenfb_cleanup(void) +{ + return xenbus_unregister_driver(&xenfb); +} + +module_init(xenfb_init); +module_exit(xenfb_cleanup); + +MODULE_LICENSE("GPL"); diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/xenkbd/Makefile linux-2.6.16.29-xen-pvfb/drivers/xen/xenkbd/Makefile --- linux-2.6.16.29-xen/drivers/xen/xenkbd/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.29-xen-pvfb/drivers/xen/xenkbd/Makefile 2006-11-17 13:38:02.000000000 +0100 @@ -0,0 +1 @@ +obj-$(CONFIG_XEN_KEYBOARD) += xenkbd.o diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/xenkbd/xenkbd.c linux-2.6.16.29-xen-pvfb/drivers/xen/xenkbd/xenkbd.c --- linux-2.6.16.29-xen/drivers/xen/xenkbd/xenkbd.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.29-xen-pvfb/drivers/xen/xenkbd/xenkbd.c 2006-11-17 13:38:02.000000000 +0100 @@ -0,0 +1,271 @@ +/* + * linux/drivers/input/keyboard/xenkbd.c -- Xen para-virtual input device + * + * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com> + * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> + * + * Based on linux/drivers/input/mouse/sermouse.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 together with xenfb.c. + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/module.h> +#include <linux/input.h> +#include <asm/hypervisor.h> +#include <xen/evtchn.h> +#include <xen/interface/io/xenfb.h> +#include <xen/interface/io/xenkbd.h> +#include <xen/xenbus.h> + +struct xenkbd_info +{ + struct input_dev *dev; + struct xenkbd_page *page; + unsigned evtchn; + int irq; + struct xenbus_device *xbdev; +}; + +static int xenkbd_remove(struct xenbus_device *); + +/* + * Note: if you need to send out events, see xenfb_do_update() for how + * to do that. + */ + +static irqreturn_t input_handler(int rq, void *dev_id, struct pt_regs *regs) +{ + struct xenkbd_info *info = dev_id; + struct xenkbd_page *page = info->page; + __u32 cons, prod; + + prod = page->in_prod; + if (prod == page->out_cons) + return IRQ_HANDLED; + rmb(); /* ensure we see ring contents up to prod */ + for (cons = page->in_cons; cons != prod; cons++) { + union xenkbd_in_event *event; + event = &XENKBD_IN_RING_REF(page, cons); + + switch (event->type) { + case XENKBD_TYPE_MOTION: + input_report_rel(info->dev, REL_X, event->motion.rel_x); + input_report_rel(info->dev, REL_Y, event->motion.rel_y); + break; + case XENKBD_TYPE_KEY: + input_report_key(info->dev, event->key.keycode, event->key.pressed); + break; + case XENKBD_TYPE_POS: + input_report_abs(info->dev, ABS_X, event->pos.abs_x); + input_report_abs(info->dev, ABS_Y, event->pos.abs_y); + break; + } + } + input_sync(info->dev); + mb(); /* ensure we got ring contents */ + page->in_cons = cons; + notify_remote_via_evtchn(info->evtchn); + + return IRQ_HANDLED; +} + +int __devinit xenkbd_probe(struct xenbus_device *dev, + const struct xenbus_device_id *id) +{ + int ret, i; + struct xenkbd_info *info; + struct input_dev *input_dev; + struct xenbus_transaction xbt; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); + return -ENOMEM; + } + dev->dev.driver_data = info; + info->xbdev = dev; + + info->page = (void *)__get_free_page(GFP_KERNEL); + if (!info->page) + goto error_nomem; + info->page->in_cons = info->page->in_prod = 0; + info->page->out_cons = info->page->out_prod = 0; + + input_dev = input_allocate_device(); + if (!input_dev) + goto error_nomem; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_MOUSE)] + = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + /* TODO additional buttons */ + input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); + + /* FIXME not sure this is quite right */ + for (i = 0; i < 256; i++) + set_bit(i, input_dev->keybit); + + input_dev->name = "Xen Virtual Keyboard/Mouse"; + + input_set_abs_params(input_dev, ABS_X, 0, XENFB_WIDTH, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, XENFB_HEIGHT, 0, 0); + + /* FIXME should this be delayed until backend XenbusStateConnected? */ + ret = input_register_device(input_dev); + if (ret) { + input_free_device(input_dev); + xenbus_dev_fatal(dev, ret, "input_register_device"); + goto error; + } + info->dev = input_dev; + + ret = xenbus_alloc_evtchn(dev, &info->evtchn); + if (ret) + goto error; + ret = bind_evtchn_to_irqhandler(info->evtchn, input_handler, 0, + "xenkbd", info); + if (ret < 0) { + xenbus_free_evtchn(dev, info->evtchn); + goto error; + } + info->irq = ret; + + again: + ret = xenbus_transaction_start(&xbt); + if (ret) { + xenbus_dev_fatal(dev, ret, "starting transaction"); + goto error; + } + ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", + virt_to_mfn(info->page)); + if (ret) + goto error_xenbus; + ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", + info->evtchn); + if (ret) + goto error_xenbus; + ret = xenbus_transaction_end(xbt, 0); + if (ret) { + if (ret == -EAGAIN) + goto again; + xenbus_dev_fatal(dev, ret, "completing transaction"); + goto error; + } + + xenbus_switch_state(dev, XenbusStateInitialised); + return 0; + + error_xenbus: + xenbus_transaction_end(xbt, 1); + xenbus_dev_fatal(dev, ret, "writing xenstore"); + goto error; + error_nomem: + ret = -ENOMEM; + xenbus_dev_fatal(dev, ret, "allocating device memory"); + error: + xenkbd_remove(dev); + return ret; +} + +static void xenkbd_backend_changed(struct xenbus_device *dev, + enum xenbus_state backend_state) +{ + struct xenkbd_info *info = dev->dev.driver_data; + int ret, val; + + switch (backend_state) { + case XenbusStateInitialising: + case XenbusStateInitialised: + case XenbusStateUnknown: + case XenbusStateClosed: + break; + + case XenbusStateInitWait: + InitWait: + ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend, + "feature-abs-pointer", "%d", &val); + if (ret < 0) + val = 0; + if (val) { + ret = xenbus_printf(XBT_NIL, info->xbdev->nodename, + "request-abs-pointer", "1"); + if (ret) + ; /* FIXME */ + } + xenbus_switch_state(dev, XenbusStateConnected); + break; + + case XenbusStateConnected: + /* + * Work around xenbus race condition: If backend goes + * through InitWait to Connected fast enough, we can + * get Connected twice here. + */ + if (dev->state != XenbusStateConnected) + goto InitWait; /* no InitWait seen yet, fudge it */ + break; + + case XenbusStateClosing: + xenbus_frontend_closed(dev); + break; + } +} + +static int xenkbd_remove(struct xenbus_device *dev) +{ + struct xenkbd_info *info = dev->dev.driver_data; + + if (info->irq >= 0) + unbind_from_irqhandler(info->irq, info); + input_unregister_device(info->dev); + free_page((unsigned long)info->page); + kfree(info); + return 0; +} + +static struct xenbus_device_id xenkbd_ids[] = { + { "vkbd" }, + { "" } +}; + +static struct xenbus_driver xenkbd = { + .name = "vkbd", + .owner = THIS_MODULE, + .ids = xenkbd_ids, + .probe = xenkbd_probe, + .remove = xenkbd_remove, + //.resume = xenkbd_resume, + .otherend_changed = xenkbd_backend_changed, +}; + +static int __init xenkbd_init(void) +{ + if (!is_running_on_xen()) + return -ENODEV; + + /* Nothing to do if running in dom0. */ + if (is_initial_xendomain()) + return -ENODEV; + + return xenbus_register_frontend(&xenkbd); +} + +static void __exit xenkbd_cleanup(void) +{ + return xenbus_unregister_driver(&xenkbd); +} + +module_init(xenkbd_init); +module_exit(xenkbd_cleanup); + +MODULE_LICENSE("GPL"); diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/include/xen/interface/io/xenfb.h linux-2.6.16.29-xen-pvfb/include/xen/interface/io/xenfb.h --- linux-2.6.16.29-xen/include/xen/interface/io/xenfb.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.29-xen-pvfb/include/xen/interface/io/xenfb.h 2006-11-17 13:38:02.000000000 +0100 @@ -0,0 +1,116 @@ +/* + * linux/include/linux/xenfb.h -- Xen virtual frame buffer device + * + * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com> + * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> + * + * 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. + */ + +#ifndef _LINUX_XENFB_H +#define _LINUX_XENFB_H + +#include <asm/types.h> + +/* Out events (frontend -> backend) */ + +/* + * Out events may be sent only when requested by backend, and receipt + * of an unknown out event is an error. + */ + +/* Event type 1 currently not used */ +/* + * Framebuffer update notification event + * Capable frontend sets feature-update in xenstore. + * Backend requests it by setting request-update in xenstore. + */ +#define XENFB_TYPE_UPDATE 2 + +struct xenfb_update +{ + __u8 type; /* XENFB_TYPE_UPDATE */ + __s32 x; /* source x */ + __s32 y; /* source y */ + __s32 width; /* rect width */ + __s32 height; /* rect height */ +}; + +#define XENFB_OUT_EVENT_SIZE 40 + +union xenfb_out_event +{ + __u8 type; + struct xenfb_update update; + char pad[XENFB_OUT_EVENT_SIZE]; +}; + +/* In events (backend -> frontend) */ + +/* + * Frontends should ignore unknown in events. + * No in events currently defined. + */ + +#define XENFB_IN_EVENT_SIZE 40 + +union xenfb_in_event +{ + __u8 type; + char pad[XENFB_OUT_EVENT_SIZE]; +}; + +/* shared page */ + +#define XENFB_IN_RING_SIZE 1024 +#define XENFB_IN_RING_LEN (XENFB_IN_RING_SIZE / XENFB_IN_EVENT_SIZE) +#define XENFB_IN_RING_OFFS 1024 +#define XENFB_IN_RING(page) \ + ((union xenfb_in_event *)((char *)(page) + XENFB_IN_RING_OFFS)) +#define XENFB_IN_RING_REF(page, idx) \ + (XENFB_IN_RING((page))[(idx) % XENFB_IN_RING_LEN]) + +#define XENFB_OUT_RING_SIZE 2048 +#define XENFB_OUT_RING_LEN (XENFB_OUT_RING_SIZE / XENFB_OUT_EVENT_SIZE) +#define XENFB_OUT_RING_OFFS (XENFB_IN_RING_OFFS + XENFB_IN_RING_SIZE) +#define XENFB_OUT_RING(page) \ + ((union xenfb_out_event *)((char *)(page) + XENFB_OUT_RING_OFFS)) +#define XENFB_OUT_RING_REF(page, idx) \ + (XENFB_OUT_RING((page))[(idx) % XENFB_OUT_RING_LEN]) + +struct xenfb_page +{ + __u32 in_cons, in_prod; + __u32 out_cons, out_prod; + + __s32 width; /* the width of the framebuffer (in pixels) */ + __s32 height; /* the height of the framebuffer (in pixels) */ + __u32 line_length; /* the length of a row of pixels (in bytes) */ + __u32 mem_length; /* the length of the framebuffer (in bytes) */ + __u8 depth; /* the depth of a pixel (in bits) */ + + /* + * Framebuffer page directory + * + * Each directory page holds PAGE_SIZE / sizeof(*pd) + * framebuffer pages, and can thus map up to PAGE_SIZE * + * PAGE_SIZE / sizeof(*pd) bytes. With PAGE_SIZE == 4096 and + * sizeof(unsigned long) == 4, that''s 4 Megs. Two directory + * pages should be enough for a while. + */ + unsigned long pd[2]; +}; + +/* + * Wart: xenkbd needs to know resolution. Put it here until a better + * solution is found, but don''t leak it to the backend. + */ +#ifdef __KERNEL__ +#define XENFB_WIDTH 800 +#define XENFB_HEIGHT 600 +#define XENFB_DEPTH 32 +#endif + +#endif diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/include/xen/interface/io/xenkbd.h linux-2.6.16.29-xen-pvfb/include/xen/interface/io/xenkbd.h --- linux-2.6.16.29-xen/include/xen/interface/io/xenkbd.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.29-xen-pvfb/include/xen/interface/io/xenkbd.h 2006-11-17 13:38:02.000000000 +0100 @@ -0,0 +1,108 @@ +/* + * linux/include/linux/xenkbd.h -- Xen virtual keyboard/mouse + * + * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com> + * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> + * + * 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. + */ + +#ifndef _LINUX_XENKBD_H +#define _LINUX_XENKBD_H + +#include <asm/types.h> + +/* In events (backend -> frontend) */ + +/* + * Frontends should ignore unknown in events. + */ + +/* Pointer movement event */ +#define XENKBD_TYPE_MOTION 1 +/* Event type 2 currently not used */ +/* Key event (includes pointer buttons) */ +#define XENKBD_TYPE_KEY 3 +/* + * Pointer position event + * Capable backend sets feature-abs-pointer in xenstore. + * Frontend requests ot instead of XENKBD_TYPE_MOTION by setting + * request-abs-update in xenstore. + */ +#define XENKBD_TYPE_POS 4 + +struct xenkbd_motion +{ + __u8 type; /* XENKBD_TYPE_MOTION */ + __s32 rel_x; /* relative X motion */ + __s32 rel_y; /* relative Y motion */ +}; + +struct xenkbd_key +{ + __u8 type; /* XENKBD_TYPE_KEY */ + __u8 pressed; /* 1 if pressed; 0 otherwise */ + __u32 keycode; /* KEY_* from linux/input.h */ +}; + +struct xenkbd_position +{ + __u8 type; /* XENKBD_TYPE_POS */ + __s32 abs_x; /* absolute X position (in FB pixels) */ + __s32 abs_y; /* absolute Y position (in FB pixels) */ +}; + +#define XENKBD_IN_EVENT_SIZE 40 + +union xenkbd_in_event +{ + __u8 type; + struct xenkbd_motion motion; + struct xenkbd_key key; + struct xenkbd_position pos; + char pad[XENKBD_IN_EVENT_SIZE]; +}; + +/* Out events (frontend -> backend) */ + +/* + * Out events may be sent only when requested by backend, and receipt + * of an unknown out event is an error. + * No out events currently defined. + */ + +#define XENKBD_OUT_EVENT_SIZE 40 + +union xenkbd_out_event +{ + __u8 type; + char pad[XENKBD_OUT_EVENT_SIZE]; +}; + +/* shared page */ + +#define XENKBD_IN_RING_SIZE 2048 +#define XENKBD_IN_RING_LEN (XENKBD_IN_RING_SIZE / XENKBD_IN_EVENT_SIZE) +#define XENKBD_IN_RING_OFFS 1024 +#define XENKBD_IN_RING(page) \ + ((union xenkbd_in_event *)((char *)(page) + XENKBD_IN_RING_OFFS)) +#define XENKBD_IN_RING_REF(page, idx) \ + (XENKBD_IN_RING((page))[(idx) % XENKBD_IN_RING_LEN]) + +#define XENKBD_OUT_RING_SIZE 1024 +#define XENKBD_OUT_RING_LEN (XENKBD_OUT_RING_SIZE / XENKBD_OUT_EVENT_SIZE) +#define XENKBD_OUT_RING_OFFS (XENKBD_IN_RING_OFFS + XENKBD_IN_RING_SIZE) +#define XENKBD_OUT_RING(page) \ + ((union xenkbd_out_event *)((char *)(page) + XENKBD_OUT_RING_OFFS)) +#define XENKBD_OUT_RING_REF(page, idx) \ + (XENKBD_OUT_RING((page))[(idx) % XENKBD_OUT_RING_LEN]) + +struct xenkbd_page +{ + __u32 in_cons, in_prod; + __u32 out_cons, out_prod; +}; + +#endif diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/mm/memory.c linux-2.6.16.29-xen-pvfb/mm/memory.c --- linux-2.6.16.29-xen/mm/memory.c 2006-10-13 19:47:16.000000000 +0200 +++ linux-2.6.16.29-xen-pvfb/mm/memory.c 2006-11-17 13:38:02.000000000 +0100 @@ -882,6 +882,7 @@ unsigned long zap_page_range(struct vm_a tlb_finish_mmu(tlb, address, end); return end; } +EXPORT_SYMBOL(zap_page_range); /* * Do a quick page-table lookup for a single page. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Diffs since last iteration: diff -rupN -x ''*.orig'' linux-2.6.16.29-xen-pvfb.old/drivers/xen/console/console.c linux-2.6.16.29-xen-pvfb/drivers/xen/console/console.c --- linux-2.6.16.29-xen-pvfb.old/drivers/xen/console/console.c 2006-11-17 13:38:58.000000000 +0100 +++ linux-2.6.16.29-xen-pvfb/drivers/xen/console/console.c 2006-11-17 13:38:02.000000000 +0100 @@ -712,18 +712,13 @@ static int __init xencons_init(void) printk("Xen virtual console successfully installed as %s%d\n", DRV(xencons_driver)->name, xc_num); - /* Don''t need to check about graphical fb for domain 0 */ - if (is_initial_xendomain()) - return 0; - - rc = 0; - if (xenbus_scanf(XBT_NIL, "console", "use_graphics", "%d", &rc) < 0) - printk(KERN_ERR "Unable to read console/use_graphics\n"); - if (rc == 0) { - /* FIXME: this is ugly */ - unregister_console(&kcons_info); - kcons_info.flags |= CON_CONSDEV; - register_console(&kcons_info); + /* Check about framebuffer messing up the console */ + if (!is_initial_xendomain() && + !xenbus_exists(XBT_NIL, "device", "vfb")) { + /* FIXME: this is ugly */ + unregister_console(&kcons_info); + kcons_info.flags |= CON_CONSDEV; + register_console(&kcons_info); } return 0; diff -rupN -x ''*.orig'' linux-2.6.16.29-xen-pvfb.old/drivers/xen/Kconfig linux-2.6.16.29-xen-pvfb/drivers/xen/Kconfig --- linux-2.6.16.29-xen-pvfb.old/drivers/xen/Kconfig 2006-11-17 13:38:58.000000000 +0100 +++ linux-2.6.16.29-xen-pvfb/drivers/xen/Kconfig 2006-11-17 13:38:02.000000000 +0100 @@ -187,7 +187,7 @@ config XEN_FRAMEBUFFER config XEN_KEYBOARD tristate "Keyboard-device frontend driver" - depends on XEN + depends on XEN && XEN_FRAMEBUFFER && INPUT default y help The keyboard-device frontend driver allows the kernel to create a diff -rupN -x ''*.orig'' linux-2.6.16.29-xen-pvfb.old/drivers/xen/xenfb/xenfb.c linux-2.6.16.29-xen-pvfb/drivers/xen/xenfb/xenfb.c --- linux-2.6.16.29-xen-pvfb.old/drivers/xen/xenfb/xenfb.c 2006-11-17 13:38:58.000000000 +0100 +++ linux-2.6.16.29-xen-pvfb/drivers/xen/xenfb/xenfb.c 2006-11-17 13:38:02.000000000 +0100 @@ -67,7 +67,7 @@ struct xenfb_info static int xenfb_fps = 20; static unsigned long xenfb_mem_len = XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8; -static int __devexit xenfb_remove(struct xenbus_device *); +static int xenfb_remove(struct xenbus_device *); static void xenfb_do_update(struct xenfb_info *info, int x, int y, int w, int h) @@ -482,7 +482,6 @@ static int __devinit xenfb_probe(struct goto error; } - /* FIXME should this be delayed until backend XenbusStateConnected? */ ret = register_framebuffer(fb_info); if (ret) { fb_dealloc_cmap(&info->fb_info->cmap); @@ -492,9 +491,11 @@ static int __devinit xenfb_probe(struct } info->fb_info = fb_info; + /* FIXME should this be delayed until backend XenbusStateConnected? */ info->kthread = kthread_run(xenfb_thread, info, "xenfb thread"); if (IS_ERR(info->kthread)) { ret = PTR_ERR(info->kthread); + info->kthread = NULL; xenbus_dev_fatal(dev, ret, "register_framebuffer"); goto error; } @@ -553,10 +554,19 @@ static void xenfb_backend_changed(struct break; case XenbusStateInitWait: + InitWait: xenbus_switch_state(dev, XenbusStateConnected); break; case XenbusStateConnected: + /* + * Work around xenbus race condition: If backend goes + * through InitWait to Connected fast enough, we can + * get Connected twice here. + */ + if (dev->state != XenbusStateConnected) + goto InitWait; /* no InitWait seen yet, fudge it */ + if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, "request-update", "%d", &val) < 0) val = 0; @@ -565,12 +575,13 @@ static void xenfb_backend_changed(struct break; case XenbusStateClosing: + // FIXME is this safe in any dev->state? xenbus_frontend_closed(dev); break; } } -static int __devexit xenfb_remove(struct xenbus_device *dev) +static int xenfb_remove(struct xenbus_device *dev) { struct xenfb_info *info = dev->dev.driver_data; @@ -610,19 +621,12 @@ static struct xenbus_driver xenfb = { static int __init xenfb_init(void) { - int ret; - if (!is_running_on_xen()) return -ENODEV; /* Nothing to do if running in dom0. */ if (is_initial_xendomain()) return -ENODEV; - /* if we''re not set up to use graphics mode, then don''t initialize */ - if (xenbus_scanf(XBT_NIL, "console", "use_graphics", "%d", &ret) < 0) - return -ENODEV; - if (ret == 0) - return -ENODEV; return xenbus_register_frontend(&xenfb); } diff -rupN -x ''*.orig'' linux-2.6.16.29-xen-pvfb.old/drivers/xen/xenkbd/xenkbd.c linux-2.6.16.29-xen-pvfb/drivers/xen/xenkbd/xenkbd.c --- linux-2.6.16.29-xen-pvfb.old/drivers/xen/xenkbd/xenkbd.c 2006-11-17 13:38:58.000000000 +0100 +++ linux-2.6.16.29-xen-pvfb/drivers/xen/xenkbd/xenkbd.c 2006-11-17 13:38:02.000000000 +0100 @@ -36,7 +36,7 @@ struct xenkbd_info struct xenbus_device *xbdev; }; -static int __devexit xenkbd_remove(struct xenbus_device *); +static int xenkbd_remove(struct xenbus_device *); /* * Note: if you need to send out events, see xenfb_do_update() for how @@ -108,7 +108,7 @@ int __devinit xenkbd_probe(struct xenbus input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); - /* FIXME more buttons? */ + /* TODO additional buttons */ input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); /* FIXME not sure this is quite right */ @@ -191,6 +191,7 @@ static void xenkbd_backend_changed(struc break; case XenbusStateInitWait: + InitWait: ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend, "feature-abs-pointer", "%d", &val); if (ret < 0) @@ -205,6 +206,13 @@ static void xenkbd_backend_changed(struc break; case XenbusStateConnected: + /* + * Work around xenbus race condition: If backend goes + * through InitWait to Connected fast enough, we can + * get Connected twice here. + */ + if (dev->state != XenbusStateConnected) + goto InitWait; /* no InitWait seen yet, fudge it */ break; case XenbusStateClosing: @@ -213,7 +221,7 @@ static void xenkbd_backend_changed(struc } } -static int __devexit xenkbd_remove(struct xenbus_device *dev) +static int xenkbd_remove(struct xenbus_device *dev) { struct xenkbd_info *info = dev->dev.driver_data; @@ -242,20 +250,12 @@ static struct xenbus_driver xenkbd = { static int __init xenkbd_init(void) { - int ret; - if (!is_running_on_xen()) return -ENODEV; /* Nothing to do if running in dom0. */ if (is_initial_xendomain()) return -ENODEV; - /* if we''re not set up to use graphics mode, then don''t initialize */ - if (xenbus_scanf(XBT_NIL, "console", "use_graphics", "%d", &ret) < 0) - return -ENODEV; - if (ret == 0) - return -ENODEV; - return xenbus_register_frontend(&xenkbd); } diff -rupN -x ''*.orig'' linux-2.6.16.29-xen-pvfb.old/mm/memory.c linux-2.6.16.29-xen-pvfb/mm/memory.c --- linux-2.6.16.29-xen-pvfb.old/mm/memory.c 2006-10-13 19:47:16.000000000 +0200 +++ linux-2.6.16.29-xen-pvfb/mm/memory.c 2006-11-17 13:38:02.000000000 +0100 @@ -882,6 +882,7 @@ unsigned long zap_page_range(struct vm_a tlb_finish_mmu(tlb, address, end); return end; } +EXPORT_SYMBOL(zap_page_range); /* * Do a quick page-table lookup for a single page. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Markus Armbruster <armbru@redhat.com> writes:> Steven Smith <sos22-xen@srcf.ucam.org> writes:[...]>>> diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/console/console.c linux-2.6.16.29-xen-vfb/drivers/xen/console/console.c >>> --- linux-2.6.16.29-xen/drivers/xen/console/console.c 2006-09-29 16:11:51.000000000 +0200 >>> +++ linux-2.6.16.29-xen-vfb/drivers/xen/console/console.c 2006-11-10 09:43:37.000000000 +0100 >>> @@ -680,3 +712,17 @@ static int __init xencons_init(void) >>> printk("Xen virtual console successfully installed as %s%d\n", >>> DRV(xencons_driver)->name, xc_num); >>> >>> + /* Don''t need to check about graphical fb for domain 0 */ >>> + if (is_initial_xendomain()) >>> + return 0; >>> + >>> + rc = 0; >>> + if (xenbus_scanf(XBT_NIL, "console", "use_graphics", "%d", &rc) < 0) >>> + printk(KERN_ERR "Unable to read console/use_graphics\n"); >>> + if (rc == 0) { >>> + /* FIXME: this is ugly */ >>> + unregister_console(&kcons_info); >>> + kcons_info.flags |= CON_CONSDEV; >>> + register_console(&kcons_info); >>> + } >> I''m still not entirely sure I understand why this bit is necessary. >> >> From talking to katz@redhat.com last time: >> >>> > > > > Also, why do you need to set CON_CONSDEV at all? >>> > > > Otherwise, you don''t get kernel console messages. >>> > > Why not? None of the other console drivers seem to need to set it >>> > > explicitly, and it seems like it would break setting console=blah on >>> > > the kernel command line. >>> > Nothing else sets it explicitly because it happens implicitly in the >>> > console registration code for the first thing registered with >>> > register_console(). Alternately, if you have a console=, then >>> > register_console ensures that your console device has CON_CONSDEV set. >>> > kernel/printk.c if you want to read all the gory details >>> The intent of this code seems to be to make sure that CON_CONSDEV is >>> definitely set on xenconsole if use_graphics is not set, yes? But as >>> far as I can see, if use_graphics is not set, xenfb should never call >>> register_console(), and so this is all redundant. >> >> >> I''m still just as unenlightened as I was then. Plus, xen_console_init >> should be called before any of the pvfb stuff anyway, since it''s a >> console_initcall and pvfb starts from a module_init, so it''s doubly >> redundant. > > Jeremy, could you elaborate?Jeremy is buried alive in email right now. This is what he wrote to me, quoted with permission: The reason why this is needed is because the Linux console code is a mess. xen_console_init _does_ get called earlier but dummycon gets initialized first and ends up as the primary console. When the fb layer starts going, xenfb takes over from dummycon and it''s the primary console. All good if you''re wanting the fb. If you''re _not_ though and you have it any of the VC stuff compiled into the kernel, then you need to reset xencons as the actual primary console dev. The better thing to do in the longer term is to actually have a xen_early_console along the lines of the ppc early console stuff (see viocons_early in drivers/char/viocons.c) so that you''re doing a sane hand-off. But the (reasonable, IMHO) consensus after the last cycle was to do that as a separate patch set as it''s not fundamentally related to the pvfb stuff. If I understand this correctly, the hack is required to make xencons working when xenfb is compiled in but not active. Since we let xend create the xenstore for the devices now, we can check whether the frontend device is in xenstore here, and drop console/use_graphics. We could also conditionalize on XEN_FRAMEBUFFER, but I doubt it''s worth the bother. [...] _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
PV framebuffer frontend. Derived from http://www.cs.utexas.edu/users/aliguori/vfb-20060124.bundle Extensive changes based on feedback from xen-devel. Signed-off-by: Markus Armbruster <armbru@redhat.com> --- arch/i386/kernel/setup-xen.c | 5 arch/ia64/kernel/setup.c | 4 arch/x86_64/kernel/setup-xen.c | 7 drivers/char/tty_io.c | 6 drivers/xen/Kconfig | 23 + drivers/xen/Makefile | 2 drivers/xen/console/console.c | 44 ++ drivers/xen/xenfb/Makefile | 1 drivers/xen/xenfb/xenfb.c | 682 ++++++++++++++++++++++++++++++++++++++ drivers/xen/xenkbd/Makefile | 1 drivers/xen/xenkbd/xenkbd.c | 300 ++++++++++++++++ include/xen/interface/io/xenfb.h | 116 ++++++ include/xen/interface/io/xenkbd.h | 108 ++++++ mm/memory.c | 1 14 files changed, 1284 insertions(+), 16 deletions(-) diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/arch/i386/kernel/setup-xen.c linux-2.6.16.29-xen-pvfb/arch/i386/kernel/setup-xen.c --- linux-2.6.16.29-xen/arch/i386/kernel/setup-xen.c 2006-09-29 16:11:51.000000000 +0200 +++ linux-2.6.16.29-xen-pvfb/arch/i386/kernel/setup-xen.c 2006-11-24 08:41:09.000000000 +0100 @@ -1850,8 +1850,9 @@ void __init setup_arch(char **cmdline_p) #endif #endif } else { - extern int console_use_vt; - console_use_vt = 0; +#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE) + conswitchp = &dummy_con; +#endif } } diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/arch/ia64/kernel/setup.c linux-2.6.16.29-xen-pvfb/arch/ia64/kernel/setup.c --- linux-2.6.16.29-xen/arch/ia64/kernel/setup.c 2006-11-09 17:54:47.000000000 +0100 +++ linux-2.6.16.29-xen-pvfb/arch/ia64/kernel/setup.c 2006-11-24 08:41:09.000000000 +0100 @@ -550,9 +550,9 @@ setup_arch (char **cmdline_p) xen_start_info->nr_pages, xen_start_info->flags); if (!is_initial_xendomain()) { - extern int console_use_vt; +#if !defined(CONFIG_VT) || !defined(CONFIG_DUMMY_CONSOLE) conswitchp = NULL; - console_use_vt = 0; +#endif } } #endif diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/arch/x86_64/kernel/setup-xen.c linux-2.6.16.29-xen-pvfb/arch/x86_64/kernel/setup-xen.c --- linux-2.6.16.29-xen/arch/x86_64/kernel/setup-xen.c 2006-09-29 16:11:51.000000000 +0200 +++ linux-2.6.16.29-xen-pvfb/arch/x86_64/kernel/setup-xen.c 2006-11-24 08:41:09.000000000 +0100 @@ -970,9 +970,10 @@ void __init setup_arch(char **cmdline_p) #endif #endif } else { - extern int console_use_vt; - console_use_vt = 0; - } +#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE) + conswitchp = &dummy_con; +#endif + } } #else /* CONFIG_XEN */ diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/char/tty_io.c linux-2.6.16.29-xen-pvfb/drivers/char/tty_io.c --- linux-2.6.16.29-xen/drivers/char/tty_io.c 2006-09-29 16:11:51.000000000 +0200 +++ linux-2.6.16.29-xen-pvfb/drivers/char/tty_io.c 2006-11-24 08:41:09.000000000 +0100 @@ -132,8 +132,6 @@ LIST_HEAD(tty_drivers); /* linked list vt.c for deeply disgusting hack reasons */ DECLARE_MUTEX(tty_sem); -int console_use_vt = 1; - #ifdef CONFIG_UNIX98_PTYS extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */ extern int pty_limit; /* Config limit on Unix98 ptys */ @@ -2056,7 +2054,7 @@ retry_open: goto got_driver; } #ifdef CONFIG_VT - if (console_use_vt && (device == MKDEV(TTY_MAJOR,0))) { + if (device == MKDEV(TTY_MAJOR,0)) { extern struct tty_driver *console_driver; driver = console_driver; index = fg_console; @@ -3247,8 +3245,6 @@ static int __init tty_init(void) #endif #ifdef CONFIG_VT - if (!console_use_vt) - goto out_vt; cdev_init(&vc0_cdev, &console_fops); if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) || register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/console/console.c linux-2.6.16.29-xen-pvfb/drivers/xen/console/console.c --- linux-2.6.16.29-xen/drivers/xen/console/console.c 2006-09-29 16:11:51.000000000 +0200 +++ linux-2.6.16.29-xen-pvfb/drivers/xen/console/console.c 2006-11-24 08:41:09.000000000 +0100 @@ -58,20 +58,28 @@ #include <asm/hypervisor.h> #include <xen/evtchn.h> #include <xen/xencons.h> +#include <xen/xenbus.h> /* * Modes: * ''xencons=off'' [XC_OFF]: Console is disabled. * ''xencons=tty'' [XC_TTY]: Console attached to ''/dev/tty[0-9]+''. * ''xencons=ttyS'' [XC_SERIAL]: Console attached to ''/dev/ttyS[0-9]+''. + * ''xencons=xvc'' [XC_XVC]: Console attached to ''/dev/xvc[0-9]+''. * [XC_DEFAULT]: DOM0 -> XC_SERIAL ; all others -> XC_TTY. * * NB. In mode XC_TTY, we create dummy consoles for tty2-63. This suppresses * warnings from standard distro startup scripts. */ -static enum { XC_OFF, XC_DEFAULT, XC_TTY, XC_SERIAL } xc_mode = XC_DEFAULT; +static enum { XC_OFF, XC_DEFAULT, XC_TTY, XC_SERIAL, XC_XVC } + xc_mode = XC_DEFAULT; static int xc_num = -1; +/* If we are in XC_XVC mode (a virtual console at /dev/xvcX), we need to + * comply with Lanana and use a minor under the low density serial major. + */ +#define XEN_XVC_MINOR 187 + #ifdef CONFIG_MAGIC_SYSRQ static unsigned long sysrq_requested; extern int sysrq_enabled; @@ -86,6 +94,8 @@ static int __init xencons_setup(char *st xc_mode = XC_SERIAL; else if (!strncmp(str, "tty", 3)) xc_mode = XC_TTY; + else if (!strncmp(str, "xvc", 3)) + xc_mode = XC_XVC; else if (!strncmp(str, "off", 3)) xc_mode = XC_OFF; @@ -100,6 +110,11 @@ static int __init xencons_setup(char *st if (q > (str + 3)) xc_num = n; break; + case XC_XVC: + n = simple_strtol(str+3, &q, 10); + if (q > (str + 3)) + xc_num = n; + break; default: break; } @@ -196,11 +211,17 @@ static int __init xen_console_init(void) if (!xen_start_info->console.domU.evtchn) goto out; if (xc_mode == XC_DEFAULT) - xc_mode = XC_TTY; + xc_mode = XC_TTY; kcons_info.write = kcons_write; } switch (xc_mode) { + case XC_XVC: + strcpy(kcons_info.name, "xvc"); + if (xc_num == -1) + xc_num = 0; + break; + case XC_SERIAL: strcpy(kcons_info.name, "ttyS"); if (xc_num == -1) @@ -305,7 +326,7 @@ void dom0_init_screen_info(const struct /******************** User-space console driver (/dev/console) ************/ #define DRV(_d) (_d) -#define DUMMY_TTY(_tty) ((xc_mode != XC_SERIAL) && \ +#define DUMMY_TTY(_tty) ((xc_mode != XC_SERIAL) && (xc_mode != XC_XVC) && \ ((_tty)->index != (xc_num - 1))) static struct termios *xencons_termios[MAX_NR_CONSOLES]; @@ -628,7 +649,8 @@ static int __init xencons_init(void) return rc; } - xencons_driver = alloc_tty_driver((xc_mode == XC_SERIAL) ? + xencons_driver = alloc_tty_driver(((xc_mode == XC_SERIAL) || + (xc_mode == XC_XVC)) ? 1 : MAX_NR_CONSOLES); if (xencons_driver == NULL) return -ENOMEM; @@ -648,6 +670,11 @@ static int __init xencons_init(void) DRV(xencons_driver)->name = "ttyS"; DRV(xencons_driver)->minor_start = 64 + xc_num; DRV(xencons_driver)->name_base = 0 + xc_num; + } else if (xc_mode == XC_XVC) { + DRV(xencons_driver)->name = "xvc"; + DRV(xencons_driver)->major = 250; /* FIXME: until lanana approves for 204:187 */ + DRV(xencons_driver)->minor_start = XEN_XVC_MINOR; + DRV(xencons_driver)->name_base = xc_num; } else { DRV(xencons_driver)->name = "tty"; DRV(xencons_driver)->minor_start = 1; @@ -680,6 +707,15 @@ static int __init xencons_init(void) printk("Xen virtual console successfully installed as %s%d\n", DRV(xencons_driver)->name, xc_num); + /* Check about framebuffer messing up the console */ + if (!is_initial_xendomain() && + !xenbus_exists(XBT_NIL, "device", "vfb")) { + /* FIXME: this is ugly */ + unregister_console(&kcons_info); + kcons_info.flags |= CON_CONSDEV; + register_console(&kcons_info); + } + return 0; } diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/Kconfig linux-2.6.16.29-xen-pvfb/drivers/xen/Kconfig --- linux-2.6.16.29-xen/drivers/xen/Kconfig 2006-08-16 09:20:03.000000000 +0200 +++ linux-2.6.16.29-xen-pvfb/drivers/xen/Kconfig 2006-11-24 08:41:09.000000000 +0100 @@ -172,6 +172,29 @@ config XEN_NETDEV_FRONTEND dedicated device-driver domain, or your master control domain (domain 0), then you almost certainly want to say Y here. +config XEN_FRAMEBUFFER + tristate "Framebuffer-device frontend driver" + depends on XEN && FB + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + default y + help + The framebuffer-device frontend drivers allows the kernel to create a + virtual framebuffer. This framebuffer can be viewed in another + domain. Unless this domain has access to a real video card, you + probably want to say Y here. + +config XEN_KEYBOARD + tristate "Keyboard-device frontend driver" + depends on XEN && XEN_FRAMEBUFFER && INPUT + default y + help + The keyboard-device frontend driver allows the kernel to create a + virtual keyboard. This keyboard can then be driven by another + domain. If you''ve said Y to CONFIG_XEN_FRAMEBUFFER, you probably + want to say Y here. + config XEN_SCRUB_PAGES bool "Scrub memory before freeing it to Xen" default y diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/Makefile linux-2.6.16.29-xen-pvfb/drivers/xen/Makefile --- linux-2.6.16.29-xen/drivers/xen/Makefile 2006-07-20 14:12:19.000000000 +0200 +++ linux-2.6.16.29-xen-pvfb/drivers/xen/Makefile 2006-11-24 08:41:09.000000000 +0100 @@ -15,3 +15,5 @@ obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += blk obj-$(CONFIG_XEN_NETDEV_FRONTEND) += netfront/ obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback/ obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += pcifront/ +obj-$(CONFIG_XEN_FRAMEBUFFER) += xenfb/ +obj-$(CONFIG_XEN_KEYBOARD) += xenkbd/ diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/xenfb/Makefile linux-2.6.16.29-xen-pvfb/drivers/xen/xenfb/Makefile --- linux-2.6.16.29-xen/drivers/xen/xenfb/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.29-xen-pvfb/drivers/xen/xenfb/Makefile 2006-11-24 08:41:09.000000000 +0100 @@ -0,0 +1 @@ +obj-$(CONFIG_XEN_FRAMEBUFFER) := xenfb.o diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/xenfb/xenfb.c linux-2.6.16.29-xen-pvfb/drivers/xen/xenfb/xenfb.c --- linux-2.6.16.29-xen/drivers/xen/xenfb/xenfb.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.29-xen-pvfb/drivers/xen/xenfb/xenfb.c 2006-11-24 08:41:09.000000000 +0100 @@ -0,0 +1,682 @@ +/* + * linux/drivers/video/xenfb.c -- Xen para-virtual frame buffer device + * + * Copyright (C) 2005-2006 Anthony Liguori <aliguori@us.ibm.com> + * Copyright (C) 2006 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/kernel.h> +#include <linux/errno.h> +#include <linux/fb.h> +#include <linux/module.h> +#include <linux/vmalloc.h> +#include <linux/mm.h> +#include <asm/hypervisor.h> +#include <xen/evtchn.h> +#include <xen/interface/io/xenfb.h> +#include <xen/xenbus.h> +#include <linux/kthread.h> + +struct xenfb_mapping +{ + struct list_head link; + struct vm_area_struct *vma; + atomic_t map_refs; + int faults; + struct xenfb_info *info; +}; + +struct xenfb_info +{ + struct task_struct *kthread; + wait_queue_head_t wq; + + unsigned char *fb; + struct fb_info *fb_info; + struct timer_list refresh; + int dirty; + int x1, y1, x2, y2; /* dirty rectangle, + protected by mm_lock */ + spinlock_t mm_lock; + int nr_pages; + struct page **pages; + struct list_head mappings; /* protected by mm_lock */ + + unsigned evtchn; + int irq; + struct xenfb_page *page; + unsigned long *mfns; + int update_wanted; /* XENFB_TYPE_UPDATE wanted */ + + struct xenbus_device *xbdev; +}; + +static int xenfb_fps = 20; +static unsigned long xenfb_mem_len = XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8; + +static int xenfb_remove(struct xenbus_device *); +static void xenfb_init_shared_page(struct xenfb_info *); +static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info *); +static void xenfb_disconnect_backend(struct xenfb_info *); + +static void xenfb_do_update(struct xenfb_info *info, + int x, int y, int w, int h) +{ + union xenfb_out_event event; + __u32 prod; + + event.type = XENFB_TYPE_UPDATE; + event.update.x = x; + event.update.y = y; + event.update.width = w; + event.update.height = h; + + 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_evtchn(info->evtchn); +} + +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_update_screen(struct xenfb_info *info) +{ + unsigned long flags; + int y1, y2, x1, x2; + struct xenfb_mapping *map; + + if (!info->update_wanted) + return; + if (xenfb_queue_full(info)) + return; + + spin_lock_irqsave(&info->mm_lock, flags); + + y1 = info->y1; + y2 = info->y2; + x1 = info->x1; + x2 = info->x2; + info->x1 = info->y1 = INT_MAX; + info->x2 = info->y2 = 0; + + list_for_each_entry(map, &info->mappings, link) { + if (!map->faults) + continue; + zap_page_range(map->vma, map->vma->vm_start, + map->vma->vm_end - map->vma->vm_start, NULL); + map->faults = 0; + } + + spin_unlock_irqrestore(&info->mm_lock, flags); + + xenfb_do_update(info, x1, y1, x2 - x1, y2 - y1); +} + +static int xenfb_thread(void *data) +{ + struct xenfb_info *info = data; + + while (!kthread_should_stop()) { + if (info->dirty) { + info->dirty = 0; + xenfb_update_screen(info); + } + wait_event_interruptible(info->wq, + kthread_should_stop() || info->dirty); + try_to_freeze(); + } + return 0; +} + +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; + + red >>= (16 - info->var.red.length); + green >>= (16 - info->var.green.length); + blue >>= (16 - info->var.blue.length); + + v = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + + /* FIXME is this sane? check against xxxfb_setcolreg()! */ + switch (info->var.bits_per_pixel) { + case 16: + case 24: + case 32: + ((u32 *)info->pseudo_palette)[regno] = v; + break; + } + + return 0; +} + +static void xenfb_timer(unsigned long data) +{ + struct xenfb_info *info = (struct xenfb_info *)data; + info->dirty = 1; + wake_up(&info->wq); +} + +static void __xenfb_refresh(struct xenfb_info *info, + int x1, int y1, int w, int h) +{ + int y2, x2; + + y2 = y1 + h; + x2 = x1 + w; + + if (info->y1 > y1) + info->y1 = y1; + if (info->y2 < y2) + info->y2 = y2; + if (info->x1 > x1) + info->x1 = x1; + if (info->x2 < x2) + info->x2 = x2; + + if (timer_pending(&info->refresh)) + return; + + mod_timer(&info->refresh, jiffies + HZ/xenfb_fps); +} + +static void xenfb_refresh(struct xenfb_info *info, + int x1, int y1, int w, int h) +{ + unsigned long flags; + + spin_lock_irqsave(&info->mm_lock, flags); + __xenfb_refresh(info, x1, y1, w, h); + spin_unlock_irqrestore(&info->mm_lock, flags); +} + +static void xenfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) +{ + struct xenfb_info *info = p->par; + + cfb_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; + + cfb_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; + + cfb_copyarea(p, area); + xenfb_refresh(info, area->dx, area->dy, area->width, area->height); +} + +static void xenfb_vm_open(struct vm_area_struct *vma) +{ + struct xenfb_mapping *map = vma->vm_private_data; + atomic_inc(&map->map_refs); +} + +static void xenfb_vm_close(struct vm_area_struct *vma) +{ + struct xenfb_mapping *map = vma->vm_private_data; + struct xenfb_info *info = map->info; + unsigned long flags; + + spin_lock_irqsave(&info->mm_lock, flags); + if (atomic_dec_and_test(&map->map_refs)) { + list_del(&map->link); + kfree(map); + } + spin_unlock_irqrestore(&info->mm_lock, flags); +} + +static struct page *xenfb_vm_nopage(struct vm_area_struct *vma, + unsigned long vaddr, int *type) +{ + struct xenfb_mapping *map = vma->vm_private_data; + struct xenfb_info *info = map->info; + int pgnr = (vaddr - vma->vm_start) >> PAGE_SHIFT; + unsigned long flags; + struct page *page; + int y1, y2; + + if (pgnr >= info->nr_pages) + return NOPAGE_SIGBUS; + + spin_lock_irqsave(&info->mm_lock, flags); + page = info->pages[pgnr]; + get_page(page); + map->faults++; + + y1 = pgnr * PAGE_SIZE / info->fb_info->fix.line_length; + y2 = (pgnr * PAGE_SIZE + PAGE_SIZE - 1) / info->fb_info->fix.line_length; + if (y2 > info->fb_info->var.yres) + y2 = info->fb_info->var.yres; + __xenfb_refresh(info, 0, y1, info->fb_info->var.xres, y2 - y1); + spin_unlock_irqrestore(&info->mm_lock, flags); + + if (type) + *type = VM_FAULT_MINOR; + + return page; +} + +static struct vm_operations_struct xenfb_vm_ops = { + .open = xenfb_vm_open, + .close = xenfb_vm_close, + .nopage = xenfb_vm_nopage, +}; + +static int xenfb_mmap(struct fb_info *fb_info, struct vm_area_struct *vma) +{ + struct xenfb_info *info = fb_info->par; + unsigned long flags; + struct xenfb_mapping *map; + int map_pages; + + if (!(vma->vm_flags & VM_WRITE)) + return -EINVAL; + if (!(vma->vm_flags & VM_SHARED)) + return -EINVAL; + if (vma->vm_pgoff != 0) + return -EINVAL; + + map_pages = (vma->vm_end - vma->vm_start + PAGE_SIZE-1) >> PAGE_SHIFT; + if (map_pages > info->nr_pages) + return -EINVAL; + + map = kzalloc(sizeof(*map), GFP_KERNEL); + if (map == NULL) + return -ENOMEM; + + map->vma = vma; + map->faults = 0; + map->info = info; + atomic_set(&map->map_refs, 1); + + spin_lock_irqsave(&info->mm_lock, flags); + list_add(&map->link, &info->mappings); + spin_unlock_irqrestore(&info->mm_lock, flags); + + vma->vm_ops = &xenfb_vm_ops; + vma->vm_flags |= (VM_DONTEXPAND | VM_RESERVED); + vma->vm_private_data = map; + + return 0; +} + +static struct fb_ops xenfb_fb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = xenfb_setcolreg, + .fb_fillrect = xenfb_fillrect, + .fb_copyarea = xenfb_copyarea, + .fb_imageblit = xenfb_imageblit, + .fb_mmap = xenfb_mmap, +}; + +static irqreturn_t xenfb_event_handler(int rq, void *dev_id, + struct pt_regs *regs) +{ + /* + * No in events recognized, simply ignore them all. + * If you need to recognize some, see xenbkd''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_evtchn(info->evtchn); + } + return IRQ_HANDLED; +} + +static unsigned long vmalloc_to_mfn(void *address) +{ + return pfn_to_mfn(vmalloc_to_pfn(address)); +} + +static int __devinit xenfb_probe(struct xenbus_device *dev, + const struct xenbus_device_id *id) +{ + struct xenfb_info *info; + struct fb_info *fb_info; + int ret; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (info == NULL) { + xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); + return -ENOMEM; + } + dev->dev.driver_data = info; + info->xbdev = dev; + info->irq = -1; + info->x1 = info->y1 = INT_MAX; + spin_lock_init(&info->mm_lock); + init_waitqueue_head(&info->wq); + init_timer(&info->refresh); + info->refresh.function = xenfb_timer; + info->refresh.data = (unsigned long)info; + INIT_LIST_HEAD(&info->mappings); + + info->fb = vmalloc(xenfb_mem_len); + if (info->fb == NULL) + goto error_nomem; + memset(info->fb, 0, xenfb_mem_len); + + info->nr_pages = (xenfb_mem_len + PAGE_SIZE - 1) >> PAGE_SHIFT; + + info->pages = kmalloc(sizeof(struct page *) * info->nr_pages, + GFP_KERNEL); + if (info->pages == NULL) + goto error_nomem; + + info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages); + if (!info->mfns) + goto error_nomem; + + /* set up shared page */ + info->page = (void *)__get_free_page(GFP_KERNEL); + if (!info->page) + goto error_nomem; + + xenfb_init_shared_page(info); + + fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL); + /* see fishy hackery below */ + if (fb_info == NULL) + goto error_nomem; + + /* FIXME fishy hackery */ + fb_info->pseudo_palette = fb_info->par; + fb_info->par = info; + /* /FIXME */ + fb_info->screen_base = info->fb; + + fb_info->fbops = &xenfb_fb_ops; + fb_info->var.xres_virtual = fb_info->var.xres = info->page->width; + fb_info->var.yres_virtual = fb_info->var.yres = info->page->height; + fb_info->var.bits_per_pixel = info->page->depth; + + fb_info->var.red = (struct fb_bitfield){16, 8, 0}; + fb_info->var.green = (struct fb_bitfield){8, 8, 0}; + fb_info->var.blue = (struct fb_bitfield){0, 8, 0}; + + fb_info->var.activate = FB_ACTIVATE_NOW; + fb_info->var.height = -1; + fb_info->var.width = -1; + fb_info->var.vmode = FB_VMODE_NONINTERLACED; + + fb_info->fix.visual = FB_VISUAL_TRUECOLOR; + fb_info->fix.line_length = info->page->line_length; + fb_info->fix.smem_start = 0; + fb_info->fix.smem_len = xenfb_mem_len; + strcpy(fb_info->fix.id, "xen"); + fb_info->fix.type = FB_TYPE_PACKED_PIXELS; + fb_info->fix.accel = FB_ACCEL_NONE; + + fb_info->flags = FBINFO_FLAG_DEFAULT; + + ret = fb_alloc_cmap(&fb_info->cmap, 256, 0); + if (ret < 0) { + framebuffer_release(fb_info); + xenbus_dev_fatal(dev, ret, "fb_alloc_cmap"); + goto error; + } + + ret = register_framebuffer(fb_info); + if (ret) { + fb_dealloc_cmap(&info->fb_info->cmap); + framebuffer_release(fb_info); + xenbus_dev_fatal(dev, ret, "register_framebuffer"); + goto error; + } + info->fb_info = fb_info; + + /* FIXME should this be delayed until backend XenbusStateConnected? */ + info->kthread = kthread_run(xenfb_thread, info, "xenfb thread"); + if (IS_ERR(info->kthread)) { + ret = PTR_ERR(info->kthread); + info->kthread = NULL; + xenbus_dev_fatal(dev, ret, "register_framebuffer"); + goto error; + } + + ret = xenfb_connect_backend(dev, info); + if (ret < 0) + goto error; + + return 0; + + error_nomem: + ret = -ENOMEM; + xenbus_dev_fatal(dev, ret, "allocating device memory"); + error: + xenfb_remove(dev); + return ret; +} + +static int xenfb_resume(struct xenbus_device *dev) +{ + struct xenfb_info *info = dev->dev.driver_data; + + xenfb_disconnect_backend(info); + xenfb_init_shared_page(info); + return xenfb_connect_backend(dev, info); +} + +static int xenfb_remove(struct xenbus_device *dev) +{ + struct xenfb_info *info = dev->dev.driver_data; + + del_timer(&info->refresh); + if (info->kthread) + kthread_stop(info->kthread); + xenfb_disconnect_backend(info); + if (info->fb_info) { + unregister_framebuffer(info->fb_info); + fb_dealloc_cmap(&info->fb_info->cmap); + framebuffer_release(info->fb_info); + } + free_page((unsigned long)info->page); + vfree(info->mfns); + kfree(info->pages); + vfree(info->fb); + kfree(info); + + return 0; +} + +static void xenfb_init_shared_page(struct xenfb_info *info) +{ + int i; + + for (i = 0; i < info->nr_pages; i++) + info->pages[i] = vmalloc_to_page(info->fb + i * PAGE_SIZE); + + for (i = 0; i < info->nr_pages; i++) + info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE); + + info->page->pd[0] = vmalloc_to_mfn(info->mfns); + info->page->pd[1] = 0; + info->page->width = XENFB_WIDTH; + info->page->height = XENFB_HEIGHT; + info->page->depth = XENFB_DEPTH; + info->page->line_length = (info->page->depth / 8) * info->page->width; + info->page->mem_length = xenfb_mem_len; + info->page->in_cons = info->page->in_prod = 0; + info->page->out_cons = info->page->out_prod = 0; +} + +static int xenfb_connect_backend(struct xenbus_device *dev, + struct xenfb_info *info) +{ + int ret; + struct xenbus_transaction xbt; + + ret = xenbus_alloc_evtchn(dev, &info->evtchn); + if (ret) + return ret; + ret = bind_evtchn_to_irqhandler(info->evtchn, xenfb_event_handler, + 0, "xenfb", info); + if (ret < 0) { + xenbus_free_evtchn(dev, info->evtchn); + xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler"); + return ret; + } + info->irq = ret; + + again: + ret = xenbus_transaction_start(&xbt); + if (ret) { + xenbus_dev_fatal(dev, ret, "starting transaction"); + return ret; + } + ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", + virt_to_mfn(info->page)); + if (ret) + goto error_xenbus; + ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", + info->evtchn); + if (ret) + goto error_xenbus; + ret = xenbus_printf(xbt, dev->nodename, "feature-update", "1"); + if (ret) + goto error_xenbus; + ret = xenbus_transaction_end(xbt, 0); + if (ret) { + if (ret == -EAGAIN) + goto again; + xenbus_dev_fatal(dev, ret, "completing transaction"); + return ret; + } + + xenbus_switch_state(dev, XenbusStateInitialised); + return 0; + + error_xenbus: + xenbus_transaction_end(xbt, 1); + xenbus_dev_fatal(dev, ret, "writing xenstore"); + return ret; +} + +static void xenfb_disconnect_backend(struct xenfb_info *info) +{ + if (info->irq >= 0) + unbind_from_irqhandler(info->irq, info); + info->irq = -1; +} + +static void xenfb_backend_changed(struct xenbus_device *dev, + enum xenbus_state backend_state) +{ + struct xenfb_info *info = dev->dev.driver_data; + int val; + + switch (backend_state) { + case XenbusStateInitialising: + case XenbusStateInitialised: + case XenbusStateUnknown: + case XenbusStateClosed: + break; + + case XenbusStateInitWait: + InitWait: + xenbus_switch_state(dev, XenbusStateConnected); + break; + + case XenbusStateConnected: + /* + * Work around xenbus race condition: If backend goes + * through InitWait to Connected fast enough, we can + * get Connected twice here. + */ + if (dev->state != XenbusStateConnected) + goto InitWait; /* no InitWait seen yet, fudge it */ + + if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, + "request-update", "%d", &val) < 0) + val = 0; + if (val) + info->update_wanted = 1; + break; + + case XenbusStateClosing: + // FIXME is this safe in any dev->state? + xenbus_frontend_closed(dev); + break; + } +} + +static struct xenbus_device_id xenfb_ids[] = { + { "vfb" }, + { "" } +}; + +static struct xenbus_driver xenfb = { + .name = "vfb", + .owner = THIS_MODULE, + .ids = xenfb_ids, + .probe = xenfb_probe, + .remove = xenfb_remove, + .resume = xenfb_resume, + .otherend_changed = xenfb_backend_changed, +}; + +static int __init xenfb_init(void) +{ + if (!is_running_on_xen()) + return -ENODEV; + + /* Nothing to do if running in dom0. */ + if (is_initial_xendomain()) + return -ENODEV; + + return xenbus_register_frontend(&xenfb); +} + +static void __exit xenfb_cleanup(void) +{ + return xenbus_unregister_driver(&xenfb); +} + +module_init(xenfb_init); +module_exit(xenfb_cleanup); + +MODULE_LICENSE("GPL"); diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/xenkbd/Makefile linux-2.6.16.29-xen-pvfb/drivers/xen/xenkbd/Makefile --- linux-2.6.16.29-xen/drivers/xen/xenkbd/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.29-xen-pvfb/drivers/xen/xenkbd/Makefile 2006-11-24 08:41:09.000000000 +0100 @@ -0,0 +1 @@ +obj-$(CONFIG_XEN_KEYBOARD) += xenkbd.o diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/drivers/xen/xenkbd/xenkbd.c linux-2.6.16.29-xen-pvfb/drivers/xen/xenkbd/xenkbd.c --- linux-2.6.16.29-xen/drivers/xen/xenkbd/xenkbd.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.29-xen-pvfb/drivers/xen/xenkbd/xenkbd.c 2006-11-24 08:41:09.000000000 +0100 @@ -0,0 +1,300 @@ +/* + * linux/drivers/input/keyboard/xenkbd.c -- Xen para-virtual input device + * + * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com> + * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> + * + * Based on linux/drivers/input/mouse/sermouse.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 together with xenfb.c. + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/module.h> +#include <linux/input.h> +#include <asm/hypervisor.h> +#include <xen/evtchn.h> +#include <xen/interface/io/xenfb.h> +#include <xen/interface/io/xenkbd.h> +#include <xen/xenbus.h> + +struct xenkbd_info +{ + struct input_dev *dev; + struct xenkbd_page *page; + unsigned evtchn; + int irq; + struct xenbus_device *xbdev; +}; + +static int xenkbd_remove(struct xenbus_device *); +static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *); +static void xenkbd_disconnect_backend(struct xenkbd_info *); + +/* + * Note: if you need to send out events, see xenfb_do_update() for how + * to do that. + */ + +static irqreturn_t input_handler(int rq, void *dev_id, struct pt_regs *regs) +{ + struct xenkbd_info *info = dev_id; + struct xenkbd_page *page = info->page; + __u32 cons, prod; + + prod = page->in_prod; + if (prod == page->out_cons) + return IRQ_HANDLED; + rmb(); /* ensure we see ring contents up to prod */ + for (cons = page->in_cons; cons != prod; cons++) { + union xenkbd_in_event *event; + event = &XENKBD_IN_RING_REF(page, cons); + + switch (event->type) { + case XENKBD_TYPE_MOTION: + input_report_rel(info->dev, REL_X, event->motion.rel_x); + input_report_rel(info->dev, REL_Y, event->motion.rel_y); + break; + case XENKBD_TYPE_KEY: + input_report_key(info->dev, event->key.keycode, event->key.pressed); + break; + case XENKBD_TYPE_POS: + input_report_abs(info->dev, ABS_X, event->pos.abs_x); + input_report_abs(info->dev, ABS_Y, event->pos.abs_y); + break; + } + } + input_sync(info->dev); + mb(); /* ensure we got ring contents */ + page->in_cons = cons; + notify_remote_via_evtchn(info->evtchn); + + return IRQ_HANDLED; +} + +int __devinit xenkbd_probe(struct xenbus_device *dev, + const struct xenbus_device_id *id) +{ + int ret, i; + struct xenkbd_info *info; + struct input_dev *input_dev; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); + return -ENOMEM; + } + dev->dev.driver_data = info; + info->xbdev = dev; + + info->page = (void *)__get_free_page(GFP_KERNEL); + if (!info->page) + goto error_nomem; + info->page->in_cons = info->page->in_prod = 0; + info->page->out_cons = info->page->out_prod = 0; + + input_dev = input_allocate_device(); + if (!input_dev) + goto error_nomem; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_MOUSE)] + = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + /* TODO additional buttons */ + input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); + + /* FIXME not sure this is quite right */ + for (i = 0; i < 256; i++) + set_bit(i, input_dev->keybit); + + input_dev->name = "Xen Virtual Keyboard/Mouse"; + + input_set_abs_params(input_dev, ABS_X, 0, XENFB_WIDTH, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, XENFB_HEIGHT, 0, 0); + + ret = input_register_device(input_dev); + if (ret) { + input_free_device(input_dev); + xenbus_dev_fatal(dev, ret, "input_register_device"); + goto error; + } + info->dev = input_dev; + + ret = xenkbd_connect_backend(dev, info); + if (ret < 0) + goto error; + + return 0; + + error_nomem: + ret = -ENOMEM; + xenbus_dev_fatal(dev, ret, "allocating device memory"); + error: + xenkbd_remove(dev); + return ret; +} + +static int xenkbd_resume(struct xenbus_device *dev) +{ + struct xenkbd_info *info = dev->dev.driver_data; + + xenkbd_disconnect_backend(info); + return xenkbd_connect_backend(dev, info); +} + +static int xenkbd_remove(struct xenbus_device *dev) +{ + struct xenkbd_info *info = dev->dev.driver_data; + + xenkbd_disconnect_backend(info); + input_unregister_device(info->dev); + free_page((unsigned long)info->page); + kfree(info); + return 0; +} + +static int xenkbd_connect_backend(struct xenbus_device *dev, + struct xenkbd_info *info) +{ + int ret; + struct xenbus_transaction xbt; + + ret = xenbus_alloc_evtchn(dev, &info->evtchn); + if (ret) + return ret; + ret = bind_evtchn_to_irqhandler(info->evtchn, input_handler, 0, + "xenkbd", info); + if (ret < 0) { + xenbus_free_evtchn(dev, info->evtchn); + xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler"); + return ret; + } + info->irq = ret; + + again: + ret = xenbus_transaction_start(&xbt); + if (ret) { + xenbus_dev_fatal(dev, ret, "starting transaction"); + return ret; + } + ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", + virt_to_mfn(info->page)); + if (ret) + goto error_xenbus; + ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", + info->evtchn); + if (ret) + goto error_xenbus; + ret = xenbus_transaction_end(xbt, 0); + if (ret) { + if (ret == -EAGAIN) + goto again; + xenbus_dev_fatal(dev, ret, "completing transaction"); + return ret; + } + + xenbus_switch_state(dev, XenbusStateInitialised); + return 0; + + error_xenbus: + xenbus_transaction_end(xbt, 1); + xenbus_dev_fatal(dev, ret, "writing xenstore"); + return ret; +} + +static void xenkbd_disconnect_backend(struct xenkbd_info *info) +{ + if (info->irq >= 0) + unbind_from_irqhandler(info->irq, info); + info->irq = -1; +} + +static void xenkbd_backend_changed(struct xenbus_device *dev, + enum xenbus_state backend_state) +{ + struct xenkbd_info *info = dev->dev.driver_data; + int ret, val; + + switch (backend_state) { + case XenbusStateInitialising: + case XenbusStateInitialised: + case XenbusStateUnknown: + case XenbusStateClosed: + break; + + case XenbusStateInitWait: + InitWait: + ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend, + "feature-abs-pointer", "%d", &val); + if (ret < 0) + val = 0; + if (val) { + ret = xenbus_printf(XBT_NIL, info->xbdev->nodename, + "request-abs-pointer", "1"); + if (ret) + ; /* FIXME */ + } + xenbus_switch_state(dev, XenbusStateConnected); + break; + + case XenbusStateConnected: + /* + * Work around xenbus race condition: If backend goes + * through InitWait to Connected fast enough, we can + * get Connected twice here. + */ + if (dev->state != XenbusStateConnected) + goto InitWait; /* no InitWait seen yet, fudge it */ + break; + + case XenbusStateClosing: + xenbus_frontend_closed(dev); + break; + } +} + +static struct xenbus_device_id xenkbd_ids[] = { + { "vkbd" }, + { "" } +}; + +static struct xenbus_driver xenkbd = { + .name = "vkbd", + .owner = THIS_MODULE, + .ids = xenkbd_ids, + .probe = xenkbd_probe, + .remove = xenkbd_remove, + .resume = xenkbd_resume, + .otherend_changed = xenkbd_backend_changed, +}; + +static int __init xenkbd_init(void) +{ + if (!is_running_on_xen()) + return -ENODEV; + + /* Nothing to do if running in dom0. */ + if (is_initial_xendomain()) + return -ENODEV; + + return xenbus_register_frontend(&xenkbd); +} + +static void __exit xenkbd_cleanup(void) +{ + return xenbus_unregister_driver(&xenkbd); +} + +module_init(xenkbd_init); +module_exit(xenkbd_cleanup); + +MODULE_LICENSE("GPL"); diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/include/xen/interface/io/xenfb.h linux-2.6.16.29-xen-pvfb/include/xen/interface/io/xenfb.h --- linux-2.6.16.29-xen/include/xen/interface/io/xenfb.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.29-xen-pvfb/include/xen/interface/io/xenfb.h 2006-11-24 08:41:09.000000000 +0100 @@ -0,0 +1,116 @@ +/* + * linux/include/linux/xenfb.h -- Xen virtual frame buffer device + * + * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com> + * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> + * + * 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. + */ + +#ifndef _LINUX_XENFB_H +#define _LINUX_XENFB_H + +#include <asm/types.h> + +/* Out events (frontend -> backend) */ + +/* + * Out events may be sent only when requested by backend, and receipt + * of an unknown out event is an error. + */ + +/* Event type 1 currently not used */ +/* + * Framebuffer update notification event + * Capable frontend sets feature-update in xenstore. + * Backend requests it by setting request-update in xenstore. + */ +#define XENFB_TYPE_UPDATE 2 + +struct xenfb_update +{ + __u8 type; /* XENFB_TYPE_UPDATE */ + __s32 x; /* source x */ + __s32 y; /* source y */ + __s32 width; /* rect width */ + __s32 height; /* rect height */ +}; + +#define XENFB_OUT_EVENT_SIZE 40 + +union xenfb_out_event +{ + __u8 type; + struct xenfb_update update; + char pad[XENFB_OUT_EVENT_SIZE]; +}; + +/* In events (backend -> frontend) */ + +/* + * Frontends should ignore unknown in events. + * No in events currently defined. + */ + +#define XENFB_IN_EVENT_SIZE 40 + +union xenfb_in_event +{ + __u8 type; + char pad[XENFB_IN_EVENT_SIZE]; +}; + +/* shared page */ + +#define XENFB_IN_RING_SIZE 1024 +#define XENFB_IN_RING_LEN (XENFB_IN_RING_SIZE / XENFB_IN_EVENT_SIZE) +#define XENFB_IN_RING_OFFS 1024 +#define XENFB_IN_RING(page) \ + ((union xenfb_in_event *)((char *)(page) + XENFB_IN_RING_OFFS)) +#define XENFB_IN_RING_REF(page, idx) \ + (XENFB_IN_RING((page))[(idx) % XENFB_IN_RING_LEN]) + +#define XENFB_OUT_RING_SIZE 2048 +#define XENFB_OUT_RING_LEN (XENFB_OUT_RING_SIZE / XENFB_OUT_EVENT_SIZE) +#define XENFB_OUT_RING_OFFS (XENFB_IN_RING_OFFS + XENFB_IN_RING_SIZE) +#define XENFB_OUT_RING(page) \ + ((union xenfb_out_event *)((char *)(page) + XENFB_OUT_RING_OFFS)) +#define XENFB_OUT_RING_REF(page, idx) \ + (XENFB_OUT_RING((page))[(idx) % XENFB_OUT_RING_LEN]) + +struct xenfb_page +{ + __u32 in_cons, in_prod; + __u32 out_cons, out_prod; + + __s32 width; /* the width of the framebuffer (in pixels) */ + __s32 height; /* the height of the framebuffer (in pixels) */ + __u32 line_length; /* the length of a row of pixels (in bytes) */ + __u32 mem_length; /* the length of the framebuffer (in bytes) */ + __u8 depth; /* the depth of a pixel (in bits) */ + + /* + * Framebuffer page directory + * + * Each directory page holds PAGE_SIZE / sizeof(*pd) + * framebuffer pages, and can thus map up to PAGE_SIZE * + * PAGE_SIZE / sizeof(*pd) bytes. With PAGE_SIZE == 4096 and + * sizeof(unsigned long) == 4, that''s 4 Megs. Two directory + * pages should be enough for a while. + */ + unsigned long pd[2]; +}; + +/* + * Wart: xenkbd needs to know resolution. Put it here until a better + * solution is found, but don''t leak it to the backend. + */ +#ifdef __KERNEL__ +#define XENFB_WIDTH 800 +#define XENFB_HEIGHT 600 +#define XENFB_DEPTH 32 +#endif + +#endif diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/include/xen/interface/io/xenkbd.h linux-2.6.16.29-xen-pvfb/include/xen/interface/io/xenkbd.h --- linux-2.6.16.29-xen/include/xen/interface/io/xenkbd.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.29-xen-pvfb/include/xen/interface/io/xenkbd.h 2006-11-24 08:41:09.000000000 +0100 @@ -0,0 +1,108 @@ +/* + * linux/include/linux/xenkbd.h -- Xen virtual keyboard/mouse + * + * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com> + * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> + * + * 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. + */ + +#ifndef _LINUX_XENKBD_H +#define _LINUX_XENKBD_H + +#include <asm/types.h> + +/* In events (backend -> frontend) */ + +/* + * Frontends should ignore unknown in events. + */ + +/* Pointer movement event */ +#define XENKBD_TYPE_MOTION 1 +/* Event type 2 currently not used */ +/* Key event (includes pointer buttons) */ +#define XENKBD_TYPE_KEY 3 +/* + * Pointer position event + * Capable backend sets feature-abs-pointer in xenstore. + * Frontend requests ot instead of XENKBD_TYPE_MOTION by setting + * request-abs-update in xenstore. + */ +#define XENKBD_TYPE_POS 4 + +struct xenkbd_motion +{ + __u8 type; /* XENKBD_TYPE_MOTION */ + __s32 rel_x; /* relative X motion */ + __s32 rel_y; /* relative Y motion */ +}; + +struct xenkbd_key +{ + __u8 type; /* XENKBD_TYPE_KEY */ + __u8 pressed; /* 1 if pressed; 0 otherwise */ + __u32 keycode; /* KEY_* from linux/input.h */ +}; + +struct xenkbd_position +{ + __u8 type; /* XENKBD_TYPE_POS */ + __s32 abs_x; /* absolute X position (in FB pixels) */ + __s32 abs_y; /* absolute Y position (in FB pixels) */ +}; + +#define XENKBD_IN_EVENT_SIZE 40 + +union xenkbd_in_event +{ + __u8 type; + struct xenkbd_motion motion; + struct xenkbd_key key; + struct xenkbd_position pos; + char pad[XENKBD_IN_EVENT_SIZE]; +}; + +/* Out events (frontend -> backend) */ + +/* + * Out events may be sent only when requested by backend, and receipt + * of an unknown out event is an error. + * No out events currently defined. + */ + +#define XENKBD_OUT_EVENT_SIZE 40 + +union xenkbd_out_event +{ + __u8 type; + char pad[XENKBD_OUT_EVENT_SIZE]; +}; + +/* shared page */ + +#define XENKBD_IN_RING_SIZE 2048 +#define XENKBD_IN_RING_LEN (XENKBD_IN_RING_SIZE / XENKBD_IN_EVENT_SIZE) +#define XENKBD_IN_RING_OFFS 1024 +#define XENKBD_IN_RING(page) \ + ((union xenkbd_in_event *)((char *)(page) + XENKBD_IN_RING_OFFS)) +#define XENKBD_IN_RING_REF(page, idx) \ + (XENKBD_IN_RING((page))[(idx) % XENKBD_IN_RING_LEN]) + +#define XENKBD_OUT_RING_SIZE 1024 +#define XENKBD_OUT_RING_LEN (XENKBD_OUT_RING_SIZE / XENKBD_OUT_EVENT_SIZE) +#define XENKBD_OUT_RING_OFFS (XENKBD_IN_RING_OFFS + XENKBD_IN_RING_SIZE) +#define XENKBD_OUT_RING(page) \ + ((union xenkbd_out_event *)((char *)(page) + XENKBD_OUT_RING_OFFS)) +#define XENKBD_OUT_RING_REF(page, idx) \ + (XENKBD_OUT_RING((page))[(idx) % XENKBD_OUT_RING_LEN]) + +struct xenkbd_page +{ + __u32 in_cons, in_prod; + __u32 out_cons, out_prod; +}; + +#endif diff -rupN -x ''*.orig'' linux-2.6.16.29-xen/mm/memory.c linux-2.6.16.29-xen-pvfb/mm/memory.c --- linux-2.6.16.29-xen/mm/memory.c 2006-10-13 19:47:16.000000000 +0200 +++ linux-2.6.16.29-xen-pvfb/mm/memory.c 2006-11-24 08:41:09.000000000 +0100 @@ -882,6 +882,7 @@ unsigned long zap_page_range(struct vm_a tlb_finish_mmu(tlb, address, end); return end; } +EXPORT_SYMBOL(zap_page_range); /* * Do a quick page-table lookup for a single page. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel