WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [PATCH 1/2] Virtual frame buffer: frontend

To: xen-devel@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-devel] [PATCH 1/2] Virtual frame buffer: frontend
From: Markus Armbruster <armbru@xxxxxxxxxx>
Date: Mon, 26 Jun 2006 15:39:40 +0200
Delivery-date: Mon, 26 Jun 2006 06:40:13 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
In-reply-to: <87ac80ghox.fsf@xxxxxxxxxxxxxxxxx> (Markus Armbruster's message of "Mon, 26 Jun 2006 15:38:54 +0200")
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
References: <87ac80ghox.fsf@xxxxxxxxxxxxxxxxx>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Gnus/5.1008 (Gnus v5.10.8) Emacs/21.4 (gnu/linux)
Derived from
http://www.cs.utexas.edu/users/aliguori/vfb-20060124.bundle

Converted to Xenstore and ported to current kernels.

Signed-off-by: Markus Armbruster <armbru@xxxxxxxxxx>


diff -r d8434a6fdd05 arch/i386/kernel/setup-xen.c
--- a/arch/i386/kernel/setup-xen.c      Fri Jun 16 19:34:13 2006 +0200
+++ b/arch/i386/kernel/setup-xen.c      Fri Jun 23 10:07:51 2006 +0200
@@ -1787,8 +1787,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 d8434a6fdd05 drivers/xen/Kconfig
--- a/drivers/xen/Kconfig       Fri Jun 16 19:34:13 2006 +0200
+++ b/drivers/xen/Kconfig       Fri Jun 23 10:07:51 2006 +0200
@@ -173,6 +173,29 @@ config XEN_BLKDEV_TAP
          to a character device, allowing device prototyping in application
          space.  Odds are that you want to say N 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 d8434a6fdd05 drivers/xen/Makefile
--- a/drivers/xen/Makefile      Fri Jun 16 19:34:13 2006 +0200
+++ b/drivers/xen/Makefile      Fri Jun 23 10:07:51 2006 +0200
@@ -15,3 +15,5 @@ obj-$(CONFIG_XEN_BLKDEV_TAP)          += blkt
 obj-$(CONFIG_XEN_BLKDEV_TAP)           += blktap/
 obj-$(CONFIG_XEN_PCIDEV_BACKEND)       += pciback/
 obj-$(CONFIG_XEN_PCIDEV_FRONTEND)      += pcifront/
+obj-$(CONFIG_XEN_FRAMEBUFFER)          += xenfb/
+obj-$(CONFIG_XEN_KEYBOARD)             += xenkbd/
diff -r d8434a6fdd05 drivers/xen/xenfb/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/xenfb/Makefile        Fri Jun 23 10:07:51 2006 +0200
@@ -0,0 +1,1 @@
+obj-$(CONFIG_XEN_FRAMEBUFFER)  := xenfb.o
diff -r d8434a6fdd05 drivers/xen/xenfb/xenfb.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/xenfb/xenfb.c Fri Jun 23 10:07:51 2006 +0200
@@ -0,0 +1,579 @@
+/*
+ * linux/drivers/video/xenfb.c -- Xen para-virtual frame buffer device
+ *
+ * Copyright (C) 2005-2006
+ *
+ *      Anthony Liguori <aliguori@xxxxxxxxxx>
+ *
+ *  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>
+
+static int xenfb_fps = 20;
+static unsigned long xenfb_mem_len = 2 * 1024 * 1024;
+
+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;
+       struct xenfb_page               *page;
+       unsigned long                   *mfns;
+};
+
+static void xenfb_do_update(struct xenfb_info *info,
+                           int x, int y, int w, int h)
+{
+       union xenfb_out_event event;
+       __u32 cons, prod;
+
+       event.type = XENFB_TYPE_UPDATE;
+       event.update.x = x;
+       event.update.y = y;
+       event.update.width = w;
+       event.update.height = h;
+
+       /* FIXME barriers */
+       prod = XENFB_MASK_RING(info->page->out_prod, info->page->out);
+       cons = XENFB_MASK_RING(info->page->out_cons, info->page->out);
+       prod = XENFB_MASK_RING(prod + 1, info->page->out);
+
+       if (prod == cons)
+               return;
+
+       memcpy(&info->page->out[prod], &event, sizeof(event));
+       info->page->out_prod = prod;
+
+       notify_remote_via_evtchn(info->evtchn);
+}
+
+static int xenfb_queue_full(struct xenfb_info *info)
+{
+       __u32 cons, prod;
+
+       prod = XENFB_MASK_RING(info->page->out_prod, info->page->out);
+       cons = XENFB_MASK_RING(info->page->out_cons, info->page->out);
+       prod = XENFB_MASK_RING(prod + 1, info->page->out);
+
+       return (prod == cons);
+}
+
+static void xenfb_update_screen(struct xenfb_info *info)
+{
+       int y1, y2, x1, x2;
+       struct list_head *item;
+       struct xenfb_mapping *map;
+
+       if (xenfb_queue_full(info))
+               return;
+
+       y1 = info->y1;
+       y2 = info->y2;
+       x1 = info->x1;
+       x2 = info->x2;
+       info->dirty = 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;
+       DECLARE_WAITQUEUE(wait, current);
+
+       add_wait_queue(&info->wq, &wait);
+       for (;;) {
+               if (kthread_should_stop())
+                       break;
+               if (info->dirty)
+                       xenfb_update_screen(info);
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule();
+       }
+       remove_wait_queue(&info->wq, &wait);
+       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++;
+       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;
+
+       if (!info->page || !info->page->initialized)
+               return IRQ_NONE;
+
+       /* FIXME barriers */
+       prod = XENFB_MASK_RING(info->page->in_prod, info->page->in);
+       cons = XENFB_MASK_RING(info->page->in_cons, info->page->in);
+
+       if (prod == cons)
+               return IRQ_HANDLED;
+
+       for (; cons!=prod; cons = XENFB_MASK_RING(cons+1, info->page->in)) {
+               union xenfb_in_event *event;
+               event = &info->page->in[cons];
+               notify_remote_via_evtchn(info->evtchn);
+       }
+
+       info->page->in_cons = cons;
+
+       return IRQ_HANDLED;
+}
+
+static unsigned long vmalloc_to_mfn(void *address)
+{
+       return pfn_to_mfn(vmalloc_to_pfn(address));
+}
+
+static struct xenfb_info *xenfb_info;
+static int xenfb_irq;
+
+static int __init xenfb_probe(void)
+{
+       struct xenfb_info *info;
+       int i, ret;
+       struct fb_info *fb_info;
+       struct evtchn_alloc_unbound alloc_unbound;
+       xenbus_transaction_t xbt;
+
+       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);
+       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->width = 800;
+       info->page->height = 600;
+       info->page->depth = 32; // FIXME was 24;
+       info->page->line_length = (info->page->depth / 8) * info->page->width;
+       info->page->mem_length = xenfb_mem_len;
+
+       ret = bind_evtchn_to_irqhandler(info->evtchn, xenfb_event_handler,
+                                       0, "xenfb", info);
+       if (ret < 0)
+               // FIXME need to close evtchn?
+               goto error_kfree;
+
+       xenfb_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");
+
+       ret = register_framebuffer(fb_info);
+       if (ret)
+               goto error_unbind;
+
+       ret = xenbus_transaction_start(&xbt);
+       if (ret)
+               goto error_unreg;
+       ret = xenbus_printf(xbt, "vfb", "page-ref", "%lu",
+                           virt_to_mfn(info->page));
+       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)
+               goto error_unreg;
+
+       info->page->initialized = 1; /* FIXME needed?  move up? */
+
+       return 0;
+
+ error_xenbus:
+       xenbus_transaction_end(xbt, 1);
+ error_unreg:
+       unregister_framebuffer(fb_info);
+ error_unbind:
+       unbind_from_irqhandler(xenfb_irq, info);
+       xenfb_irq = 0;
+ 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;
+}
+
+void xenfb_resume(void)
+{
+#if 0 /* FIXME */
+       int i, ret;
+
+#if 0
+       xenfb_info->page = mfn_to_virt(xen_start_info->fbdev_mfn);
+#endif
+       for (i = 0; i < xenfb_info->nr_pages; i++)
+               xenfb_info->mfns[i] = vmalloc_to_mfn(xenfb_info->fb + i * 
PAGE_SIZE);
+       xenfb_info->page->pd[0] = vmalloc_to_mfn(xenfb_info->mfns);
+
+#if 0
+       if (xenfb_irq)
+               unbind_from_irqhandler(xenfb_irq, NULL);
+#endif
+
+#if 0
+       printk("xenfb: resume(%d)\n", xen_start_info->fbdev_evtchn);
+       ret = bind_evtchn_to_irqhandler(xen_start_info->fbdev_evtchn,
+                                       xenfb_event_handler, 0, "xenfb", 
xenfb_info);
+#endif
+       if (ret <= 0)
+               return;
+       xenfb_irq = ret;
+#else
+       printk(KERN_DEBUG "xenfb_resume not implemented\n");
+#endif
+}
+
+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(xenfb_irq, info);
+       xenfb_irq = 0;
+       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 d8434a6fdd05 drivers/xen/xenkbd/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/xenkbd/Makefile       Fri Jun 23 10:07:51 2006 +0200
@@ -0,0 +1,1 @@
+obj-$(CONFIG_XEN_KEYBOARD)     += xenkbd.o
diff -r d8434a6fdd05 drivers/xen/xenkbd/xenkbd.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/xenkbd/xenkbd.c       Fri Jun 23 10:07:51 2006 +0200
@@ -0,0 +1,206 @@
+/*
+ * linux/drivers/input/keyboard/xenkbd.c -- Xen para-virtual input device
+ *
+ * Copyright (C) 2005
+ *
+ *      Anthony Liguori <aliguori@xxxxxxxxxx>
+ *
+ *  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;
+};
+
+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;
+
+       if (!info || !info->initialized)
+               return IRQ_NONE;
+
+       /* FIXME barriers */
+       prod = XENKBD_MASK_RING(info->in_prod, info->in);
+       cons = XENKBD_MASK_RING(info->in_cons, info->in);
+
+       if (prod == cons)
+               return IRQ_HANDLED;
+
+       for (; cons != prod; cons = XENKBD_MASK_RING(cons + 1, info->in)) {
+               union xenkbd_in_event *event;
+
+               event = &info->in[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;
+               }
+
+               notify_remote_via_evtchn(dev->evtchn);
+       }
+       input_sync(dev->dev);
+
+       info->in_cons = cons;
+
+       return IRQ_HANDLED;
+}
+
+static struct xenkbd_device *xenkbd_dev;
+static int xenkbd_irq;
+
+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;
+       xenbus_transaction_t xbt;
+
+       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;
+       }
+       dev->info->initialized = 0;
+
+       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;
+
+       xenkbd_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 */
+       for (i = 0; i < 256; i++)
+               set_bit(i, input_dev->keybit);
+
+       input_dev->name = "Xen Virtual Keyboard/Mouse";
+
+       input_register_device(input_dev);
+
+       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)
+               goto error_unreg;
+
+       dev->info->in_cons = dev->info->in_prod = 0;
+       dev->info->out_cons = dev->info->out_prod = 0;
+       dev->info->initialized = 1; /* FIXME needed?  move up? */
+
+       xenkbd_dev = dev;
+
+       return ret;
+
+       
+ error_xenbus:
+       xenbus_transaction_end(xbt, 1);
+ error_unreg:
+       input_unregister_device(input_dev);
+       unbind_from_irqhandler(xenkbd_irq, dev);
+       xenkbd_irq = 0;
+ error_freep:
+       free_page((unsigned long)dev->info);
+ error:
+       kfree(dev);
+       xenkbd_dev = NULL;
+       return ret;
+}
+
+static void __exit xenkbd_cleanup(void)
+{
+       input_unregister_device(xenkbd_dev->dev);
+       unbind_from_irqhandler(xenkbd_irq, xenkbd_dev);
+       xenkbd_irq = 0;
+       free_page((unsigned long)xenkbd_dev->info);
+       kfree(xenkbd_dev);
+       xenkbd_dev = NULL;
+}
+
+void xenkbd_resume(void)
+{
+#if 0
+       int ret;
+
+       if (xenkbd_dev && xen_start_info->kbd_evtchn) {
+               if (xenkbd_irq)
+                       unbind_from_irqhandler(xenkbd_irq, NULL);
+
+               ret = bind_evtchn_to_irqhandler(xen_start_info->kbd_evtchn,
+                                               input_handler,
+                                               0,
+                                               "xenkbd",
+                                               xenkbd_dev);
+
+               if (ret <= 0)
+                       return;
+
+               xenkbd_irq = ret;
+               xenkbd_dev->info = mfn_to_virt(xen_start_info->kbd_mfn);
+       }
+#else
+       printk(KERN_DEBUG "xenkbd_resume not implemented\n");
+#endif
+}
+
+module_init(xenkbd_init);
+module_exit(xenkbd_cleanup);
+
+MODULE_LICENSE("GPL");

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

<Prev in Thread] Current Thread [Next in Thread>