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

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

To: Christian.Limpach@xxxxxxxxxxxx
Subject: Re: [Xen-devel] [PATCH 1/2] Virtual frame buffer: frontend
From: Markus Armbruster <armbru@xxxxxxxxxx>
Date: Mon, 10 Jul 2006 20:29:22 +0200
Cc: xen-devel@xxxxxxxxxxxxxxxxxxx
Delivery-date: Mon, 10 Jul 2006 11:29:54 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
In-reply-to: <3d8eece20607070945saad66c2hfc29b765db0c06bc@xxxxxxxxxxxxxx> (Christian Limpach's message of "Fri, 7 Jul 2006 17:45:30 +0100")
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> <8764ioghnn.fsf@xxxxxxxxxxxxxxxxx> <3d8eece20607070945saad66c2hfc29b765db0c06bc@xxxxxxxxxxxxxx>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Gnus/5.1008 (Gnus v5.10.8) Emacs/21.4 (gnu/linux)
"Christian Limpach" <christian.limpach@xxxxxxxxx> writes:

> On 6/26/06, Markus Armbruster <armbru@xxxxxxxxxx> wrote:
>> Derived from
>> http://www.cs.utexas.edu/users/aliguori/vfb-20060124.bundle
>>
>> Converted to Xenstore and ported to current kernels.
>
> This looks good.
>
> Could you address the following issues:
>
> - the patch which defined struct xenfb_page seems to be missing

This time it's included.

> - handling of the ring indexes:
>  + we generally prefer to store ring indexes in their unmasked form,
> it makes debugging easier and it allows the ring to be used to its
> full capacity instead of requiring leaving one slot empty to be able
> distinguish empty/full

Done.

>  + unless I misread the code, the producer (for frontend to backend
> messages) seems to write to out_prod + 1 > out_cons, then increment
> out_prob (xenfb_do_update) and then the consumer processes entries
> from out_cons upto but not include the updated out_prod
> (xenfb_on_fb_event) -- the producer for the other way around (backend
> to frontend, xenfb_fb_event) seems to be correcter.

The old code confused me.  I guess my ring index change takes care of
this one, too.

>  + the lack of barriers -- /* FIXME barriers */ doesn't really cut it ;-)
> ==> I would suggest looking at the block or net frontend/backend
> drivers and copy/pasting some code from there...

Found only read barriers in block fe/be.  console has read and write
barriers.  Now I'm confused.  I added read barriers and documented my
confusion.

> - xenbus transactions can fail and there's no code to retry failed 
> transactions

Done.

> Additionally, I think that the dirty region protocol doesn't really
> perform too well in quite simple usage cases like having video play in
> one corner of the screen and the mouse being moved in the opposite
> corner.  It's probably good enough for this version and supporting
> this protocol in the future isn't too bad.

Saved for later.

> I'm looking forward to seeing a new version of this patch, thanks!
>
>    christian

Here you go :)

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      Mon Jul 10 20:18:50 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       Mon Jul 10 20:18:50 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      Mon Jul 10 20:18:50 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        Mon Jul 10 20:18:50 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 Mon Jul 10 20:18:50 2006 +0200
@@ -0,0 +1,565 @@
+/*
+ * 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 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_RING_SIZE(info->page->out))
+               return;         /* ring buffer full, event lost */
+       XENFB_RING_REF(info->page->out, prod) = event;
+       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_RING_SIZE(info->page->out);
+}
+
+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;
+
+       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_RING_REF(info->page->in, cons);
+               notify_remote_via_evtchn(info->evtchn);
+       }
+       /* FIXME do I need a wmb() here? */
+       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;
+       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;
+
+ again:
+       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) {
+               if (ret == -EAGAIN)
+                       goto again;
+               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;
+
+       xenfb_info->page = mfn_to_virt(xen_start_info->fbdev_mfn);
+       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 (xenfb_irq)
+               unbind_from_irqhandler(xenfb_irq, NULL);
+
+       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);
+       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       Mon Jul 10 20:18:50 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       Mon Jul 10 20:18:50 2006 +0200
@@ -0,0 +1,205 @@
+/*
+ * 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;
+
+       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_RING_REF(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);
+       /* FIXME do I need a wmb() here? */
+       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 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;
+               /* FIXME really retry forever? */
+               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 /* FIXME */
+       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");
diff -r d8434a6fdd05 include/linux/xenfb.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/include/linux/xenfb.h     Mon Jul 10 20:18:50 2006 +0200
@@ -0,0 +1,97 @@
+/*
+ * linux/include/linux/xenfb.h -- Xen virtual frame buffer device
+ *
+ * Copyright (C) 2005
+ *
+ *      Anthony Liguori <aliguori@xxxxxxxxxx>
+ *
+ *  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_TYPE_MOTION 1
+#define XENFB_TYPE_UPDATE 2
+
+struct xenfb_motion
+{
+       __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 _[40];
+};
+
+/* in events */
+
+#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 _[40];
+};
+
+/* shared page */
+
+#define XENFB_IN_RING_SIZE (1024 / 40)
+#define XENFB_OUT_RING_SIZE (2048 / 40)
+
+#define XENFB_RING_SIZE(ring) (sizeof((ring)) / sizeof(*(ring)))
+#define XENFB_RING_REF(ring, idx) (ring)[(idx) % XENFB_RING_SIZE((ring))]
+
+struct xenfb_page
+{
+       __u8 initialized;
+       __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];
+
+       __u32 in_cons, in_prod;
+       __u32 out_cons, out_prod;
+
+       union xenfb_in_event in[XENFB_IN_RING_SIZE];
+       union xenfb_out_event out[XENFB_OUT_RING_SIZE];
+};
+
+void xenfb_resume(void);
+
+#endif
diff -r d8434a6fdd05 include/linux/xenkbd.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/include/linux/xenkbd.h    Mon Jul 10 20:18:50 2006 +0200
@@ -0,0 +1,82 @@
+/*
+ * linux/include/linux/xenkbd.h -- Xen virtual keyboard/mouse
+ *
+ * Copyright (C) 2005
+ *
+ *      Anthony Liguori <aliguori@xxxxxxxxxx>
+ *
+ *  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_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 _[40];
+};
+
+/* out events */
+
+union xenkbd_out_event
+{
+       __u8 type;
+       char _[40];
+};
+
+/* shared page */
+
+#define XENKBD_IN_RING_SIZE (2048 / 40)
+#define XENKBD_OUT_RING_SIZE (1024 / 40)
+
+#define XENKBD_RING_SIZE(ring) (sizeof((ring)) / sizeof(*(ring)))
+#define XENKBD_RING_REF(ring, idx) (ring)[(idx) % XENKBD_RING_SIZE((ring))]
+
+struct xenkbd_info
+{
+       __u8 initialized;
+       __u32 in_cons, in_prod;
+       __u32 out_cons, out_prod;
+
+       union xenkbd_in_event in[XENKBD_IN_RING_SIZE];
+       union xenkbd_out_event out[XENKBD_OUT_RING_SIZE];
+};
+
+void xenkbd_resume(void);
+
+#endif

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