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-changelog

[Xen-changelog] [xen-unstable] Merge.

# HG changeset patch
# User Steven Smith <ssmith@xxxxxxxxxxxxx>
# Node ID dfaf8493a21170b04719ee94f00a6ce26a549030
# Parent  056050ceb30090ad46f88e974e79864a0ddb346a
# Parent  d57b0e2834d7a6890a397e3419de469fe4ff1ee0
Merge.
---
 linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c   |    8 
 linux-2.6-xen-sparse/arch/ia64/kernel/setup.c       |   10 
 linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c |   10 
 linux-2.6-xen-sparse/drivers/xen/Kconfig            |   23 
 linux-2.6-xen-sparse/drivers/xen/Makefile           |    2 
 linux-2.6-xen-sparse/drivers/xen/console/console.c  |   28 
 linux-2.6-xen-sparse/drivers/xen/fbfront/Makefile   |    2 
 linux-2.6-xen-sparse/drivers/xen/fbfront/xenfb.c    |  682 +++++++++++++++++++
 linux-2.6-xen-sparse/drivers/xen/fbfront/xenkbd.c   |  300 ++++++++
 linux-2.6-xen-sparse/include/xen/xencons.h          |    2 
 linux-2.6-xen-sparse/mm/memory.c                    |    1 
 tools/Makefile                                      |    1 
 tools/python/xen/xend/XendDevices.py                |    4 
 tools/python/xen/xend/server/vfbif.py               |   74 ++
 tools/python/xen/xm/create.py                       |   34 
 tools/xenfb/Makefile                                |   35 
 tools/xenfb/sdlfb.c                                 |  342 +++++++++
 tools/xenfb/vncfb.c                                 |  401 +++++++++++
 tools/xenfb/xenfb.c                                 |  711 ++++++++++++++++++++
 tools/xenfb/xenfb.h                                 |   35 
 xen/include/public/io/fbif.h                        |  116 +++
 xen/include/public/io/kbdif.h                       |  108 +++
 22 files changed, 2907 insertions(+), 22 deletions(-)

diff -r 056050ceb300 -r dfaf8493a211 
linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c
--- a/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c Fri Dec 01 13:08:36 
2006 +0000
+++ b/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c Fri Dec 01 13:12:41 
2006 +0000
@@ -1867,9 +1867,11 @@ void __init setup_arch(char **cmdline_p)
 #endif
 #endif
        } else {
-               extern int console_use_vt;
-               console_use_vt = 0;
-       }
+#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE)
+               conswitchp = &dummy_con;
+#endif
+       }
+       xencons_early_setup();
 }
 
 static int
diff -r 056050ceb300 -r dfaf8493a211 
linux-2.6-xen-sparse/arch/ia64/kernel/setup.c
--- a/linux-2.6-xen-sparse/arch/ia64/kernel/setup.c     Fri Dec 01 13:08:36 
2006 +0000
+++ b/linux-2.6-xen-sparse/arch/ia64/kernel/setup.c     Fri Dec 01 13:12:41 
2006 +0000
@@ -550,13 +550,15 @@ setup_arch (char **cmdline_p)
                       xen_start_info->nr_pages, xen_start_info->flags);
 
                if (!is_initial_xendomain()) {
-                       extern int console_use_vt;
+#if !defined(CONFIG_VT) || !defined(CONFIG_DUMMY_CONSOLE)
                        conswitchp = NULL;
-                       console_use_vt = 0;
+#endif
                }
        }
-#endif
-#endif
+       xencons_early_setup();
+#endif
+#endif
+
 
        /* enable IA-64 Machine Check Abort Handling unless disabled */
        if (!strstr(saved_command_line, "nomca"))
diff -r 056050ceb300 -r dfaf8493a211 
linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c
--- a/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c       Fri Dec 01 
13:08:36 2006 +0000
+++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c       Fri Dec 01 
13:12:41 2006 +0000
@@ -983,10 +983,12 @@ void __init setup_arch(char **cmdline_p)
 #endif
 #endif
                } else {
-                       extern int console_use_vt;
-                       console_use_vt = 0;
-               }
-       }
+#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE)
+                       conswitchp = &dummy_con;
+#endif
+                }
+       }
+       xencons_early_setup();
 #else  /* CONFIG_XEN */
 
 #ifdef CONFIG_VT
diff -r 056050ceb300 -r dfaf8493a211 linux-2.6-xen-sparse/drivers/xen/Kconfig
--- a/linux-2.6-xen-sparse/drivers/xen/Kconfig  Fri Dec 01 13:08:36 2006 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/Kconfig  Fri Dec 01 13:12:41 2006 +0000
@@ -172,6 +172,29 @@ config XEN_NETDEV_FRONTEND
          dedicated device-driver domain, or your master control domain
          (domain 0), then you almost certainly want to say Y here.
 
+config XEN_FRAMEBUFFER
+       tristate "Framebuffer-device frontend driver"
+       depends on XEN && FB
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+       default y
+       help
+         The framebuffer-device frontend drivers allows the kernel to create a
+         virtual framebuffer.  This framebuffer can be viewed in another
+         domain.  Unless this domain has access to a real video card, you
+         probably want to say Y here.
+
+config XEN_KEYBOARD
+       tristate "Keyboard-device frontend driver"
+       depends on XEN && XEN_FRAMEBUFFER && INPUT
+       default y
+       help
+         The keyboard-device frontend driver allows the kernel to create a
+         virtual keyboard.  This keyboard can then be driven by another
+         domain.  If you've said Y to CONFIG_XEN_FRAMEBUFFER, you probably
+         want to say Y here.
+
 config XEN_SCRUB_PAGES
        bool "Scrub memory before freeing it to Xen"
        default y
diff -r 056050ceb300 -r dfaf8493a211 linux-2.6-xen-sparse/drivers/xen/Makefile
--- a/linux-2.6-xen-sparse/drivers/xen/Makefile Fri Dec 01 13:08:36 2006 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/Makefile Fri Dec 01 13:12:41 2006 +0000
@@ -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)          += fbfront/
+obj-$(CONFIG_XEN_KEYBOARD)             += fbfront/
diff -r 056050ceb300 -r dfaf8493a211 
linux-2.6-xen-sparse/drivers/xen/console/console.c
--- a/linux-2.6-xen-sparse/drivers/xen/console/console.c        Fri Dec 01 
13:08:36 2006 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/console/console.c        Fri Dec 01 
13:12:41 2006 +0000
@@ -57,6 +57,7 @@
 #include <xen/interface/event_channel.h>
 #include <asm/hypervisor.h>
 #include <xen/evtchn.h>
+#include <xen/xenbus.h>
 #include <xen/xencons.h>
 
 /*
@@ -65,14 +66,14 @@
  *  'xencons=tty'  [XC_TTY]:     Console attached to '/dev/tty[0-9]+'.
  *  'xencons=ttyS' [XC_SERIAL]:  Console attached to '/dev/ttyS[0-9]+'.
  *  'xencons=xvc'  [XC_XVC]:     Console attached to '/dev/xvc0'.
- *                 [XC_DEFAULT]: DOM0 -> XC_SERIAL ; all others -> XC_TTY.
+ *  default:                     DOM0 -> XC_SERIAL ; all others -> XC_TTY.
  * 
  * NB. In mode XC_TTY, we create dummy consoles for tty2-63. This suppresses
  * warnings from standard distro startup scripts.
  */
 static enum {
-       XC_OFF, XC_DEFAULT, XC_TTY, XC_SERIAL, XC_XVC
-} xc_mode = XC_DEFAULT;
+       XC_OFF, XC_TTY, XC_SERIAL, XC_XVC
+} xc_mode;
 static int xc_num = -1;
 
 /* /dev/xvc0 device number allocated by lanana.org. */
@@ -84,17 +85,32 @@ extern int sysrq_enabled;
 extern int sysrq_enabled;
 #endif
 
+void xencons_early_setup(void)
+{
+       extern int console_use_vt;
+
+       if (is_initial_xendomain()) {
+               xc_mode = XC_SERIAL;
+       } else {
+               xc_mode = XC_TTY;
+               console_use_vt = 0;
+       }
+}
+
 static int __init xencons_setup(char *str)
 {
        char *q;
        int n;
-
+       extern int console_use_vt;
+
+       console_use_vt = 1;
        if (!strncmp(str, "ttyS", 4)) {
                xc_mode = XC_SERIAL;
                str += 4;
        } else if (!strncmp(str, "tty", 3)) {
                xc_mode = XC_TTY;
                str += 3;
+               console_use_vt = 0;
        } else if (!strncmp(str, "xvc", 3)) {
                xc_mode = XC_XVC;
                str += 3;
@@ -192,14 +208,10 @@ static int __init xen_console_init(void)
                goto out;
 
        if (is_initial_xendomain()) {
-               if (xc_mode == XC_DEFAULT)
-                       xc_mode = XC_SERIAL;
                kcons_info.write = kcons_write_dom0;
        } else {
                if (!xen_start_info->console.domU.evtchn)
                        goto out;
-               if (xc_mode == XC_DEFAULT)
-                       xc_mode = XC_TTY;
                kcons_info.write = kcons_write;
        }
 
diff -r 056050ceb300 -r dfaf8493a211 linux-2.6-xen-sparse/include/xen/xencons.h
--- a/linux-2.6-xen-sparse/include/xen/xencons.h        Fri Dec 01 13:08:36 
2006 +0000
+++ b/linux-2.6-xen-sparse/include/xen/xencons.h        Fri Dec 01 13:12:41 
2006 +0000
@@ -14,4 +14,6 @@ int xencons_ring_init(void);
 int xencons_ring_init(void);
 int xencons_ring_send(const char *data, unsigned len);
 
+void xencons_early_setup(void);
+
 #endif /* __ASM_XENCONS_H__ */
diff -r 056050ceb300 -r dfaf8493a211 linux-2.6-xen-sparse/mm/memory.c
--- a/linux-2.6-xen-sparse/mm/memory.c  Fri Dec 01 13:08:36 2006 +0000
+++ b/linux-2.6-xen-sparse/mm/memory.c  Fri Dec 01 13:12:41 2006 +0000
@@ -882,6 +882,7 @@ unsigned long zap_page_range(struct vm_a
                tlb_finish_mmu(tlb, address, end);
        return end;
 }
+EXPORT_SYMBOL(zap_page_range);
 
 /*
  * Do a quick page-table lookup for a single page.
diff -r 056050ceb300 -r dfaf8493a211 tools/Makefile
--- a/tools/Makefile    Fri Dec 01 13:08:36 2006 +0000
+++ b/tools/Makefile    Fri Dec 01 13:12:41 2006 +0000
@@ -19,6 +19,7 @@ SUBDIRS-y += libaio
 SUBDIRS-y += libaio
 SUBDIRS-y += blktap
 SUBDIRS-y += libfsimage
+SUBDIRS-y += xenfb
 SUBDIRS-$(LIBXENAPI_BINDINGS) += libxen
 
 # These don't cross-compile
diff -r 056050ceb300 -r dfaf8493a211 tools/python/xen/xend/XendDevices.py
--- a/tools/python/xen/xend/XendDevices.py      Fri Dec 01 13:08:36 2006 +0000
+++ b/tools/python/xen/xend/XendDevices.py      Fri Dec 01 13:12:41 2006 +0000
@@ -19,7 +19,7 @@
 # A collection of DevControllers 
 #
 
-from xen.xend.server import blkif, netif, tpmif, pciif, iopif, irqif, usbif
+from xen.xend.server import blkif, netif, tpmif, pciif, iopif, irqif, usbif, 
vfbif
 from xen.xend.server.BlktapController import BlktapController
 
 class XendDevices:
@@ -41,6 +41,8 @@ class XendDevices:
         'irq': irqif.IRQController,
         'usb': usbif.UsbifController,
         'tap': BlktapController,
+        'vfb': vfbif.VfbifController,
+        'vkbd': vfbif.VkbdifController,
     }
 
     #@classmethod
diff -r 056050ceb300 -r dfaf8493a211 tools/python/xen/xm/create.py
--- a/tools/python/xen/xm/create.py     Fri Dec 01 13:08:36 2006 +0000
+++ b/tools/python/xen/xm/create.py     Fri Dec 01 13:12:41 2006 +0000
@@ -284,6 +284,18 @@ gopts.var('usbport', val='PATH',
           use="""Add a physical USB port to a domain, as specified by the path
           to that port.  This option may be repeated to add more than one 
port.""")
 
+gopts.var('vfb', 
val="type={vnc,sdl},vncunused=1,vncdisplay=N,vnclisten=ADDR,display=DISPLAY,xauthority=XAUTHORITY",
+          fn=append_value, default=[],
+          use="""Make the domain a framebuffer backend.
+          The backend type should be either sdl or vnc.
+          For type=vnc, connect an external vncviewer.  The server will listen
+          on ADDR (default 127.0.0.1) on port N+5900.  N defaults to the
+          domain id.  If vncunused=1, the server will try to find an arbitrary
+          unused port above 5900.
+          For type=sdl, a viewer will be started automatically using the
+          given DISPLAY and XAUTHORITY, which default to the current user's
+          ones.""")
+
 gopts.var('vif', 
val="type=TYPE,mac=MAC,bridge=BRIDGE,ip=IPADDR,script=SCRIPT,backend=DOM,vifname=NAME",
           fn=append_value, default=[],
           use="""Add a network interface with the given MAC address and bridge.
@@ -512,8 +524,8 @@ def configure_image(vals):
         config_image.append(['args', vals.extra])
 
     if vals.builder == 'hvm':
-        configure_hvm(config_image, vals)
-        
+        configure_hvm(config_image, vals) 
+       
     return config_image
     
 def configure_disks(config_devs, vals):
@@ -564,6 +576,23 @@ def configure_usb(config_devs, vals):
         config_usb = ['usbport', ['path', path]]
         config_devs.append(['device', config_usb])
 
+def configure_vfbs(config_devs, vals):
+    for f in vals.vfb:
+        d = comma_sep_kv_to_dict(f)
+        config = ['vfb']
+        if not d.has_key("type"):
+            d['type'] = 'sdl'
+        for (k,v) in d.iteritems():
+            if not k in [ 'vnclisten', 'vncunused', 'vncdisplay', 'display',
+                          'xauthority', 'type' ]:
+                err("configuration option %s unknown to vfbs" % k)
+            config.append([k,v])
+        if not d.has_key("display") and os.environ.has_key("DISPLAY"):
+            config.append(["display", os.environ['DISPLAY']])
+        if not d.has_key("xauthority"):
+            config.append(["xauthority", get_xauthority()])
+        config_devs.append(['device', ['vkbd']])
+        config_devs.append(['device', config])
 
 def configure_security(config, vals):
     """Create the config for ACM security labels.
@@ -742,6 +771,7 @@ def make_config(vals):
     configure_vifs(config_devs, vals)
     configure_usb(config_devs, vals)
     configure_vtpm(config_devs, vals)
+    configure_vfbs(config_devs, vals)
     configure_security(config, vals)
     config += config_devs
 
diff -r 056050ceb300 -r dfaf8493a211 
linux-2.6-xen-sparse/drivers/xen/fbfront/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/fbfront/Makefile Fri Dec 01 13:12:41 
2006 +0000
@@ -0,0 +1,2 @@
+obj-$(CONFIG_XEN_FRAMEBUFFER)  := xenfb.o
+obj-$(CONFIG_XEN_KEYBOARD)     += xenkbd.o
diff -r 056050ceb300 -r dfaf8493a211 
linux-2.6-xen-sparse/drivers/xen/fbfront/xenfb.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/fbfront/xenfb.c  Fri Dec 01 13:12:41 
2006 +0000
@@ -0,0 +1,682 @@
+/*
+ * linux/drivers/video/xenfb.c -- Xen para-virtual frame buffer device
+ *
+ * Copyright (C) 2005-2006 Anthony Liguori <aliguori@xxxxxxxxxx>
+ * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@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.
+ */
+
+/*
+ * TODO:
+ *
+ * Switch to grant tables when they become capable of dealing with the
+ * frame buffer.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <asm/hypervisor.h>
+#include <xen/evtchn.h>
+#include <xen/interface/io/fbif.h>
+#include <xen/xenbus.h>
+#include <linux/kthread.h>
+
+struct xenfb_mapping
+{
+       struct list_head        link;
+       struct vm_area_struct   *vma;
+       atomic_t                map_refs;
+       int                     faults;
+       struct xenfb_info       *info;
+};
+
+struct xenfb_info
+{
+       struct task_struct      *kthread;
+       wait_queue_head_t       wq;
+
+       unsigned char           *fb;
+       struct fb_info          *fb_info;
+       struct timer_list       refresh;
+       int                     dirty;
+       int                     x1, y1, x2, y2; /* dirty rectangle,
+                                                  protected by mm_lock */
+       spinlock_t              mm_lock;
+       int                     nr_pages;
+       struct page             **pages;
+       struct list_head        mappings; /* protected by mm_lock */
+
+       unsigned                evtchn;
+       int                     irq;
+       struct xenfb_page       *page;
+       unsigned long           *mfns;
+       int                     update_wanted; /* XENFB_TYPE_UPDATE wanted */
+
+       struct xenbus_device    *xbdev;
+};
+
+static int xenfb_fps = 20;
+static unsigned long xenfb_mem_len = XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH 
/ 8;
+
+static int xenfb_remove(struct xenbus_device *);
+static void xenfb_init_shared_page(struct xenfb_info *);
+static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info *);
+static void xenfb_disconnect_backend(struct xenfb_info *);
+
+static void xenfb_do_update(struct xenfb_info *info,
+                           int x, int y, int w, int h)
+{
+       union xenfb_out_event event;
+       __u32 prod;
+
+       event.type = XENFB_TYPE_UPDATE;
+       event.update.x = x;
+       event.update.y = y;
+       event.update.width = w;
+       event.update.height = h;
+
+       prod = info->page->out_prod;
+       /* caller ensures !xenfb_queue_full() */
+       mb();                   /* ensure ring space available */
+       XENFB_OUT_RING_REF(info->page, prod) = event;
+       wmb();                  /* ensure ring contents visible */
+       info->page->out_prod = prod + 1;
+
+       notify_remote_via_evtchn(info->evtchn);
+}
+
+static int xenfb_queue_full(struct xenfb_info *info)
+{
+       __u32 cons, prod;
+
+       prod = info->page->out_prod;
+       cons = info->page->out_cons;
+       return prod - cons == XENFB_OUT_RING_LEN;
+}
+
+static void xenfb_update_screen(struct xenfb_info *info)
+{
+       unsigned long flags;
+       int y1, y2, x1, x2;
+       struct xenfb_mapping *map;
+
+       if (!info->update_wanted)
+               return;
+       if (xenfb_queue_full(info))
+               return;
+
+       spin_lock_irqsave(&info->mm_lock, flags);
+
+       y1 = info->y1;
+       y2 = info->y2;
+       x1 = info->x1;
+       x2 = info->x2;
+       info->x1 = info->y1 = INT_MAX;
+       info->x2 = info->y2 = 0;
+
+       list_for_each_entry(map, &info->mappings, link) {
+               if (!map->faults)
+                       continue;
+               zap_page_range(map->vma, map->vma->vm_start,
+                              map->vma->vm_end - map->vma->vm_start, NULL);
+               map->faults = 0;
+       }
+
+       spin_unlock_irqrestore(&info->mm_lock, flags);
+
+       xenfb_do_update(info, x1, y1, x2 - x1, y2 - y1);
+}
+
+static int xenfb_thread(void *data)
+{
+       struct xenfb_info *info = data;
+
+       while (!kthread_should_stop()) {
+               if (info->dirty) {
+                       info->dirty = 0;
+                       xenfb_update_screen(info);
+               }
+               wait_event_interruptible(info->wq,
+                       kthread_should_stop() || info->dirty);
+               try_to_freeze();
+       }
+       return 0;
+}
+
+static int xenfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+                          unsigned blue, unsigned transp,
+                          struct fb_info *info)
+{
+       u32 v;
+
+       if (regno > info->cmap.len)
+               return 1;
+
+       red   >>= (16 - info->var.red.length);
+       green >>= (16 - info->var.green.length);
+       blue  >>= (16 - info->var.blue.length);
+
+       v = (red << info->var.red.offset) |
+           (green << info->var.green.offset) |
+           (blue << info->var.blue.offset);
+
+       /* FIXME is this sane?  check against xxxfb_setcolreg()!  */
+       switch (info->var.bits_per_pixel) {
+       case 16:
+       case 24:
+       case 32:
+               ((u32 *)info->pseudo_palette)[regno] = v;
+               break;
+       }
+       
+       return 0;
+}
+
+static void xenfb_timer(unsigned long data)
+{
+       struct xenfb_info *info = (struct xenfb_info *)data;
+       info->dirty = 1;
+       wake_up(&info->wq);
+}
+
+static void __xenfb_refresh(struct xenfb_info *info,
+                           int x1, int y1, int w, int h)
+{
+       int y2, x2;
+
+       y2 = y1 + h;
+       x2 = x1 + w;
+
+       if (info->y1 > y1)
+               info->y1 = y1;
+       if (info->y2 < y2)
+               info->y2 = y2;
+       if (info->x1 > x1)
+               info->x1 = x1;
+       if (info->x2 < x2)
+               info->x2 = x2;
+
+       if (timer_pending(&info->refresh))
+               return;
+
+       mod_timer(&info->refresh, jiffies + HZ/xenfb_fps);
+}
+
+static void xenfb_refresh(struct xenfb_info *info,
+                         int x1, int y1, int w, int h)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&info->mm_lock, flags);
+       __xenfb_refresh(info, x1, y1, w, h);
+       spin_unlock_irqrestore(&info->mm_lock, flags);
+}
+
+static void xenfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
+{
+       struct xenfb_info *info = p->par;
+
+       cfb_fillrect(p, rect);
+       xenfb_refresh(info, rect->dx, rect->dy, rect->width, rect->height);
+}
+
+static void xenfb_imageblit(struct fb_info *p, const struct fb_image *image)
+{
+       struct xenfb_info *info = p->par;
+
+       cfb_imageblit(p, image);
+       xenfb_refresh(info, image->dx, image->dy, image->width, image->height);
+}
+
+static void xenfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
+{
+       struct xenfb_info *info = p->par;
+
+       cfb_copyarea(p, area);
+       xenfb_refresh(info, area->dx, area->dy, area->width, area->height);
+}
+
+static void xenfb_vm_open(struct vm_area_struct *vma)
+{
+       struct xenfb_mapping *map = vma->vm_private_data;
+       atomic_inc(&map->map_refs);
+}
+
+static void xenfb_vm_close(struct vm_area_struct *vma)
+{
+       struct xenfb_mapping *map = vma->vm_private_data;
+       struct xenfb_info *info = map->info;
+       unsigned long flags;
+
+       spin_lock_irqsave(&info->mm_lock, flags);
+       if (atomic_dec_and_test(&map->map_refs)) {
+               list_del(&map->link);
+               kfree(map);
+       }
+       spin_unlock_irqrestore(&info->mm_lock, flags);
+}
+
+static struct page *xenfb_vm_nopage(struct vm_area_struct *vma,
+                                   unsigned long vaddr, int *type)
+{
+       struct xenfb_mapping *map = vma->vm_private_data;
+       struct xenfb_info *info = map->info;
+       int pgnr = (vaddr - vma->vm_start) >> PAGE_SHIFT;
+       unsigned long flags;
+       struct page *page;
+       int y1, y2;
+
+       if (pgnr >= info->nr_pages)
+               return NOPAGE_SIGBUS;
+
+       spin_lock_irqsave(&info->mm_lock, flags);
+       page = info->pages[pgnr];
+       get_page(page);
+       map->faults++;
+
+       y1 = pgnr * PAGE_SIZE / info->fb_info->fix.line_length;
+       y2 = (pgnr * PAGE_SIZE + PAGE_SIZE - 1) / 
info->fb_info->fix.line_length;
+       if (y2 > info->fb_info->var.yres)
+               y2 = info->fb_info->var.yres;
+       __xenfb_refresh(info, 0, y1, info->fb_info->var.xres, y2 - y1);
+       spin_unlock_irqrestore(&info->mm_lock, flags);
+
+       if (type)
+               *type = VM_FAULT_MINOR;
+
+       return page;
+}
+
+static struct vm_operations_struct xenfb_vm_ops = {
+       .open   = xenfb_vm_open,
+       .close  = xenfb_vm_close,
+       .nopage = xenfb_vm_nopage,
+};
+
+static int xenfb_mmap(struct fb_info *fb_info, struct vm_area_struct *vma)
+{
+       struct xenfb_info *info = fb_info->par;
+       unsigned long flags;
+       struct xenfb_mapping *map;
+       int map_pages;
+
+       if (!(vma->vm_flags & VM_WRITE))
+               return -EINVAL;
+       if (!(vma->vm_flags & VM_SHARED))
+               return -EINVAL;
+       if (vma->vm_pgoff != 0)
+               return -EINVAL;
+
+       map_pages = (vma->vm_end - vma->vm_start + PAGE_SIZE-1) >> PAGE_SHIFT;
+       if (map_pages > info->nr_pages)
+               return -EINVAL;
+
+       map = kzalloc(sizeof(*map), GFP_KERNEL);
+       if (map == NULL)
+               return -ENOMEM;
+
+       map->vma = vma;
+       map->faults = 0;
+       map->info = info;
+       atomic_set(&map->map_refs, 1);
+
+       spin_lock_irqsave(&info->mm_lock, flags);
+       list_add(&map->link, &info->mappings);
+       spin_unlock_irqrestore(&info->mm_lock, flags);
+
+       vma->vm_ops = &xenfb_vm_ops;
+       vma->vm_flags |= (VM_DONTEXPAND | VM_RESERVED);
+       vma->vm_private_data = map;
+
+       return 0;
+}
+
+static struct fb_ops xenfb_fb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_setcolreg   = xenfb_setcolreg,
+       .fb_fillrect    = xenfb_fillrect,
+       .fb_copyarea    = xenfb_copyarea,
+       .fb_imageblit   = xenfb_imageblit,
+       .fb_mmap        = xenfb_mmap,
+};
+
+static irqreturn_t xenfb_event_handler(int rq, void *dev_id,
+                                      struct pt_regs *regs)
+{
+       /*
+        * No in events recognized, simply ignore them all.
+        * If you need to recognize some, see xenbkd's input_handler()
+        * for how to do that.
+        */
+       struct xenfb_info *info = dev_id;
+       struct xenfb_page *page = info->page;
+
+       if (page->in_cons != page->in_prod) {
+               info->page->in_cons = info->page->in_prod;
+               notify_remote_via_evtchn(info->evtchn);
+       }
+       return IRQ_HANDLED;
+}
+
+static unsigned long vmalloc_to_mfn(void *address)
+{
+       return pfn_to_mfn(vmalloc_to_pfn(address));
+}
+
+static int __devinit xenfb_probe(struct xenbus_device *dev,
+                                const struct xenbus_device_id *id)
+{
+       struct xenfb_info *info;
+       struct fb_info *fb_info;
+       int ret;
+
+       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       if (info == NULL) {
+               xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
+               return -ENOMEM;
+       }
+       dev->dev.driver_data = info;
+       info->xbdev = dev;
+       info->irq = -1;
+       info->x1 = info->y1 = INT_MAX;
+       spin_lock_init(&info->mm_lock);
+       init_waitqueue_head(&info->wq);
+       init_timer(&info->refresh);
+       info->refresh.function = xenfb_timer;
+       info->refresh.data = (unsigned long)info;
+       INIT_LIST_HEAD(&info->mappings);
+
+       info->fb = vmalloc(xenfb_mem_len);
+       if (info->fb == NULL)
+               goto error_nomem;
+       memset(info->fb, 0, xenfb_mem_len);
+
+       info->nr_pages = (xenfb_mem_len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+       info->pages = kmalloc(sizeof(struct page *) * info->nr_pages,
+                             GFP_KERNEL);
+       if (info->pages == NULL)
+               goto error_nomem;
+
+       info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages);
+       if (!info->mfns)
+               goto error_nomem;
+
+       /* set up shared page */
+       info->page = (void *)__get_free_page(GFP_KERNEL);
+       if (!info->page)
+               goto error_nomem;
+
+       xenfb_init_shared_page(info);
+
+       fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL);
+                               /* see fishy hackery below */
+       if (fb_info == NULL)
+               goto error_nomem;
+
+       /* FIXME fishy hackery */
+       fb_info->pseudo_palette = fb_info->par;
+       fb_info->par = info;
+       /* /FIXME */
+       fb_info->screen_base = info->fb;
+
+       fb_info->fbops = &xenfb_fb_ops;
+       fb_info->var.xres_virtual = fb_info->var.xres = info->page->width;
+       fb_info->var.yres_virtual = fb_info->var.yres = info->page->height;
+       fb_info->var.bits_per_pixel = info->page->depth;
+
+       fb_info->var.red = (struct fb_bitfield){16, 8, 0};
+       fb_info->var.green = (struct fb_bitfield){8, 8, 0};
+       fb_info->var.blue = (struct fb_bitfield){0, 8, 0};
+
+       fb_info->var.activate = FB_ACTIVATE_NOW;
+       fb_info->var.height = -1;
+       fb_info->var.width = -1;
+       fb_info->var.vmode = FB_VMODE_NONINTERLACED;
+
+       fb_info->fix.visual = FB_VISUAL_TRUECOLOR;
+       fb_info->fix.line_length = info->page->line_length;
+       fb_info->fix.smem_start = 0;
+       fb_info->fix.smem_len = xenfb_mem_len;
+       strcpy(fb_info->fix.id, "xen");
+       fb_info->fix.type = FB_TYPE_PACKED_PIXELS;
+       fb_info->fix.accel = FB_ACCEL_NONE;
+
+       fb_info->flags = FBINFO_FLAG_DEFAULT;
+
+       ret = fb_alloc_cmap(&fb_info->cmap, 256, 0);
+       if (ret < 0) {
+               framebuffer_release(fb_info);
+               xenbus_dev_fatal(dev, ret, "fb_alloc_cmap");
+               goto error;
+       }
+
+       ret = register_framebuffer(fb_info);
+       if (ret) {
+               fb_dealloc_cmap(&info->fb_info->cmap);
+               framebuffer_release(fb_info);
+               xenbus_dev_fatal(dev, ret, "register_framebuffer");
+               goto error;
+       }
+       info->fb_info = fb_info;
+
+       /* FIXME should this be delayed until backend XenbusStateConnected? */
+       info->kthread = kthread_run(xenfb_thread, info, "xenfb thread");
+       if (IS_ERR(info->kthread)) {
+               ret = PTR_ERR(info->kthread);
+               info->kthread = NULL;
+               xenbus_dev_fatal(dev, ret, "register_framebuffer");
+               goto error;
+       }
+
+       ret = xenfb_connect_backend(dev, info);
+       if (ret < 0)
+               goto error;
+
+       return 0;
+
+ error_nomem:
+       ret = -ENOMEM;
+       xenbus_dev_fatal(dev, ret, "allocating device memory");
+ error:
+       xenfb_remove(dev);
+       return ret;
+}
+
+static int xenfb_resume(struct xenbus_device *dev)
+{
+       struct xenfb_info *info = dev->dev.driver_data;
+
+       xenfb_disconnect_backend(info);
+       xenfb_init_shared_page(info);
+       return xenfb_connect_backend(dev, info);
+}
+
+static int xenfb_remove(struct xenbus_device *dev)
+{
+       struct xenfb_info *info = dev->dev.driver_data;
+
+       del_timer(&info->refresh);
+       if (info->kthread)
+               kthread_stop(info->kthread);
+       xenfb_disconnect_backend(info);
+       if (info->fb_info) {
+               unregister_framebuffer(info->fb_info);
+               fb_dealloc_cmap(&info->fb_info->cmap);
+               framebuffer_release(info->fb_info);
+       }
+       free_page((unsigned long)info->page);
+       vfree(info->mfns);
+       kfree(info->pages);
+       vfree(info->fb);
+       kfree(info);
+
+       return 0;
+}
+
+static void xenfb_init_shared_page(struct xenfb_info *info)
+{
+       int i;
+
+       for (i = 0; i < info->nr_pages; i++)
+               info->pages[i] = vmalloc_to_page(info->fb + i * PAGE_SIZE);
+
+       for (i = 0; i < info->nr_pages; i++)
+               info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE);
+
+       info->page->pd[0] = vmalloc_to_mfn(info->mfns);
+       info->page->pd[1] = 0;
+       info->page->width = XENFB_WIDTH;
+       info->page->height = XENFB_HEIGHT;
+       info->page->depth = XENFB_DEPTH;
+       info->page->line_length = (info->page->depth / 8) * info->page->width;
+       info->page->mem_length = xenfb_mem_len;
+       info->page->in_cons = info->page->in_prod = 0;
+       info->page->out_cons = info->page->out_prod = 0;
+}
+
+static int xenfb_connect_backend(struct xenbus_device *dev,
+                                struct xenfb_info *info)
+{
+       int ret;
+       struct xenbus_transaction xbt;
+
+       ret = xenbus_alloc_evtchn(dev, &info->evtchn);
+       if (ret)
+               return ret;
+       ret = bind_evtchn_to_irqhandler(info->evtchn, xenfb_event_handler,
+                                       0, "xenfb", info);
+       if (ret < 0) {
+               xenbus_free_evtchn(dev, info->evtchn);
+               xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler");
+               return ret;
+       }
+       info->irq = ret;
+
+ again:
+       ret = xenbus_transaction_start(&xbt);
+       if (ret) {
+               xenbus_dev_fatal(dev, ret, "starting transaction");
+               return ret;
+       }
+       ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
+                           virt_to_mfn(info->page));
+       if (ret)
+               goto error_xenbus;
+       ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
+                           info->evtchn);
+       if (ret)
+               goto error_xenbus;
+       ret = xenbus_printf(xbt, dev->nodename, "feature-update", "1");
+       if (ret)
+               goto error_xenbus;
+       ret = xenbus_transaction_end(xbt, 0);
+       if (ret) {
+               if (ret == -EAGAIN)
+                       goto again;
+               xenbus_dev_fatal(dev, ret, "completing transaction");
+               return ret;
+       }
+
+       xenbus_switch_state(dev, XenbusStateInitialised);
+       return 0;
+
+ error_xenbus:
+       xenbus_transaction_end(xbt, 1);
+       xenbus_dev_fatal(dev, ret, "writing xenstore");
+       return ret;
+}
+
+static void xenfb_disconnect_backend(struct xenfb_info *info)
+{
+       if (info->irq >= 0)
+               unbind_from_irqhandler(info->irq, info);
+       info->irq = -1;
+}
+
+static void xenfb_backend_changed(struct xenbus_device *dev,
+                                 enum xenbus_state backend_state)
+{
+       struct xenfb_info *info = dev->dev.driver_data;
+       int val;
+
+       switch (backend_state) {
+       case XenbusStateInitialising:
+       case XenbusStateInitialised:
+       case XenbusStateUnknown:
+       case XenbusStateClosed:
+               break;
+
+       case XenbusStateInitWait:
+       InitWait:
+               xenbus_switch_state(dev, XenbusStateConnected);
+               break;
+
+       case XenbusStateConnected:
+               /*
+                * Work around xenbus race condition: If backend goes
+                * through InitWait to Connected fast enough, we can
+                * get Connected twice here.
+                */
+               if (dev->state != XenbusStateConnected)
+                       goto InitWait; /* no InitWait seen yet, fudge it */
+
+               if (xenbus_scanf(XBT_NIL, info->xbdev->otherend,
+                                "request-update", "%d", &val) < 0)
+                       val = 0;
+               if (val)
+                       info->update_wanted = 1;
+               break;
+
+       case XenbusStateClosing:
+               // FIXME is this safe in any dev->state?
+               xenbus_frontend_closed(dev);
+               break;
+       }
+}
+
+static struct xenbus_device_id xenfb_ids[] = {
+       { "vfb" },
+       { "" }
+};
+
+static struct xenbus_driver xenfb = {
+       .name = "vfb",
+       .owner = THIS_MODULE,
+       .ids = xenfb_ids,
+       .probe = xenfb_probe,
+       .remove = xenfb_remove,
+       .resume = xenfb_resume,
+       .otherend_changed = xenfb_backend_changed,
+};
+
+static int __init xenfb_init(void)
+{
+       if (!is_running_on_xen())
+               return -ENODEV;
+
+       /* Nothing to do if running in dom0. */
+       if (is_initial_xendomain())
+               return -ENODEV;
+
+       return xenbus_register_frontend(&xenfb);
+}
+
+static void __exit xenfb_cleanup(void)
+{
+       return xenbus_unregister_driver(&xenfb);
+}
+
+module_init(xenfb_init);
+module_exit(xenfb_cleanup);
+
+MODULE_LICENSE("GPL");
diff -r 056050ceb300 -r dfaf8493a211 
linux-2.6-xen-sparse/drivers/xen/fbfront/xenkbd.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/fbfront/xenkbd.c Fri Dec 01 13:12:41 
2006 +0000
@@ -0,0 +1,300 @@
+/*
+ * linux/drivers/input/keyboard/xenkbd.c -- Xen para-virtual input device
+ *
+ * Copyright (C) 2005 Anthony Liguori <aliguori@xxxxxxxxxx>
+ * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@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.
+ */
+
+/*
+ * TODO:
+ *
+ * Switch to grant tables together with xenfb.c.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <asm/hypervisor.h>
+#include <xen/evtchn.h>
+#include <xen/interface/io/fbif.h>
+#include <xen/interface/io/kbdif.h>
+#include <xen/xenbus.h>
+
+struct xenkbd_info
+{
+       struct input_dev *dev;
+       struct xenkbd_page *page;
+       unsigned evtchn;
+       int irq;
+       struct xenbus_device *xbdev;
+};
+
+static int xenkbd_remove(struct xenbus_device *);
+static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info 
*);
+static void xenkbd_disconnect_backend(struct xenkbd_info *);
+
+/*
+ * Note: if you need to send out events, see xenfb_do_update() for how
+ * to do that.
+ */
+
+static irqreturn_t input_handler(int rq, void *dev_id, struct pt_regs *regs)
+{
+       struct xenkbd_info *info = dev_id;
+       struct xenkbd_page *page = info->page;
+       __u32 cons, prod;
+
+       prod = page->in_prod;
+       if (prod == page->out_cons)
+               return IRQ_HANDLED;
+       rmb();                  /* ensure we see ring contents up to prod */
+       for (cons = page->in_cons; cons != prod; cons++) {
+               union xenkbd_in_event *event;
+               event = &XENKBD_IN_RING_REF(page, cons);
+
+               switch (event->type) {
+               case XENKBD_TYPE_MOTION:
+                       input_report_rel(info->dev, REL_X, event->motion.rel_x);
+                       input_report_rel(info->dev, REL_Y, event->motion.rel_y);
+                       break;
+               case XENKBD_TYPE_KEY:
+                       input_report_key(info->dev, event->key.keycode, 
event->key.pressed);
+                       break;
+               case XENKBD_TYPE_POS:
+                       input_report_abs(info->dev, ABS_X, event->pos.abs_x);
+                       input_report_abs(info->dev, ABS_Y, event->pos.abs_y);
+                       break;
+               }
+       }
+       input_sync(info->dev);
+       mb();                   /* ensure we got ring contents */
+       page->in_cons = cons;
+       notify_remote_via_evtchn(info->evtchn);
+
+       return IRQ_HANDLED;
+}
+
+int __devinit xenkbd_probe(struct xenbus_device *dev,
+                          const struct xenbus_device_id *id)
+{
+       int ret, i;
+       struct xenkbd_info *info;
+       struct input_dev *input_dev;
+
+       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       if (!info) {
+               xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
+               return -ENOMEM;
+       }
+       dev->dev.driver_data = info;
+       info->xbdev = dev;
+
+       info->page = (void *)__get_free_page(GFP_KERNEL);
+       if (!info->page)
+               goto error_nomem;
+       info->page->in_cons = info->page->in_prod = 0;
+       info->page->out_cons = info->page->out_prod = 0;
+
+       input_dev = input_allocate_device();
+       if (!input_dev)
+               goto error_nomem;
+
+       input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);
+       input_dev->keybit[LONG(BTN_MOUSE)]
+               = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+       /* TODO additional buttons */
+       input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+
+       /* FIXME not sure this is quite right */
+       for (i = 0; i < 256; i++)
+               set_bit(i, input_dev->keybit);
+
+       input_dev->name = "Xen Virtual Keyboard/Mouse";
+
+       input_set_abs_params(input_dev, ABS_X, 0, XENFB_WIDTH, 0, 0);
+       input_set_abs_params(input_dev, ABS_Y, 0, XENFB_HEIGHT, 0, 0);
+
+       ret = input_register_device(input_dev);
+       if (ret) {
+               input_free_device(input_dev);
+               xenbus_dev_fatal(dev, ret, "input_register_device");
+               goto error;
+       }
+       info->dev = input_dev;
+
+       ret = xenkbd_connect_backend(dev, info);
+       if (ret < 0)
+               goto error;
+
+       return 0;
+
+ error_nomem:
+       ret = -ENOMEM;
+       xenbus_dev_fatal(dev, ret, "allocating device memory");
+ error:
+       xenkbd_remove(dev);
+       return ret;
+}
+
+static int xenkbd_resume(struct xenbus_device *dev)
+{
+       struct xenkbd_info *info = dev->dev.driver_data;
+
+       xenkbd_disconnect_backend(info);
+       return xenkbd_connect_backend(dev, info);
+}
+
+static int xenkbd_remove(struct xenbus_device *dev)
+{
+       struct xenkbd_info *info = dev->dev.driver_data;
+
+       xenkbd_disconnect_backend(info);
+       input_unregister_device(info->dev);
+       free_page((unsigned long)info->page);
+       kfree(info);
+       return 0;
+}
+
+static int xenkbd_connect_backend(struct xenbus_device *dev,
+                                 struct xenkbd_info *info)
+{
+       int ret;
+       struct xenbus_transaction xbt;
+
+       ret = xenbus_alloc_evtchn(dev, &info->evtchn);
+       if (ret)
+               return ret;
+       ret = bind_evtchn_to_irqhandler(info->evtchn, input_handler, 0,
+                                       "xenkbd", info);
+       if (ret < 0) {
+               xenbus_free_evtchn(dev, info->evtchn);
+               xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler");
+               return ret;
+       }
+       info->irq = ret;
+
+ again:
+       ret = xenbus_transaction_start(&xbt);
+       if (ret) {
+               xenbus_dev_fatal(dev, ret, "starting transaction");
+               return ret;
+       }
+       ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
+                           virt_to_mfn(info->page));
+       if (ret)
+               goto error_xenbus;
+       ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
+                           info->evtchn);
+       if (ret)
+               goto error_xenbus;
+       ret = xenbus_transaction_end(xbt, 0);
+       if (ret) {
+               if (ret == -EAGAIN)
+                       goto again;
+               xenbus_dev_fatal(dev, ret, "completing transaction");
+               return ret;
+       }
+
+       xenbus_switch_state(dev, XenbusStateInitialised);
+       return 0;
+
+ error_xenbus:
+       xenbus_transaction_end(xbt, 1);
+       xenbus_dev_fatal(dev, ret, "writing xenstore");
+       return ret;
+}
+
+static void xenkbd_disconnect_backend(struct xenkbd_info *info)
+{
+       if (info->irq >= 0)
+               unbind_from_irqhandler(info->irq, info);
+       info->irq = -1;
+}
+
+static void xenkbd_backend_changed(struct xenbus_device *dev,
+                                  enum xenbus_state backend_state)
+{
+       struct xenkbd_info *info = dev->dev.driver_data;
+       int ret, val;
+
+       switch (backend_state) {
+       case XenbusStateInitialising:
+       case XenbusStateInitialised:
+       case XenbusStateUnknown:
+       case XenbusStateClosed:
+               break;
+
+       case XenbusStateInitWait:
+       InitWait:
+               ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend,
+                                  "feature-abs-pointer", "%d", &val);
+               if (ret < 0)
+                       val = 0;
+               if (val) {
+                       ret = xenbus_printf(XBT_NIL, info->xbdev->nodename,
+                                           "request-abs-pointer", "1");
+                       if (ret)
+                               ; /* FIXME */
+               }
+               xenbus_switch_state(dev, XenbusStateConnected);
+               break;
+
+       case XenbusStateConnected:
+               /*
+                * Work around xenbus race condition: If backend goes
+                * through InitWait to Connected fast enough, we can
+                * get Connected twice here.
+                */
+               if (dev->state != XenbusStateConnected)
+                       goto InitWait; /* no InitWait seen yet, fudge it */
+               break;
+
+       case XenbusStateClosing:
+               xenbus_frontend_closed(dev);
+               break;
+       }
+}
+
+static struct xenbus_device_id xenkbd_ids[] = {
+       { "vkbd" },
+       { "" }
+};
+
+static struct xenbus_driver xenkbd = {
+       .name = "vkbd",
+       .owner = THIS_MODULE,
+       .ids = xenkbd_ids,
+       .probe = xenkbd_probe,
+       .remove = xenkbd_remove,
+       .resume = xenkbd_resume,
+       .otherend_changed = xenkbd_backend_changed,
+};
+
+static int __init xenkbd_init(void)
+{
+       if (!is_running_on_xen())
+               return -ENODEV;
+
+       /* Nothing to do if running in dom0. */
+       if (is_initial_xendomain())
+               return -ENODEV;
+
+       return xenbus_register_frontend(&xenkbd);
+}
+
+static void __exit xenkbd_cleanup(void)
+{
+       return xenbus_unregister_driver(&xenkbd);
+}
+
+module_init(xenkbd_init);
+module_exit(xenkbd_cleanup);
+
+MODULE_LICENSE("GPL");
diff -r 056050ceb300 -r dfaf8493a211 tools/python/xen/xend/server/vfbif.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/xend/server/vfbif.py     Fri Dec 01 13:12:41 2006 +0000
@@ -0,0 +1,74 @@
+from xen.xend.server.DevController import DevController
+
+from xen.xend.XendError import VmError
+import xen.xend
+import os
+
+def spawn_detached(path, args, env):
+    p = os.fork()
+    if p == 0:
+        os.spawnve(os.P_NOWAIT, path, args, env)
+        os._exit(0)
+    else:
+        os.waitpid(p, 0)
+        
+class VfbifController(DevController):
+    """Virtual frame buffer controller. Handles all vfb devices for a domain.
+    Note that we only support a single vfb per domain at the moment.
+    """
+
+    def __init__(self, vm):
+        DevController.__init__(self, vm)
+        self.config = {}
+        
+    def getDeviceDetails(self, config):
+        """@see DevController.getDeviceDetails"""
+        devid = 0
+        back = {}
+        front = {}
+        return (devid, back, front)
+
+    def getDeviceConfiguration(self, devid):
+        r = DevController.getDeviceConfiguration(self, devid)
+        for (k,v) in self.config.iteritems():
+            r[k] = v
+        return r
+    
+    def createDevice(self, config):
+        DevController.createDevice(self, config)
+        self.config = config
+        std_args = [ "--domid", "%d" % self.vm.getDomid(),
+                     "--title", self.vm.getName() ]
+        t = config.get("type", None)
+        if t == "vnc":
+            # Try to start the vnc backend
+            args = [xen.util.auxbin.pathTo("xen-vncfb")]
+            if config.has_key("vncunused"):
+                args += ["--unused"]
+            elif config.has_key("vncdisplay"):
+                args += ["--vncport", "%d" % (5900 + config["vncdisplay"])]
+            vnclisten = config.get("vnclisten",
+                                   
xen.xend.XendRoot.instance().get_vnclisten_address())
+            args += [ "--listen", vnclisten ]
+            spawn_detached(args[0], args + std_args, os.environ)
+        elif t == "sdl":
+            args = [xen.util.auxbin.pathTo("xen-sdlfb")]
+            env = dict(os.environ)
+            if config.has_key("display"):
+                env['DISPLAY'] = config["display"]
+            if config.has_key("xauthority"):
+                env['XAUTHORITY'] = config["xauthority"]
+            spawn_detached(args[0], args + std_args, env)
+        else:
+            raise VmError('Unknown vfb type %s (%s)' % (t, repr(config)))
+
+class VkbdifController(DevController):
+    """Virtual keyboard controller. Handles all vkbd devices for a domain.
+    """
+
+    def getDeviceDetails(self, config):
+        """@see DevController.getDeviceDetails"""
+        devid = 0
+        back = {}
+        front = {}
+        return (devid, back, front)
diff -r 056050ceb300 -r dfaf8493a211 tools/xenfb/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/Makefile      Fri Dec 01 13:12:41 2006 +0000
@@ -0,0 +1,35 @@
+XEN_ROOT=../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+CFLAGS += -I$(XEN_LIBXC) -I$(XEN_XENSTORE) 
-I$(XEN_ROOT)/linux-2.6-xen-sparse/include
+LDFLAGS += -L$(XEN_LIBXC) -L$(XEN_XENSTORE)
+
+INSTALL         = install
+INSTALL_PROG    = $(INSTALL) -m0755
+INSTALL_DIR     = $(INSTALL) -d -m0755
+
+.PHONY: all
+all: build
+
+.PHONY: build
+build: mk-symlinks
+       $(MAKE) vncfb sdlfb
+
+install: all
+       $(INSTALL_DIR) -p $(DESTDIR)/usr/$(LIBDIR)/xen/bin
+       $(INSTALL_PROG) vncfb $(DESTDIR)/usr/$(LIBDIR)/xen/bin/xen-vncfb
+       $(INSTALL_PROG) sdlfb $(DESTDIR)/usr/$(LIBDIR)/xen/bin/xen-sdlfb
+
+sdlfb: sdlfb.o xenfb.o
+
+sdlfb.o: CFLAGS += $(shell sdl-config --cflags)
+sdlfb: LDLIBS += $(shell sdl-config --libs) -lxenctrl -lxenstore
+
+clean:
+       $(RM) *.o *~ vncfb sdlfb
+
+vncfb: vncfb.o xenfb.o
+vncfb.o: CFLAGS += $(shell libvncserver-config --cflags)
+vncfb: LDLIBS += $(shell libvncserver-config --libs) -lxenctrl -lxenstore
+
+sdlfb.o xenfb.o vncfb.o: xenfb.h
diff -r 056050ceb300 -r dfaf8493a211 tools/xenfb/sdlfb.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/sdlfb.c       Fri Dec 01 13:12:41 2006 +0000
@@ -0,0 +1,342 @@
+#include <SDL.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/select.h>
+#include <stdlib.h>
+#include <linux/input.h>
+#include <getopt.h>
+#include <string.h>
+#include "xenfb.h"
+
+struct SDLFBData
+{
+       SDL_Surface *dst;
+       SDL_Surface *src;
+};
+
+/*
+ * Map from scancode to Linux input layer keycode.  Scancodes are
+ * hardware-specific.  This map assumes a standard AT or PS/2
+ * keyboard.
+ *
+ * Why use scancodes?  We can't use key symbols, because they don't
+ * identify keys --- they're what keys are mapped to.  The standard
+ * German keymap, for instance, maps both KEY_COMMA and KEY_102ND to
+ * SDLK_LESS.
+ */
+static int keymap[256] = {
+       [9] = KEY_ESC,
+       [10] = KEY_1,
+       [11] = KEY_2,
+       [12] = KEY_3,
+       [13] = KEY_4,
+       [14] = KEY_5,
+       [15] = KEY_6,
+       [16] = KEY_7,
+       [17] = KEY_8,
+       [18] = KEY_9,
+       [19] = KEY_0,
+       [20] = KEY_MINUS,
+       [21] = KEY_EQUAL,
+       [22] = KEY_BACKSPACE,
+       [23] = KEY_TAB,
+       [24] = KEY_Q,
+       [25] = KEY_W,
+       [26] = KEY_E,
+       [27] = KEY_R,
+       [28] = KEY_T,
+       [29] = KEY_Y,
+       [30] = KEY_U,
+       [31] = KEY_I,
+       [32] = KEY_O,
+       [33] = KEY_P,
+       [34] = KEY_LEFTBRACE,
+       [35] = KEY_RIGHTBRACE,
+       [36] = KEY_ENTER,
+       [37] = KEY_LEFTCTRL,
+       [38] = KEY_A,
+       [39] = KEY_S,
+       [40] = KEY_D,
+       [41] = KEY_F,
+       [42] = KEY_G,
+       [43] = KEY_H,
+       [44] = KEY_J,
+       [45] = KEY_K,
+       [46] = KEY_L,
+       [47] = KEY_SEMICOLON,
+       [48] = KEY_APOSTROPHE,
+       [49] = KEY_GRAVE,
+       [50] = KEY_LEFTSHIFT,
+       [51] = KEY_BACKSLASH,
+       [52] = KEY_Z,
+       [53] = KEY_X,
+       [54] = KEY_C,
+       [55] = KEY_V,
+       [56] = KEY_B,
+       [57] = KEY_N,
+       [58] = KEY_M,
+       [59] = KEY_COMMA,
+       [60] = KEY_DOT,
+       [61] = KEY_SLASH,
+       [62] = KEY_RIGHTSHIFT,
+       [63] = KEY_KPASTERISK,
+       [64] = KEY_LEFTALT,
+       [65] = KEY_SPACE,
+       [66] = KEY_CAPSLOCK,
+       [67] = KEY_F1,
+       [68] = KEY_F2,
+       [69] = KEY_F3,
+       [70] = KEY_F4,
+       [71] = KEY_F5,
+       [72] = KEY_F6,
+       [73] = KEY_F7,
+       [74] = KEY_F8,
+       [75] = KEY_F9,
+       [76] = KEY_F10,
+       [77] = KEY_NUMLOCK,
+       [78] = KEY_SCROLLLOCK,
+       [79] = KEY_KP7,
+       [80] = KEY_KP8,
+       [81] = KEY_KP9,
+       [82] = KEY_KPMINUS,
+       [83] = KEY_KP4,
+       [84] = KEY_KP5,
+       [85] = KEY_KP6,
+       [86] = KEY_KPPLUS,
+       [87] = KEY_KP1,
+       [88] = KEY_KP2,
+       [89] = KEY_KP3,
+       [90] = KEY_KP0,
+       [91] = KEY_KPDOT,
+       [94] = KEY_102ND,       /* FIXME is this correct? */
+       [95] = KEY_F11,
+       [96] = KEY_F12,
+       [108] = KEY_KPENTER,
+       [109] = KEY_RIGHTCTRL,
+       [112] = KEY_KPSLASH,
+       [111] = KEY_SYSRQ,
+       [113] = KEY_RIGHTALT,
+       [97] = KEY_HOME,
+       [98] = KEY_UP,
+       [99] = KEY_PAGEUP,
+       [100] = KEY_LEFT,
+       [102] = KEY_RIGHT,
+       [103] = KEY_END,
+       [104] = KEY_DOWN,
+       [105] = KEY_PAGEDOWN,
+       [106] = KEY_INSERT,
+       [107] = KEY_DELETE,
+       [110] = KEY_PAUSE,
+       [115] = KEY_LEFTMETA,
+       [116] = KEY_RIGHTMETA,
+       [117] = KEY_MENU,
+};
+
+static int btnmap[] = {
+       [SDL_BUTTON_LEFT] = BTN_LEFT,
+       [SDL_BUTTON_MIDDLE] = BTN_MIDDLE,
+       [SDL_BUTTON_RIGHT] = BTN_RIGHT,
+       /* FIXME not 100% sure about these: */
+       [SDL_BUTTON_WHEELUP] = BTN_FORWARD,
+       [SDL_BUTTON_WHEELDOWN] BTN_BACK
+};
+
+static void sdl_update(struct xenfb *xenfb, int x, int y, int width, int 
height)
+{
+       struct SDLFBData *data = xenfb->user_data;
+       SDL_Rect r = { x, y, width, height };
+       SDL_BlitSurface(data->src, &r, data->dst, &r);
+       SDL_UpdateRect(data->dst, x, y, width, height);
+}
+
+static int sdl_on_event(struct xenfb *xenfb, SDL_Event *event)
+{
+       int x, y, ret;
+
+       switch (event->type) {
+       case SDL_KEYDOWN:
+       case SDL_KEYUP:
+               if (keymap[event->key.keysym.scancode] == 0)
+                       break;
+               ret = xenfb_send_key(xenfb,
+                                    event->type == SDL_KEYDOWN,
+                                    keymap[event->key.keysym.scancode]);
+               if (ret < 0)
+                       fprintf(stderr, "Key %d %s lost (%s)\n",
+                               keymap[event->key.keysym.scancode],
+                               event->type == SDL_KEYDOWN ? "down" : "up",
+                               strerror(errno));
+               break;
+       case SDL_MOUSEMOTION:
+               if (xenfb->abs_pointer_wanted) {
+                       SDL_GetMouseState(&x, &y);
+                       ret = xenfb_send_position(xenfb, x, y);
+               } else {
+                       SDL_GetRelativeMouseState(&x, &y);
+                       ret = xenfb_send_motion(xenfb, x, y);
+               }
+               if (ret < 0)
+                       fprintf(stderr, "Pointer to %d,%d lost (%s)\n",
+                               x, y, strerror(errno));
+               break;
+       case SDL_MOUSEBUTTONDOWN:
+       case SDL_MOUSEBUTTONUP:
+               if (event->button.button >= sizeof(btnmap) / sizeof(*btnmap))
+                       break;
+               if (btnmap[event->button.button] == 0)
+                       break;
+               ret = xenfb_send_key(xenfb,
+                                    event->type == SDL_MOUSEBUTTONDOWN,
+                                    btnmap[event->button.button]);
+               if (ret < 0)
+                       fprintf(stderr, "Button %d %s lost (%s)\n",
+                               btnmap[event->button.button] - BTN_MOUSE,
+                               event->type == SDL_MOUSEBUTTONDOWN ? "down" : 
"up",
+                               strerror(errno));
+               break;
+       case SDL_QUIT:
+               return 0;
+       }
+
+       return 1;
+}
+
+static struct option options[] = {
+       { "domid", 1, NULL, 'd' },
+       { "title", 1, NULL, 't' },
+       { NULL }
+};
+
+int main(int argc, char **argv)
+{
+       struct xenfb *xenfb;
+       int domid = -1;
+        char * title = NULL;
+       fd_set readfds;
+       int nfds;
+       struct SDLFBData data;
+       SDL_Rect r;
+       struct timeval tv;
+       SDL_Event event;
+       int do_quit = 0;
+       int opt;
+       char *endp;
+       int retval;
+
+       while ((opt = getopt_long(argc, argv, "d:t:", options,
+                                 NULL)) != -1) {
+               switch (opt) {
+                case 'd':
+                       domid = strtol(optarg, &endp, 10);
+                       if (endp == optarg || *endp) {
+                               fprintf(stderr, "Invalid domain id 
specified\n");
+                               exit(1);
+                       }
+                       break;
+                case 't':
+                       title = strdup(optarg);
+                       break;
+               case '?':
+                       exit(1);
+                }
+        }
+        if (optind != argc) {
+               fprintf(stderr, "Invalid options!\n");
+               exit(1);
+        }
+        if (domid <= 0) {
+               fprintf(stderr, "Domain ID must be specified!\n");
+               exit(1);
+        }
+
+       xenfb = xenfb_new();
+       if (xenfb == NULL) {
+               fprintf(stderr, "Could not create framebuffer (%s)\n",
+                       strerror(errno));
+               exit(1);
+        }
+
+       if (xenfb_attach_dom(xenfb, domid) < 0) {
+               fprintf(stderr, "Could not connect to domain (%s)\n",
+                       strerror(errno));
+               exit(1);
+        }
+
+       if (SDL_Init(SDL_INIT_VIDEO) < 0) {
+               fprintf(stderr, "Could not initialize SDL\n");
+               exit(1);
+       }
+
+       data.dst = SDL_SetVideoMode(xenfb->width, xenfb->height, xenfb->depth,
+                                   SDL_SWSURFACE);
+       if (!data.dst) {
+               fprintf(stderr, "SDL_SetVideoMode failed\n");
+               exit(1);
+       }
+
+       data.src = SDL_CreateRGBSurfaceFrom(xenfb->pixels,
+                                           xenfb->width, xenfb->height,
+                                           xenfb->depth, xenfb->row_stride,
+                                           0xFF0000, 0xFF00, 0xFF, 0);
+
+       if (!data.src) {
+               fprintf(stderr, "SDL_CreateRGBSurfaceFrom failed\n");
+               exit(1);
+       }
+
+        if (title == NULL)
+               title = strdup("xen-sdlfb");
+        SDL_WM_SetCaption(title, title);
+
+       r.x = r.y = 0;
+       r.w = xenfb->width;
+       r.h = xenfb->height;
+       SDL_BlitSurface(data.src, &r, data.dst, &r);
+       SDL_UpdateRect(data.dst, 0, 0, xenfb->width, xenfb->height);
+
+       xenfb->update = sdl_update;
+       xenfb->user_data = &data;
+
+       SDL_ShowCursor(0);
+
+       /*
+        * We need to wait for fds becoming ready or SDL events to
+        * arrive.  We time out the select after 10ms to poll for SDL
+        * events.  Clunky, but works.  Could avoid the clunkiness
+        * with a separate thread.
+        */
+       for (;;) {
+               FD_ZERO(&readfds);
+               nfds = xenfb_select_fds(xenfb, &readfds);
+               tv = (struct timeval){0, 10000};
+
+               if (select(nfds, &readfds, NULL, NULL, &tv) < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       fprintf(stderr,
+                               "Can't select() on event channel (%s)\n",
+                               strerror(errno));
+                       break;
+               }
+
+               while (SDL_PollEvent(&event)) {
+                       if (!sdl_on_event(xenfb, &event))
+                               do_quit = 1;
+               }
+
+                if (do_quit)
+                       break;
+
+               retval = xenfb_poll(xenfb, &readfds);
+               if (retval == -2)
+                   xenfb_teardown(xenfb);
+               if (retval < 0)
+                   break;
+       }
+
+       xenfb_delete(xenfb);
+
+       SDL_Quit();
+
+       return 0;
+}
diff -r 056050ceb300 -r dfaf8493a211 tools/xenfb/vncfb.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/vncfb.c       Fri Dec 01 13:12:41 2006 +0000
@@ -0,0 +1,401 @@
+#define _GNU_SOURCE
+#include <errno.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <rfb/rfb.h>
+#include <rfb/keysym.h>
+#include <linux/input.h>
+#include <xs.h>
+#include "xenfb.h"
+
+static int xk2linux[0x10000] = {
+       [XK_a] = KEY_A,
+       [XK_b] = KEY_B,
+       [XK_c] = KEY_C,
+       [XK_d] = KEY_D,
+       [XK_e] = KEY_E,
+       [XK_f] = KEY_F,
+       [XK_g] = KEY_G,
+       [XK_h] = KEY_H,
+       [XK_i] = KEY_I,
+       [XK_j] = KEY_J,
+       [XK_k] = KEY_K,
+       [XK_l] = KEY_L,
+       [XK_m] = KEY_M,
+       [XK_n] = KEY_N,
+       [XK_o] = KEY_O,
+       [XK_p] = KEY_P,
+       [XK_q] = KEY_Q,
+       [XK_r] = KEY_R,
+       [XK_s] = KEY_S,
+       [XK_t] = KEY_T,
+       [XK_u] = KEY_U,
+       [XK_v] = KEY_V,
+       [XK_w] = KEY_W,
+       [XK_x] = KEY_X,
+       [XK_y] = KEY_Y,
+       [XK_z] = KEY_Z,
+       [XK_A] = KEY_A,
+       [XK_B] = KEY_B,
+       [XK_C] = KEY_C,
+       [XK_D] = KEY_D,
+       [XK_E] = KEY_E,
+       [XK_F] = KEY_F,
+       [XK_G] = KEY_G,
+       [XK_H] = KEY_H,
+       [XK_I] = KEY_I,
+       [XK_J] = KEY_J,
+       [XK_K] = KEY_K,
+       [XK_L] = KEY_L,
+       [XK_M] = KEY_M,
+       [XK_N] = KEY_N,
+       [XK_O] = KEY_O,
+       [XK_P] = KEY_P,
+       [XK_Q] = KEY_Q,
+       [XK_R] = KEY_R,
+       [XK_S] = KEY_S,
+       [XK_T] = KEY_T,
+       [XK_U] = KEY_U,
+       [XK_V] = KEY_V,
+       [XK_W] = KEY_W,
+       [XK_X] = KEY_X,
+       [XK_Y] = KEY_Y,
+       [XK_Z] = KEY_Z,
+       [XK_0] = KEY_0,
+       [XK_1] = KEY_1,
+       [XK_2] = KEY_2,
+       [XK_3] = KEY_3,
+       [XK_4] = KEY_4,
+       [XK_5] = KEY_5,
+       [XK_6] = KEY_6,
+       [XK_7] = KEY_7,
+       [XK_8] = KEY_8,
+       [XK_9] = KEY_9,
+       [XK_Return] = KEY_ENTER,
+       [XK_BackSpace] = KEY_BACKSPACE,
+       [XK_Tab] = KEY_TAB,
+       [XK_Pause] = KEY_PAUSE,
+       [XK_Delete] = KEY_DELETE,
+       [XK_slash] = KEY_SLASH,
+       [XK_minus] = KEY_MINUS,
+       [XK_equal] = KEY_EQUAL,
+       [XK_Escape] = KEY_ESC,
+       [XK_braceleft] = KEY_LEFTBRACE,
+       [XK_braceright] = KEY_RIGHTBRACE,
+       [XK_bracketleft] = KEY_LEFTMETA,
+       [XK_bracketright] = KEY_RIGHTMETA,
+       [XK_Control_L] = KEY_LEFTCTRL,
+       [XK_Control_R] = KEY_RIGHTCTRL,
+       [XK_Shift_L] = KEY_LEFTSHIFT,
+       [XK_Shift_R] = KEY_RIGHTSHIFT,
+       [XK_Alt_L] = KEY_LEFTALT,
+       [XK_Alt_R] = KEY_RIGHTALT,
+       [XK_semicolon] = KEY_SEMICOLON, 
+       [XK_apostrophe] = KEY_APOSTROPHE,
+       [XK_grave] = KEY_GRAVE,
+       [XK_backslash] = KEY_BACKSLASH,
+       [XK_comma] = KEY_COMMA,
+       [XK_period] = KEY_DOT,
+       [XK_space] = KEY_SPACE,
+       [XK_Caps_Lock] = KEY_CAPSLOCK,
+       [XK_Num_Lock] = KEY_NUMLOCK,
+       [XK_Scroll_Lock] = KEY_SCROLLLOCK,
+       [XK_Sys_Req] = KEY_SYSRQ,
+       [XK_Linefeed] = KEY_LINEFEED,
+       [XK_Home] = KEY_HOME,
+       [XK_Pause] = KEY_PAUSE,
+       [XK_F1] = KEY_F1,
+       [XK_F2] = KEY_F2,
+       [XK_F3] = KEY_F3,
+       [XK_F4] = KEY_F4,
+       [XK_F5] = KEY_F5,
+       [XK_F6] = KEY_F6,
+       [XK_F7] = KEY_F7,
+       [XK_F8] = KEY_F8,
+       [XK_F9] = KEY_F9,
+       [XK_F10] = KEY_F10,
+       [XK_F11] = KEY_F11,
+       [XK_F12] = KEY_F12,
+       [XK_Up] = KEY_UP,
+       [XK_Page_Up] = KEY_PAGEUP,
+       [XK_Left] = KEY_LEFT,
+       [XK_Right] = KEY_RIGHT,
+       [XK_End] = KEY_END,
+       [XK_Down] = KEY_DOWN,
+       [XK_Page_Down] = KEY_PAGEDOWN,
+       [XK_Insert] = KEY_INSERT, 
+       [XK_colon] = KEY_SEMICOLON,
+       [XK_quotedbl] = KEY_APOSTROPHE,
+       [XK_less] = KEY_COMMA,
+       [XK_greater] = KEY_DOT,
+       [XK_question] = KEY_SLASH,
+       [XK_bar] = KEY_BACKSLASH,
+       [XK_asciitilde] = KEY_GRAVE,
+       [XK_exclam] = KEY_1,
+       [XK_at] = KEY_2,
+       [XK_numbersign] = KEY_3,
+       [XK_dollar] = KEY_4,
+       [XK_percent] = KEY_5,
+       [XK_asciicircum] = KEY_6,
+       [XK_ampersand] = KEY_7,
+       [XK_asterisk] = KEY_8,
+       [XK_parenleft] = KEY_9,
+       [XK_parenright] = KEY_0,
+       [XK_underscore] = KEY_MINUS,
+       [XK_plus] = KEY_EQUAL,
+};
+
+static void on_kbd_event(rfbBool down, rfbKeySym keycode, rfbClientPtr cl)
+{
+       /*
+        * We need to map to the key's Linux input layer keycode.
+        * Unfortunately, we don't get the key here, only the
+        * rfbKeySym, which is what the key is mapped to.  Mapping
+        * back to the key is impossible in general, even when you
+        * know the keymap.  For instance, the standard German keymap
+        * maps both KEY_COMMA and KEY_102ND to XK_less.  We simply
+        * assume standard US layout.  This sucks.
+        */
+       rfbScreenInfoPtr server = cl->screen;
+       struct xenfb *xenfb = server->screenData;
+       if (keycode >= sizeof(xk2linux) / sizeof(*xk2linux))
+               return;
+       if (xk2linux[keycode] == 0)
+               return;
+       if (xenfb_send_key(xenfb, down, xk2linux[keycode]) < 0)
+               fprintf(stderr, "Key %d %s lost (%s)\n",
+                       xk2linux[keycode], down ? "down" : "up",
+                       strerror(errno));
+}
+
+static void on_ptr_event(int buttonMask, int x, int y, rfbClientPtr cl)
+{
+       /* initial pointer state: at (0,0), buttons up */
+       static int last_x, last_y, last_button;
+       rfbScreenInfoPtr server = cl->screen;
+       struct xenfb *xenfb = server->screenData;
+       int i, last_down, down, ret;
+
+       for (i = 0; i < 8; i++) {
+               last_down = last_button & (1 << i);
+               down = buttonMask & (1 << i);
+               if (down == last_down)
+                       continue;
+               /* FIXME this assumes buttons are numbered the same; verify 
they are */
+               if (xenfb_send_key(xenfb, down != 0, BTN_MOUSE + i) < 0)
+                       fprintf(stderr, "Button %d %s lost (%s)\n",
+                               i, down ? "down" : "up", strerror(errno));
+       }
+
+       if (x != last_x || y != last_y) {
+               if (xenfb->abs_pointer_wanted) 
+                       ret = xenfb_send_position(xenfb, x, y);
+               else
+                       ret = xenfb_send_motion(xenfb, x - last_x, y - last_y);
+               if (ret < 0)
+                       fprintf(stderr, "Pointer to %d,%d lost (%s)\n",
+                               x, y, strerror(errno));
+       }
+
+       last_button = buttonMask;
+       last_x = x;
+       last_y = y;
+}
+
+static void xenstore_write_vncport(int port, int domid)
+{
+       char *buf = NULL, *path;
+       char portstr[10];
+       struct xs_handle *xsh = NULL;
+
+       xsh = xs_daemon_open();
+       if (xsh == NULL)
+               return;
+
+       path = xs_get_domain_path(xsh, domid);
+       if (path == NULL) {
+               fprintf(stderr, "Can't get domain path (%s)\n",
+                       strerror(errno));
+               goto out;
+       }
+
+       if (asprintf(&buf, "%s/console/vnc-port", path) == -1) {
+               fprintf(stderr, "Can't make vncport path\n");
+               goto out;
+       }
+
+       if (snprintf(portstr, sizeof(portstr), "%d", port) == -1) {
+               fprintf(stderr, "Can't make vncport value\n");
+               goto out;
+       }
+
+       if (!xs_write(xsh, XBT_NULL, buf, portstr, strlen(portstr)))
+               fprintf(stderr, "Can't set vncport (%s)\n",
+                       strerror(errno));
+
+ out:
+       free(buf);
+}
+
+
+static void vnc_update(struct xenfb *xenfb, int x, int y, int w, int h)
+{
+       rfbScreenInfoPtr server = xenfb->user_data;
+       rfbMarkRectAsModified(server, x, y, x + w, y + h);
+}
+
+static struct option options[] = {
+       { "domid", 1, NULL, 'd' },
+       { "vncport", 1, NULL, 'p' },
+       { "title", 1, NULL, 't' },
+       { "unused", 0, NULL, 'u' },
+       { "listen", 1, NULL, 'l' },
+       { NULL }
+};
+
+int main(int argc, char **argv)
+{
+       rfbScreenInfoPtr server;
+       char *fake_argv[7] = { "vncfb", "-rfbport", "5901", 
+                               "-desktop", "xen-vncfb", 
+                               "-listen", "127.0.0.1" };
+       int fake_argc = sizeof(fake_argv) / sizeof(fake_argv[0]);
+       int domid = -1, port = -1;
+       char *title = NULL;
+       char *listen = NULL;
+       bool unused = false;
+       int opt;
+       struct xenfb *xenfb;
+       fd_set readfds;
+       int nfds;
+       char portstr[10];
+       char *endp;
+       int r;
+
+       while ((opt = getopt_long(argc, argv, "d:p:t:u", options,
+                                 NULL)) != -1) {
+               switch (opt) {
+                case 'd':
+                       errno = 0;
+                       domid = strtol(optarg, &endp, 10);
+                       if (endp == optarg || *endp || errno) {
+                               fprintf(stderr, "Invalid domain id 
specified\n");
+                               exit(1);
+                       }
+                       break;
+                case 'p':
+                       errno = 0;
+                       port = strtol(optarg, &endp, 10);
+                       if (endp == optarg || *endp || errno) {
+                               fprintf(stderr, "Invalid port specified\n");
+                               exit(1);
+                       }
+                       break;
+                case 't':
+                       title = strdup(optarg);
+                       break;
+                case 'u':
+                       unused = true;
+                       break;
+                case 'l':
+                       listen = strdup(optarg);
+                       break;
+               case '?':
+                       exit(1);
+                }
+        }
+        if (optind != argc) {
+               fprintf(stderr, "Invalid options!\n");
+               exit(1);
+        }
+        if (domid <= 0) {
+               fprintf(stderr, "Domain ID must be specified!\n");
+               exit(1);
+        }
+            
+        if (port <= 0)
+               port = 5900 + domid;
+       if (snprintf(portstr, sizeof(portstr), "%d", port) == -1) {
+               fprintf(stderr, "Invalid port specified\n");
+               exit(1);
+        }
+            
+       fake_argv[2] = portstr;
+
+        if (title != NULL)
+               fake_argv[4] = title;
+
+        if (listen != NULL)
+               fake_argv[6] = listen;
+
+       signal(SIGPIPE, SIG_IGN);
+
+       xenfb = xenfb_new();
+       if (xenfb == NULL) {
+               fprintf(stderr, "Could not create framebuffer (%s)\n",
+                       strerror(errno));
+               exit(1);
+       }
+
+       if (xenfb_attach_dom(xenfb, domid) < 0) {
+               fprintf(stderr, "Could not connect to domain (%s)\n",
+                       strerror(errno));
+               exit(1);
+       }
+
+       server = rfbGetScreen(&fake_argc, fake_argv, 
+                             xenfb->width, xenfb->height,
+                             8, 3, xenfb->depth / 8);
+       if (server == NULL) {
+               fprintf(stderr, "Could not create VNC server\n");
+               exit(1);
+       }
+
+       xenfb->user_data = server;
+       xenfb->update = vnc_update;
+
+        if (unused)
+               server->autoPort = true;
+
+       server->serverFormat.redShift = 16;
+       server->serverFormat.greenShift = 8;
+       server->serverFormat.blueShift = 0;
+       server->kbdAddEvent = on_kbd_event;
+       server->ptrAddEvent = on_ptr_event;
+       server->frameBuffer = xenfb->pixels;
+       server->screenData = xenfb;
+       server->cursor = NULL;
+       rfbInitServer(server);
+
+       rfbRunEventLoop(server, -1, true);
+
+        xenstore_write_vncport(server->port, domid);
+
+       for (;;) {
+               FD_ZERO(&readfds);
+               nfds = xenfb_select_fds(xenfb, &readfds);
+
+               if (select(nfds, &readfds, NULL, NULL, NULL) < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       fprintf(stderr,
+                               "Can't select() on event channel (%s)\n",
+                               strerror(errno));
+                       break;
+               }
+
+               r = xenfb_poll(xenfb, &readfds);
+               if (r == -2)
+                   xenfb_teardown(xenfb);
+               if (r < 0)
+                   break;
+       }
+
+       rfbScreenCleanup(server);
+       xenfb_delete(xenfb);
+
+       return 0;
+}
diff -r 056050ceb300 -r dfaf8493a211 tools/xenfb/xenfb.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/xenfb.c       Fri Dec 01 13:12:41 2006 +0000
@@ -0,0 +1,711 @@
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <xenctrl.h>
+#include <xen/io/xenbus.h>
+#include <xen/io/fbif.h>
+#include <xen/io/kbdif.h>
+#include <sys/select.h>
+#include <stdbool.h>
+#include <xen/linux/evtchn.h>
+#include <xen/event_channel.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <xs.h>
+
+#include "xenfb.h"
+
+// FIXME defend against malicious frontend?
+
+struct xenfb_device {
+       const char *devicetype;
+       char nodename[64];      /* backend xenstore dir */
+       char otherend[64];      /* frontend xenstore dir */
+       int otherend_id;        /* frontend domid */
+       enum xenbus_state state; /* backend state */
+       void *page;             /* shared page */
+       evtchn_port_t port;
+       struct xenfb_private *xenfb;
+};
+
+struct xenfb_private {
+       struct xenfb pub;
+       int evt_xch;            /* event channel driver handle */
+       int xc;                 /* hypervisor interface handle */
+       struct xs_handle *xsh;  /* xs daemon handle */
+       struct xenfb_device fb, kbd;
+       size_t fb_len;          /* size of framebuffer */
+};
+
+static void xenfb_detach_dom(struct xenfb_private *);
+
+static char *xenfb_path_in_dom(struct xs_handle *xsh,
+                              char *buf, size_t size,
+                              unsigned domid, const char *fmt, ...)
+{
+       va_list ap;
+       char *domp = xs_get_domain_path(xsh, domid);
+       int n;
+
+        if (domp == NULL)
+               return NULL;
+
+       n = snprintf(buf, size, "%s/", domp);
+       free(domp);
+       if (n >= size)
+               return NULL;
+
+       va_start(ap, fmt);
+       n += vsnprintf(buf + n, size - n, fmt, ap);
+       va_end(ap);
+       if (n >= size)
+               return NULL;
+
+       return buf;
+}
+
+static int xenfb_xs_scanf1(struct xs_handle *xsh,
+                          const char *dir, const char *node,
+                          const char *fmt, void *dest)
+{
+       char buf[1024];
+       char *p;
+       int ret;
+
+       if (snprintf(buf, sizeof(buf), "%s/%s", dir, node) >= sizeof(buf)) {
+               errno = ENOENT;
+               return -1;
+        }
+       p = xs_read(xsh, XBT_NULL, buf, NULL);
+       if (!p) {
+               errno = ENOENT;
+               return -1;
+        }
+       ret = sscanf(p, fmt, dest);
+       free(p);
+       if (ret != 1) {
+               errno = EDOM;
+               return -1;
+        }
+       return ret;
+}
+
+static int xenfb_xs_printf(struct xs_handle *xsh,
+                          const char *dir, const char *node, char *fmt, ...)
+{
+       va_list ap;
+       char key[1024];
+       char val[1024];
+       int n;
+
+       if (snprintf(key, sizeof(key), "%s/%s", dir, node) >= sizeof(key)) {
+               errno = ENOENT;
+               return -1;
+        }
+
+       va_start(ap, fmt);
+       n = vsnprintf(val, sizeof(val), fmt, ap);
+       va_end(ap);
+       if (n >= sizeof(val)) {
+               errno = ENOSPC; /* close enough */
+               return -1;
+       }
+
+       if (!xs_write(xsh, XBT_NULL, key, val, n))
+               return -1;
+       return 0;
+}
+
+static void xenfb_device_init(struct xenfb_device *dev,
+                             const char *type,
+                             struct xenfb_private *xenfb)
+{
+       dev->devicetype = type;
+       dev->otherend_id = -1;
+       dev->port = -1;
+       dev->xenfb = xenfb;
+}
+
+int xenfb_device_set_domain(struct xenfb_device *dev, int domid)
+{
+       struct xenfb_private *xenfb = dev->xenfb;
+
+       dev->otherend_id = domid;
+
+       if (!xenfb_path_in_dom(xenfb->xsh,
+                              dev->otherend, sizeof(dev->otherend),
+                              domid, "device/%s/0", dev->devicetype)) {
+               errno = ENOENT;
+               return -1;
+       }
+       if (!xenfb_path_in_dom(xenfb->xsh,
+                              dev->nodename, sizeof(dev->nodename),
+                              0, "backend/%s/%d/0", dev->devicetype, domid)) {
+               errno = ENOENT;
+               return -1;
+       }
+
+       return 0;
+}
+
+struct xenfb *xenfb_new(void)
+{
+       struct xenfb_private *xenfb = malloc(sizeof(*xenfb));
+       int serrno;
+
+       if (xenfb == NULL)
+               return NULL;
+
+       memset(xenfb, 0, sizeof(*xenfb));
+       xenfb->evt_xch = xenfb->xc = -1;
+       xenfb_device_init(&xenfb->fb, "vfb", xenfb);
+       xenfb_device_init(&xenfb->kbd, "vkbd", xenfb);
+
+       xenfb->evt_xch = xc_evtchn_open();
+       if (xenfb->evt_xch == -1)
+               goto fail;
+
+       xenfb->xc = xc_interface_open();
+       if (xenfb->xc == -1)
+               goto fail;
+
+       xenfb->xsh = xs_daemon_open();
+       if (!xenfb->xsh)
+               goto fail;
+
+       return &xenfb->pub;
+
+ fail:
+       serrno = errno;
+       xenfb_delete(&xenfb->pub);
+       errno = serrno;
+       return NULL;
+}
+
+/* Remove the backend area in xenbus since the framebuffer really is
+   going away. */
+void xenfb_teardown(struct xenfb *xenfb_pub)
+{
+       struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+
+       xs_rm(xenfb->xsh, XBT_NULL, xenfb->fb.nodename);
+       xs_rm(xenfb->xsh, XBT_NULL, xenfb->kbd.nodename);
+}
+
+
+void xenfb_delete(struct xenfb *xenfb_pub)
+{
+       struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+
+       xenfb_detach_dom(xenfb);
+       if (xenfb->xc >= 0)
+               xc_interface_close(xenfb->xc);
+       if (xenfb->evt_xch >= 0)
+               xc_evtchn_close(xenfb->evt_xch);
+       if (xenfb->xsh)
+               xs_daemon_close(xenfb->xsh);
+       free(xenfb);
+}
+
+static enum xenbus_state xenfb_read_state(struct xs_handle *xsh,
+                                         const char *dir)
+{
+       int ret, state;
+
+       ret = xenfb_xs_scanf1(xsh, dir, "state", "%d", &state);
+       if (ret < 0)
+               return XenbusStateUnknown;
+
+       if ((unsigned)state > XenbusStateClosed)
+               state = XenbusStateUnknown;
+       return state;
+}
+
+static int xenfb_switch_state(struct xenfb_device *dev,
+                             enum xenbus_state state)
+{
+       struct xs_handle *xsh = dev->xenfb->xsh;
+
+       if (xenfb_xs_printf(xsh, dev->nodename, "state", "%d", state) < 0)
+               return -1;
+       dev->state = state;
+       return 0;
+}
+
+static int xenfb_wait_for_state(struct xs_handle *xsh, const char *dir,
+                               unsigned awaited)
+{
+       unsigned state, dummy;
+       char **vec;
+
+       for (;;) {
+               state = xenfb_read_state(xsh, dir);
+               if (state < 0)
+                       return -1;
+
+               if ((1 << state) & awaited)
+                       return state;
+
+               vec = xs_read_watch(xsh, &dummy);
+               if (!vec)
+                       return -1;
+               free(vec);
+       }
+}
+
+static int xenfb_wait_for_backend_creation(struct xenfb_device *dev)
+{
+       struct xs_handle *xsh = dev->xenfb->xsh;
+       int state;
+
+       if (!xs_watch(xsh, dev->nodename, ""))
+               return -1;
+       state = xenfb_wait_for_state(xsh, dev->nodename,
+                       (1 << XenbusStateInitialising)
+                       | (1 << XenbusStateClosed)
+#if 1 /* TODO fudging state to permit restarting; to be removed */
+                       | (1 << XenbusStateInitWait)
+                       | (1 << XenbusStateConnected)
+                       | (1 << XenbusStateClosing)
+#endif
+                       );
+       xs_unwatch(xsh, dev->nodename, "");
+
+       switch (state) {
+#if 1
+       case XenbusStateInitWait:
+       case XenbusStateConnected:
+               printf("Fudging state to %d\n", XenbusStateInitialising); /* 
FIXME */
+#endif
+       case XenbusStateInitialising:
+       case XenbusStateClosing:
+       case XenbusStateClosed:
+               break;
+       default:
+               return -1;
+       }
+
+       return 0;
+}
+
+static int xenfb_hotplug(struct xenfb_device *dev)
+{
+       if (xenfb_xs_printf(dev->xenfb->xsh, dev->nodename,
+                           "hotplug-status", "connected"))
+               return -1;
+       return 0;
+}
+
+static int xenfb_wait_for_frontend_initialised(struct xenfb_device *dev)
+{
+       switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend,
+#if 1 /* TODO fudging state to permit restarting; to be removed */
+                       (1 << XenbusStateInitialised)
+                       | (1 << XenbusStateConnected)
+#else
+                       1 << XenbusStateInitialised,
+#endif
+                       )) {
+#if 1
+       case XenbusStateConnected:
+               printf("Fudging state to %d\n", XenbusStateInitialised); /* 
FIXME */
+#endif
+       case XenbusStateInitialised:
+               break;
+       default:
+               return -1;
+       }
+
+       return 0;
+}
+
+static int xenfb_map_fb(struct xenfb_private *xenfb, int domid)
+{
+       struct xenfb_page *page = xenfb->fb.page;
+       int n_fbmfns;
+       int n_fbdirs;
+       unsigned long *fbmfns;
+
+       n_fbmfns = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
+       n_fbdirs = n_fbmfns * sizeof(unsigned long);
+       n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
+
+       /*
+        * Bug alert: xc_map_foreign_batch() can fail partly and
+        * return a non-null value.  This is a design flaw.  When it
+        * happens, we happily continue here, and later crash on
+        * access.
+        */
+       fbmfns = xc_map_foreign_batch(xenfb->xc, domid,
+                       PROT_READ, page->pd, n_fbdirs);
+       if (fbmfns == NULL)
+               return -1;
+
+       xenfb->pub.pixels = xc_map_foreign_batch(xenfb->xc, domid,
+                               PROT_READ | PROT_WRITE, fbmfns, n_fbmfns);
+       if (xenfb->pub.pixels == NULL) {
+               munmap(fbmfns, n_fbdirs * XC_PAGE_SIZE);
+               return -1;
+       }
+
+       return munmap(fbmfns, n_fbdirs * XC_PAGE_SIZE);
+}
+
+static int xenfb_bind(struct xenfb_device *dev)
+{
+       struct xenfb_private *xenfb = dev->xenfb;
+       unsigned long mfn;
+       evtchn_port_t evtchn;
+
+       if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "page-ref", "%lu",
+                           &mfn) < 0)
+               return -1;
+       if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "event-channel", "%u",
+                           &evtchn) < 0)
+               return -1;
+
+       dev->port = xc_evtchn_bind_interdomain(xenfb->evt_xch,
+                                              dev->otherend_id, evtchn);
+       if (dev->port == -1)
+               return -1;
+
+       dev->page = xc_map_foreign_range(xenfb->xc, dev->otherend_id,
+                       XC_PAGE_SIZE, PROT_READ | PROT_WRITE, mfn);
+       if (dev->page == NULL)
+               return -1;
+
+       return 0;
+}
+
+static void xenfb_unbind(struct xenfb_device *dev)
+{
+       if (dev->page) {
+               munmap(dev->page, XC_PAGE_SIZE);
+               dev->page = NULL;
+       }
+        if (dev->port >= 0) {
+               xc_evtchn_unbind(dev->xenfb->evt_xch, dev->port);
+               dev->port = -1;
+       }
+}
+
+static int xenfb_wait_for_frontend_connected(struct xenfb_device *dev)
+{
+       switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend,
+                                    1 << XenbusStateConnected)) {
+       case XenbusStateConnected:
+               break;
+       default:
+               return -1;
+       }
+
+       return 0;
+}
+
+static void xenfb_dev_fatal(struct xenfb_device *dev, int err,
+                           const char *fmt, ...)
+{
+       struct xs_handle *xsh = dev->xenfb->xsh;
+       va_list ap;
+       char errdir[80];
+       char buf[1024];
+       int n;
+
+       fprintf(stderr, "%s ", dev->nodename); /* somewhat crude */
+       va_start(ap, fmt);
+       vfprintf(stderr, fmt, ap);
+       va_end(ap);
+       if (err)
+               fprintf(stderr, " (%s)", strerror(err));
+       putc('\n', stderr);
+
+       if (!xenfb_path_in_dom(xsh, errdir, sizeof(errdir), 0,
+                              "error/%s", dev->nodename))
+               goto out;       /* FIXME complain */
+
+       va_start(ap, fmt);
+       n = snprintf(buf, sizeof(buf), "%d ", err);
+       snprintf(buf + n, sizeof(buf) - n, fmt, ap);
+       va_end(ap);
+
+       if (xenfb_xs_printf(xsh, buf, "error", "%s", buf) < 0)
+               goto out;       /* FIXME complain */
+
+ out:
+       xenfb_switch_state(dev, XenbusStateClosing);
+}
+
+int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid)
+{
+       struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+       struct xs_handle *xsh = xenfb->xsh;
+       int val, serrno;
+       struct xenfb_page *fb_page;
+
+       xenfb_detach_dom(xenfb);
+
+       xenfb_device_set_domain(&xenfb->fb, domid);
+       xenfb_device_set_domain(&xenfb->kbd, domid);
+
+       if (xenfb_wait_for_backend_creation(&xenfb->fb) < 0)
+               goto error;
+       if (xenfb_wait_for_backend_creation(&xenfb->kbd) < 0)
+               goto error;
+
+       if (xenfb_xs_printf(xsh, xenfb->kbd.nodename, "feature-abs-pointer", 
"1"))
+               goto error;
+       if (xenfb_switch_state(&xenfb->fb, XenbusStateInitWait))
+               goto error;
+       if (xenfb_switch_state(&xenfb->kbd, XenbusStateInitWait))
+               goto error;
+
+       if (xenfb_hotplug(&xenfb->fb) < 0)
+               goto error;
+       if (xenfb_hotplug(&xenfb->kbd) < 0)
+               goto error;
+
+       if (!xs_watch(xsh, xenfb->fb.otherend, ""))
+               goto error;
+       if (!xs_watch(xsh, xenfb->kbd.otherend, ""))
+               goto error;
+
+       if (xenfb_wait_for_frontend_initialised(&xenfb->fb) < 0)
+               goto error;
+       if (xenfb_wait_for_frontend_initialised(&xenfb->kbd) < 0)
+               goto error;
+
+       if (xenfb_bind(&xenfb->fb) < 0)
+               goto error;
+       if (xenfb_bind(&xenfb->kbd) < 0)
+               goto error;
+
+       if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "feature-update",
+                           "%d", &val) < 0)
+               val = 0;
+       if (!val) {
+               errno = ENOTSUP;
+               goto error;
+       }
+       xenfb_xs_printf(xsh, xenfb->fb.nodename, "request-update", "1");
+
+       /* TODO check for permitted ranges */
+       fb_page = xenfb->fb.page;
+       xenfb->pub.depth = fb_page->depth;
+       xenfb->pub.width = fb_page->width;
+       xenfb->pub.height = fb_page->height;
+       /* TODO check for consistency with the above */
+       xenfb->fb_len = fb_page->mem_length;
+       xenfb->pub.row_stride = fb_page->line_length;
+
+       if (xenfb_map_fb(xenfb, domid) < 0)
+               goto error;
+
+       if (xenfb_switch_state(&xenfb->fb, XenbusStateConnected))
+               goto error;
+       if (xenfb_switch_state(&xenfb->kbd, XenbusStateConnected))
+               goto error;
+
+       if (xenfb_wait_for_frontend_connected(&xenfb->kbd) < 0)
+               goto error;
+       if (xenfb_xs_scanf1(xsh, xenfb->kbd.otherend, "request-abs-pointer",
+                           "%d", &val) < 0)
+               val = 0;
+       xenfb->pub.abs_pointer_wanted = val;
+
+       return 0;
+
+ error:
+       serrno = errno;
+       xenfb_detach_dom(xenfb);
+       xenfb_dev_fatal(&xenfb->fb, serrno, "on fire");
+       xenfb_dev_fatal(&xenfb->kbd, serrno, "on fire");
+        errno = serrno;
+        return -1;
+}
+
+static void xenfb_detach_dom(struct xenfb_private *xenfb)
+{
+       xenfb_unbind(&xenfb->fb);
+       xenfb_unbind(&xenfb->kbd);
+       if (xenfb->pub.pixels) {
+               munmap(xenfb->pub.pixels, xenfb->fb_len);
+               xenfb->pub.pixels = NULL;
+       }
+}
+
+static void xenfb_on_fb_event(struct xenfb_private *xenfb)
+{
+       uint32_t prod, cons;
+       struct xenfb_page *page = xenfb->fb.page;
+
+       prod = page->out_prod;
+       if (prod == page->out_cons)
+               return;
+       rmb();                  /* ensure we see ring contents up to prod */
+       for (cons = page->out_cons; cons != prod; cons++) {
+               union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
+
+               switch (event->type) {
+               case XENFB_TYPE_UPDATE:
+                    if (xenfb->pub.update)
+                       xenfb->pub.update(&xenfb->pub,
+                                         event->update.x, event->update.y,
+                                         event->update.width, 
event->update.height);
+                    break;
+               }
+       }
+       mb();                   /* ensure we're done with ring contents */
+       page->out_cons = cons;
+       xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port);
+}
+
+static void xenfb_on_kbd_event(struct xenfb_private *xenfb)
+{
+       struct xenkbd_page *page = xenfb->kbd.page;
+
+       /* We don't understand any keyboard events, so just ignore them. */
+       if (page->out_prod == page->out_cons)
+               return;
+       page->out_cons = page->out_prod;
+       xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port);
+}
+
+static int xenfb_on_state_change(struct xenfb_device *dev)
+{
+       enum xenbus_state state;
+
+       state = xenfb_read_state(dev->xenfb->xsh, dev->otherend);
+
+       switch (state) {
+       case XenbusStateUnknown:
+               /* There was an error reading the frontend state.  The
+                  domain has probably gone away; in any case, there's
+                  not much point in us continuing. */
+               return -1;
+       case XenbusStateInitialising:
+       case XenbusStateInitWait:
+       case XenbusStateInitialised:
+       case XenbusStateConnected:
+               break;
+       case XenbusStateClosing:
+               xenfb_unbind(dev);
+               xenfb_switch_state(dev, state);
+               break;
+       case XenbusStateClosed:
+               xenfb_switch_state(dev, state);
+       }
+       return 0;
+}
+
+/* Returns 0 normally, -1 on error, or -2 if the domain went away. */
+int xenfb_poll(struct xenfb *xenfb_pub, fd_set *readfds)
+{
+       struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+       evtchn_port_t port;
+       unsigned dummy;
+       char **vec;
+       int r;
+
+       if (FD_ISSET(xc_evtchn_fd(xenfb->evt_xch), readfds)) {
+               port = xc_evtchn_pending(xenfb->evt_xch);
+               if (port == -1)
+                       return -1;
+
+               if (port == xenfb->fb.port)
+                       xenfb_on_fb_event(xenfb);
+               else if (port == xenfb->kbd.port)
+                       xenfb_on_kbd_event(xenfb);
+
+               if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1)
+                       return -1;
+       }
+
+       if (FD_ISSET(xs_fileno(xenfb->xsh), readfds)) {
+               vec = xs_read_watch(xenfb->xsh, &dummy);
+               free(vec);
+               r = xenfb_on_state_change(&xenfb->fb);
+               if (r == 0)
+                       r = xenfb_on_state_change(&xenfb->kbd);
+               if (r == -1)
+                       return -2;
+       }
+
+       return 0;
+}
+
+int xenfb_select_fds(struct xenfb *xenfb_pub, fd_set *readfds)
+{
+       struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+       int fd1 = xc_evtchn_fd(xenfb->evt_xch);
+       int fd2 = xs_fileno(xenfb->xsh);
+
+       FD_SET(fd1, readfds);
+       FD_SET(fd2, readfds);
+       return fd1 > fd2 ? fd1 + 1 : fd2 + 1;
+}
+
+static int xenfb_kbd_event(struct xenfb_private *xenfb,
+                          union xenkbd_in_event *event)
+{
+       uint32_t prod;
+       struct xenkbd_page *page = xenfb->kbd.page;
+
+       if (xenfb->kbd.state != XenbusStateConnected)
+               return 0;
+
+       prod = page->in_prod;
+       if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
+               errno = EAGAIN;
+               return -1;
+       }
+
+       mb();                   /* ensure ring space available */
+       XENKBD_IN_RING_REF(page, prod) = *event;
+       wmb();                  /* ensure ring contents visible */
+       page->in_prod = prod + 1;
+       return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port);
+}
+
+int xenfb_send_key(struct xenfb *xenfb_pub, bool down, int keycode)
+{
+       struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+       union xenkbd_in_event event;
+
+       memset(&event, 0, XENKBD_IN_EVENT_SIZE);
+       event.type = XENKBD_TYPE_KEY;
+       event.key.pressed = down ? 1 : 0;
+       event.key.keycode = keycode;
+
+       return xenfb_kbd_event(xenfb, &event);
+}
+
+int xenfb_send_motion(struct xenfb *xenfb_pub, int rel_x, int rel_y)
+{
+       struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+       union xenkbd_in_event event;
+
+       memset(&event, 0, XENKBD_IN_EVENT_SIZE);
+       event.type = XENKBD_TYPE_MOTION;
+       event.motion.rel_x = rel_x;
+       event.motion.rel_y = rel_y;
+
+       return xenfb_kbd_event(xenfb, &event);
+}
+
+int xenfb_send_position(struct xenfb *xenfb_pub, int abs_x, int abs_y)
+{
+       struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+       union xenkbd_in_event event;
+
+       memset(&event, 0, XENKBD_IN_EVENT_SIZE);
+       event.type = XENKBD_TYPE_POS;
+       event.pos.abs_x = abs_x;
+       event.pos.abs_y = abs_y;
+
+       return xenfb_kbd_event(xenfb, &event);
+}
diff -r 056050ceb300 -r dfaf8493a211 tools/xenfb/xenfb.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/xenfb.h       Fri Dec 01 13:12:41 2006 +0000
@@ -0,0 +1,35 @@
+#ifndef _XENFB_H_
+#define _XENFB_H_
+
+#include <stdbool.h>
+#include <sys/types.h>
+
+struct xenfb
+{
+       void *pixels;
+
+       int row_stride;
+       int depth;
+       int width;
+       int height;
+       int abs_pointer_wanted;
+
+       void *user_data;
+
+       void (*update)(struct xenfb *xenfb, int x, int y, int width, int 
height);
+};
+
+struct xenfb *xenfb_new(void);
+void xenfb_delete(struct xenfb *xenfb);
+void xenfb_teardown(struct xenfb *xenfb);
+
+int xenfb_attach_dom(struct xenfb *xenfb, int domid);
+
+int xenfb_select_fds(struct xenfb *xenfb, fd_set *readfds);
+int xenfb_poll(struct xenfb *xenfb, fd_set *readfds);
+
+int xenfb_send_key(struct xenfb *xenfb, bool down, int keycode);
+int xenfb_send_motion(struct xenfb *xenfb, int rel_x, int rel_y);
+int xenfb_send_position(struct xenfb *xenfb, int abs_x, int abs_y);
+
+#endif
diff -r 056050ceb300 -r dfaf8493a211 xen/include/public/io/fbif.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/include/public/io/fbif.h      Fri Dec 01 13:12:41 2006 +0000
@@ -0,0 +1,116 @@
+/*
+ * fbif.h -- Xen virtual frame buffer device
+ *
+ * Copyright (C) 2005 Anthony Liguori <aliguori@xxxxxxxxxx>
+ * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@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 __XEN_PUBLIC_IO_FBIF_H__
+#define __XEN_PUBLIC_IO_FBIF_H__
+
+#include <asm/types.h>
+
+/* Out events (frontend -> backend) */
+
+/*
+ * Out events may be sent only when requested by backend, and receipt
+ * of an unknown out event is an error.
+ */
+
+/* Event type 1 currently not used */
+/*
+ * Framebuffer update notification event
+ * Capable frontend sets feature-update in xenstore.
+ * Backend requests it by setting request-update in xenstore.
+ */
+#define XENFB_TYPE_UPDATE 2
+
+struct xenfb_update
+{
+       __u8 type;              /* XENFB_TYPE_UPDATE */
+       __s32 x;                /* source x */
+       __s32 y;                /* source y */
+       __s32 width;            /* rect width */
+       __s32 height;           /* rect height */
+};
+
+#define XENFB_OUT_EVENT_SIZE 40
+
+union xenfb_out_event
+{
+       __u8 type;
+       struct xenfb_update update;
+       char pad[XENFB_OUT_EVENT_SIZE];
+};
+
+/* In events (backend -> frontend) */
+
+/*
+ * Frontends should ignore unknown in events.
+ * No in events currently defined.
+ */
+
+#define XENFB_IN_EVENT_SIZE 40
+
+union xenfb_in_event
+{
+       __u8 type;
+       char pad[XENFB_IN_EVENT_SIZE];
+};
+
+/* shared page */
+
+#define XENFB_IN_RING_SIZE 1024
+#define XENFB_IN_RING_LEN (XENFB_IN_RING_SIZE / XENFB_IN_EVENT_SIZE)
+#define XENFB_IN_RING_OFFS 1024
+#define XENFB_IN_RING(page) \
+    ((union xenfb_in_event *)((char *)(page) + XENFB_IN_RING_OFFS))
+#define XENFB_IN_RING_REF(page, idx) \
+    (XENFB_IN_RING((page))[(idx) % XENFB_IN_RING_LEN])
+
+#define XENFB_OUT_RING_SIZE 2048
+#define XENFB_OUT_RING_LEN (XENFB_OUT_RING_SIZE / XENFB_OUT_EVENT_SIZE)
+#define XENFB_OUT_RING_OFFS (XENFB_IN_RING_OFFS + XENFB_IN_RING_SIZE)
+#define XENFB_OUT_RING(page) \
+    ((union xenfb_out_event *)((char *)(page) + XENFB_OUT_RING_OFFS))
+#define XENFB_OUT_RING_REF(page, idx) \
+    (XENFB_OUT_RING((page))[(idx) % XENFB_OUT_RING_LEN])
+
+struct xenfb_page
+{
+       __u32 in_cons, in_prod;
+       __u32 out_cons, out_prod;
+
+       __s32 width;         /* the width of the framebuffer (in pixels) */
+       __s32 height;        /* the height of the framebuffer (in pixels) */
+       __u32 line_length;   /* the length of a row of pixels (in bytes) */
+       __u32 mem_length;    /* the length of the framebuffer (in bytes) */
+       __u8 depth;          /* the depth of a pixel (in bits) */
+
+       /*
+        * Framebuffer page directory
+        *
+        * Each directory page holds PAGE_SIZE / sizeof(*pd)
+        * framebuffer pages, and can thus map up to PAGE_SIZE *
+        * PAGE_SIZE / sizeof(*pd) bytes.  With PAGE_SIZE == 4096 and
+        * sizeof(unsigned long) == 4, that's 4 Megs.  Two directory
+        * pages should be enough for a while.
+        */
+       unsigned long pd[2];
+};
+
+/*
+ * Wart: xenkbd needs to know resolution.  Put it here until a better
+ * solution is found, but don't leak it to the backend.
+ */
+#ifdef __KERNEL__
+#define XENFB_WIDTH 800
+#define XENFB_HEIGHT 600
+#define XENFB_DEPTH 32
+#endif
+
+#endif
diff -r 056050ceb300 -r dfaf8493a211 xen/include/public/io/kbdif.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/include/public/io/kbdif.h     Fri Dec 01 13:12:41 2006 +0000
@@ -0,0 +1,108 @@
+/*
+ * kbdif.h -- Xen virtual keyboard/mouse
+ *
+ * Copyright (C) 2005 Anthony Liguori <aliguori@xxxxxxxxxx>
+ * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@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 __XEN_PUBLIC_IO_KBDIF_H__
+#define __XEN_PUBLIC_IO_KBDIF_H__
+
+#include <asm/types.h>
+
+/* In events (backend -> frontend) */
+
+/*
+ * Frontends should ignore unknown in events.
+ */
+
+/* Pointer movement event */
+#define XENKBD_TYPE_MOTION  1
+/* Event type 2 currently not used */
+/* Key event (includes pointer buttons) */
+#define XENKBD_TYPE_KEY     3
+/*
+ * Pointer position event
+ * Capable backend sets feature-abs-pointer in xenstore.
+ * Frontend requests ot instead of XENKBD_TYPE_MOTION by setting
+ * request-abs-update in xenstore.
+ */
+#define XENKBD_TYPE_POS     4
+
+struct xenkbd_motion
+{
+       __u8 type;         /* XENKBD_TYPE_MOTION */
+       __s32 rel_x;       /* relative X motion */
+       __s32 rel_y;       /* relative Y motion */
+};
+
+struct xenkbd_key
+{
+       __u8 type;         /* XENKBD_TYPE_KEY */
+       __u8 pressed;      /* 1 if pressed; 0 otherwise */
+       __u32 keycode;     /* KEY_* from linux/input.h */
+};
+
+struct xenkbd_position
+{
+       __u8 type;         /* XENKBD_TYPE_POS */
+       __s32 abs_x;       /* absolute X position (in FB pixels) */
+       __s32 abs_y;       /* absolute Y position (in FB pixels) */
+};
+
+#define XENKBD_IN_EVENT_SIZE 40
+
+union xenkbd_in_event
+{
+       __u8 type;
+       struct xenkbd_motion motion;
+       struct xenkbd_key key;
+       struct xenkbd_position pos;
+       char pad[XENKBD_IN_EVENT_SIZE];
+};
+
+/* Out events (frontend -> backend) */
+
+/*
+ * Out events may be sent only when requested by backend, and receipt
+ * of an unknown out event is an error.
+ * No out events currently defined.
+ */
+
+#define XENKBD_OUT_EVENT_SIZE 40
+
+union xenkbd_out_event
+{
+       __u8 type;
+       char pad[XENKBD_OUT_EVENT_SIZE];
+};
+
+/* shared page */
+
+#define XENKBD_IN_RING_SIZE 2048
+#define XENKBD_IN_RING_LEN (XENKBD_IN_RING_SIZE / XENKBD_IN_EVENT_SIZE)
+#define XENKBD_IN_RING_OFFS 1024
+#define XENKBD_IN_RING(page) \
+    ((union xenkbd_in_event *)((char *)(page) + XENKBD_IN_RING_OFFS))
+#define XENKBD_IN_RING_REF(page, idx) \
+    (XENKBD_IN_RING((page))[(idx) % XENKBD_IN_RING_LEN])
+
+#define XENKBD_OUT_RING_SIZE 1024
+#define XENKBD_OUT_RING_LEN (XENKBD_OUT_RING_SIZE / XENKBD_OUT_EVENT_SIZE)
+#define XENKBD_OUT_RING_OFFS (XENKBD_IN_RING_OFFS + XENKBD_IN_RING_SIZE)
+#define XENKBD_OUT_RING(page) \
+    ((union xenkbd_out_event *)((char *)(page) + XENKBD_OUT_RING_OFFS))
+#define XENKBD_OUT_RING_REF(page, idx) \
+    (XENKBD_OUT_RING((page))[(idx) % XENKBD_OUT_RING_LEN])
+
+struct xenkbd_page
+{
+       __u32 in_cons, in_prod;
+       __u32 out_cons, out_prod;
+};
+
+#endif

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

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