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
|