aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir@xensource.com>2007-10-25 14:39:33 +0100
committerKeir Fraser <keir@xensource.com>2007-10-25 14:39:33 +0100
commit10aca7bae9a602b6c7060b6fe862e7d7ed3205e9 (patch)
treec85d779d47413e50509ea5e87fddb99a5d7cc43b
parent59e7941a6caf782c94a19e5eab95d3026bdf15af (diff)
downloadxen-10aca7bae9a602b6c7060b6fe862e7d7ed3205e9.tar.gz
xen-10aca7bae9a602b6c7060b6fe862e7d7ed3205e9.tar.bz2
xen-10aca7bae9a602b6c7060b6fe862e7d7ed3205e9.zip
pv-qemu 5/10: Refactor QEMU console integration
This patch moves a bunch of code out of the xen_machine_pv.c file and into the xenfb.c file. This is simply a re-factoring to facilitate the two patches which follow. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
-rw-r--r--tools/ioemu/hw/xen_machine_pv.c214
-rw-r--r--tools/ioemu/hw/xenfb.c325
-rw-r--r--tools/ioemu/hw/xenfb.h8
3 files changed, 280 insertions, 267 deletions
diff --git a/tools/ioemu/hw/xen_machine_pv.c b/tools/ioemu/hw/xen_machine_pv.c
index 9a273c119b..30b88d5712 100644
--- a/tools/ioemu/hw/xen_machine_pv.c
+++ b/tools/ioemu/hw/xen_machine_pv.c
@@ -24,194 +24,6 @@
#include "vl.h"
#include "xenfb.h"
-#include <linux/input.h>
-
-/*
- * Tables to map from scancode to Linux input layer keycode.
- * Scancodes are hardware-specific. These maps assumes a
- * standard AT or PS/2 keyboard which is what QEMU feeds us.
- */
-static const 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 const 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
-
-};
-
-static unsigned char scancode2linux[512];
-
-/* A convenient function for munging pixels between different depths */
-#define BLT(SRC_T,DST_T,RLS,GLS,BLS,RRS,GRS,BRS,RM,GM,BM) \
- for (line = y ; line < h ; line++) { \
- SRC_T *src = (SRC_T *)(xenfb->pixels \
- + (line * xenfb->row_stride) \
- + (x * xenfb->depth / 8)); \
- DST_T *dst = (DST_T *)(ds->data \
- + (line * ds->linesize) \
- + (x * ds->depth / 8)); \
- int col; \
- for (col = x ; col < w ; col++) { \
- *dst = (((*src >> RRS) & RM) << RLS) | \
- (((*src >> GRS) & GM) << GLS) | \
- (((*src >> GRS) & BM) << BLS); \
- src++; \
- dst++; \
- } \
- }
-
-/* This copies data from the guest framebuffer region, into QEMU's copy
- * NB. QEMU's copy is stored in the pixel format of a) the local X
- * server (SDL case) or b) the current VNC client pixel format.
- */
-static void xen_pvfb_guest_copy(struct xenfb *xenfb, int x, int y, int w, int h)
-{
- DisplayState *ds = (DisplayState *)xenfb->user_data;
- int line;
-
- if (xenfb->depth == ds->depth) { /* Perfect match can use fast path */
- for (line = y ; line < (y+h) ; line++) {
- memcpy(ds->data + (line * ds->linesize) + (x * ds->depth / 8),
- xenfb->pixels + (line * xenfb->row_stride) + (x * xenfb->depth / 8),
- w * xenfb->depth / 8);
- }
- } else { /* Mismatch requires slow pixel munging */
- if (xenfb->depth == 8) {
- /* 8 bit source == r:3 g:3 b:2 */
- if (ds->depth == 16) {
- BLT(uint8_t, uint16_t, 5, 2, 0, 11, 5, 0, 7, 7, 3);
- } else if (ds->depth == 32) {
- BLT(uint8_t, uint32_t, 5, 2, 0, 16, 8, 0, 7, 7, 3);
- }
- } else if (xenfb->depth == 16) {
- /* 16 bit source == r:5 g:6 b:5 */
- if (ds->depth == 8) {
- BLT(uint16_t, uint8_t, 11, 5, 0, 5, 2, 0, 31, 63, 31);
- } else if (ds->depth == 32) {
- BLT(uint16_t, uint32_t, 11, 5, 0, 16, 8, 0, 31, 63, 31);
- }
- } else if (xenfb->depth == 32) {
- /* 32 bit source == r:8 g:8 b:8 (padding:8) */
- if (ds->depth == 8) {
- BLT(uint32_t, uint8_t, 16, 8, 0, 5, 2, 0, 255, 255, 255);
- } else if (ds->depth == 16) {
- BLT(uint32_t, uint16_t, 16, 8, 0, 11, 5, 0, 255, 255, 255);
- }
- }
- }
- dpy_update(ds, x, y, w, h);
-}
-
-/*
- * Send a key event from the client to the guest OS
- * QEMU gives us a raw scancode from an AT / PS/2 style keyboard.
- * We have to turn this into a Linux Input layer keycode.
- *
- * Extra complexity from the fact that with extended scancodes
- * (like those produced by arrow keys) this method gets called
- * twice, but we only want to send a single event. So we have to
- * track the '0xe0' scancode state & collapse the extended keys
- * as needed.
- *
- * Wish we could just send scancodes straight to the guest which
- * already has code for dealing with this...
- */
-static void xen_pvfb_key_event(void *opaque, int scancode)
-{
- static int extended = 0;
- int down = 1;
- if (scancode == 0xe0) {
- extended = 1;
- return;
- } else if (scancode & 0x80) {
- scancode &= 0x7f;
- down = 0;
- }
- if (extended) {
- scancode |= 0x80;
- extended = 0;
- }
- xenfb_send_key(opaque, down, scancode2linux[scancode]);
-}
-
-/*
- * Send a mouse event from the client to the guest OS
- *
- * The QEMU mouse can be in either relative, or absolute mode.
- * Movement is sent separately from button state, which has to
- * be encoded as virtual key events. We also don't actually get
- * given any button up/down events, so have to track changes in
- * the button state.
- */
-static void xen_pvfb_mouse_event(void *opaque,
- int dx, int dy, int dz, int button_state)
-{
- static int old_state = 0;
- int i;
- struct xenfb *xenfb = opaque;
- DisplayState *ds = (DisplayState *)xenfb->user_data;
- if (xenfb->abs_pointer_wanted)
- xenfb_send_position(xenfb,
- dx * ds->width / 0x7fff,
- dy * ds->height / 0x7fff);
- else
- xenfb_send_motion(xenfb, dx, dy);
-
- for (i = 0 ; i < 8 ; i++) {
- int lastDown = old_state & (1 << i);
- int down = button_state & (1 << i);
- if (down == lastDown)
- continue;
-
- if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
- return;
- }
- old_state = button_state;
-}
-
-/* QEMU display state changed, so refresh the framebuffer copy */
-/* XXX - can we optimize this, or the next func at all ? */
-void xen_pvfb_update(void *opaque)
-{
- struct xenfb *xenfb = opaque;
- xen_pvfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
-}
-
-/* QEMU display state changed, so refresh the framebuffer copy */
-void xen_pvfb_invalidate(void *opaque)
-{
- xen_pvfb_update(opaque);
-}
-
-/* Screen dump is not used in Xen, so no need to impl this ? */
-void xen_pvfb_screen_dump(void *opaque, const char *name) { }
/* The Xen PV machine currently provides
* - a virtual framebuffer
@@ -226,14 +38,6 @@ static void xen_init_pv(uint64_t ram_size, int vga_ram_size, char *boot_device,
{
struct xenfb *xenfb;
extern int domid;
- int i;
-
- /* Prepare scancode mapping table */
- for (i = 0; i < 128; i++) {
- scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
- scancode2linux[i | 0x80] =
- atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
- }
/* Prepare PVFB state */
xenfb = xenfb_new();
@@ -244,27 +48,11 @@ static void xen_init_pv(uint64_t ram_size, int vga_ram_size, char *boot_device,
}
/* Talk to the guest */
- if (xenfb_attach_dom(xenfb, domid) < 0) {
+ if (xenfb_attach_dom(xenfb, domid, ds) < 0) {
fprintf(stderr, "Could not connect to domain (%s)\n",
strerror(errno));
exit(1);
}
- xenfb->update = xen_pvfb_guest_copy;
- xenfb->user_data = ds;
-
- /* Tell QEMU to allocate a graphical console */
- graphic_console_init(ds,
- xen_pvfb_update,
- xen_pvfb_invalidate,
- xen_pvfb_screen_dump,
- xenfb);
-
- /* Register our keyboard & mouse handlers */
- qemu_add_kbd_event_handler(xen_pvfb_key_event, xenfb);
- qemu_add_mouse_event_handler(xen_pvfb_mouse_event, xenfb,
- xenfb->abs_pointer_wanted,
- "Xen PVFB Mouse");
-
/* Setup QEMU display */
dpy_resize(ds, xenfb->width, xenfb->height);
diff --git a/tools/ioemu/hw/xenfb.c b/tools/ioemu/hw/xenfb.c
index d098e46bc4..3b93dc4d87 100644
--- a/tools/ioemu/hw/xenfb.c
+++ b/tools/ioemu/hw/xenfb.c
@@ -16,8 +16,8 @@
#include <string.h>
#include <time.h>
#include <xs.h>
+#include <linux/input.h>
-#include "vl.h"
#include "xenfb.h"
// FIXME defend against malicious frontend?
@@ -43,6 +43,58 @@ struct xenfb_private {
char protocol[64]; /* frontend protocol */
};
+/* Functions which tie the PVFB into the QEMU device model */
+static void xenfb_key_event(void *opaque, int keycode);
+static void xenfb_mouse_event(void *opaque,
+ int dx, int dy, int dz, int button_state);
+static void xenfb_guest_copy(struct xenfb *xenfb, int x, int y, int w, int h);
+static void xenfb_update(void *opaque);
+static void xenfb_invalidate(void *opaque);
+static void xenfb_screen_dump(void *opaque, const char *name);
+
+/*
+ * Tables to map from scancode to Linux input layer keycode.
+ * Scancodes are hardware-specific. These maps assumes a
+ * standard AT or PS/2 keyboard which is what QEMU feeds us.
+ */
+static const 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 const 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
+
+};
+
+static unsigned char scancode2linux[512];
+
+
static void xenfb_detach_dom(struct xenfb_private *);
static char *xenfb_path_in_dom(struct xs_handle *xsh,
@@ -158,10 +210,18 @@ struct xenfb *xenfb_new(void)
{
struct xenfb_private *xenfb = malloc(sizeof(*xenfb));
int serrno;
+ int i;
if (xenfb == NULL)
return NULL;
+ /* Prepare scancode mapping table */
+ for (i = 0; i < 128; i++) {
+ scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
+ scancode2linux[i | 0x80] =
+ atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
+ }
+
memset(xenfb, 0, sizeof(*xenfb));
xenfb->evt_xch = xenfb->xc = -1;
xenfb_device_init(&xenfb->fb, "vfb", xenfb);
@@ -580,6 +640,68 @@ static int xenfb_on_state_change(struct xenfb_device *dev)
return 0;
}
+static int xenfb_kbd_event(struct xenfb_private *xenfb,
+ union xenkbd_in_event *event)
+{
+ uint32_t prod;
+ struct xenkbd_page *page = xenfb->kbd.page;
+
+ if (xenfb->kbd.state != XenbusStateConnected)
+ return 0;
+
+ prod = page->in_prod;
+ if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
+ errno = EAGAIN;
+ return -1;
+ }
+
+ mb(); /* ensure ring space available */
+ XENKBD_IN_RING_REF(page, prod) = *event;
+ wmb(); /* ensure ring contents visible */
+ page->in_prod = prod + 1;
+ return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port);
+}
+
+static int xenfb_send_key(struct xenfb *xenfb_pub, bool down, int keycode)
+{
+ struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+ union xenkbd_in_event event;
+
+ memset(&event, 0, XENKBD_IN_EVENT_SIZE);
+ event.type = XENKBD_TYPE_KEY;
+ event.key.pressed = down ? 1 : 0;
+ event.key.keycode = keycode;
+
+ return xenfb_kbd_event(xenfb, &event);
+}
+
+static int xenfb_send_motion(struct xenfb *xenfb_pub, int rel_x, int rel_y)
+{
+ struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+ union xenkbd_in_event event;
+
+ memset(&event, 0, XENKBD_IN_EVENT_SIZE);
+ event.type = XENKBD_TYPE_MOTION;
+ event.motion.rel_x = rel_x;
+ event.motion.rel_y = rel_y;
+
+ return xenfb_kbd_event(xenfb, &event);
+}
+
+static int xenfb_send_position(struct xenfb *xenfb_pub, int abs_x, int abs_y)
+{
+ struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+ union xenkbd_in_event event;
+
+ memset(&event, 0, XENKBD_IN_EVENT_SIZE);
+ event.type = XENKBD_TYPE_POS;
+ event.pos.abs_x = abs_x;
+ event.pos.abs_y = abs_y;
+
+ return xenfb_kbd_event(xenfb, &event);
+}
+
+
static void xenfb_dispatch_channel(void *xenfb_pub)
{
struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
@@ -614,7 +736,7 @@ static void xenfb_dispatch_store(void *xenfb_pub)
}
-int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid)
+int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid, DisplayState *ds)
{
struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
struct xs_handle *xsh = xenfb->xsh;
@@ -702,6 +824,23 @@ int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid)
if (qemu_set_fd_handler2(xc_evtchn_fd(xenfb->evt_xch), NULL, xenfb_dispatch_channel, NULL, xenfb) < 0)
goto error;
+ /* Register our keyboard & mouse handlers */
+ qemu_add_kbd_event_handler(xenfb_key_event, xenfb);
+ qemu_add_mouse_event_handler(xenfb_mouse_event, xenfb,
+ xenfb_pub->abs_pointer_wanted,
+ "Xen PVFB Mouse");
+
+ xenfb_pub->update = xenfb_guest_copy;
+ xenfb_pub->user_data = ds;
+
+ /* Tell QEMU to allocate a graphical console */
+ graphic_console_init(ds,
+ xenfb_update,
+ xenfb_invalidate,
+ xenfb_screen_dump,
+ xenfb_pub);
+ dpy_resize(ds, xenfb_pub->width, xenfb_pub->height);
+
return 0;
error:
@@ -713,66 +852,154 @@ int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid)
return -1;
}
-static int xenfb_kbd_event(struct xenfb_private *xenfb,
- union xenkbd_in_event *event)
+/*
+ * Send a key event from the client to the guest OS
+ * QEMU gives us a raw scancode from an AT / PS/2 style keyboard.
+ * We have to turn this into a Linux Input layer keycode.
+ *
+ * Extra complexity from the fact that with extended scancodes
+ * (like those produced by arrow keys) this method gets called
+ * twice, but we only want to send a single event. So we have to
+ * track the '0xe0' scancode state & collapse the extended keys
+ * as needed.
+ *
+ * Wish we could just send scancodes straight to the guest which
+ * already has code for dealing with this...
+ */
+static void xenfb_key_event(void *opaque, int scancode)
{
- uint32_t prod;
- struct xenkbd_page *page = xenfb->kbd.page;
-
- if (xenfb->kbd.state != XenbusStateConnected)
- return 0;
-
- prod = page->in_prod;
- if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
- errno = EAGAIN;
- return -1;
- }
-
- mb(); /* ensure ring space available */
- XENKBD_IN_RING_REF(page, prod) = *event;
- wmb(); /* ensure ring contents visible */
- page->in_prod = prod + 1;
- return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port);
+ static int extended = 0;
+ int down = 1;
+ if (scancode == 0xe0) {
+ extended = 1;
+ return;
+ } else if (scancode & 0x80) {
+ scancode &= 0x7f;
+ down = 0;
+ }
+ if (extended) {
+ scancode |= 0x80;
+ extended = 0;
+ }
+ xenfb_send_key(opaque, down, scancode2linux[scancode]);
}
-int xenfb_send_key(struct xenfb *xenfb_pub, bool down, int keycode)
+/*
+ * Send a mouse event from the client to the guest OS
+ *
+ * The QEMU mouse can be in either relative, or absolute mode.
+ * Movement is sent separately from button state, which has to
+ * be encoded as virtual key events. We also don't actually get
+ * given any button up/down events, so have to track changes in
+ * the button state.
+ */
+static void xenfb_mouse_event(void *opaque,
+ int dx, int dy, int dz, int button_state)
{
- struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
- union xenkbd_in_event event;
-
- memset(&event, 0, XENKBD_IN_EVENT_SIZE);
- event.type = XENKBD_TYPE_KEY;
- event.key.pressed = down ? 1 : 0;
- event.key.keycode = keycode;
-
- return xenfb_kbd_event(xenfb, &event);
+ int i;
+ struct xenfb *xenfb = opaque;
+ DisplayState *ds = (DisplayState *)xenfb->user_data;
+ if (xenfb->abs_pointer_wanted)
+ xenfb_send_position(xenfb,
+ dx * ds->width / 0x7fff,
+ dy * ds->height / 0x7fff);
+ else
+ xenfb_send_motion(xenfb, dx, dy);
+
+ for (i = 0 ; i < 8 ; i++) {
+ int lastDown = xenfb->button_state & (1 << i);
+ int down = button_state & (1 << i);
+ if (down == lastDown)
+ continue;
+
+ if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
+ return;
+ }
+ xenfb->button_state = button_state;
}
-int xenfb_send_motion(struct xenfb *xenfb_pub, int rel_x, int rel_y)
+/* A convenient function for munging pixels between different depths */
+#define BLT(SRC_T,DST_T,RLS,GLS,BLS,RRS,GRS,BRS,RM,GM,BM) \
+ for (line = y ; line < h ; line++) { \
+ SRC_T *src = (SRC_T *)(xenfb->pixels \
+ + (line * xenfb->row_stride) \
+ + (x * xenfb->depth / 8)); \
+ DST_T *dst = (DST_T *)(ds->data \
+ + (line * ds->linesize) \
+ + (x * ds->depth / 8)); \
+ int col; \
+ for (col = x ; col < w ; col++) { \
+ *dst = (((*src >> RRS) & RM) << RLS) | \
+ (((*src >> GRS) & GM) << GLS) | \
+ (((*src >> GRS) & BM) << BLS); \
+ src++; \
+ dst++; \
+ } \
+ }
+
+
+/* This copies data from the guest framebuffer region, into QEMU's copy
+ * NB. QEMU's copy is stored in the pixel format of a) the local X
+ * server (SDL case) or b) the current VNC client pixel format.
+ * When shifting between colour depths we preserve the MSB.
+ */
+static void xenfb_guest_copy(struct xenfb *xenfb, int x, int y, int w, int h)
{
- struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
- union xenkbd_in_event event;
-
- memset(&event, 0, XENKBD_IN_EVENT_SIZE);
- event.type = XENKBD_TYPE_MOTION;
- event.motion.rel_x = rel_x;
- event.motion.rel_y = rel_y;
+ DisplayState *ds = (DisplayState *)xenfb->user_data;
+ int line;
+
+ if (xenfb->depth == ds->depth) { /* Perfect match can use fast path */
+ for (line = y ; line < (y+h) ; line++) {
+ memcpy(ds->data + (line * ds->linesize) + (x * ds->depth / 8),
+ xenfb->pixels + (line * xenfb->row_stride) + (x * xenfb->depth / 8),
+ w * xenfb->depth / 8);
+ }
+ } else { /* Mismatch requires slow pixel munging */
+ if (xenfb->depth == 8) {
+ /* 8 bit source == r:3 g:3 b:2 */
+ if (ds->depth == 16) {
+ BLT(uint8_t, uint16_t, 5, 2, 0, 11, 5, 0, 7, 7, 3);
+ } else if (ds->depth == 32) {
+ BLT(uint8_t, uint32_t, 5, 2, 0, 16, 8, 0, 7, 7, 3);
+ }
+ } else if (xenfb->depth == 16) {
+ /* 16 bit source == r:5 g:6 b:5 */
+ if (ds->depth == 8) {
+ BLT(uint16_t, uint8_t, 11, 5, 0, 5, 2, 0, 31, 63, 31);
+ } else if (ds->depth == 32) {
+ BLT(uint16_t, uint32_t, 11, 5, 0, 16, 8, 0, 31, 63, 31);
+ }
+ } else if (xenfb->depth == 32) {
+ /* 32 bit source == r:8 g:8 b:8 (padding:8) */
+ if (ds->depth == 8) {
+ BLT(uint32_t, uint8_t, 16, 8, 0, 5, 2, 0, 255, 255, 255);
+ } else if (ds->depth == 16) {
+ BLT(uint32_t, uint16_t, 16, 8, 0, 11, 5, 0, 255, 255, 255);
+ }
+ }
+ }
+ dpy_update(ds, x, y, w, h);
+}
- return xenfb_kbd_event(xenfb, &event);
+/* QEMU display state changed, so refresh the framebuffer copy */
+/* XXX - can we optimize this, or the next func at all ? */
+static void xenfb_update(void *opaque)
+{
+ struct xenfb *xenfb = opaque;
+ xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
}
-int xenfb_send_position(struct xenfb *xenfb_pub, int abs_x, int abs_y)
+/* QEMU display state changed, so refresh the framebuffer copy */
+static void xenfb_invalidate(void *opaque)
{
- struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
- union xenkbd_in_event event;
+ struct xenfb *xenfb = opaque;
+ xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
+}
+
+/* Screen dump is not used in Xen, so no need to impl this....yet */
+static void xenfb_screen_dump(void *opaque, const char *name) { }
- memset(&event, 0, XENKBD_IN_EVENT_SIZE);
- event.type = XENKBD_TYPE_POS;
- event.pos.abs_x = abs_x;
- event.pos.abs_y = abs_y;
- return xenfb_kbd_event(xenfb, &event);
-}
/*
* Local variables:
* c-indent-level: 8
diff --git a/tools/ioemu/hw/xenfb.h b/tools/ioemu/hw/xenfb.h
index 000a06e6ea..c494bee06b 100644
--- a/tools/ioemu/hw/xenfb.h
+++ b/tools/ioemu/hw/xenfb.h
@@ -1,6 +1,7 @@
#ifndef _XENFB_H_
#define _XENFB_H_
+#include "vl.h"
#include <stdbool.h>
#include <sys/types.h>
@@ -13,6 +14,7 @@ struct xenfb
int width;
int height;
int abs_pointer_wanted;
+ int button_state;
void *user_data;
@@ -23,10 +25,6 @@ struct xenfb *xenfb_new(void);
void xenfb_delete(struct xenfb *xenfb);
void xenfb_teardown(struct xenfb *xenfb);
-int xenfb_attach_dom(struct xenfb *xenfb, int domid);
-
-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_position(struct xenfb *xenfb, int abs_x, int abs_y);
+int xenfb_attach_dom(struct xenfb *xenfb, int domid, DisplayState *ds);
#endif