mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
pv-qemu: Remove standalone xenfb code
This patch removes all trace of the standalone paravirt framebuffer daemon. With this there is no longer any requirement for LibVNCServer. Everything is handled by the QEMU device model. The xenfb.c and xenfb.h files are now moved (without code change) into tools/ioemu/hw/ & the temporary Makefile hack from the previous patch is removed. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
1 parent
3bc128ebcf
commit
8731b7b939
12 files changed
+4
-967
No files matched your search
@@ -89,7 +89,6 @@ ACM_SECURITY ?= n
|
||||
XENSTAT_XENTOP ?= y
|
||||
VTPM_TOOLS ?= n
|
||||
LIBXENAPI_BINDINGS ?= n
|
||||
XENFB_TOOLS ?= n
|
||||
PYTHON_TOOLS ?= y
|
||||
|
||||
-include $(XEN_ROOT)/.config
|
||||
@@ -20,7 +20,6 @@ SUBDIRS-y += xenstat
|
||||
SUBDIRS-y += libaio
|
||||
SUBDIRS-y += blktap
|
||||
SUBDIRS-y += libfsimage
|
||||
SUBDIRS-$(XENFB_TOOLS) += xenfb
|
||||
SUBDIRS-$(LIBXENAPI_BINDINGS) += libxen
|
||||
|
||||
# These don't cross-compile
|
||||
|
||||
@@ -7,7 +7,7 @@ all: build
|
||||
# Check this machine is OK for building on.
|
||||
.PHONY: build
|
||||
build:
|
||||
XENFB_TOOLS=$(XENFB_TOOLS) LIBXENAPI_BINDINGS=$(LIBXENAPI_BINDINGS) ACM_SECURITY=$(ACM_SECURITY) ./chk build
|
||||
LIBXENAPI_BINDINGS=$(LIBXENAPI_BINDINGS) ACM_SECURITY=$(ACM_SECURITY) ./chk build
|
||||
|
||||
# Check this machine is OK for installing on.
|
||||
# DO NOT use this check from 'make install' in the parent
|
||||
@@ -15,7 +15,7 @@ build:
|
||||
# copy rather than actually installing.
|
||||
.PHONY: install
|
||||
install:
|
||||
XENFB_TOOLS=$(XENFB_TOOLS) LIBXENAPI_BINDINGS=$(LIBXENAPI_BINDINGS) ACM_SECURITY=$(ACM_SECURITY) ./chk install
|
||||
LIBXENAPI_BINDINGS=$(LIBXENAPI_BINDINGS) ACM_SECURITY=$(ACM_SECURITY) ./chk install
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
#!/bin/sh
|
||||
# CHECK-BUILD CHECK-INSTALL
|
||||
|
||||
if [ ! "$XENFB_TOOLS" = "y" ]
|
||||
then
|
||||
echo -n "unused, "
|
||||
exit 0
|
||||
fi
|
||||
|
||||
RC=0
|
||||
|
||||
LIBVNCSERVER_CONFIG="$(which libvncserver-config)"
|
||||
tmpfile=$(mktemp)
|
||||
|
||||
if test -z ${LIBVNCSERVER_CONFIG}; then
|
||||
RC=1
|
||||
else
|
||||
${LIBVNCSERVER_CONFIG} --libs 2>&1 > /dev/null
|
||||
RC=$?
|
||||
fi
|
||||
|
||||
if test $RC -ne 0; then
|
||||
echo "FAILED"
|
||||
echo " *** libvncserver-config is missing. "
|
||||
echo " *** Please install libvncserver."
|
||||
elif ! ld $($LIBVNCSERVER_CONFIG --libs) -o $tmpfile >/dev/null 2>&1; then
|
||||
echo "FAILED"
|
||||
echo " *** dependency libraries for libvncserver are missing: "
|
||||
RC=1
|
||||
for i in $(ld $($LIBVNCSERVER_CONFIG --libs) -o $tmpfile 2>&1 >/dev/null); do
|
||||
case $i in
|
||||
-l*) echo lib${i#-l}
|
||||
esac
|
||||
done
|
||||
fi
|
||||
rm -f $tmpfile
|
||||
|
||||
exit $RC
|
||||
@@ -1,27 +0,0 @@
|
||||
#!/bin/sh
|
||||
# CHECK-BUILD CHECK-INSTALL
|
||||
|
||||
if [ ! "$XENFB_TOOLS" = "y" ]
|
||||
then
|
||||
echo -n "unused, "
|
||||
exit 0
|
||||
fi
|
||||
|
||||
RC=0
|
||||
|
||||
SDL_CONFIG="$(which sdl-config)"
|
||||
|
||||
if test -z ${SDL_CONFIG}; then
|
||||
RC=1
|
||||
else
|
||||
${SDL_CONFIG} --libs 2>&1 > /dev/null
|
||||
RC=$?
|
||||
fi
|
||||
|
||||
if test $RC -ne 0; then
|
||||
echo "FAILED"
|
||||
echo " *** sdl-config is missing. "
|
||||
echo " *** Please install libsdl-dev or sdl."
|
||||
fi
|
||||
|
||||
exit $RC
|
||||
@@ -411,7 +411,7 @@ VL_OBJS+= xenstore.o
|
||||
VL_OBJS+= xen_platform.o
|
||||
VL_OBJS+= xen_machine_fv.o
|
||||
VL_OBJS+= xen_machine_pv.o
|
||||
VL_OBJS+= ../../xenfb/xenfb.o
|
||||
VL_OBJS+= xenfb.o
|
||||
VL_OBJS+= tpm_tis.o
|
||||
CPPFLAGS += -DHAS_AUDIO
|
||||
endif
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "vl.h"
|
||||
#include "../../xenfb/xenfb.h"
|
||||
#include "xenfb.h"
|
||||
#include <linux/input.h>
|
||||
|
||||
/*
|
||||
|
||||
File renamed without changes.
File renamed without changes.
@@ -1,32 +0,0 @@
|
||||
XEN_ROOT=../..
|
||||
include $(XEN_ROOT)/tools/Rules.mk
|
||||
|
||||
CFLAGS += -I$(XEN_LIBXC) -I$(XEN_XENSTORE)
|
||||
CFLAGS += -I$(XEN_ROOT)/tools/ioemu
|
||||
LDFLAGS += -L$(XEN_LIBXC) -L$(XEN_XENSTORE)
|
||||
|
||||
.PHONY: all
|
||||
all: build
|
||||
|
||||
.PHONY: build
|
||||
build:
|
||||
$(MAKE) vncfb sdlfb
|
||||
|
||||
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
|
||||
|
||||
sdlfb: sdlfb.o xenfb.o
|
||||
|
||||
sdlfb.o: CFLAGS += $(shell sdl-config --cflags)
|
||||
sdlfb: LDLIBS += $(shell sdl-config --libs) -lxenctrl -lxenstore
|
||||
|
||||
clean:
|
||||
$(RM) *.o *~ vncfb sdlfb
|
||||
|
||||
vncfb: vncfb.o xenfb.o
|
||||
vncfb.o: CFLAGS += $(shell libvncserver-config --cflags)
|
||||
vncfb: LDLIBS += $(shell libvncserver-config --libs) -lxenctrl -lxenstore
|
||||
|
||||
sdlfb.o xenfb.o vncfb.o: xenfb.h
|
||||
@@ -1,342 +0,0 @@
|
||||
#include <SDL.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/select.h>
|
||||
#include <stdlib.h>
|
||||
#include <linux/input.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
#include "xenfb.h"
|
||||
|
||||
struct SDLFBData
|
||||
{
|
||||
SDL_Surface *dst;
|
||||
SDL_Surface *src;
|
||||
};
|
||||
|
||||
/*
|
||||
* Map from scancode to Linux input layer keycode. Scancodes are
|
||||
* hardware-specific. This map assumes a standard AT or PS/2
|
||||
* keyboard.
|
||||
*
|
||||
* Why use scancodes? We can't use key symbols, because they don't
|
||||
* identify keys --- they're what keys are mapped to. The standard
|
||||
* German keymap, for instance, maps both KEY_COMMA and KEY_102ND to
|
||||
* SDLK_LESS.
|
||||
*/
|
||||
static int keymap[256] = {
|
||||
[9] = KEY_ESC,
|
||||
[10] = KEY_1,
|
||||
[11] = KEY_2,
|
||||
[12] = KEY_3,
|
||||
[13] = KEY_4,
|
||||
[14] = KEY_5,
|
||||
[15] = KEY_6,
|
||||
[16] = KEY_7,
|
||||
[17] = KEY_8,
|
||||
[18] = KEY_9,
|
||||
[19] = KEY_0,
|
||||
[20] = KEY_MINUS,
|
||||
[21] = KEY_EQUAL,
|
||||
[22] = KEY_BACKSPACE,
|
||||
[23] = KEY_TAB,
|
||||
[24] = KEY_Q,
|
||||
[25] = KEY_W,
|
||||
[26] = KEY_E,
|
||||
[27] = KEY_R,
|
||||
[28] = KEY_T,
|
||||
[29] = KEY_Y,
|
||||
[30] = KEY_U,
|
||||
[31] = KEY_I,
|
||||
[32] = KEY_O,
|
||||
[33] = KEY_P,
|
||||
[34] = KEY_LEFTBRACE,
|
||||
[35] = KEY_RIGHTBRACE,
|
||||
[36] = KEY_ENTER,
|
||||
[37] = KEY_LEFTCTRL,
|
||||
[38] = KEY_A,
|
||||
[39] = KEY_S,
|
||||
[40] = KEY_D,
|
||||
[41] = KEY_F,
|
||||
[42] = KEY_G,
|
||||
[43] = KEY_H,
|
||||
[44] = KEY_J,
|
||||
[45] = KEY_K,
|
||||
[46] = KEY_L,
|
||||
[47] = KEY_SEMICOLON,
|
||||
[48] = KEY_APOSTROPHE,
|
||||
[49] = KEY_GRAVE,
|
||||
[50] = KEY_LEFTSHIFT,
|
||||
[51] = KEY_BACKSLASH,
|
||||
[52] = KEY_Z,
|
||||
[53] = KEY_X,
|
||||
[54] = KEY_C,
|
||||
[55] = KEY_V,
|
||||
[56] = KEY_B,
|
||||
[57] = KEY_N,
|
||||
[58] = KEY_M,
|
||||
[59] = KEY_COMMA,
|
||||
[60] = KEY_DOT,
|
||||
[61] = KEY_SLASH,
|
||||
[62] = KEY_RIGHTSHIFT,
|
||||
[63] = KEY_KPASTERISK,
|
||||
[64] = KEY_LEFTALT,
|
||||
[65] = KEY_SPACE,
|
||||
[66] = KEY_CAPSLOCK,
|
||||
[67] = KEY_F1,
|
||||
[68] = KEY_F2,
|
||||
[69] = KEY_F3,
|
||||
[70] = KEY_F4,
|
||||
[71] = KEY_F5,
|
||||
[72] = KEY_F6,
|
||||
[73] = KEY_F7,
|
||||
[74] = KEY_F8,
|
||||
[75] = KEY_F9,
|
||||
[76] = KEY_F10,
|
||||
[77] = KEY_NUMLOCK,
|
||||
[78] = KEY_SCROLLLOCK,
|
||||
[79] = KEY_KP7,
|
||||
[80] = KEY_KP8,
|
||||
[81] = KEY_KP9,
|
||||
[82] = KEY_KPMINUS,
|
||||
[83] = KEY_KP4,
|
||||
[84] = KEY_KP5,
|
||||
[85] = KEY_KP6,
|
||||
[86] = KEY_KPPLUS,
|
||||
[87] = KEY_KP1,
|
||||
[88] = KEY_KP2,
|
||||
[89] = KEY_KP3,
|
||||
[90] = KEY_KP0,
|
||||
[91] = KEY_KPDOT,
|
||||
[94] = KEY_102ND, /* FIXME is this correct? */
|
||||
[95] = KEY_F11,
|
||||
[96] = KEY_F12,
|
||||
[108] = KEY_KPENTER,
|
||||
[109] = KEY_RIGHTCTRL,
|
||||
[112] = KEY_KPSLASH,
|
||||
[111] = KEY_SYSRQ,
|
||||
[113] = KEY_RIGHTALT,
|
||||
[97] = KEY_HOME,
|
||||
[98] = KEY_UP,
|
||||
[99] = KEY_PAGEUP,
|
||||
[100] = KEY_LEFT,
|
||||
[102] = KEY_RIGHT,
|
||||
[103] = KEY_END,
|
||||
[104] = KEY_DOWN,
|
||||
[105] = KEY_PAGEDOWN,
|
||||
[106] = KEY_INSERT,
|
||||
[107] = KEY_DELETE,
|
||||
[110] = KEY_PAUSE,
|
||||
[115] = KEY_LEFTMETA,
|
||||
[116] = KEY_RIGHTMETA,
|
||||
[117] = KEY_MENU,
|
||||
};
|
||||
|
||||
static int btnmap[] = {
|
||||
[SDL_BUTTON_LEFT] = BTN_LEFT,
|
||||
[SDL_BUTTON_MIDDLE] = BTN_MIDDLE,
|
||||
[SDL_BUTTON_RIGHT] = BTN_RIGHT,
|
||||
/* FIXME not 100% sure about these: */
|
||||
[SDL_BUTTON_WHEELUP] = BTN_FORWARD,
|
||||
[SDL_BUTTON_WHEELDOWN] BTN_BACK
|
||||
};
|
||||
|
||||
static void sdl_update(struct xenfb *xenfb, int x, int y, int width, int height)
|
||||
{
|
||||
struct SDLFBData *data = xenfb->user_data;
|
||||
SDL_Rect r = { x, y, width, height };
|
||||
SDL_BlitSurface(data->src, &r, data->dst, &r);
|
||||
SDL_UpdateRect(data->dst, x, y, width, height);
|
||||
}
|
||||
|
||||
static int sdl_on_event(struct xenfb *xenfb, SDL_Event *event)
|
||||
{
|
||||
int x, y, ret;
|
||||
|
||||
switch (event->type) {
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
if (keymap[event->key.keysym.scancode] == 0)
|
||||
break;
|
||||
ret = xenfb_send_key(xenfb,
|
||||
event->type == SDL_KEYDOWN,
|
||||
keymap[event->key.keysym.scancode]);
|
||||
if (ret < 0)
|
||||
fprintf(stderr, "Key %d %s lost (%s)\n",
|
||||
keymap[event->key.keysym.scancode],
|
||||
event->type == SDL_KEYDOWN ? "down" : "up",
|
||||
strerror(errno));
|
||||
break;
|
||||
case SDL_MOUSEMOTION:
|
||||
if (xenfb->abs_pointer_wanted) {
|
||||
SDL_GetMouseState(&x, &y);
|
||||
ret = xenfb_send_position(xenfb, x, y);
|
||||
} else {
|
||||
SDL_GetRelativeMouseState(&x, &y);
|
||||
ret = xenfb_send_motion(xenfb, x, y);
|
||||
}
|
||||
if (ret < 0)
|
||||
fprintf(stderr, "Pointer to %d,%d lost (%s)\n",
|
||||
x, y, strerror(errno));
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
if (event->button.button >= sizeof(btnmap) / sizeof(*btnmap))
|
||||
break;
|
||||
if (btnmap[event->button.button] == 0)
|
||||
break;
|
||||
ret = xenfb_send_key(xenfb,
|
||||
event->type == SDL_MOUSEBUTTONDOWN,
|
||||
btnmap[event->button.button]);
|
||||
if (ret < 0)
|
||||
fprintf(stderr, "Button %d %s lost (%s)\n",
|
||||
btnmap[event->button.button] - BTN_MOUSE,
|
||||
event->type == SDL_MOUSEBUTTONDOWN ? "down" : "up",
|
||||
strerror(errno));
|
||||
break;
|
||||
case SDL_QUIT:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct option options[] = {
|
||||
{ "domid", 1, NULL, 'd' },
|
||||
{ "title", 1, NULL, 't' },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct xenfb *xenfb;
|
||||
int domid = -1;
|
||||
char * title = NULL;
|
||||
fd_set readfds;
|
||||
int nfds;
|
||||
struct SDLFBData data;
|
||||
SDL_Rect r;
|
||||
struct timeval tv;
|
||||
SDL_Event event;
|
||||
int do_quit = 0;
|
||||
int opt;
|
||||
char *endp;
|
||||
int retval;
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "d:t:", options,
|
||||
NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
domid = strtol(optarg, &endp, 10);
|
||||
if (endp == optarg || *endp) {
|
||||
fprintf(stderr, "Invalid domain id specified\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
title = strdup(optarg);
|
||||
break;
|
||||
case '?':
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (optind != argc) {
|
||||
fprintf(stderr, "Invalid options!\n");
|
||||
exit(1);
|
||||
}
|
||||
if (domid <= 0) {
|
||||
fprintf(stderr, "Domain ID must be specified!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
xenfb = xenfb_new();
|
||||
if (xenfb == NULL) {
|
||||
fprintf(stderr, "Could not create framebuffer (%s)\n",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (xenfb_attach_dom(xenfb, domid) < 0) {
|
||||
fprintf(stderr, "Could not connect to domain (%s)\n",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
||||
fprintf(stderr, "Could not initialize SDL\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
data.dst = SDL_SetVideoMode(xenfb->width, xenfb->height, xenfb->depth,
|
||||
SDL_SWSURFACE);
|
||||
if (!data.dst) {
|
||||
fprintf(stderr, "SDL_SetVideoMode failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
data.src = SDL_CreateRGBSurfaceFrom(xenfb->pixels,
|
||||
xenfb->width, xenfb->height,
|
||||
xenfb->depth, xenfb->row_stride,
|
||||
0xFF0000, 0xFF00, 0xFF, 0);
|
||||
|
||||
if (!data.src) {
|
||||
fprintf(stderr, "SDL_CreateRGBSurfaceFrom failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (title == NULL)
|
||||
title = strdup("xen-sdlfb");
|
||||
SDL_WM_SetCaption(title, title);
|
||||
|
||||
r.x = r.y = 0;
|
||||
r.w = xenfb->width;
|
||||
r.h = xenfb->height;
|
||||
SDL_BlitSurface(data.src, &r, data.dst, &r);
|
||||
SDL_UpdateRect(data.dst, 0, 0, xenfb->width, xenfb->height);
|
||||
|
||||
xenfb->update = sdl_update;
|
||||
xenfb->user_data = &data;
|
||||
|
||||
SDL_ShowCursor(0);
|
||||
|
||||
/*
|
||||
* We need to wait for fds becoming ready or SDL events to
|
||||
* arrive. We time out the select after 10ms to poll for SDL
|
||||
* events. Clunky, but works. Could avoid the clunkiness
|
||||
* with a separate thread.
|
||||
*/
|
||||
for (;;) {
|
||||
FD_ZERO(&readfds);
|
||||
nfds = xenfb_select_fds(xenfb, &readfds);
|
||||
tv = (struct timeval){0, 10000};
|
||||
|
||||
if (select(nfds, &readfds, NULL, NULL, &tv) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
fprintf(stderr,
|
||||
"Can't select() on event channel (%s)\n",
|
||||
strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
while (SDL_PollEvent(&event)) {
|
||||
if (!sdl_on_event(xenfb, &event))
|
||||
do_quit = 1;
|
||||
}
|
||||
|
||||
if (do_quit)
|
||||
break;
|
||||
|
||||
retval = xenfb_poll(xenfb, &readfds);
|
||||
if (retval == -2)
|
||||
xenfb_teardown(xenfb);
|
||||
if (retval < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
xenfb_delete(xenfb);
|
||||
|
||||
SDL_Quit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,522 +0,0 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <malloc.h>
|
||||
#include <rfb/rfb.h>
|
||||
#include <rfb/keysym.h>
|
||||
#include <linux/input.h>
|
||||
#include <xs.h>
|
||||
#include "xenfb.h"
|
||||
|
||||
/* Grab key translation support routines from qemu directory. */
|
||||
#define qemu_mallocz(size) calloc(1, (size))
|
||||
static const char *bios_dir = "/usr/share/xen/qemu";
|
||||
#include "vnc_keysym.h"
|
||||
#include "keymaps.c"
|
||||
|
||||
static unsigned char atkbd_set2_keycode[512] = {
|
||||
|
||||
0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117,
|
||||
0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0,
|
||||
0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183,
|
||||
0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185,
|
||||
0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
|
||||
0, 89, 40, 0, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 85,
|
||||
0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0,
|
||||
82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125,
|
||||
173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127,
|
||||
159, 0,115, 0,164, 0, 0,116,158, 0,150,166, 0, 0, 0,142,
|
||||
157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0,
|
||||
226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112,
|
||||
110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0,
|
||||
|
||||
};
|
||||
|
||||
static unsigned char atkbd_unxlate_table[128] = {
|
||||
|
||||
0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
|
||||
21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
|
||||
35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
|
||||
50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3,
|
||||
11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105,
|
||||
114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63,
|
||||
71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
|
||||
19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
|
||||
|
||||
};
|
||||
|
||||
unsigned char keycode_table[512];
|
||||
|
||||
static void *kbd_layout;
|
||||
uint8_t modifiers_state[256];
|
||||
|
||||
static int btnmap[] = {
|
||||
BTN_LEFT, BTN_MIDDLE, BTN_RIGHT, BTN_SIDE,
|
||||
BTN_EXTRA, BTN_FORWARD, BTN_BACK, BTN_TASK
|
||||
};
|
||||
|
||||
static void press_key_shift_down(struct xenfb* xenfb, int down, int scancode)
|
||||
{
|
||||
if (down)
|
||||
xenfb_send_key(xenfb, 1, keycode_table[0x2a]);
|
||||
|
||||
if (xenfb_send_key(xenfb, down, keycode_table[scancode]) < 0)
|
||||
fprintf(stderr, "Key %d %s lost (%s)\n",
|
||||
scancode, "down", strerror(errno));
|
||||
|
||||
if (!down)
|
||||
xenfb_send_key(xenfb, 0, keycode_table[0x2a]);
|
||||
}
|
||||
|
||||
static void press_key_shift_up(struct xenfb* xenfb, int down, int scancode)
|
||||
{
|
||||
if (down) {
|
||||
if (modifiers_state[0x2a])
|
||||
xenfb_send_key(xenfb, 0, keycode_table[0x2a]);
|
||||
if (modifiers_state[0x36])
|
||||
xenfb_send_key(xenfb, 0, keycode_table[0x36]);
|
||||
}
|
||||
|
||||
if (xenfb_send_key(xenfb, down, keycode_table[scancode]) < 0)
|
||||
fprintf(stderr, "Key %d %s lost (%s)\n",
|
||||
scancode, "down", strerror(errno));
|
||||
|
||||
if (!down) {
|
||||
if (modifiers_state[0x2a])
|
||||
xenfb_send_key(xenfb, 1, keycode_table[0x2a]);
|
||||
if (modifiers_state[0x36])
|
||||
xenfb_send_key(xenfb, 1, keycode_table[0x36]);
|
||||
}
|
||||
}
|
||||
|
||||
static void on_kbd_event(rfbBool down, rfbKeySym keycode, rfbClientPtr cl)
|
||||
{
|
||||
/*
|
||||
* We need to map to the key's Linux input layer keycode.
|
||||
* Unfortunately, we don't get the key here, only the
|
||||
* rfbKeySym, which is what the key is mapped to. Mapping
|
||||
* back to the key is impossible in general, even when you
|
||||
* know the keymap. For instance, the standard German keymap
|
||||
* maps both KEY_COMMA and KEY_102ND to XK_less. We simply
|
||||
* assume standard US layout. This sucks.
|
||||
*/
|
||||
rfbScreenInfoPtr server = cl->screen;
|
||||
struct xenfb *xenfb = server->screenData;
|
||||
int scancode;
|
||||
int shift = 0;
|
||||
int shift_keys = 0;
|
||||
|
||||
if (keycode >= 'A' && keycode <= 'Z') {
|
||||
keycode += 'a' - 'A';
|
||||
shift = 1;
|
||||
}
|
||||
else {
|
||||
shift = keysymIsShift(kbd_layout, keycode);
|
||||
}
|
||||
shift_keys = modifiers_state[0x2a] | modifiers_state[0x36];
|
||||
|
||||
scancode = keysym2scancode(kbd_layout, keycode);
|
||||
if (scancode == 0)
|
||||
return;
|
||||
|
||||
switch(scancode) {
|
||||
case 0x2a: /* Left Shift */
|
||||
case 0x36: /* Right Shift */
|
||||
case 0x1d: /* Left CTRL */
|
||||
case 0x9d: /* Right CTRL */
|
||||
case 0x38: /* Left ALT */
|
||||
case 0xb8: /* Right ALT */
|
||||
if (down)
|
||||
modifiers_state[scancode] = 1;
|
||||
else
|
||||
modifiers_state[scancode] = 0;
|
||||
xenfb_send_key(xenfb, down, keycode_table[scancode]);
|
||||
return;
|
||||
case 0x45: /* NumLock */
|
||||
if (!down)
|
||||
modifiers_state[scancode] ^= 1;
|
||||
xenfb_send_key(xenfb, down, keycode_table[scancode]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (keycodeIsKeypad(kbd_layout, scancode)) {
|
||||
/* If the numlock state needs to change then simulate an additional
|
||||
keypress before sending this one. This will happen if the user
|
||||
toggles numlock away from the VNC window.
|
||||
*/
|
||||
if (keysymIsNumlock(kbd_layout, keycode)) {
|
||||
if (!modifiers_state[0x45]) {
|
||||
modifiers_state[0x45] = 1;
|
||||
xenfb_send_key(xenfb, 1, keycode_table[0x45]);
|
||||
xenfb_send_key(xenfb, 0, keycode_table[0x45]);
|
||||
}
|
||||
} else {
|
||||
if (modifiers_state[0x45]) {
|
||||
modifiers_state[0x45] = 0;
|
||||
xenfb_send_key(xenfb, 1, keycode_table[0x45]);
|
||||
xenfb_send_key(xenfb, 0, keycode_table[0x45]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If the shift state needs to change then simulate an additional
|
||||
keypress before sending this one.
|
||||
*/
|
||||
if (shift && !shift_keys) {
|
||||
press_key_shift_down(xenfb, down, scancode);
|
||||
return;
|
||||
}
|
||||
else if (!shift && shift_keys) {
|
||||
press_key_shift_up(xenfb, down, scancode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (xenfb_send_key(xenfb, down, keycode_table[scancode]) < 0)
|
||||
fprintf(stderr, "Key %d %s lost (%s)\n",
|
||||
scancode, down ? "down" : "up",
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
static void on_ptr_event(int buttonMask, int x, int y, rfbClientPtr cl)
|
||||
{
|
||||
/* initial pointer state: at (0,0), buttons up */
|
||||
static int last_x, last_y, last_button;
|
||||
rfbScreenInfoPtr server = cl->screen;
|
||||
struct xenfb *xenfb = server->screenData;
|
||||
int i, last_down, down, ret;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
last_down = last_button & (1 << i);
|
||||
down = buttonMask & (1 << i);
|
||||
if (down == last_down)
|
||||
continue;
|
||||
if (i >= sizeof(btnmap) / sizeof(*btnmap))
|
||||
break;
|
||||
if (btnmap[i] == 0)
|
||||
break;
|
||||
if (xenfb_send_key(xenfb, down != 0, btnmap[i]) < 0)
|
||||
fprintf(stderr, "Button %d %s lost (%s)\n",
|
||||
i, down ? "down" : "up", strerror(errno));
|
||||
}
|
||||
|
||||
if (x != last_x || y != last_y) {
|
||||
if (xenfb->abs_pointer_wanted)
|
||||
ret = xenfb_send_position(xenfb, x, y);
|
||||
else
|
||||
ret = xenfb_send_motion(xenfb, x - last_x, y - last_y);
|
||||
if (ret < 0)
|
||||
fprintf(stderr, "Pointer to %d,%d lost (%s)\n",
|
||||
x, y, strerror(errno));
|
||||
}
|
||||
|
||||
last_button = buttonMask;
|
||||
last_x = x;
|
||||
last_y = y;
|
||||
}
|
||||
|
||||
static void xenstore_write_vncport(struct xs_handle *xsh, int port, int domid)
|
||||
{
|
||||
char *buf, *path;
|
||||
char portstr[10];
|
||||
|
||||
path = xs_get_domain_path(xsh, domid);
|
||||
if (path == NULL) {
|
||||
fprintf(stderr, "Can't get domain path (%s)\n",
|
||||
strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (asprintf(&buf, "%s/console/vnc-port", path) == -1) {
|
||||
fprintf(stderr, "Can't make vncport path\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (snprintf(portstr, sizeof(portstr), "%d", port) == -1) {
|
||||
fprintf(stderr, "Can't make vncport value\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!xs_write(xsh, XBT_NULL, buf, portstr, strlen(portstr)))
|
||||
fprintf(stderr, "Can't set vncport (%s)\n",
|
||||
strerror(errno));
|
||||
|
||||
out:
|
||||
free(buf);
|
||||
}
|
||||
|
||||
|
||||
static int xenstore_read_vncpasswd(struct xs_handle *xsh, int domid, char *pwbuf, int pwbuflen)
|
||||
{
|
||||
char buf[256], *path, *uuid = NULL, *passwd = NULL;
|
||||
unsigned int len, rc = 0;
|
||||
|
||||
if (xsh == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
path = xs_get_domain_path(xsh, domid);
|
||||
if (path == NULL) {
|
||||
fprintf(stderr, "xs_get_domain_path() error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(buf, 256, "%s/vm", path);
|
||||
uuid = xs_read(xsh, XBT_NULL, buf, &len);
|
||||
if (uuid == NULL) {
|
||||
fprintf(stderr, "xs_read(): uuid get error\n");
|
||||
free(path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(buf, 256, "%s/vncpasswd", uuid);
|
||||
passwd = xs_read(xsh, XBT_NULL, buf, &len);
|
||||
if (passwd == NULL) {
|
||||
free(uuid);
|
||||
free(path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
strncpy(pwbuf, passwd, pwbuflen-1);
|
||||
pwbuf[pwbuflen-1] = '\0';
|
||||
|
||||
fprintf(stderr, "Got a VNC password read from XenStore\n");
|
||||
|
||||
passwd[0] = '\0';
|
||||
snprintf(buf, 256, "%s/vncpasswd", uuid);
|
||||
if (xs_write(xsh, XBT_NULL, buf, passwd, len) == 0) {
|
||||
fprintf(stderr, "xs_write() vncpasswd failed\n");
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
free(passwd);
|
||||
free(uuid);
|
||||
free(path);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void vnc_update(struct xenfb *xenfb, int x, int y, int w, int h)
|
||||
{
|
||||
rfbScreenInfoPtr server = xenfb->user_data;
|
||||
rfbMarkRectAsModified(server, x, y, x + w, y + h);
|
||||
}
|
||||
|
||||
static struct option options[] = {
|
||||
{ "domid", 1, NULL, 'd' },
|
||||
{ "vncport", 1, NULL, 'p' },
|
||||
{ "title", 1, NULL, 't' },
|
||||
{ "unused", 0, NULL, 'u' },
|
||||
{ "listen", 1, NULL, 'l' },
|
||||
{ "keymap", 1, NULL, 'k' },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
rfbScreenInfoPtr server;
|
||||
char *fake_argv[7] = { "vncfb", "-rfbport", "5901",
|
||||
"-desktop", "xen-vncfb",
|
||||
"-listen", "127.0.0.1" };
|
||||
int fake_argc = sizeof(fake_argv) / sizeof(fake_argv[0]);
|
||||
int domid = -1, port = -1;
|
||||
char *title = NULL;
|
||||
char *listen = NULL;
|
||||
char *keymap = NULL;
|
||||
bool unused = false;
|
||||
int opt;
|
||||
struct xenfb *xenfb;
|
||||
fd_set readfds;
|
||||
int nfds;
|
||||
char portstr[10];
|
||||
char *endp;
|
||||
int r;
|
||||
struct xs_handle *xsh;
|
||||
char vncpasswd[1024];
|
||||
int i;
|
||||
|
||||
vncpasswd[0] = '\0';
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "d:p:t:uk:", options,
|
||||
NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
errno = 0;
|
||||
domid = strtol(optarg, &endp, 10);
|
||||
if (endp == optarg || *endp || errno) {
|
||||
fprintf(stderr, "Invalid domain id specified\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
errno = 0;
|
||||
port = strtol(optarg, &endp, 10);
|
||||
if (endp == optarg || *endp || errno) {
|
||||
fprintf(stderr, "Invalid port specified\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
title = strdup(optarg);
|
||||
break;
|
||||
case 'u':
|
||||
unused = true;
|
||||
break;
|
||||
case 'l':
|
||||
listen = strdup(optarg);
|
||||
break;
|
||||
case 'k':
|
||||
keymap = strdup(optarg);
|
||||
break;
|
||||
case '?':
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (optind != argc) {
|
||||
fprintf(stderr, "Invalid options!\n");
|
||||
exit(1);
|
||||
}
|
||||
if (domid <= 0) {
|
||||
fprintf(stderr, "Domain ID must be specified!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (port <= 0)
|
||||
port = 5900 + domid;
|
||||
if (snprintf(portstr, sizeof(portstr), "%d", port) == -1) {
|
||||
fprintf(stderr, "Invalid port specified\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (keymap == NULL){
|
||||
keymap = "en-us";
|
||||
}
|
||||
|
||||
kbd_layout = init_keyboard_layout(keymap);
|
||||
if( !kbd_layout ){
|
||||
fprintf(stderr, "Invalid keyboard_layout\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (i = 0; i < 128; i++) {
|
||||
keycode_table[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
|
||||
keycode_table[i | 0x80] =
|
||||
atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
|
||||
}
|
||||
|
||||
for (i = 0; i < 256; i++ ) {
|
||||
modifiers_state[i] = 0;
|
||||
}
|
||||
|
||||
fake_argv[2] = portstr;
|
||||
|
||||
if (title != NULL)
|
||||
fake_argv[4] = title;
|
||||
|
||||
if (listen != NULL)
|
||||
fake_argv[6] = listen;
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
xenfb = xenfb_new();
|
||||
if (xenfb == NULL) {
|
||||
fprintf(stderr, "Could not create framebuffer (%s)\n",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (xenfb_attach_dom(xenfb, domid) < 0) {
|
||||
fprintf(stderr, "Could not connect to domain (%s)\n",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
xsh = xs_daemon_open();
|
||||
if (xsh == NULL) {
|
||||
fprintf(stderr, "cannot open connection to xenstore\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
if (xenstore_read_vncpasswd(xsh, domid, vncpasswd,
|
||||
sizeof(vncpasswd)/sizeof(char)) < 0) {
|
||||
fprintf(stderr, "cannot read VNC password from xenstore\n");
|
||||
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;
|
||||
|
||||
if (vncpasswd[0]) {
|
||||
char **passwds = malloc(sizeof(char**)*2);
|
||||
if (!passwds) {
|
||||
fprintf(stderr, "cannot allocate memory (%s)\n",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
fprintf(stderr, "Registered password\n");
|
||||
passwds[0] = vncpasswd;
|
||||
passwds[1] = NULL;
|
||||
|
||||
server->authPasswdData = passwds;
|
||||
server->passwordCheck = rfbCheckPasswordByList;
|
||||
} else {
|
||||
fprintf(stderr, "Running with no password\n");
|
||||
}
|
||||
server->serverFormat.redShift = 16;
|
||||
server->serverFormat.greenShift = 8;
|
||||
server->serverFormat.blueShift = 0;
|
||||
server->kbdAddEvent = on_kbd_event;
|
||||
server->ptrAddEvent = on_ptr_event;
|
||||
server->frameBuffer = xenfb->pixels;
|
||||
server->screenData = xenfb;
|
||||
server->cursor = NULL;
|
||||
rfbInitServer(server);
|
||||
|
||||
rfbRunEventLoop(server, -1, true);
|
||||
|
||||
xenstore_write_vncport(xsh, server->port, domid);
|
||||
|
||||
for (;;) {
|
||||
FD_ZERO(&readfds);
|
||||
nfds = xenfb_select_fds(xenfb, &readfds);
|
||||
|
||||
if (select(nfds, &readfds, NULL, NULL, NULL) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
fprintf(stderr,
|
||||
"Can't select() on event channel (%s)\n",
|
||||
strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
r = xenfb_poll(xenfb, &readfds);
|
||||
if (r == -2)
|
||||
xenfb_teardown(xenfb);
|
||||
if (r < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
rfbScreenCleanup(server);
|
||||
xenfb_delete(xenfb);
|
||||
|
||||
return 0;
|
||||
}
|
||||