[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] Re: [PATCH 2/2] PV framebuffer


  • To: xen-devel@xxxxxxxxxxxxxxxxxxx
  • From: Markus Armbruster <armbru@xxxxxxxxxx>
  • Date: Fri, 17 Nov 2006 14:23:13 +0100
  • Delivery-date: Fri, 17 Nov 2006 05:23:52 -0800
  • List-id: Xen developer discussion <xen-devel.lists.xensource.com>

PV framebuffer backend.  Derived from http://hg.codemonkey.ws/vncfb

Extensive changes based on feedback from xen-devel.

Signed-off-by: Markus Armbruster <armbru@xxxxxxxxxx>
---
 tools/Makefile                        |    1 
 tools/python/xen/xend/XendDevices.py  |    4 
 tools/python/xen/xend/server/vfbif.py |   29 +
 tools/python/xen/xm/create.py         |   17 
 tools/xenfb/Makefile                  |   33 +
 tools/xenfb/sdlfb.c                   |  337 ++++++++++++++++++
 tools/xenfb/vncfb.c                   |  396 +++++++++++++++++++++
 tools/xenfb/xenfb.c                   |  619 ++++++++++++++++++++++++++++++++++
 tools/xenfb/xenfb.h                   |   34 +
 9 files changed, 1469 insertions(+), 1 deletion(-)

diff -r c677f4e75608 tools/Makefile
--- a/tools/Makefile    Thu Nov 16 11:11:17 2006 +0000
+++ b/tools/Makefile    Fri Nov 10 08:01:00 2006 +0100
@@ -19,6 +19,7 @@ SUBDIRS-y += libaio
 SUBDIRS-y += libaio
 SUBDIRS-y += blktap
 SUBDIRS-y += libfsimage
+SUBDIRS-y += xenfb
 
 # These don't cross-compile
 ifeq ($(XEN_COMPILE_ARCH),$(XEN_TARGET_ARCH))
diff -r c677f4e75608 tools/python/xen/xend/XendDevices.py
--- a/tools/python/xen/xend/XendDevices.py      Thu Nov 16 11:11:17 2006 +0000
+++ b/tools/python/xen/xend/XendDevices.py      Mon Nov 13 15:00:34 2006 +0100
@@ -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 c677f4e75608 tools/python/xen/xm/create.py
--- a/tools/python/xen/xm/create.py     Thu Nov 16 11:11:17 2006 +0000
+++ b/tools/python/xen/xm/create.py     Tue Nov 14 14:51:37 2006 +0100
@@ -280,6 +280,14 @@ 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="no|yes'",
+          fn=set_bool, default=0,
+          use="Make the domain a framebuffer backend.")
+
+gopts.var('vkbd', val="no|yes'",
+          fn=set_bool, default=0,
+          use="Make the domain a keyboard backend.")
+
 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.
@@ -556,6 +564,13 @@ def configure_usb(config_devs, vals):
         config_usb = ['usbport', ['path', path]]
         config_devs.append(['device', config_usb])
 
+def configure_vfbs(config_devs, vals):
+    if vals.vfb:
+        config_devs.append(['device', ['vfb', []]])
+
+def configure_vkbds(config_devs, vals):
+    if vals.vkbd:
+        config_devs.append(['device', ['vkbd', []]])
 
 def configure_security(config, vals):
     """Create the config for ACM security labels.
@@ -734,6 +749,8 @@ 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_vkbds(config_devs, vals)
     configure_security(config, vals)
     config += config_devs
 
diff -r c677f4e75608 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     Tue Nov 07 14:46:46 2006 +0100
@@ -0,0 +1,29 @@
+from xen.xend.server.DevController import DevController
+
+class VfbifController(DevController):
+    """Virtual frame buffer controller. Handles all vfb devices for a domain.
+    """
+
+    def __init__(self, vm):
+        DevController.__init__(self, vm)
+
+    def getDeviceDetails(self, config):
+        """@see DevController.getDeviceDetails"""
+        devid = 0
+        back = {}
+        front = {}
+        return (devid, back, front)
+
+class VkbdifController(DevController):
+    """Virtual keyboard controller. Handles all vkbd devices for a domain.
+    """
+
+    def __init__(self, vm):
+        DevController.__init__(self, vm)
+
+    def getDeviceDetails(self, config):
+        """@see DevController.getDeviceDetails"""
+        devid = 0
+        back = {}
+        front = {}
+        return (devid, back, front)
diff -r c677f4e75608 tools/xenfb/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/Makefile      Thu Nov 09 10:19:26 2006 +0100
@@ -0,0 +1,33 @@
+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
diff -r c677f4e75608 tools/xenfb/sdlfb.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/sdlfb.c       Wed Nov 08 11:35:54 2006 +0100
@@ -0,0 +1,337 @@
+#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' },
+};
+
+int main(int argc, char **argv)
+{
+       struct xenfb *xenfb;
+       int fd;
+       int domid = -1;
+        char * title = NULL;
+       fd_set readfds;
+       struct SDLFBData data;
+       SDL_Rect r;
+       struct timeval tv;
+       SDL_Event event;
+       int do_quit = 0;
+       int opt;
+       char *endp;
+
+       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;
+                }
+        }
+        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)) {
+               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);
+       }
+
+       fd = xenfb_get_fileno(xenfb);
+
+       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 fd 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);
+               FD_SET(fd, &readfds);
+               tv = (struct timeval){0, 10000};
+
+               if (select(fd + 1, &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;
+
+               if (FD_ISSET(fd, &readfds))
+                       xenfb_on_incoming(xenfb);
+       }
+
+       xenfb_delete(xenfb);
+
+       SDL_Quit();
+
+       return 0;
+}
diff -r c677f4e75608 tools/xenfb/vncfb.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/vncfb.c       Mon Nov 13 15:00:47 2006 +0100
@@ -0,0 +1,396 @@
+#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' },
+};
+
+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 fd;
+       char portstr[10];
+       char *endp;
+
+       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;
+                }
+        }
+        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)) {
+               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 = (char *)xenfb->pixels;
+       server->screenData = xenfb;
+       server->cursor = NULL;
+       rfbInitServer(server);
+
+       rfbRunEventLoop(server, -1, true);
+
+       fd = xenfb_get_fileno(xenfb);
+
+        xenstore_write_vncport(server->port, domid);
+
+       for (;;) {
+               FD_ZERO(&readfds);
+               FD_SET(fd, &readfds);
+
+               if (select(fd + 1, &readfds, NULL, NULL, NULL) < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       fprintf(stderr,
+                               "Can't select() on event channel (%s)\n",
+                               strerror(errno));
+                       break;
+               }
+
+               if (FD_ISSET(fd, &readfds))
+                       xenfb_on_incoming(xenfb);
+       }
+
+       rfbScreenCleanup(server);
+       xenfb_delete(xenfb);
+
+       return 0;
+}
diff -r c677f4e75608 tools/xenfb/xenfb.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/xenfb.c       Fri Nov 17 11:16:32 2006 +0100
@@ -0,0 +1,619 @@
+#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/xenfb.h>
+#include <xen/io/xenkbd.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_private
+{
+       struct xenfb pub;
+       int domid;
+       evtchn_port_t fbdev_port, kbd_port;
+       int evt_xch;
+       int xc;
+       unsigned char *fb;
+       size_t fb_len;
+       struct xenfb_page *fb_info;
+       struct xenkbd_page *kbd_info;
+};
+
+struct xenfb *xenfb_new(void)
+{
+       struct xenfb_private *xenfb = malloc(sizeof(*xenfb));
+
+       if (xenfb == NULL)
+               return NULL;
+
+       memset(xenfb, 0, sizeof(*xenfb));
+
+       xenfb->domid = -1;
+
+       xenfb->evt_xch = xc_evtchn_open();
+       if (xenfb->evt_xch == -1) {
+               int serrno = errno;
+               free(xenfb);
+               errno = serrno;
+               return NULL;
+       }
+
+       xenfb->xc = xc_interface_open();
+       if (xenfb->xc == -1) {
+               int serrno = errno;
+               xc_evtchn_close(xenfb->evt_xch);
+               free(xenfb);
+               errno = serrno;
+               return NULL;
+       }
+
+       return &xenfb->pub;
+}
+
+int xenfb_get_fileno(struct xenfb *xenfb_pub)
+{
+       struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+
+       return xc_evtchn_fd(xenfb->evt_xch);
+}
+
+static void xenfb_detach_dom(struct xenfb_private *xenfb)
+{
+       xenfb->domid = -1;
+       munmap(xenfb->fb, xenfb->fb_len);
+       munmap(xenfb->fb_info, XC_PAGE_SIZE);
+       munmap(xenfb->kbd_info, XC_PAGE_SIZE);
+       xc_evtchn_unbind(xenfb->evt_xch, xenfb->fbdev_port);
+       xc_evtchn_unbind(xenfb->evt_xch, xenfb->kbd_port);
+}
+
+void xenfb_delete(struct xenfb *xenfb_pub)
+{
+       struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+       if (xenfb->domid != -1)
+               xenfb_detach_dom(xenfb);
+       free(xenfb);
+}
+
+static int xenfb_kbd_event(struct xenfb_private *xenfb,
+                          union xenkbd_in_event *event)
+{
+       uint32_t prod;
+       struct xenkbd_page *info = xenfb->kbd_info;
+
+       prod = info->in_prod;
+       if (prod - info->in_cons == XENKBD_IN_RING_LEN) {
+               errno = EAGAIN;
+               return -1;
+       }
+
+       mb();                   /* ensure ring space available */
+       XENKBD_IN_RING_REF(info, prod) = *event;
+       wmb();                  /* ensure ring contents visible */
+       info->in_prod = prod + 1;
+       return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd_port);
+}
+
+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_dev_fatal(struct xs_handle *xsh, unsigned domid,
+                           const char *dir, int err, const char *fmt, ...)
+{
+       va_list ap;
+       char errdir[80];
+       char buf[1024];
+       int n;
+
+       fprintf(stderr, "%s ", dir); /* 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), domid,
+                              "error/%s", dir))
+               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_xs_printf(xsh, dir, "state", "%d", XenbusStateClosing);
+}
+
+static int xenfb_wait_for_state(struct xs_handle *xsh, const char *dir,
+                               unsigned awaited)
+{
+       int ret;
+       unsigned state, dummy;
+       char **vec;
+
+       for (;;) {
+               ret = xenfb_xs_scanf1(xsh, dir, "state", "%u", &state);
+               if (ret < 0 && errno != -ENOENT)
+                       return ret;
+               if (state > XenbusStateClosed)
+                       state = XenbusStateUnknown;
+               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 xs_handle *xsh,
+                                          const char *backdir)
+{
+       if (!xs_watch(xsh, backdir, ""))
+               return -1;
+
+       switch (xenfb_wait_for_state(xsh, backdir,
+                       (1 << XenbusStateInitialising)
+                       | (1 << XenbusStateClosed)
+#if 1 /* TODO fudging state to permit restarting; to be removed */
+                       | (1 << XenbusStateInitWait)
+                       | (1 << XenbusStateConnected)
+                       | (1 << XenbusStateClosing)
+#endif
+                       )) {
+#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;
+       }
+
+       xs_unwatch(xsh, backdir, "");
+       return 0;
+}
+
+static int xenfb_hotplug(struct xs_handle *xsh, const char *backdir)
+{
+       printf("Hotplugging %s\n", backdir);
+       if (xenfb_xs_printf(xsh, backdir, "hotplug-status", "connected"))
+               return -1;
+       return 0;
+}
+
+static int xenfb_wait_for_frontend_initialised(struct xs_handle *xsh,
+                                              const char *frontdir)
+{
+       switch (xenfb_wait_for_state(xsh, frontdir,
+#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_wait_for_frontend_connected(struct xs_handle *xsh,
+                                            const char *frontdir)
+{
+       switch (xenfb_wait_for_state(xsh, frontdir,
+                                    1 << XenbusStateConnected)) {
+       case XenbusStateConnected:
+               break;
+       default:
+               return -1;
+       }
+
+       return 0;
+}
+
+static int xenfb_get_connection(struct xs_handle *xsh, const char *frontdir,
+                               unsigned long *mfn, int *evtchn)
+{
+       if (xenfb_xs_scanf1(xsh, frontdir, "page-ref", "%lu", mfn) < 0)
+               return -1;
+       if (xenfb_xs_scanf1(xsh, frontdir, "event-channel", "%u", evtchn)
+           < 0)
+               return -1;
+       return 0;
+}
+
+bool xenfb_attach_dom(struct xenfb *xenfb_pub, int domid)
+{
+       struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+       char vfb_frontdir[64], vfb_backdir[64];
+       char vkbd_frontdir[64], vkbd_backdir[64];
+       struct xs_handle *xsh;
+       int ret, val;
+       int n_fbmfns;
+       int n_fbdirs = 0;
+       unsigned long *fbmfns = NULL;
+        int serrno;
+        int fbdev_evtchn, kbd_evtchn;
+       unsigned long fbdev_mfn, kbd_mfn;
+
+       if (xenfb->domid != -1) {
+               xenfb_detach_dom(xenfb);
+               if (domid == -1)
+                       return true;
+       }
+
+       xsh = xs_daemon_open();
+       if (!xsh)
+               goto error;
+
+       if (!xenfb_path_in_dom(xsh, vfb_frontdir, sizeof(vfb_frontdir),
+                              domid, "device/vfb/0")) {
+               errno = -ENOENT;
+               goto error;
+       }
+       if (!xenfb_path_in_dom(xsh, vfb_backdir, sizeof(vfb_backdir),
+                              0, "backend/vfb/%d/0", domid)) {
+               errno = -ENOENT;
+               goto error;
+       }
+       if (!xenfb_path_in_dom(xsh, vkbd_frontdir, sizeof(vkbd_frontdir),
+                              domid, "device/vkbd/0")) {
+               errno = -ENOENT;
+               goto error;
+       }
+       if (!xenfb_path_in_dom(xsh, vkbd_backdir, sizeof(vkbd_backdir),
+                              0, "backend/vkbd/%d/0", domid)) {
+               errno = -ENOENT;
+               goto error;
+       }
+
+       if (xenfb_wait_for_backend_creation(xsh, vfb_backdir) < 0)
+               goto error;
+       if (xenfb_wait_for_backend_creation(xsh, vkbd_backdir) < 0)
+               goto error;
+
+       if (xenfb_xs_printf(xsh, vkbd_backdir, "feature-abs-pointer", "1"))
+               goto error;
+
+       if (xenfb_xs_printf(xsh, vfb_backdir, "state", "%d",
+                           XenbusStateInitWait))
+               goto error;
+       if (xenfb_xs_printf(xsh, vkbd_backdir, "state", "%d",
+                           XenbusStateInitWait))
+               goto error;
+
+       if (xenfb_hotplug(xsh, vfb_backdir) < 0)
+               goto error;
+       if (xenfb_hotplug(xsh, vkbd_backdir) < 0)
+               goto error;
+
+       if (!xs_watch(xsh, vfb_frontdir, ""))
+               goto error;
+       if (!xs_watch(xsh, vkbd_frontdir, ""))
+               goto error;
+
+       if (xenfb_wait_for_frontend_initialised(xsh, vfb_frontdir) < 0)
+               goto error;
+       if (xenfb_wait_for_frontend_initialised(xsh, vkbd_frontdir) < 0)
+               goto error;
+
+       if (xenfb_get_connection(xsh, vfb_frontdir, &fbdev_mfn, &fbdev_evtchn)
+           < 0)
+               goto error;
+       if (xenfb_get_connection(xsh, vkbd_frontdir, &kbd_mfn, &kbd_evtchn)
+           < 0)
+               goto error;
+
+       if (xenfb_xs_scanf1(xsh, vfb_frontdir, "feature-update",
+                           "%d", &val) < 0)
+               val = 0;
+       if (!val) {
+               errno = ENOTSUP;
+               goto error;
+       }
+       xenfb_xs_printf(xsh, vfb_backdir, "request-update", "1");
+
+       xenfb->fbdev_port = xc_evtchn_bind_interdomain(xenfb->evt_xch, domid,
+                                                      fbdev_evtchn);
+       if (xenfb->fbdev_port == -1)
+               goto error;
+
+       xenfb->kbd_port = xc_evtchn_bind_interdomain(xenfb->evt_xch, domid,
+                                                    kbd_evtchn);
+       if (xenfb->kbd_port == -1) 
+               goto error;
+
+       ret = xc_domain_translate_gpfn_list(xenfb->xc, domid, 1,
+                                           &fbdev_mfn, &fbdev_mfn);
+       if (ret < 0 && errno != EINVAL)
+               goto error;
+       xenfb->fb_info = xc_map_foreign_range(xenfb->xc, domid, XC_PAGE_SIZE,
+                                             PROT_READ | PROT_WRITE,
+                                             fbdev_mfn);
+       if (xenfb->fb_info == NULL)
+               goto error;
+
+       xenfb->kbd_info = xc_map_foreign_range(xenfb->xc, domid, XC_PAGE_SIZE,
+                                              PROT_READ | PROT_WRITE,
+                                              kbd_mfn);
+       if (xenfb->kbd_info == NULL)
+               goto error;
+
+       /* TODO check for permitted ranges */
+       xenfb->pub.depth = xenfb->fb_info->depth;
+       xenfb->pub.width = xenfb->fb_info->width;
+       xenfb->pub.height = xenfb->fb_info->height;
+       /* TODO check for consistency with the above */
+       xenfb->fb_len = xenfb->fb_info->mem_length;
+       xenfb->pub.row_stride = xenfb->fb_info->line_length;
+
+       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, 
xenfb->fb_info->pd, n_fbdirs);
+       if (fbmfns == NULL)
+               goto error;
+
+       xenfb->fb = xc_map_foreign_batch(xenfb->xc, domid, PROT_READ | 
PROT_WRITE, fbmfns, n_fbmfns);
+       if (xenfb->fb == NULL)
+               goto error;
+
+       if (xenfb_xs_printf(xsh, vfb_backdir, "state", "%d",
+                           XenbusStateConnected))
+               goto error;
+       if (xenfb_xs_printf(xsh, vkbd_backdir, "state", "%d",
+                           XenbusStateConnected))
+               goto error;
+
+       if (xenfb_wait_for_frontend_connected(xsh, vkbd_frontdir) < 0)
+               goto error;
+       if (xenfb_xs_scanf1(xsh, vkbd_frontdir, "request-abs-pointer",
+                           "%d", &val) < 0)
+               val = 0;
+       xenfb->pub.abs_pointer_wanted = val;
+
+       xs_daemon_close(xsh);
+       xsh = NULL;
+
+       munmap(fbmfns, n_fbdirs * XC_PAGE_SIZE);
+
+       xenfb->domid = domid;
+
+       xenfb->pub.pixels = xenfb->fb;
+
+       return true;
+
+ error:
+       serrno = errno;
+       if (xenfb->fb)
+               munmap(xenfb->fb, xenfb->fb_len);
+       if (fbmfns)
+               munmap(fbmfns, n_fbdirs * XC_PAGE_SIZE);
+        if (xenfb->kbd_info)
+               munmap(xenfb->kbd_info, XC_PAGE_SIZE);
+        if (xenfb->fb_info)
+               munmap(xenfb->fb_info, XC_PAGE_SIZE);
+        if (xenfb->kbd_port);
+       xc_evtchn_unbind(xenfb->evt_xch, xenfb->kbd_port);
+        if (xenfb->fbdev_port)
+               xc_evtchn_unbind(xenfb->evt_xch, xenfb->fbdev_port);
+       xenfb_dev_fatal(xsh, domid, vfb_backdir, serrno, "on fire");
+       xenfb_dev_fatal(xsh, domid, vkbd_backdir, serrno, "on fire");
+        if (xsh) 
+               xs_daemon_close(xsh);
+        errno = serrno;
+        return false;
+}
+
+static void xenfb_on_fb_event(struct xenfb_private *xenfb)
+{
+       uint32_t prod, cons;
+       struct xenfb_page *info = xenfb->fb_info;
+
+       prod = info->out_prod;
+       if (prod == info->out_cons)
+               return;
+       rmb();                  /* ensure we see ring contents up to prod */
+       for (cons = info->out_cons; cons != prod; cons++) {
+               union xenfb_out_event *event = &XENFB_OUT_RING_REF(info, 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 */
+       info->out_cons = cons;
+       xc_evtchn_notify(xenfb->evt_xch, xenfb->fbdev_port);
+}
+
+static void xenfb_on_kbd_event(struct xenfb_private *xenfb)
+{
+       struct xenkbd_page *info = xenfb->kbd_info;
+
+       /* We don't understand any keyboard events, so just ignore them. */
+       if (info->out_prod == info->out_cons)
+               return;
+       info->out_cons = info->out_prod;
+       xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd_port);
+}
+
+int xenfb_on_incoming(struct xenfb *xenfb_pub)
+{
+       struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+       evtchn_port_t port;
+
+       port = xc_evtchn_pending(xenfb->evt_xch);
+       if (port == -1)
+               return -1;
+
+       if (port == xenfb->fbdev_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;
+
+       return 0;
+}
+
+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 c677f4e75608 tools/xenfb/xenfb.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/xenfb.h       Wed Nov 08 09:26:08 2006 +0100
@@ -0,0 +1,34 @@
+#ifndef _XENFB_H_
+#define _XENFB_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+struct xenfb
+{
+       uint8_t *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);
+
+bool xenfb_attach_dom(struct xenfb *xenfb, int domid);
+
+int xenfb_get_fileno(struct xenfb *xenfb);
+int xenfb_on_incoming(struct xenfb *xenfb);
+
+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

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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.