Blob Blame History Raw
diff -r a2618d3912e7 tools/python/xen/xend/server/vfbif.py
--- a/tools/python/xen/xend/server/vfbif.py	Mon Dec 04 19:13:55 2006 +0000
+++ b/tools/python/xen/xend/server/vfbif.py	Tue Dec 05 10:29:17 2006 +0100
@@ -50,6 +50,9 @@ class VfbifController(DevController):
             # is HVM, so qemu-dm will handle the vfb.
             return
         
+        # old frontend compatibility
+        self.vm._writeDom("console/use_graphics", "1")
+        # /old
         std_args = [ "--domid", "%d" % self.vm.getDomid(),
                      "--title", self.vm.getName() ]
         t = config.get("type", None)
diff -r 7df4d8cfba3b tools/python/xen/xm/create.py
--- a/tools/python/xen/xm/create.py	Tue Dec 05 12:42:29 2006 +0000
+++ b/tools/python/xen/xm/create.py	Thu Dec 07 15:50:07 2006 +0100
@@ -577,6 +577,24 @@ def configure_usb(config_devs, vals):
         config_devs.append(['device', config_usb])
 
 def configure_vfbs(config_devs, vals):
+    # old config compatibility
+    if vals.vfb == [] and (vals.sdl or vals.vnc):
+        if vals.vnc:
+            cfg = 'type=vnc'
+            if vals.vncdisplay:
+                cfg += ',vncdisplay=%s' % vals.vncdisplay
+            if vals.vncunused:
+                cfg += ',vncunused=%s' % vals.vncunused
+            if vals.vnclisten:
+                cfg += ',vnclisten=%s' % vals.vnclisten
+        else:
+            cfg = 'type=sdl'
+        if vals.xauthority:
+            cfg += ',xauthority=%s' % vals.xauthority
+        if vals.display:
+            cfg += ',display=%s' % vals.display
+        vals.vfb = [ cfg, ]
+    # /old
     for f in vals.vfb:
         d = comma_sep_kv_to_dict(f)
         config = ['vfb']
diff -r a2618d3912e7 tools/xenfb/Makefile
--- a/tools/xenfb/Makefile	Mon Dec 04 19:13:55 2006 +0000
+++ b/tools/xenfb/Makefile	Tue Dec 05 10:26:52 2006 +0100
@@ -13,12 +17,14 @@ all: build
 
 .PHONY: build
 build:
-	$(MAKE) vncfb sdlfb
+	$(MAKE) vncfb sdlfb vncfbo sdlfbo
 
 install: all
 	$(INSTALL_DIR) $(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
+	$(INSTALL_PROG) vncfbo $(DESTDIR)/usr/$(LIBDIR)/xen/bin/xen-vncfbo
+	$(INSTALL_PROG) sdlfbo $(DESTDIR)/usr/$(LIBDIR)/xen/bin/xen-sdlfbo
 
 sdlfb: sdlfb.o xenfb.o
 
@@ -33,3 +39,14 @@ vncfb: LDLIBS += $(shell libvncserver-co
 vncfb: LDLIBS += $(shell libvncserver-config --libs) -lxenctrl -lxenstore
 
 sdlfb.o xenfb.o vncfb.o: xenfb.h
+
+sdlfbo vncfbo:
+	$(CC) $(LDFLAGS) -o $@ $^ $(LOADLIBES) $(LDLIBS)
+
+sdlfbo: sdlfb.o oldxenfb.o
+sdlfbo: LDLIBS += $(shell sdl-config --libs) -lxenctrl -lxenstore
+
+vncfbo: vncfb.o oldxenfb.o
+vncfbo: LDLIBS += $(shell libvncserver-config --libs) -lxenctrl -lxenstore
+
+oldxenfb.o: xenfb.h oldxenfb.h oldxenkbd.h
diff -r a2618d3912e7 tools/xenfb/sdlfb.c
--- a/tools/xenfb/sdlfb.c	Tue Dec 05 12:42:29 2006 +0000
+++ b/tools/xenfb/sdlfb.c	Thu Dec 07 19:45:51 2006 +0100
@@ -212,6 +212,7 @@ int main(int argc, char **argv)
 	struct xenfb *xenfb;
 	int domid = -1;
         char * title = NULL;
+	int ret;
 	fd_set readfds;
 	int nfds;
 	struct SDLFBData data;
@@ -256,11 +257,19 @@ int main(int argc, char **argv)
 		exit(1);
         }
 
-	if (xenfb_attach_dom(xenfb, domid) < 0) {
+	ret = xenfb_attach_dom(xenfb, domid);
+	if (ret < 0) {
 		fprintf(stderr, "Could not connect to domain (%s)\n",
 			strerror(errno));
 		exit(1);
         }
+	if (ret > 0) {
+		if (xenfb_switch_to_old_protocol(argv) < 0) {
+			fprintf(stderr, "Could not switch to old protocol (%s)\n",
+				strerror(errno));
+			exit(1);
+		}
+	}
 
 	if (SDL_Init(SDL_INIT_VIDEO) < 0) {
 		fprintf(stderr, "Could not initialize SDL\n");
diff -r a2618d3912e7 tools/xenfb/vncfb.c
--- a/tools/xenfb/vncfb.c	Mon Dec 04 19:13:55 2006 +0000
+++ b/tools/xenfb/vncfb.c	Tue Dec 05 10:26:52 2006 +0100
@@ -269,6 +269,7 @@ int main(int argc, char **argv)
 	bool unused = false;
 	int opt;
 	struct xenfb *xenfb;
+	int ret;
 	fd_set readfds;
 	int nfds;
 	char portstr[10];
@@ -340,10 +341,18 @@ int main(int argc, char **argv)
 		exit(1);
 	}
 
-	if (xenfb_attach_dom(xenfb, domid) < 0) {
+	ret = xenfb_attach_dom(xenfb, domid);
+	if (ret < 0) {
 		fprintf(stderr, "Could not connect to domain (%s)\n",
 			strerror(errno));
 		exit(1);
+	}
+	if (ret > 0) {
+		if (xenfb_switch_to_old_protocol(argv) < 0) {
+			fprintf(stderr, "Could not switch to old protocol (%s)\n",
+				strerror(errno));
+			exit(1);
+		}
 	}
 
 	server = rfbGetScreen(&fake_argc, fake_argv, 
diff -r a2618d3912e7 tools/xenfb/xenfb.c
--- a/tools/xenfb/xenfb.c	Mon Dec 04 19:13:55 2006 +0000
+++ b/tools/xenfb/xenfb.c	Tue Dec 05 10:26:52 2006 +0100
@@ -290,6 +301,60 @@ static int xenfb_hotplug(struct xenfb_de
 	return 0;
 }
 
+static int xenfb_using_old_protocol(struct xenfb_private *xenfb)
+{
+	struct xs_handle *xsh = xenfb->xsh;
+	char buf[64];
+	char *p, *v, **vec;
+	enum xenbus_state state;
+	unsigned dummy;
+	int ret;
+
+	p = xenfb_path_in_dom(xsh, buf, sizeof(buf),
+			      xenfb->fb.otherend_id, "vfb/page-ref");
+	if (!xs_watch(xsh, p, ""))
+		return -1;
+
+	for (;;) {
+		state = xenfb_read_state(xsh, xenfb->fb.otherend);
+		if (state > XenbusStateInitialising) {
+			ret = 0; /* frontend talks xenbus protocol */
+			break;
+		}
+
+		v = xs_read(xsh, XBT_NULL, p, NULL);
+		free(v);
+		if (v) {
+			ret = 1; /* frontend talks old protocol */
+			break;
+		}
+
+		vec = xs_read_watch(xsh, &dummy);
+		if (!vec) {
+			ret = -1;
+			break;
+		}
+		free(vec);
+	}
+
+	xs_unwatch(xsh, p, "");
+	return ret;
+}
+
+int xenfb_switch_to_old_protocol(char **argv)
+{
+	size_t len = strlen(argv[0]);
+	char *prog;
+
+	prog = malloc(len + 2);
+	if (!prog)
+		return -1;
+	strcpy(prog, argv[0]);
+	strcpy(prog + len, "o");
+	argv[0] = prog;
+	return execv(prog, argv);
+}
+
 static int xenfb_wait_for_frontend_initialised(struct xenfb_device *dev)
 {
 	switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend,
@@ -473,6 +534,9 @@ int xenfb_attach_dom(struct xenfb *xenfb
 		goto error;
 	if (!xs_watch(xsh, xenfb->kbd.otherend, ""))
 		goto error;
+
+	if (xenfb_using_old_protocol(xenfb))
+		return 1;
 
 	if (xenfb_wait_for_frontend_initialised(&xenfb->fb) < 0)
 		goto error;
diff -r a2618d3912e7 tools/xenfb/xenfb.h
--- a/tools/xenfb/xenfb.h	Mon Dec 04 19:13:55 2006 +0000
+++ b/tools/xenfb/xenfb.h	Tue Dec 05 10:26:52 2006 +0100
@@ -32,4 +32,6 @@ int xenfb_send_motion(struct xenfb *xenf
 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);
 
+int xenfb_switch_to_old_protocol(char **);
+
 #endif
diff -r 3f0ca90351e2 tools/xenfb/oldxenfb.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/oldxenfb.c	Fri Dec 08 16:31:34 2006 +0100
@@ -0,0 +1,611 @@
+#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 "oldxenfb.h"
+#include "oldxenkbd.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 int xenfb_fb_event(struct xenfb_private *, union xenfb_in_event *);
+
+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;
+}
+
+int xenfb_switch_to_old_protocol(char **argv)
+{
+	abort();
+}
+
+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;
+	char buf[64];
+	char *p, **vec;
+	unsigned dummy;
+
+	p = xenfb_path_in_dom(xenfb->xsh, buf, sizeof(buf),
+			      dev->otherend_id, dev->devicetype);
+	if (!xs_watch(xenfb->xsh, p, ""))
+		return -1;
+	for (;;) {
+		if (xenfb_xs_scanf1(xenfb->xsh, p, "page-ref", "%lu",
+				    &mfn) < 0) {
+			if (errno == ENOENT || errno == EAGAIN)
+				goto wait;
+			return -1;
+		}
+		if (xenfb_xs_scanf1(xenfb->xsh, p, "event-channel", "%u",
+				    &evtchn) < 0) {
+			if (errno == ENOENT || errno == EAGAIN)
+				goto wait;
+			return -1;
+		}
+		break;
+
+	wait:
+		printf("Waiting...\n");
+		vec = xs_read_watch(xenfb->xsh, &dummy);
+		if (!vec)
+			return -1;
+		free(vec);
+	}
+
+	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 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;
+	union xenfb_in_event event;
+
+	xenfb_detach_dom(xenfb);
+
+	xenfb_device_set_domain(&xenfb->fb, domid);
+	xenfb_device_set_domain(&xenfb->kbd, domid);
+
+	if (!xs_watch(xsh, xenfb->fb.otherend, ""))
+		goto error;
+	if (!xs_watch(xsh, xenfb->kbd.otherend, ""))
+		goto error;
+
+	if (xenfb_bind(&xenfb->fb) < 0)
+		goto error;
+	if (xenfb_bind(&xenfb->kbd) < 0)
+		goto error;
+
+	/* 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;
+
+	event.type = XENFB_TYPE_SET_EVENTS;
+	event.set_events.flags = XENFB_FLAG_UPDATE;
+	if (xenfb_fb_event(xenfb, &event))
+		goto error;
+
+	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_info *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_fb_event(struct xenfb_private *xenfb,
+			  union xenfb_in_event *event)
+{
+	uint32_t prod;
+	struct xenfb_page *page = xenfb->fb.page;
+
+	prod = page->in_prod;
+	if (prod - page->in_cons == XENFB_IN_RING_LEN) {
+		errno = EAGAIN;
+		return -1;
+	}
+
+	mb();			/* ensure ring space available */
+	XENFB_IN_RING_REF(page, prod) = *event;
+	wmb();			/* ensure ring contents visible */
+	page->in_prod = prod + 1;
+	return xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port);
+}
+
+static int xenfb_kbd_event(struct xenfb_private *xenfb,
+			   union xenkbd_in_event *event)
+{
+	uint32_t prod;
+	struct xenkbd_info *page = xenfb->kbd.page;
+
+	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)
+{
+	abort();
+}
diff -r 7df4d8cfba3b tools/xenfb/oldxenfb.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/oldxenfb.h	Tue Dec 05 10:26:52 2006 +0100
@@ -0,0 +1,108 @@
+/*
+ * linux/include/linux/xenfb.h -- Xen virtual frame buffer device
+ *
+ * Copyright (C) 2005
+ *
+ *      Anthony Liguori <aliguori@us.ibm.com>
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#ifndef _LINUX_XENFB_H
+#define _LINUX_XENFB_H
+
+#include <asm/types.h>
+
+/* out events */
+
+#define XENFB_OUT_EVENT_SIZE 40
+
+#define XENFB_TYPE_MOTION 1
+#define XENFB_TYPE_UPDATE 2
+
+struct xenfb_motion	    /* currently unused */
+{
+	__u8 type;          /* XENFB_TYPE_MOTION */
+	__u16 x;            /* The new x coordinate */
+	__u16 y;            /* The new y coordinate */
+};
+
+struct xenfb_update
+{
+	__u8 type;          /* XENFB_TYPE_UPDATE */
+	__u16 x;            /* source x */
+	__u16 y;            /* source y */
+	__u16 width;        /* rect width */
+	__u16 height;       /* rect height */
+};
+
+union xenfb_out_event
+{
+	__u8 type;
+	struct xenfb_motion motion;
+	struct xenfb_update update;
+	char _[XENFB_OUT_EVENT_SIZE];
+};
+
+/* in events */
+
+#define XENFB_IN_EVENT_SIZE 40
+
+#define XENFB_TYPE_SET_EVENTS 1
+
+#define XENFB_FLAG_MOTION 1
+#define XENFB_FLAG_UPDATE 2
+#define XENFB_FLAG_COPY 4
+#define XENFB_FLAG_FILL 8
+
+struct xenfb_set_events
+{
+	__u8 type;          /* XENFB_TYPE_SET_EVENTS */
+	__u32 flags;        /* combination of XENFB_FLAG_* */
+};
+
+union xenfb_in_event
+{
+	__u8 type;
+	struct xenfb_set_events set_events;
+	char _[XENFB_OUT_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
+{
+	__u16 width;         /* the width of the framebuffer (in pixels) */
+	__u16 height;        /* the height of the framebuffer (in pixels) */
+	__u32 line_length;   /* the length of a row of pixels (in bytes) */
+	__u32 mem_length;    /* the length of the framebuffer (in bytes) */
+	__u8 depth;          /* the depth of a pixel (in bits) */
+
+	unsigned long pd[2];	/* FIXME rename to pgdir? */
+	/* FIXME pd[1] unused at this time, shrink? */
+
+	__u32 in_cons, in_prod;
+	__u32 out_cons, out_prod;
+};
+
+void xenfb_resume(void);
+
+#endif
diff -r 7df4d8cfba3b tools/xenfb/oldxenkbd.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/oldxenkbd.h	Tue Dec 05 10:26:52 2006 +0100
@@ -0,0 +1,92 @@
+/*
+ * linux/include/linux/xenkbd.h -- Xen virtual keyboard/mouse
+ *
+ * Copyright (C) 2005
+ *
+ *      Anthony Liguori <aliguori@us.ibm.com>
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#ifndef _LINUX_XENKBD_H
+#define _LINUX_XENKBD_H
+
+#include <asm/types.h>
+
+/* in events */
+
+#define XENKBD_IN_EVENT_SIZE 40
+
+#define XENKBD_TYPE_MOTION  1     /* mouse movement event */
+#define XENKBD_TYPE_BUTTON  2     /* mouse button event */
+#define XENKBD_TYPE_KEY     3     /* keyboard event */
+
+struct xenkbd_motion
+{
+	__u8 type;         /* XENKBD_TYPE_MOTION */
+	__s16 rel_x;       /* relative X motion */
+	__s16 rel_y;       /* relative Y motion */
+};
+
+struct xenkbd_button
+{
+	__u8 type;         /* XENKBD_TYPE_BUTTON */
+	__u8 pressed;      /* 1 if pressed; 0 otherwise */
+	__u8 button;       /* the button (0, 1, 2 is right, middle, left) */
+};
+
+struct xenkbd_key
+{
+	__u8 type;         /* XENKBD_TYPE_KEY */
+	__u8 pressed;      /* 1 if pressed; 0 otherwise */
+	__u16 keycode;     /* KEY_* from linux/input.h */
+};
+
+union xenkbd_in_event
+{
+	__u8 type;
+	struct xenkbd_motion motion;
+	struct xenkbd_button button;
+	struct xenkbd_key key;
+	char _[XENKBD_IN_EVENT_SIZE];
+};
+
+/* out events */
+
+#define XENKBD_OUT_EVENT_SIZE 40
+
+union xenkbd_out_event
+{
+	__u8 type;
+	char _[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_info
+{
+	__u32 in_cons, in_prod;
+	__u32 out_cons, out_prod;
+};
+
+void xenkbd_resume(void);
+
+#endif