1123 lines
27 KiB
Diff
1123 lines
27 KiB
Diff
|
Index: xen-unstable/tools/Makefile
|
||
|
===================================================================
|
||
|
--- xen-unstable.orig/tools/Makefile
|
||
|
+++ xen-unstable/tools/Makefile
|
||
|
@@ -18,6 +18,7 @@ SUBDIRS-$(VTPM_TOOLS) += vtpm
|
||
|
SUBDIRS-y += xenstat
|
||
|
SUBDIRS-y += libaio
|
||
|
SUBDIRS-y += blktap
|
||
|
+SUBDIRS-y += xenfb
|
||
|
|
||
|
# These don't cross-compile
|
||
|
ifeq ($(XEN_COMPILE_ARCH),$(XEN_TARGET_ARCH))
|
||
|
Index: xen-unstable/tools/xenfb/Makefile
|
||
|
===================================================================
|
||
|
--- /dev/null
|
||
|
+++ xen-unstable/tools/xenfb/Makefile
|
||
|
@@ -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
|
||
|
Index: xen-unstable/tools/xenfb/keymapping.c
|
||
|
===================================================================
|
||
|
--- /dev/null
|
||
|
+++ xen-unstable/tools/xenfb/keymapping.c
|
||
|
@@ -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,
|
||
|
+};
|
||
|
+
|
||
|
Index: xen-unstable/tools/xenfb/sdlfb.c
|
||
|
===================================================================
|
||
|
--- /dev/null
|
||
|
+++ xen-unstable/tools/xenfb/sdlfb.c
|
||
|
@@ -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;
|
||
|
+}
|
||
|
Index: xen-unstable/tools/xenfb/vncfb.c
|
||
|
===================================================================
|
||
|
--- /dev/null
|
||
|
+++ xen-unstable/tools/xenfb/vncfb.c
|
||
|
@@ -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, NULL);
|
||
|
+ 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;
|
||
|
+}
|
||
|
Index: xen-unstable/tools/xenfb/xenfb.c
|
||
|
===================================================================
|
||
|
--- /dev/null
|
||
|
+++ xen-unstable/tools/xenfb/xenfb.c
|
||
|
@@ -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);
|
||
|
+}
|
||
|
Index: xen-unstable/tools/xenfb/xenfb.h
|
||
|
===================================================================
|
||
|
--- /dev/null
|
||
|
+++ xen-unstable/tools/xenfb/xenfb.h
|
||
|
@@ -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
|