From: Jeremy Katz <katzj@redhat.com>
To: xen-devel <xen-devel@lists.xensource.com>
Cc: Ian Pratt <ian.pratt@xensource.com>,
Anthony Liguori <aliguori@us.ibm.com>,
Markus Armbruster <armbru@redhat.com>,
Christian Limpach <chris@xensource.com>
Subject: [PATCH] Paravirt framebuffer userspace tools [2/6]
Date: Fri, 18 Aug 2006 17:05:11 -0400 [thread overview]
Message-ID: <1155935111.11663.50.camel@aglarond.local> (raw)
[-- Attachment #1: Type: text/plain, Size: 273 bytes --]
Adds the basic userspace support for the VNC and SDL framebuffer pieces
that run in dom0. Slightly modified by me to add some option parsing
Signed-off-by: Jeremy Katz <katzj@redhat.com>
Cc: Anthony Liguori <aliguori@redhat.com>
Cc: Markus Armbruster <armbru@redhat.com>
[-- Attachment #2: xen-pvfb-2.patch --]
[-- Type: text/x-patch, Size: 25705 bytes --]
diff -r 6ca424e1867e -r 103a9f38f17f tools/Makefile
--- a/tools/Makefile Fri Aug 18 16:17:58 2006 -0400
+++ b/tools/Makefile Fri Aug 18 16:20:27 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))
diff -r 6ca424e1867e -r 103a9f38f17f tools/xenfb/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/Makefile Fri Aug 18 16:20:27 2006 -0400
@@ -0,0 +1,36 @@
+XEN_ROOT=../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+CFLAGS += -g -Wall
+CFLAGS += -I$(XEN_LIBXC) -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/lib/xen/bin
+ $(INSTALL_PROG) vncfb $(DESTDIR)/usr/lib/xen/bin/xen-vncfb
+ $(INSTALL_PROG) sdlfb $(DESTDIR)/usr/lib/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
diff -r 6ca424e1867e -r 103a9f38f17f tools/xenfb/keymapping.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/keymapping.c Fri Aug 18 16:20:27 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,
+};
+
diff -r 6ca424e1867e -r 103a9f38f17f tools/xenfb/sdlfb.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/sdlfb.c Fri Aug 18 16:20:27 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 <stdlib.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_set_domid(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;
+}
diff -r 6ca424e1867e -r 103a9f38f17f tools/xenfb/vncfb.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/vncfb.c Fri Aug 18 16:20:27 2006 -0400
@@ -0,0 +1,154 @@
+#define _GNU_SOURCE
+#include <getopt.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <rfb/rfb.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;
+}
+
+#if 0
+#define BUG() do { printf("%d\n", __LINE__); return 1; } while(0)
+#else
+extern void abort();
+#define BUG() abort();
+#endif
+
+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' },
+};
+
+int main(int argc, char **argv)
+{
+ rfbScreenInfoPtr server;
+ char *fake_argv[5] = { "vncfb", "-rfbport", "5901",
+ "-desktop", "xen-vncfb" };
+ int fake_argc = sizeof(fake_argv) / sizeof(fake_argv[0]);
+ int domid = -1, port = -1;
+ char * title = NULL;
+ struct xenfb *xenfb;
+ fd_set readfds;
+ int fd;
+ char buffer[1024];
+ int opt;
+
+ 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;
+ }
+ }
+ 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;
+
+ xenfb = xenfb_new();
+ if (xenfb == NULL)
+ BUG();
+
+ if (!xenfb_set_domid(xenfb, domid))
+ BUG();
+
+ server = rfbGetScreen(&fake_argc, fake_argv,
+ xenfb->width, xenfb->height,
+ 8, 3, xenfb->depth / 8);
+ if (server == NULL)
+ BUG();
+
+ xenfb->user_data = server;
+ xenfb->update = vnc_update;
+
+ 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);
+
+ 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;
+}
diff -r 6ca424e1867e -r 103a9f38f17f tools/xenfb/xenfb.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/xenfb.c Fri Aug 18 16:20:27 2006 -0400
@@ -0,0 +1,457 @@
+#include <malloc.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.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"
+
+struct xenfb_private
+{
+ struct xenfb pub;
+ int domid;
+ unsigned long fbdev_mfn, kbd_mfn;
+ int fbdev_evtchn, kbd_evtchn;
+ int fbdev_port, kbd_port;
+ int fd;
+ 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->fd = open("/dev/xen/evtchn", O_RDWR);
+ if (xenfb->fd == -1) {
+ int serrno = errno;
+ free(xenfb);
+ errno = serrno;
+ return NULL;
+ }
+
+ xenfb->xc = xc_interface_open();
+ if (xenfb->xc == -1) {
+ int serrno = errno;
+ close(xenfb->fd);
+ 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;
+ if (xenfb->domid == -1)
+ return -1;
+
+ return xenfb->fd;
+}
+
+static void xenfb_unset_domid(struct xenfb_private *xenfb)
+{
+ struct ioctl_evtchn_unbind unbind;
+
+ 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);
+ unbind.port = xenfb->fbdev_port;
+ ioctl(xenfb->fd, IOCTL_EVTCHN_UNBIND, &unbind);
+ unbind.port = xenfb->kbd_port;
+ ioctl(xenfb->fd, IOCTL_EVTCHN_UNBIND, &unbind);
+}
+
+void xenfb_delete(struct xenfb *xenfb_pub)
+{
+ struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+ if (xenfb->domid != -1)
+ xenfb_unset_domid(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;
+ struct ioctl_evtchn_notify notify;
+
+ prod = info->in_prod;
+ if (prod - info->in_cons == XENFB_RING_SIZE(info->in)) {
+ errno = EAGAIN;
+ return -1;
+ }
+
+ XENFB_RING_REF(info->in, prod) = *event;
+ info->in_prod = prod + 1;
+ notify.port = xenfb->fbdev_port;
+ return ioctl(xenfb->fd, IOCTL_EVTCHN_NOTIFY, ¬ify);
+}
+
+static int xenfb_kbd_event(struct xenfb_private *xenfb, union xenkbd_in_event *event)
+{
+ uint32_t prod;
+ struct xenkbd_info *info = xenfb->kbd_info;
+ struct ioctl_evtchn_notify notify;
+
+ prod = info->in_prod;
+ if (prod - info->in_cons == XENKBD_RING_SIZE(info->in)) {
+ errno = EAGAIN;
+ return -1;
+ }
+
+ XENKBD_RING_REF(info->in, prod) = *event;
+ info->in_prod = prod + 1;
+ notify.port = xenfb->kbd_port;
+ return ioctl(xenfb->fd, IOCTL_EVTCHN_NOTIFY, ¬ify);
+}
+
+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_set_domid(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;
+ struct ioctl_evtchn_bind_interdomain bind;
+
+ if (xenfb->domid != -1) {
+ xenfb_unset_domid(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;
+
+ printf("%d, %d, %d\n", xenfb->fd, xenfb->fbdev_evtchn, domid);
+
+ bind.remote_port = xenfb->fbdev_evtchn;
+ bind.remote_domain = domid;
+ xenfb->fbdev_port = ioctl(xenfb->fd, IOCTL_EVTCHN_BIND_INTERDOMAIN, &bind);
+ if (xenfb->fbdev_port == -1)
+ goto error;
+
+ bind.remote_port = xenfb->kbd_evtchn;
+ bind.remote_domain = domid;
+ xenfb->kbd_port = ioctl(xenfb->fd, IOCTL_EVTCHN_BIND_INTERDOMAIN, &bind);
+ 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;
+
+ while (!xenfb->fb_info->initialized) {
+ struct timeval tv = { 0, 10000 };
+ select(0, NULL, NULL, NULL, &tv);
+ }
+
+ 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;
+
+ {
+ union xenfb_in_event event;
+
+ 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;
+ struct ioctl_evtchn_unbind unbind;
+
+ unbind.port = xenfb->kbd_port;
+ ioctl(xenfb->fd, IOCTL_EVTCHN_UNBIND, &unbind);
+ errno = serrno;
+ }
+ error_fbdev:
+ printf("%d\n", __LINE__);
+ {
+ int serrno = errno;
+ struct ioctl_evtchn_unbind unbind;
+
+ unbind.port = xenfb->fbdev_port;
+ ioctl(xenfb->fd, IOCTL_EVTCHN_UNBIND, &unbind);
+ 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_RING_REF(info->out, cons);
+
+ switch (event->type) {
+ case XENFB_TYPE_UPDATE:
+ xenfb_update(xenfb, event->update.x, event->update.y, event->update.width, event->update.height);
+ break;
+ }
+ }
+ /* FIXME do I need a wmb() here? */
+ info->out_cons = cons;
+}
+
+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_RING_REF(info->out, cons);
+
+ switch (event->type) {
+ default:
+ break;
+ }
+ }
+ /* FIXME do I need a wmb() here? */
+ info->out_cons = cons;
+}
+
+int xenfb_on_incoming(struct xenfb *xenfb_pub)
+{
+ struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+ evtchn_port_t port;
+
+ if (read(xenfb->fd, &port, sizeof(port)) != sizeof(port))
+ return -1;
+
+ if (port == xenfb->fbdev_port) {
+ xenfb_on_fb_event(xenfb);
+ } else if (port == xenfb->kbd_port) {
+ xenfb_on_kbd_event(xenfb);
+ }
+
+ if (write(xenfb->fd, &port, sizeof(port)) != sizeof(port))
+ 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);
+}
diff -r 6ca424e1867e -r 103a9f38f17f tools/xenfb/xenfb.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/xenfb.h Fri Aug 18 16:20:27 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_set_domid(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
next reply other threads:[~2006-08-18 21:05 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-08-18 21:05 Jeremy Katz [this message]
2006-08-22 9:44 ` [PATCH] Paravirt framebuffer userspace tools [2/6] Laurent Vivier
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1155935111.11663.50.camel@aglarond.local \
--to=katzj@redhat.com \
--cc=aliguori@us.ibm.com \
--cc=armbru@redhat.com \
--cc=chris@xensource.com \
--cc=ian.pratt@xensource.com \
--cc=xen-devel@lists.xensource.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.