From: Jeremy Katz <katzj@redhat.com>
To: xen-devel <xen-devel@lists.xensource.com>
Cc: aliguori <aliguori@mail.utexas.edu>,
Markus Armbruster <armbru@redhat.com>
Subject: [PATCH] Paravirt framebuffer frontend kernel support [1/5]
Date: Sat, 02 Sep 2006 15:58:00 -0400 [thread overview]
Message-ID: <1157227080.11059.38.camel@aglarond.local> (raw)
[-- Attachment #1: Type: text/plain, Size: 643 bytes --]
Initial patch from Anthony Liguori, ported to xenstore and current Xen
by Markus Armbruster. Further improvements since the last submission
* Don't set up on dom0 or if our domain isn't setup for a graphics
console (katzj)
* Compute framebuffer size from screen dimension (armbru)
* Implement XENFB_TYPE_SET_EVENTS (armbru)
* Future-proof layout of shared page (armbru)
* Memory barriers (armbru)
* Coaelsce notifies: just one batch of events instead of one per event
(armbru)
* Error handling fixes (armbru)
Signed-off-by: Jeremy Katz <katzj@redhat.com>
Cc: Markus Armbruster <armbru@redhat.com>
Cc: Anthony Liguori <aliguori@us.ibm.com>
[-- Attachment #2: xen-pvfb-1.patch --]
[-- Type: text/x-patch, Size: 27920 bytes --]
diff -r 5fa9b746d24f -r 510c6bceb87f linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c
--- a/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c Sat Sep 02 12:11:54 2006 +0100
+++ b/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c Sat Sep 02 15:11:17 2006 -0400
@@ -1866,8 +1866,12 @@ void __init setup_arch(char **cmdline_p)
#endif
#endif
} else {
+#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE)
+ conswitchp = &dummy_con;
+#else
extern int console_use_vt;
console_use_vt = 0;
+#endif
}
}
diff -r 5fa9b746d24f -r 510c6bceb87f linux-2.6-xen-sparse/drivers/xen/Kconfig
--- a/linux-2.6-xen-sparse/drivers/xen/Kconfig Sat Sep 02 12:11:54 2006 +0100
+++ b/linux-2.6-xen-sparse/drivers/xen/Kconfig Sat Sep 02 15:11:17 2006 -0400
@@ -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 -r 5fa9b746d24f -r 510c6bceb87f linux-2.6-xen-sparse/drivers/xen/Makefile
--- a/linux-2.6-xen-sparse/drivers/xen/Makefile Sat Sep 02 12:11:54 2006 +0100
+++ b/linux-2.6-xen-sparse/drivers/xen/Makefile Sat Sep 02 15:11:17 2006 -0400
@@ -15,3 +15,5 @@ obj-$(CONFIG_XEN_NETDEV_FRONTEND) += net
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 -r 5fa9b746d24f -r 510c6bceb87f linux-2.6-xen-sparse/mm/memory.c
--- a/linux-2.6-xen-sparse/mm/memory.c Sat Sep 02 12:11:54 2006 +0100
+++ b/linux-2.6-xen-sparse/mm/memory.c Sat Sep 02 15:11:17 2006 -0400
@@ -881,6 +881,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.
diff -r 5fa9b746d24f -r 510c6bceb87f linux-2.6-xen-sparse/drivers/xen/xenfb/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/xenfb/Makefile Sat Sep 02 15:11:17 2006 -0400
@@ -0,0 +1,1 @@
+obj-$(CONFIG_XEN_FRAMEBUFFER) := xenfb.o
diff -r 5fa9b746d24f -r 510c6bceb87f linux-2.6-xen-sparse/drivers/xen/xenfb/xenfb.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/xenfb/xenfb.c Sat Sep 02 15:11:17 2006 -0400
@@ -0,0 +1,571 @@
+/*
+ * linux/drivers/video/xenfb.c -- Xen para-virtual frame buffer device
+ *
+ * Copyright (C) 2005-2006
+ *
+ * Anthony Liguori <aliguori@us.ibm.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.
+ */
+
+#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/xenbus.h>
+#include <linux/xenfb.h>
+#include <linux/kthread.h>
+
+#define XENFB_WIDTH 800
+#define XENFB_HEIGHT 600
+#define XENFB_DEPTH 32
+
+static int xenfb_fps = 20;
+static unsigned long xenfb_mem_len = XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8;
+
+struct xenfb_mapping
+{
+ struct list_head next;
+ 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_fix_screeninfo *fix;
+ struct fb_var_screeninfo *var;
+ struct fb_info *fb_info;
+ struct timer_list refresh;
+ int dirty;
+ int y1, y2;
+ int x1, x2;
+
+ struct semaphore mm_lock;
+ int nr_pages;
+ struct page **pages;
+ struct list_head mappings;
+
+ unsigned evtchn;
+ int irq;
+ struct xenfb_page *page;
+ unsigned long *mfns;
+ u32 flags;
+};
+
+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;
+ if (prod - info->page->out_cons == XENFB_OUT_RING_LEN)
+ return; /* ring buffer full, event lost */
+ 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)
+{
+ int y1, y2, x1, x2;
+ struct list_head *item;
+ struct xenfb_mapping *map;
+
+ if (!(info->flags & XENFB_FLAG_UPDATE))
+ return;
+ if (xenfb_queue_full(info))
+ return;
+
+ y1 = info->y1;
+ y2 = info->y2;
+ x1 = info->x1;
+ x2 = info->x2;
+ info->y1 = info->y2 = info->x1 = info->x2 = 0;
+ down(&info->mm_lock);
+ list_for_each(item, &info->mappings) {
+ map = list_entry(item, struct xenfb_mapping, next);
+ 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;
+ }
+ up(&info->mm_lock);
+
+ 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);
+
+ 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->y2 == 0) {
+ info->y1 = y1;
+ info->y2 = y2;
+ }
+ if (info->x2 == 0) {
+ info->x1 = x1;
+ info->x2 = x2;
+ }
+
+ 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_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;
+
+ down(&info->mm_lock);
+ if (atomic_dec_and_test(&map->map_refs)) {
+ list_del(&map->next);
+ kfree(map);
+ }
+ up(&info->mm_lock);
+}
+
+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;
+ struct page *page;
+ int y1, y2;
+
+ if (pgnr >= info->nr_pages)
+ return NOPAGE_SIGBUS;
+
+ down(&info->mm_lock);
+ page = info->pages[pgnr];
+ get_page(page);
+ map->faults++;
+
+ y1 = pgnr * PAGE_SIZE / info->fix->line_length;
+ y2 = (pgnr * PAGE_SIZE + PAGE_SIZE - 1) / info->fix->line_length;
+ if (y2 > info->var->yres)
+ y2 = info->var->yres;
+ xenfb_refresh(info, 0, y1, info->var->xres, y2 - y1);
+ up(&info->mm_lock);
+
+ 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;
+ struct xenfb_mapping *map;
+ int ret;
+ int map_pages;
+
+ down(&info->mm_lock);
+
+ ret = -EINVAL;
+ if (!(vma->vm_flags & VM_WRITE))
+ goto out;
+ if (!(vma->vm_flags & VM_SHARED))
+ goto out;
+ if (vma->vm_pgoff != 0)
+ goto out;
+
+ map_pages = (vma->vm_end - vma->vm_start + PAGE_SIZE-1) >> PAGE_SHIFT;
+ if (map_pages > info->nr_pages)
+ goto out;
+
+ ret = -ENOMEM;
+ map = kmalloc(sizeof(*map), GFP_KERNEL);
+ if (map == NULL)
+ goto out;
+ memset(map, 0, sizeof(*map));
+
+ map->vma = vma;
+ map->faults = 0;
+ map->info = info;
+ atomic_set(&map->map_refs, 1);
+ list_add(&map->next, &info->mappings);
+ vma->vm_ops = &xenfb_vm_ops;
+ vma->vm_flags |= (VM_DONTEXPAND | VM_RESERVED);
+ vma->vm_private_data = map;
+ ret = 0;
+
+ out:
+ up(&info->mm_lock);
+ return ret;
+}
+
+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)
+{
+ struct xenfb_info *info = dev_id;
+ __u32 cons, prod;
+
+ prod = info->page->in_prod;
+ rmb(); /* ensure we see ring contents up to prod */
+ for (cons = info->page->in_cons; cons != prod; cons++) {
+ union xenfb_in_event *event;
+ event = &XENFB_IN_RING_REF(info->page, cons);
+
+ switch (event->type) {
+ case XENFB_TYPE_SET_EVENTS:
+ info->flags = event->set_events.flags;
+ break;
+ }
+ }
+ mb(); /* ensure we're done with ring contents */
+ info->page->in_cons = cons;
+ notify_remote_via_evtchn(info->evtchn);
+
+ return IRQ_HANDLED;
+}
+
+static unsigned long vmalloc_to_mfn(void *address)
+{
+ // FIXME was return pfn_to_mfn(vmalloc_to_pfn(address));
+ return arbitrary_virt_to_machine(address) >> PAGE_SHIFT;
+}
+
+static struct xenfb_info *xenfb_info;
+
+static int __init xenfb_probe(void)
+{
+ struct xenfb_info *info;
+ int i, ret;
+ struct fb_info *fb_info;
+ struct evtchn_alloc_unbound alloc_unbound;
+ struct evtchn_close close;
+ struct xenbus_transaction xbt;
+
+ /* Nothing to do if running in dom0. */
+ if (is_initial_xendomain())
+ return -ENODEV;
+#if 0
+ /* 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;
+#endif
+
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (info == NULL)
+ return -ENOMEM;
+ memset(info, 0, sizeof(*info));
+
+ INIT_LIST_HEAD(&info->mappings);
+
+ info->fb = vmalloc(xenfb_mem_len);
+ if (info->fb == NULL)
+ goto error;
+ 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_vfree;
+ for (i = 0; i < info->nr_pages; i++)
+ info->pages[i] = vmalloc_to_page(info->fb + i * PAGE_SIZE);
+
+ fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL);
+ // FIXME sizeof(struct xenfb_info)
+ if (fb_info == NULL)
+ goto error_kfree;
+
+ info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages);
+ /* set up shared page */
+ info->page = (void *)__get_free_page(GFP_KERNEL);
+ if (!info->page)
+ goto error_kfree;
+ /* set up event channel */
+ alloc_unbound.dom = DOMID_SELF;
+ alloc_unbound.remote_dom = 0;
+ ret = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
+ &alloc_unbound);
+ if (ret)
+ goto error_freep;
+ info->evtchn = alloc_unbound.port;
+
+ 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;
+
+ ret = bind_evtchn_to_irqhandler(info->evtchn, xenfb_event_handler,
+ 0, "xenfb", info);
+ if (ret < 0) {
+ close.port = info->evtchn;
+ HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
+ goto error_freep;
+ }
+
+ info->irq = ret;
+ xenfb_info = info;
+
+ fb_info->pseudo_palette = fb_info->par;
+ fb_info->par = info;
+ fb_info->screen_base = info->fb;
+
+ memset(&fb_info->var, 0, sizeof(fb_info->var));
+ memset(&fb_info->fix, 0, sizeof(fb_info->fix));
+
+ 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;
+
+ fb_alloc_cmap(&fb_info->cmap, 256, 0);
+
+ info->fb_info = fb_info;
+ info->fix = &fb_info->fix;
+ info->var = &fb_info->var;
+
+ init_MUTEX(&info->mm_lock);
+ init_waitqueue_head(&info->wq);
+ init_timer(&info->refresh);
+ info->refresh.function = xenfb_timer;
+ info->refresh.data = (unsigned long)info;
+
+ info->kthread = kthread_run(xenfb_thread, info, "xenfb thread");
+ if (IS_ERR(info->kthread))
+ goto error_unbind;
+
+ ret = register_framebuffer(fb_info);
+ if (ret)
+ goto error_unbind;
+
+ again:
+ ret = xenbus_transaction_start(&xbt);
+ if (ret)
+ goto error_unreg;
+ ret = xenbus_printf(xbt, "vfb", "page-ref", "%lu",
+ virt_to_mfn(info->page));
+ // FIXME grant tables?
+ if (ret)
+ goto error_xenbus;
+ ret = xenbus_printf(xbt, "vfb", "event-channel", "%u",
+ info->evtchn);
+ if (ret)
+ goto error_xenbus;
+ ret = xenbus_transaction_end(xbt, 0);
+ if (ret) {
+ if (ret == -EAGAIN)
+ goto again;
+ goto error_unreg;
+ }
+
+ return 0;
+
+ error_xenbus:
+ xenbus_transaction_end(xbt, 1);
+ error_unreg:
+ unregister_framebuffer(fb_info);
+ error_unbind:
+ unbind_from_irqhandler(info->irq, info);
+ // FIXME do we have to stop info->kthread?
+ error_freep:
+ free_page((unsigned long)info->page);
+ error_kfree:
+ kfree(info->pages);
+ error_vfree:
+ vfree(info->fb);
+ error:
+ kfree(info);
+ xenfb_info = NULL;
+
+ return -ENODEV;
+}
+
+static int __init xenfb_init(void)
+{
+ return xenfb_probe();
+}
+
+static void __exit xenfb_cleanup(void)
+{
+ struct xenfb_info *info = xenfb_info;
+
+ unregister_framebuffer(info->fb_info);
+ unbind_from_irqhandler(info->irq, info);
+ free_page((unsigned long)info->page);
+ kfree(info->pages);
+ vfree(info->fb);
+ kfree(info);
+ xenfb_info = NULL;
+}
+
+module_init(xenfb_init);
+module_exit(xenfb_cleanup);
+
+MODULE_LICENSE("GPL");
diff -r 5fa9b746d24f -r 510c6bceb87f linux-2.6-xen-sparse/drivers/xen/xenkbd/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/xenkbd/Makefile Sat Sep 02 15:11:17 2006 -0400
@@ -0,0 +1,1 @@
+obj-$(CONFIG_XEN_KEYBOARD) += xenkbd.o
diff -r 5fa9b746d24f -r 510c6bceb87f linux-2.6-xen-sparse/drivers/xen/xenkbd/xenkbd.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/xenkbd/xenkbd.c Sat Sep 02 15:11:17 2006 -0400
@@ -0,0 +1,178 @@
+/*
+ * linux/drivers/input/keyboard/xenkbd.c -- Xen para-virtual input device
+ *
+ * Copyright (C) 2005
+ *
+ * Anthony Liguori <aliguori@us.ibm.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.
+ */
+
+#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/xenbus.h>
+#include <linux/xenkbd.h>
+
+struct xenkbd_device
+{
+ struct input_dev *dev;
+ struct xenkbd_info *info;
+ unsigned evtchn;
+ int irq;
+};
+
+static irqreturn_t input_handler(int rq, void *dev_id, struct pt_regs *regs)
+{
+ struct xenkbd_device *dev = dev_id;
+ struct xenkbd_info *info = dev ? dev->info : 0;
+ static int button_map[3] = { BTN_RIGHT, BTN_MIDDLE, BTN_LEFT };
+ __u32 cons, prod;
+
+ prod = info->in_prod;
+ rmb(); /* ensure we see ring contents up to prod */
+ for (cons = info->in_cons; cons != prod; cons++) {
+ union xenkbd_in_event *event;
+ event = &XENKBD_IN_RING_REF(info, cons);
+
+ switch (event->type) {
+ case XENKBD_TYPE_MOTION:
+ input_report_rel(dev->dev, REL_X, event->motion.rel_x);
+ input_report_rel(dev->dev, REL_Y, event->motion.rel_y);
+ break;
+ case XENKBD_TYPE_BUTTON:
+ if (event->button.button < 3)
+ input_report_key(dev->dev,
+ button_map[event->button.button],
+ event->button.pressed);
+ break;
+ case XENKBD_TYPE_KEY:
+ input_report_key(dev->dev, event->key.keycode, event->key.pressed);
+ break;
+ }
+ }
+ input_sync(dev->dev);
+ mb(); /* ensure we got ring contents */
+ info->in_cons = cons;
+ notify_remote_via_evtchn(dev->evtchn);
+
+ return IRQ_HANDLED;
+}
+
+static struct xenkbd_device *xenkbd_dev;
+
+int __init xenkbd_init(void)
+{
+ int ret = 0;
+ int i;
+ struct xenkbd_device *dev;
+ struct input_dev *input_dev;
+ struct evtchn_alloc_unbound alloc_unbound;
+ struct xenbus_transaction xbt;
+
+ /* Nothing to do if running in dom0. */
+ if (is_initial_xendomain())
+ return -ENODEV;
+#if 0
+ /* 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;
+#endif
+
+ dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!dev || !input_dev)
+ return -ENOMEM;
+
+ dev->dev = input_dev;
+ dev->info = (void *)__get_free_page(GFP_KERNEL);
+ if (!dev->info) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ alloc_unbound.dom = DOMID_SELF;
+ alloc_unbound.remote_dom = 0;
+ ret = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
+ &alloc_unbound);
+ if (ret)
+ goto error_freep;
+ dev->evtchn = alloc_unbound.port;
+ ret = bind_evtchn_to_irqhandler(dev->evtchn, input_handler, 0,
+ "xenkbd", dev);
+ if (ret < 0)
+ goto error_freep;
+ dev->irq = ret;
+
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+ input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
+ 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_register_device(input_dev);
+
+ again:
+ ret = xenbus_transaction_start(&xbt);
+ if (ret)
+ goto error_unreg;
+ ret = xenbus_printf(xbt, "vkbd", "page-ref", "%lu",
+ virt_to_mfn(dev->info));
+ if (ret)
+ goto error_xenbus;
+ ret = xenbus_printf(xbt, "vkbd", "event-channel", "%u",
+ dev->evtchn);
+ if (ret)
+ goto error_xenbus;
+ ret = xenbus_transaction_end(xbt, 0);
+ if (ret) {
+ if (ret == -EAGAIN)
+ goto again;
+ goto error_unreg;
+ }
+
+ dev->info->in_cons = dev->info->in_prod = 0;
+ dev->info->out_cons = dev->info->out_prod = 0;
+ xenkbd_dev = dev;
+
+ return ret;
+
+
+ error_xenbus:
+ xenbus_transaction_end(xbt, 1);
+ error_unreg:
+ input_unregister_device(input_dev);
+ unbind_from_irqhandler(dev->irq, dev);
+ error_freep:
+ free_page((unsigned long)dev->info);
+ error:
+ kfree(dev);
+ return ret;
+}
+
+static void __exit xenkbd_cleanup(void)
+{
+ input_unregister_device(xenkbd_dev->dev);
+ unbind_from_irqhandler(xenkbd_dev->irq, xenkbd_dev);
+ free_page((unsigned long)xenkbd_dev->info);
+ kfree(xenkbd_dev);
+ xenkbd_dev = NULL;
+}
+
+module_init(xenkbd_init);
+module_exit(xenkbd_cleanup);
+
+MODULE_LICENSE("GPL");
diff -r 5fa9b746d24f -r 510c6bceb87f linux-2.6-xen-sparse/include/linux/xenfb.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/include/linux/xenfb.h Sat Sep 02 15:11:17 2006 -0400
@@ -0,0 +1,108 @@
+/*
+ * linux/include/linux/xenfb.h -- Xen virtual frame buffer device
+ *
+ * Copyright (C) 2005
+ *
+ * Anthony Liguori <aliguori@us.ibm.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 */
+
+#define XENFB_OUT_EVENT_SIZE 40
+
+#define XENFB_TYPE_MOTION 1
+#define XENFB_TYPE_UPDATE 2
+
+struct xenfb_motion /* currently unused */
+{
+ __u8 type; /* XENFB_TYPE_MOTION */
+ __u16 x; /* The new x coordinate */
+ __u16 y; /* The new y coordinate */
+};
+
+struct xenfb_update
+{
+ __u8 type; /* XENFB_TYPE_UPDATE */
+ __u16 x; /* source x */
+ __u16 y; /* source y */
+ __u16 width; /* rect width */
+ __u16 height; /* rect height */
+};
+
+union xenfb_out_event
+{
+ __u8 type;
+ struct xenfb_motion motion;
+ struct xenfb_update update;
+ char _[XENFB_OUT_EVENT_SIZE];
+};
+
+/* in events */
+
+#define XENFB_IN_EVENT_SIZE 40
+
+#define XENFB_TYPE_SET_EVENTS 1
+
+#define XENFB_FLAG_MOTION 1
+#define XENFB_FLAG_UPDATE 2
+#define XENFB_FLAG_COPY 4
+#define XENFB_FLAG_FILL 8
+
+struct xenfb_set_events
+{
+ __u8 type; /* XENFB_TYPE_SET_EVENTS */
+ __u32 flags; /* combination of XENFB_FLAG_* */
+};
+
+union xenfb_in_event
+{
+ __u8 type;
+ struct xenfb_set_events set_events;
+ char _[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
+{
+ __u16 width; /* the width of the framebuffer (in pixels) */
+ __u16 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) */
+
+ unsigned long pd[2]; /* FIXME rename to pgdir? */
+ /* FIXME pd[1] unused at this time, shrink? */
+
+ __u32 in_cons, in_prod;
+ __u32 out_cons, out_prod;
+};
+
+void xenfb_resume(void);
+
+#endif
diff -r 5fa9b746d24f -r 510c6bceb87f linux-2.6-xen-sparse/include/linux/xenkbd.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/include/linux/xenkbd.h Sat Sep 02 15:11:17 2006 -0400
@@ -0,0 +1,92 @@
+/*
+ * linux/include/linux/xenkbd.h -- Xen virtual keyboard/mouse
+ *
+ * Copyright (C) 2005
+ *
+ * Anthony Liguori <aliguori@us.ibm.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 */
+
+#define XENKBD_IN_EVENT_SIZE 40
+
+#define XENKBD_TYPE_MOTION 1 /* mouse movement event */
+#define XENKBD_TYPE_BUTTON 2 /* mouse button event */
+#define XENKBD_TYPE_KEY 3 /* keyboard event */
+
+struct xenkbd_motion
+{
+ __u8 type; /* XENKBD_TYPE_MOTION */
+ __s16 rel_x; /* relative X motion */
+ __s16 rel_y; /* relative Y motion */
+};
+
+struct xenkbd_button
+{
+ __u8 type; /* XENKBD_TYPE_BUTTON */
+ __u8 pressed; /* 1 if pressed; 0 otherwise */
+ __u8 button; /* the button (0, 1, 2 is right, middle, left) */
+};
+
+struct xenkbd_key
+{
+ __u8 type; /* XENKBD_TYPE_KEY */
+ __u8 pressed; /* 1 if pressed; 0 otherwise */
+ __u16 keycode; /* KEY_* from linux/input.h */
+};
+
+union xenkbd_in_event
+{
+ __u8 type;
+ struct xenkbd_motion motion;
+ struct xenkbd_button button;
+ struct xenkbd_key key;
+ char _[XENKBD_IN_EVENT_SIZE];
+};
+
+/* out events */
+
+#define XENKBD_OUT_EVENT_SIZE 40
+
+union xenkbd_out_event
+{
+ __u8 type;
+ char _[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_info
+{
+ __u32 in_cons, in_prod;
+ __u32 out_cons, out_prod;
+};
+
+void xenkbd_resume(void);
+
+#endif
[-- Attachment #3: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
next reply other threads:[~2006-09-02 19:58 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-09-02 19:58 Jeremy Katz [this message]
2006-09-04 9:00 ` [PATCH] Paravirt framebuffer frontend kernel support [1/5] Steven Smith
2006-09-04 14:03 ` Keir Fraser
2006-09-05 16:11 ` Jeremy Katz
2006-09-06 9:11 ` Steven Smith
2006-09-06 15:56 ` Keir Fraser
2006-09-21 18:41 ` Markus Armbruster
2006-09-21 19:29 ` Keir Fraser
2006-09-21 19:33 ` Steven Smith
2006-09-10 7:39 ` Markus Armbruster
2006-09-10 9:38 ` Steven Smith
2006-09-30 8:52 ` Markus Armbruster
2006-11-02 10:10 ` Markus Armbruster
2006-11-02 10:36 ` Ewan Mellor
2006-11-02 12:34 ` Markus Armbruster
2006-11-02 16:19 ` Steven Smith
2006-11-02 16:31 ` Ewan Mellor
2006-11-03 14:18 ` Markus Armbruster
2006-11-03 17:01 ` Steven Smith
2006-11-02 15:02 ` Markus Armbruster
2006-11-02 15:38 ` Ewan Mellor
2006-11-02 7:53 ` Markus Armbruster
2006-11-02 7:58 ` Keir Fraser
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1157227080.11059.38.camel@aglarond.local \
--to=katzj@redhat.com \
--cc=aliguori@mail.utexas.edu \
--cc=armbru@redhat.com \
--cc=xen-devel@lists.xensource.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.