All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Paravirt framebuffer backend tools [2/5]
@ 2006-09-02 19:58 Jeremy Katz
  2006-09-04  9:01 ` Steven Smith
  2006-09-12 18:55 ` Daniel P. Berrange
  0 siblings, 2 replies; 42+ messages in thread
From: Jeremy Katz @ 2006-09-02 19:58 UTC (permalink / raw)
  To: xen-devel; +Cc: aliguori, Markus Armbruster

[-- Attachment #1: Type: text/plain, Size: 460 bytes --]

Initially from Anthony Liguori and then modified for
* Integration with xenstore (armrbu)
* Adding option parsing (katzj)
* Integration with Xen makefiles 
* Error handling (armbru)
* Future-proof layout of shared page (armbru)
* Memory barriers (armbru)
* Support for vncunused and vnclisten as support in qemu-dm vnc (katzj)

Signed-off-by: Jeremy Katz <katzj@redhat.com>
Cc: Markus Armbruster <armbru@redhat.com>
Cc: Anthony Liguori <aliguori@us.ibm.com>



[-- Attachment #2: xen-pvfb-2.patch --]
[-- Type: text/x-patch, Size: 27130 bytes --]

--- a/tools/Makefile	Sat Sep 02 15:11:17 2006 -0400
+++ b/tools/Makefile	Sat Sep 02 15:19:25 2006 -0400
@@ -18,6 +18,7 @@ SUBDIRS-y += xenstat
 SUBDIRS-y += xenstat
 SUBDIRS-y += libaio
 SUBDIRS-y += blktap
+SUBDIRS-y += xenfb
 
 # These don't cross-compile
 ifeq ($(XEN_COMPILE_ARCH),$(XEN_TARGET_ARCH))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/Makefile	Sat Sep 02 15:19:25 2006 -0400
@@ -0,0 +1,36 @@
+XEN_ROOT=../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+CFLAGS += -g -Wall
+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
+
+keymapping.o: CFLAGS += $(shell pkg-config --cflags gtk+-2.0)
+
+vncfb: vncfb.o xenfb.o keymapping.o
+vncfb.o: CFLAGS += $(shell libvncserver-config --cflags)
+vncfb: LDLIBS += $(shell libvncserver-config --libs) -lxenctrl -lxenstore
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/keymapping.c	Sat Sep 02 15:19:25 2006 -0400
@@ -0,0 +1,141 @@
+#include <stdint.h>
+#include <gdk/gdkkeysyms.h>
+#include <linux/input.h>
+
+uint32_t gdk_linux_mapping[0x10000] = {
+	[GDK_a] = KEY_A,
+	[GDK_b] = KEY_B,
+	[GDK_c] = KEY_C,
+	[GDK_d] = KEY_D,
+	[GDK_e] = KEY_E,
+	[GDK_f] = KEY_F,
+	[GDK_g] = KEY_G,
+	[GDK_h] = KEY_H,
+	[GDK_i] = KEY_I,
+	[GDK_j] = KEY_J,
+	[GDK_k] = KEY_K,
+	[GDK_l] = KEY_L,
+	[GDK_m] = KEY_M,
+	[GDK_n] = KEY_N,
+	[GDK_o] = KEY_O,
+	[GDK_p] = KEY_P,
+	[GDK_q] = KEY_Q,
+	[GDK_r] = KEY_R,
+	[GDK_s] = KEY_S,
+	[GDK_t] = KEY_T,
+	[GDK_u] = KEY_U,
+	[GDK_v] = KEY_V,
+	[GDK_w] = KEY_W,
+	[GDK_x] = KEY_X,
+	[GDK_y] = KEY_Y,
+	[GDK_z] = KEY_Z,
+	[GDK_A] = KEY_A,
+	[GDK_B] = KEY_B,
+	[GDK_C] = KEY_C,
+	[GDK_D] = KEY_D,
+	[GDK_E] = KEY_E,
+	[GDK_F] = KEY_F,
+	[GDK_G] = KEY_G,
+	[GDK_H] = KEY_H,
+	[GDK_I] = KEY_I,
+	[GDK_J] = KEY_J,
+	[GDK_K] = KEY_K,
+	[GDK_L] = KEY_L,
+	[GDK_M] = KEY_M,
+	[GDK_N] = KEY_N,
+	[GDK_O] = KEY_O,
+	[GDK_P] = KEY_P,
+	[GDK_Q] = KEY_Q,
+	[GDK_R] = KEY_R,
+	[GDK_S] = KEY_S,
+	[GDK_T] = KEY_T,
+	[GDK_U] = KEY_U,
+	[GDK_V] = KEY_V,
+	[GDK_W] = KEY_W,
+	[GDK_X] = KEY_X,
+	[GDK_Y] = KEY_Y,
+	[GDK_Z] = KEY_Z,
+	[GDK_0] = KEY_0,
+	[GDK_1] = KEY_1,
+	[GDK_2] = KEY_2,
+	[GDK_3] = KEY_3,
+	[GDK_4] = KEY_4,
+	[GDK_5] = KEY_5,
+	[GDK_6] = KEY_6,
+	[GDK_7] = KEY_7,
+	[GDK_8] = KEY_8,
+	[GDK_9] = KEY_9,
+	[GDK_Return] = KEY_ENTER,
+	[GDK_BackSpace] = KEY_BACKSPACE,
+	[GDK_Tab] = KEY_TAB,
+	[GDK_Pause] = KEY_PAUSE,
+	[GDK_Delete] = KEY_DELETE,
+	[GDK_slash] = KEY_SLASH,
+	[GDK_minus] = KEY_MINUS,
+	[GDK_equal] = KEY_EQUAL,
+	[GDK_Escape] = KEY_ESC,
+	[GDK_braceleft] = KEY_LEFTBRACE,
+	[GDK_braceright] = KEY_RIGHTBRACE,
+	[GDK_bracketleft] = KEY_LEFTMETA,
+	[GDK_bracketright] = KEY_RIGHTMETA,
+	[GDK_Control_L] = KEY_LEFTCTRL,
+	[GDK_Control_R] = KEY_RIGHTCTRL,
+	[GDK_Shift_L] = KEY_LEFTSHIFT,
+	[GDK_Shift_R] = KEY_RIGHTSHIFT,
+	[GDK_Alt_L] = KEY_LEFTALT,
+	[GDK_Alt_R] = KEY_RIGHTALT,
+	[GDK_semicolon] = KEY_SEMICOLON, 
+	[GDK_apostrophe] = KEY_APOSTROPHE,
+	[GDK_grave] = KEY_GRAVE,
+	[GDK_backslash] = KEY_BACKSLASH,
+	[GDK_comma] = KEY_COMMA,
+	[GDK_period] = KEY_DOT,
+	[GDK_space] = KEY_SPACE,
+	[GDK_Caps_Lock] = KEY_CAPSLOCK,
+	[GDK_Num_Lock] = KEY_NUMLOCK,
+	[GDK_Scroll_Lock] = KEY_SCROLLLOCK,
+	[GDK_Sys_Req] = KEY_SYSRQ,
+	[GDK_Linefeed] = KEY_LINEFEED,
+	[GDK_Home] = KEY_HOME,
+	[GDK_Pause] = KEY_PAUSE,
+	[GDK_F1] = KEY_F1,
+	[GDK_F2] = KEY_F2,
+	[GDK_F3] = KEY_F3,
+	[GDK_F4] = KEY_F4,
+	[GDK_F5] = KEY_F5,
+	[GDK_F6] = KEY_F6,
+	[GDK_F7] = KEY_F7,
+	[GDK_F8] = KEY_F8,
+	[GDK_F9] = KEY_F9,
+	[GDK_F10] = KEY_F10,
+	[GDK_F11] = KEY_F11,
+	[GDK_F12] = KEY_F12,
+	[GDK_Up] = KEY_UP,
+	[GDK_Page_Up] = KEY_PAGEUP,
+	[GDK_Left] = KEY_LEFT,
+	[GDK_Right] = KEY_RIGHT,
+	[GDK_End] = KEY_END,
+	[GDK_Down] = KEY_DOWN,
+	[GDK_Page_Down] = KEY_PAGEDOWN,
+	[GDK_Insert] = KEY_INSERT, 
+	[GDK_colon] = KEY_SEMICOLON,
+	[GDK_quotedbl] = KEY_APOSTROPHE,
+	[GDK_less] = KEY_COMMA,
+	[GDK_greater] = KEY_DOT,
+	[GDK_question] = KEY_SLASH,
+	[GDK_bar] = KEY_BACKSLASH,
+	[GDK_asciitilde] = KEY_GRAVE,
+	[GDK_exclam] = KEY_1,
+	[GDK_at] = KEY_2,
+	[GDK_numbersign] = KEY_3,
+	[GDK_dollar] = KEY_4,
+	[GDK_percent] = KEY_5,
+	[GDK_asciicircum] = KEY_6,
+	[GDK_ampersand] = KEY_7,
+	[GDK_asterisk] = KEY_8,
+	[GDK_parenleft] = KEY_9,
+	[GDK_parenright] = KEY_0,
+	[GDK_underscore] = KEY_MINUS,
+	[GDK_plus] = KEY_EQUAL,
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/sdlfb.c	Sat Sep 02 15:19:25 2006 -0400
@@ -0,0 +1,191 @@
+#include <SDL.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 data
+{
+	SDL_Surface *dst;
+	SDL_Surface *src;
+};
+
+void sdl_update(struct xenfb *xenfb, int x, int y, int width, int height)
+{
+	struct data *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);
+}
+
+int sdl2linux[1024] = {
+	[SDLK_a] = KEY_A,
+	[SDLK_b] = KEY_B,
+	[SDLK_c] = KEY_C,
+	[SDLK_d] = KEY_D,
+	[SDLK_e] = KEY_E,
+	[SDLK_f] = KEY_F,
+	[SDLK_g] = KEY_G,
+	[SDLK_h] = KEY_H,
+	[SDLK_i] = KEY_I,
+	[SDLK_j] = KEY_J,
+	[SDLK_k] = KEY_K,
+	[SDLK_l] = KEY_L,
+	[SDLK_m] = KEY_M,
+	[SDLK_n] = KEY_N,
+	[SDLK_o] = KEY_O,
+	[SDLK_p] = KEY_P,
+	[SDLK_q] = KEY_Q,
+	[SDLK_r] = KEY_R,
+	[SDLK_s] = KEY_S,
+	[SDLK_t] = KEY_T,
+	[SDLK_u] = KEY_U,
+	[SDLK_v] = KEY_V,
+	[SDLK_w] = KEY_W,
+	[SDLK_x] = KEY_X,
+	[SDLK_y] = KEY_Y,
+	[SDLK_z] = KEY_Z,
+	[SDLK_0] = KEY_0,
+	[SDLK_1] = KEY_1,
+	[SDLK_2] = KEY_2,
+	[SDLK_3] = KEY_3,
+	[SDLK_4] = KEY_4,
+	[SDLK_5] = KEY_5,
+	[SDLK_6] = KEY_6,
+	[SDLK_7] = KEY_7,
+	[SDLK_8] = KEY_8,
+	[SDLK_9] = KEY_9,
+	[SDLK_SPACE] = KEY_SPACE,
+	[SDLK_RETURN] = KEY_ENTER,
+	[SDLK_PERIOD] = KEY_DOT,
+	[SDLK_SLASH] = KEY_SLASH,
+	[SDLK_BACKSPACE] = KEY_BACKSPACE,
+	[SDLK_TAB] = KEY_TAB,
+	[SDLK_LSHIFT] = KEY_LEFTSHIFT,
+	[SDLK_RSHIFT] = KEY_RIGHTSHIFT,
+	[SDLK_LALT] = KEY_LEFTALT,
+	[SDLK_RALT] = KEY_RIGHTALT,
+};
+
+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 data data;
+	SDL_Rect r;
+	struct timeval tv = { 0, 500 };
+	int do_quit = 0;
+        int opt;
+
+	while ((opt = getopt_long(argc, argv, "d:t:", options,
+				  NULL)) != -1) {
+		switch (opt) {
+                case 'd':
+                    domid = strtol(optarg, NULL, 10);
+                    break;
+                case 't':
+                    title = strdup(optarg);
+                    break;
+                }
+        }
+        if (optind != argc) {
+            fprintf(stderr, "Invalid options!\n");
+            exit(1);
+        }
+        if (domid == -1) {
+            fprintf(stderr, "Domain ID must be specified!\n");
+            exit(1);
+        }
+
+	xenfb = xenfb_new();
+	if (xenfb == NULL)
+		return 1;
+
+	if (!xenfb_attach_dom(xenfb, domid))
+		return 1;
+
+	SDL_Init(SDL_INIT_VIDEO);
+
+	fd = xenfb_get_fileno(xenfb);
+
+	data.dst = SDL_SetVideoMode(xenfb->width, xenfb->height, xenfb->depth,
+				    SDL_SWSURFACE);
+
+	data.src = SDL_CreateRGBSurfaceFrom(xenfb->pixels,
+					    xenfb->width, xenfb->height,
+					    xenfb->depth, xenfb->row_stride,
+					    0xFF0000, 0xFF00, 0xFF, 0);
+
+        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;
+
+	FD_ZERO(&readfds);
+	FD_SET(fd, &readfds);
+
+	SDL_ShowCursor(0);
+
+	while (!do_quit && select(fd + 1, &readfds, NULL, NULL, &tv) != -1) {
+		SDL_Event event;
+
+		while (SDL_PollEvent(&event)) {
+			switch (event.type) {
+			case SDL_KEYDOWN:
+			case SDL_KEYUP:
+				xenfb_send_key(xenfb,
+					       event.type == SDL_KEYDOWN,
+					       sdl2linux[event.key.keysym.sym]);
+				break;
+			case SDL_MOUSEMOTION: {
+				int x, y;
+				Uint8 button;
+
+				button = SDL_GetRelativeMouseState(&x, &y);
+				xenfb_send_motion(xenfb, x, y);
+			}	break;
+			case SDL_MOUSEBUTTONDOWN:
+			case SDL_MOUSEBUTTONUP:
+				xenfb_send_button(xenfb,
+						  event.type==SDL_MOUSEBUTTONDOWN,
+						  3 - event.button.button);
+				break;
+			case SDL_QUIT:
+				do_quit = 1;
+				break;
+			}
+		}
+		if (FD_ISSET(fd, &readfds))
+			xenfb_on_incoming(xenfb);
+
+		FD_ZERO(&readfds);
+		FD_SET(fd, &readfds);
+
+		tv = (struct timeval){0, 500};
+	}
+
+	xenfb_delete(xenfb);
+
+	SDL_Quit();
+
+	return 0;
+}
--- b/tools/xenfb/vncfb.c	Sat Sep 02 15:19:25 2006 -0400
+++ b/tools/xenfb/vncfb.c	Sat Sep 02 15:22:19 2006 -0400
@@ -0,0 +1,245 @@
+#define _GNU_SOURCE
+#include <errno.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <rfb/rfb.h>
+#include <xs.h>
+#include "xenfb.h"
+
+static void on_kbd_event(rfbBool down, rfbKeySym keycode, rfbClientPtr cl)
+{
+	extern uint32_t gdk_linux_mapping[0x10000];
+	rfbScreenInfoPtr server = cl->screen;
+	struct xenfb *xenfb = server->screenData;
+	xenfb_send_key(xenfb, down, gdk_linux_mapping[keycode & 0xFFFF]);
+}
+
+static void on_ptr_event(int buttonMask, int x, int y, rfbClientPtr cl)
+{
+	static int last_x = -1, last_y = -1;
+	static int last_button = -1;
+	rfbScreenInfoPtr server = cl->screen;
+	struct xenfb *xenfb = server->screenData;
+
+	if (last_button != -1) {
+		int i;
+
+		for (i = 0; i < 8; i++) {
+			if ((last_button & (1 << i)) !=
+			    (buttonMask & (1 << i))) {
+				printf("%d %d\n", buttonMask & (1 << i), i);
+				xenfb_send_button(xenfb, buttonMask & (1 << i),
+						  2 - i);
+			}
+		}
+	}
+
+	if (last_x != -1)
+		xenfb_send_motion(xenfb, x - last_x, y - last_y);
+
+	last_button = buttonMask;
+
+	last_x = x;
+	last_y = y;
+}
+
+static void xenstore_write_vncport(int port, int domid)
+{
+    char *buf = NULL, *path;
+    char *portstr = NULL;
+    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, "xs_get_domain_path() error\n");
+        goto out;
+    }
+
+    buf = malloc(256);
+    if (snprintf(buf, 256, "%s/console/vnc-port", path) == -1)
+	goto out;
+
+    portstr = malloc(10);
+    if (snprintf(portstr, 10, "%d", port) == -1)
+	goto out;
+
+    if (xs_write(xsh, XBT_NULL, buf, portstr, strlen(portstr)) == 0)
+        fprintf(stderr, "xs_write() vncport failed\n");
+
+ out:
+    free(portstr);
+    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 int vnc_start_viewer(int port) 
+{
+    int pid;
+    char s[16];
+
+    snprintf(s, 16, ":%d", port);
+    switch (pid = fork()) {
+    case -1:
+	fprintf(stderr, "vncviewer failed fork\n");
+	exit(1);
+
+    case 0:	/* child */
+	execlp("vncviewer", "vncviewer", s, 0);
+	fprintf(stderr, "vncviewer execlp failed\n");
+	exit(1);
+
+    default:
+	return pid;
+    }
+}
+
+static struct option options[] = {
+    { "domid", 1, NULL, 'd' },
+    { "vncport", 1, NULL, 'p' },
+    { "title", 1, NULL, 't' },
+    { "unused", 0, NULL, 'u' },
+    { "listen", 1, NULL, 'l' },
+    { "vncviewer", 0, NULL, 'v' },
+};
+
+int main(int argc, char **argv)
+{
+	rfbScreenInfoPtr server;
+	char *fake_argv[7] = { "vncfb", "-rfbport", "5901", 
+                               "-desktop", "xen-vncfb", 
+                               "-listen", "0.0.0.0" };
+	int fake_argc = sizeof(fake_argv) / sizeof(fake_argv[0]);
+	int domid = -1, port = -1;
+        char * title = NULL;
+        char * listen = NULL;
+	struct xenfb *xenfb;
+	fd_set readfds;
+	int fd;
+	char buffer[1024];
+        int opt;
+        bool unused = FALSE;
+        bool viewer = FALSE;
+
+	while ((opt = getopt_long(argc, argv, "d:p:t:u", options,
+				  NULL)) != -1) {
+		switch (opt) {
+                case 'd':
+                    domid = strtol(optarg, NULL, 10);
+                    break;
+                case 'p':
+                    port = strtol(optarg, NULL, 10);
+                    break;
+                case 't':
+                    title = strdup(optarg);
+                    break;
+                case 'u':
+                    unused = TRUE;
+                    break;
+                case 'l':
+                    listen = strdup(optarg);
+                    break;
+                case 'v':
+                    viewer = TRUE;
+                    break;
+                case 'l':
+                    listen = strdup(optarg);
+                    break;
+                }
+        }
+        if (optind != argc) {
+            fprintf(stderr, "Invalid options!\n");
+            exit(1);
+        }
+        if (domid == -1) {
+            fprintf(stderr, "Domain ID must be specified!\n");
+            exit(1);
+        }
+            
+        if (port == -1)
+            port = 5900 + domid;
+	snprintf(buffer, sizeof(buffer), "%d", port);
+	fake_argv[2] = buffer;
+
+        if (title != NULL)
+            fake_argv[4] = title;
+
+        if (listen != NULL)
+            fake_argv[6] = listen;
+
+        if (listen != NULL)
+            fake_argv[6] = listen;
+
+	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;
+	rfbInitServer(server);
+
+	rfbRunEventLoop(server, -1, TRUE);
+
+	fd = xenfb_get_fileno(xenfb);
+
+	FD_ZERO(&readfds);
+	FD_SET(fd, &readfds);
+
+        xenstore_write_vncport(server->port, domid);
+
+        if (viewer)
+            vnc_start_viewer(server->port);
+
+	while (select(fd + 1, &readfds, NULL, NULL, NULL) != -1) {
+		if (FD_ISSET(fd, &readfds)) {
+			xenfb_on_incoming(xenfb);
+		}
+		
+		FD_ZERO(&readfds);
+		FD_SET(fd, &readfds);
+	}
+
+	rfbScreenCleanup(server);
+	xenfb_delete(xenfb);
+
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/xenfb.c	Sat Sep 02 15:19:25 2006 -0400
@@ -0,0 +1,434 @@
+#include <malloc.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <xenctrl.h>
+#include <linux/xenfb.h>
+#include <linux/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 malicous backend?
+
+struct xenfb_private
+{
+	struct xenfb pub;
+	int domid;
+	unsigned long fbdev_mfn, kbd_mfn;
+	int fbdev_evtchn, kbd_evtchn;
+	evtchn_port_t fbdev_port, kbd_port;
+	int evt_xch;
+	int xc;
+	unsigned char *fb;
+	struct xenfb_page *fb_info;
+	struct xenkbd_info *kbd_info;
+	unsigned long *fbmfns;
+	int n_fbmfns, n_fbdirs;
+};
+
+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_info->mem_length);
+	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_fb_event(struct xenfb_private *xenfb, union xenfb_in_event *event)
+{
+	uint32_t prod;
+	struct xenfb_page *info = xenfb->fb_info;
+
+	prod = info->in_prod;
+	if (prod - info->in_cons == XENFB_IN_RING_LEN) {
+	    errno = EAGAIN;
+	    return -1;
+	}
+
+	mb();			/* ensure ring space available */
+	XENFB_IN_RING_REF(info, prod) = *event;
+	wmb();			/* ensure ring contents visible */
+	info->in_prod = prod + 1;
+	return xc_evtchn_notify(xenfb->evt_xch, xenfb->fbdev_port);
+}
+
+static int xenfb_kbd_event(struct xenfb_private *xenfb, union xenkbd_in_event *event)
+{
+	uint32_t prod;
+	struct xenkbd_info *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 *h,
+			 unsigned domid, const char *path,
+			 char *buffer, size_t size)
+{
+	char *domp = xs_get_domain_path(h, domid);
+	int n = snprintf(buffer, size, "%s/%s", domp, path);
+	free(domp);
+	if (n >= size)
+		return NULL;
+	return buffer;
+}
+
+static int xenfb_xs_scanf1(struct xs_handle *xsh, unsigned domid,
+			   const char *path, const char *fmt,
+			   void *dest)
+{
+	char buffer[1024];
+	char *p;
+	int ret;
+
+	p = xenfb_path_in_dom(xsh, domid, path, buffer, sizeof(buffer));
+	p = xs_read(xsh, XBT_NULL, p, NULL);
+	if (!p)
+		return -ENOENT;
+	ret = sscanf(p, fmt, dest);
+	free(p);
+	if (ret != 1)
+		return -EDOM;
+	return 0;
+}
+
+bool xenfb_attach_dom(struct xenfb *xenfb_pub, int domid)
+{
+	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+	char buffer[1024];
+	struct xs_handle *xsh;
+	unsigned dummy;
+	int ret;
+	char *p, **vec;
+	union xenfb_in_event event;
+
+	if (xenfb->domid != -1) {
+		xenfb_detach_dom(xenfb);
+		if (domid == -1)
+			return true;
+	}
+
+	xsh = xs_daemon_open_readonly();
+	if (!xsh)
+	    goto error;
+
+	p = xenfb_path_in_dom(xsh, domid, "vfb", buffer, sizeof(buffer));
+	if (!xs_watch(xsh, p, ""))
+		goto error;
+	p = xenfb_path_in_dom(xsh, domid, "vkbd", buffer, sizeof(buffer));
+	if (!xs_watch(xsh, p, ""))
+		goto error;
+
+	for (;;) {
+		ret = xenfb_xs_scanf1(xsh, domid, "vfb/page-ref", "%lu",
+				      &xenfb->fbdev_mfn);
+		if (ret == -ENOENT || ret == -EAGAIN)
+			goto wait;
+		if (ret < 0)
+			goto error;
+		ret = xenfb_xs_scanf1(xsh, domid, "vfb/event-channel", "%u",
+				      &xenfb->fbdev_evtchn);
+		if (ret == -ENOENT || ret == -EAGAIN)
+			goto wait;
+		if (ret < 0)
+			goto error;
+		ret = xenfb_xs_scanf1(xsh, domid, "vkbd/page-ref", "%lu",
+				      &xenfb->kbd_mfn);
+		if (ret == -ENOENT || ret == -EAGAIN)
+			goto wait;
+		if (ret < 0)
+			goto error;
+		ret = xenfb_xs_scanf1(xsh, domid, "vkbd/event-channel", "%u",
+				      &xenfb->kbd_evtchn);
+		if (ret == -ENOENT || ret == -EAGAIN)
+			goto wait;
+		if (ret < 0)
+			goto error;
+		break;
+
+	wait:
+		printf("Waiting...\n");
+		vec = xs_read_watch(xsh, &dummy);
+		if (!vec)
+			goto error;
+		free(vec);
+	}
+	xs_daemon_close(xsh);
+	xsh = NULL;
+
+	xenfb->fbdev_port = xc_evtchn_bind_interdomain(xenfb->evt_xch, domid,
+						       xenfb->fbdev_evtchn);
+	if (xenfb->fbdev_port == -1)
+		goto error;
+
+	xenfb->kbd_port = xc_evtchn_bind_interdomain(xenfb->evt_xch, domid,
+						     xenfb->kbd_evtchn);
+	if (xenfb->kbd_port == -1) 
+		goto error_fbdev;
+
+	xenfb->fb_info = xc_map_foreign_range(xenfb->xc, domid, XC_PAGE_SIZE,
+					      PROT_READ | PROT_WRITE,
+					      xenfb->fbdev_mfn);
+	if (xenfb->fb_info == NULL)
+		goto error_kbd;
+
+	xenfb->kbd_info = xc_map_foreign_range(xenfb->xc, domid, XC_PAGE_SIZE,
+					       PROT_READ | PROT_WRITE,
+					       xenfb->kbd_mfn);
+	if (xenfb->kbd_info == NULL)
+		goto error_fbinfo;
+
+	xenfb->n_fbmfns = (xenfb->fb_info->mem_length + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
+	xenfb->n_fbdirs = xenfb->n_fbmfns * sizeof(unsigned long);
+	xenfb->n_fbdirs = (xenfb->n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
+
+	xenfb->fbmfns = xc_map_foreign_batch(xenfb->xc, domid, PROT_READ, xenfb->fb_info->pd, xenfb->n_fbdirs);
+	if (xenfb->fbmfns == NULL)
+		goto error_kbdinfo;
+
+	xenfb->fb = xc_map_foreign_batch(xenfb->xc, domid, PROT_READ | PROT_WRITE, xenfb->fbmfns, xenfb->n_fbmfns);
+	if (xenfb->fb == NULL)
+		goto error_fbmfns;
+
+	event.type = XENFB_TYPE_SET_EVENTS;
+	event.set_events.flags = XENFB_FLAG_UPDATE;
+	if (xenfb_fb_event(xenfb, &event))
+		goto error_fb;
+
+	munmap(xenfb->fbmfns, xenfb->n_fbdirs * XC_PAGE_SIZE);
+
+	xenfb->domid = domid;
+
+	xenfb->pub.pixels = xenfb->fb;
+
+	xenfb->pub.row_stride = xenfb->fb_info->line_length;
+	xenfb->pub.depth = xenfb->fb_info->depth;
+	xenfb->pub.width = xenfb->fb_info->width;
+	xenfb->pub.height = xenfb->fb_info->height;
+
+	return true;
+
+ error_fb:
+	printf("%d\n", __LINE__);
+	{
+		int serrno = errno;
+		munmap(xenfb->fb, xenfb->fb_info->mem_length);
+		errno = serrno;
+	}
+ error_fbmfns:
+	printf("%d\n", __LINE__);
+	{
+		int serrno = errno;
+		munmap(xenfb->fbmfns, xenfb->n_fbdirs * XC_PAGE_SIZE);
+		errno = serrno;
+	}
+ error_kbdinfo:
+	printf("%d\n", __LINE__);
+	{
+		int serrno = errno;
+		munmap(xenfb->kbd_info, XC_PAGE_SIZE);
+		errno = serrno;
+	}
+ error_fbinfo:
+	printf("%d\n", __LINE__);
+	{
+		int serrno = errno;
+		munmap(xenfb->fb_info, XC_PAGE_SIZE);
+		errno = serrno;
+	}
+ error_kbd:
+	printf("%d\n", __LINE__);
+	{
+		int serrno = errno;
+		xc_evtchn_unbind(xenfb->evt_xch, xenfb->kbd_port);
+		errno = serrno;
+	}
+ error_fbdev:
+	printf("%d\n", __LINE__);
+	{
+		int serrno = errno;
+		xc_evtchn_unbind(xenfb->evt_xch, xenfb->fbdev_port);
+		errno = serrno;
+	}
+ error:
+	printf("%d\n", __LINE__);
+	if (xsh) {
+		int serrno = errno;
+		xs_daemon_close(xsh);
+		errno = serrno;
+	}
+
+	return false;
+}
+
+static void xenfb_update(struct xenfb_private *xenfb, int x, int y, int width, int height)
+{
+	if (xenfb->pub.update)
+		xenfb->pub.update(&xenfb->pub, x, y, width, height);
+}
+
+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;
+	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:
+			xenfb_update(xenfb, 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;
+	// FIXME need to notify?
+}
+
+static void xenfb_on_kbd_event(struct xenfb_private *xenfb)
+{
+	uint32_t prod, cons;
+	struct xenkbd_info *info = xenfb->kbd_info;
+
+	prod = info->out_prod;
+	rmb();			/* ensure we see ring contents up to prod */
+	for (cons = info->out_cons; cons != prod; cons++) {
+		union xenkbd_out_event *event = &XENKBD_OUT_RING_REF(info, cons);
+
+		switch (event->type) {
+		default:
+			break;
+		}
+	}
+	mb();			/* ensure we're done with ring contents */
+	info->out_cons = cons;
+	// FIXME need to notify?
+}
+
+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;
+
+	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;
+
+	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_button(struct xenfb *xenfb_pub, bool down, int button)
+{
+	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+	union xenkbd_in_event event;
+
+	event.type = XENKBD_TYPE_BUTTON;
+	event.button.pressed = down ? 1 : 0;
+	event.button.button = button;
+
+	return xenfb_kbd_event(xenfb, &event);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/xenfb.h	Sat Sep 02 15:19:25 2006 -0400
@@ -0,0 +1,33 @@
+#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;
+
+	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_button(struct xenfb *xenfb, bool down, int button);
+
+#endif

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

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

^ permalink raw reply	[flat|nested] 42+ messages in thread

end of thread, other threads:[~2006-10-11 15:21 UTC | newest]

Thread overview: 42+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-09-02 19:58 [PATCH] Paravirt framebuffer backend tools [2/5] Jeremy Katz
2006-09-04  9:01 ` Steven Smith
2006-09-04 12:55   ` Laurent Vivier
2006-09-06  9:15     ` Steven Smith
2006-09-06 11:41       ` Laurent Vivier
2006-09-06 17:10         ` Steven Smith
2006-09-06 17:50           ` Gerd Hoffmann
2006-09-07  7:32             ` Laurent Vivier
2006-09-07  7:50             ` Steven Smith
2006-09-07  7:31           ` Laurent Vivier
2006-09-07  8:38             ` Steven Smith
2006-09-07  9:31               ` Laurent Vivier
2006-09-07  9:55                 ` Steven Smith
2006-09-07 12:03                   ` Laurent Vivier
2006-09-08 13:26               ` Anthony Liguori
2006-09-08 14:00                 ` Laurent Vivier
2006-09-08 14:12                 ` Steven Smith
2006-09-08 14:23                   ` Anthony Liguori
2006-10-07 16:48                     ` Markus Armbruster
2006-10-10 16:53                       ` Stephen C. Tweedie
2006-10-10 17:46                         ` Anthony Liguori
2006-10-10 17:46                         ` Anthony Liguori
2006-10-11 13:49                         ` Markus Armbruster
2006-10-11 15:18                           ` Gerd Hoffmann
2006-10-11 15:21                             ` Laurent Vivier
2006-10-10 18:48                       ` Steven Smith
2006-09-10 10:40                 ` Steven Smith
2006-09-10 13:05                   ` Anthony Liguori
2006-09-05 16:11   ` Jeremy Katz
2006-09-05 16:57     ` Anthony Liguori
2006-09-06  9:14       ` Steven Smith
2006-09-06  9:13     ` Steven Smith
2006-09-30  8:51   ` Markus Armbruster
2006-10-02  9:01     ` Steven Smith
2006-10-04 14:04       ` Markus Armbruster
2006-10-04 14:20         ` Daniel P. Berrange
2006-10-04 14:57         ` Anthony Liguori
2006-10-05 18:41           ` Steven Smith
2006-10-05 18:33         ` Steven Smith
2006-10-06 14:10           ` Markus Armbruster
2006-10-07  9:42             ` Steven Smith
2006-09-12 18:55 ` Daniel P. Berrange

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.