This patch re-factors the paravirt console xenfb_attach_dom method. The
original method blocks the caller until the front & backends have both
switched to the connected state. This isn't an immediate problem, but
patches which follow will extend qemu to also handle the text console
so blocking on graphics console startup will block the text console
processing.
The new code is basically a state machine. It starts off with a watch
waiting for the KBD backend to switch to 'initialized' mode, then does
the same for the FB backend. Now it waits for KBD & FB frontend devices
to initialize, reading & mapping the framebuffer & its config at the
appropriate step. When the KBD frontend finally reaches the connected
state it registers a graphical console with QEMU and sets up the various
framebuffer, mouse & keyboard event handlers. If a client connects to
the VNC server before this is completed, then they will merely see a
text console (or perhaps the monitor if configured that way).
xen_machine_pv.c | 9
xenfb.c | 752 ++++++++++++++++++++++++++++++++-----------------------
xenfb.h | 7
3 files changed, 445 insertions(+), 323 deletions(-)
Signed-off-by: Daniel P. Berrange <berrange@xxxxxxxxxx>
Dan.
diff -r 829464d36542 tools/ioemu/hw/xen_machine_pv.c
--- a/tools/ioemu/hw/xen_machine_pv.c Tue Aug 21 22:07:47 2007 -0400
+++ b/tools/ioemu/hw/xen_machine_pv.c Tue Aug 21 22:08:24 2007 -0400
@@ -41,16 +41,9 @@ static void xen_init_pv(uint64_t ram_siz
extern int domid;
/* Prepare PVFB state */
- xenfb = xenfb_new();
+ xenfb = xenfb_new(domid, ds);
if (xenfb == NULL) {
fprintf(stderr, "Could not create framebuffer (%s)\n",
- strerror(errno));
- exit(1);
- }
-
- /* Talk to the guest */
- if (xenfb_attach_dom(xenfb, domid, ds) < 0) {
- fprintf(stderr, "Could not connect to domain (%s)\n",
strerror(errno));
exit(1);
}
diff -r 829464d36542 tools/ioemu/hw/xenfb.c
--- a/tools/ioemu/hw/xenfb.c Tue Aug 21 22:07:47 2007 -0400
+++ b/tools/ioemu/hw/xenfb.c Tue Aug 21 22:14:04 2007 -0400
@@ -19,6 +19,12 @@
#include <linux/input.h>
#include "xenfb.h"
+#define DEBUG 1
+#if DEBUG
+#define LOGF(msg,...) fprintf(stderr, msg, ## __VA_ARGS__)
+#else
+#define LOGF(msg,...) do { } while (0)
+#endif
// FIXME defend against malicious frontend?
@@ -167,60 +173,6 @@ static int xenfb_device_set_domain(struc
return 0;
}
-struct xenfb *xenfb_new(void)
-{
- int serrno;
- struct xenfb *xenfb = qemu_malloc(sizeof(struct xenfb));
-
- if (xenfb == NULL)
- return NULL;
-
- memset(xenfb, 0, sizeof(*xenfb));
- xenfb->evt_xch = xenfb->xc = -1;
- xenfb_device_init(&xenfb->fb, "vfb", xenfb);
- xenfb_device_init(&xenfb->kbd, "vkbd", xenfb);
-
- xenfb->evt_xch = xc_evtchn_open();
- if (xenfb->evt_xch == -1)
- goto fail;
-
- xenfb->xc = xc_interface_open();
- if (xenfb->xc == -1)
- goto fail;
-
- xenfb->xsh = xs_daemon_open();
- if (!xenfb->xsh)
- goto fail;
-
- return xenfb;
-
- fail:
- serrno = errno;
- xenfb_delete(xenfb);
- errno = serrno;
- return NULL;
-}
-
-/* Remove the backend area in xenbus since the framebuffer really is
- going away. */
-void xenfb_teardown(struct xenfb *xenfb)
-{
- xs_rm(xenfb->xsh, XBT_NULL, xenfb->fb.nodename);
- xs_rm(xenfb->xsh, XBT_NULL, xenfb->kbd.nodename);
-}
-
-
-void xenfb_delete(struct xenfb *xenfb)
-{
- xenfb_detach_dom(xenfb);
- if (xenfb->xc >= 0)
- xc_interface_close(xenfb->xc);
- if (xenfb->evt_xch >= 0)
- xc_evtchn_close(xenfb->evt_xch);
- if (xenfb->xsh)
- xs_daemon_close(xenfb->xsh);
- free(xenfb);
-}
static enum xenbus_state xenfb_read_state(struct xs_handle *xsh,
const char *dir)
@@ -228,6 +180,7 @@ static enum xenbus_state xenfb_read_stat
int ret, state;
ret = xenfb_xs_scanf1(xsh, dir, "state", "%d", &state);
+ LOGF("FB: read state %d %d\n", state, ret);
if (ret < 0)
return XenbusStateUnknown;
@@ -240,65 +193,10 @@ static int xenfb_switch_state(struct xen
enum xenbus_state state)
{
struct xs_handle *xsh = dev->xenfb->xsh;
-
+ /*LOGF("FB: write state %d\n", state);*/
if (xenfb_xs_printf(xsh, dev->nodename, "state", "%d", state) < 0)
return -1;
dev->state = state;
- return 0;
-}
-
-static int xenfb_wait_for_state(struct xs_handle *xsh, const char *dir,
- unsigned awaited)
-{
- unsigned state, dummy;
- char **vec;
-
- awaited |= 1 << XenbusStateUnknown;
-
- for (;;) {
- state = xenfb_read_state(xsh, dir);
- if ((1 << state) & awaited)
- return state;
-
- vec = xs_read_watch(xsh, &dummy);
- if (!vec)
- return -1;
- free(vec);
- }
-}
-
-static int xenfb_wait_for_backend_creation(struct xenfb_device *dev)
-{
- struct xs_handle *xsh = dev->xenfb->xsh;
- int state;
-
- if (!xs_watch(xsh, dev->nodename, ""))
- return -1;
- state = xenfb_wait_for_state(xsh, dev->nodename,
- (1 << XenbusStateInitialising)
- | (1 << XenbusStateClosed)
-#if 1 /* TODO fudging state to permit restarting; to be removed */
- | (1 << XenbusStateInitWait)
- | (1 << XenbusStateConnected)
- | (1 << XenbusStateClosing)
-#endif
- );
- xs_unwatch(xsh, dev->nodename, "");
-
- switch (state) {
-#if 1
- case XenbusStateInitWait:
- case XenbusStateConnected:
- printf("Fudging state to %d\n", XenbusStateInitialising); /*
FIXME */
-#endif
- case XenbusStateInitialising:
- case XenbusStateClosing:
- case XenbusStateClosed:
- break;
- default:
- return -1;
- }
-
return 0;
}
@@ -310,28 +208,6 @@ static int xenfb_hotplug(struct xenfb_de
return 0;
}
-static int xenfb_wait_for_frontend_initialised(struct xenfb_device *dev)
-{
- switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend,
-#if 1 /* TODO fudging state to permit restarting; to be removed */
- (1 << XenbusStateInitialised)
- | (1 << XenbusStateConnected)
-#else
- 1 << XenbusStateInitialised,
-#endif
- )) {
-#if 1
- case XenbusStateConnected:
- printf("Fudging state to %d\n", XenbusStateInitialised); /*
FIXME */
-#endif
- case XenbusStateInitialised:
- break;
- default:
- return -1;
- }
-
- return 0;
-}
static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src)
{
@@ -474,52 +350,6 @@ static void xenfb_unbind(struct xenfb_de
}
}
-static int xenfb_wait_for_frontend_connected(struct xenfb_device *dev)
-{
- switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend,
- 1 << XenbusStateConnected)) {
- case XenbusStateConnected:
- break;
- default:
- return -1;
- }
-
- return 0;
-}
-
-static void xenfb_dev_fatal(struct xenfb_device *dev, int err,
- const char *fmt, ...)
-{
- struct xs_handle *xsh = dev->xenfb->xsh;
- va_list ap;
- char errdir[80];
- char buf[1024];
- int n;
-
- fprintf(stderr, "%s ", dev->nodename); /* somewhat crude */
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- if (err)
- fprintf(stderr, " (%s)", strerror(err));
- putc('\n', stderr);
-
- if (!xenfb_path_in_dom(xsh, errdir, sizeof(errdir), 0,
- "error/%s", dev->nodename))
- goto out; /* FIXME complain */
-
- va_start(ap, fmt);
- n = snprintf(buf, sizeof(buf), "%d ", err);
- snprintf(buf + n, sizeof(buf) - n, fmt, ap);
- va_end(ap);
-
- if (xenfb_xs_printf(xsh, buf, "error", "%s", buf) < 0)
- goto out; /* FIXME complain */
-
- out:
- xenfb_switch_state(dev, XenbusStateClosing);
-}
-
static void xenfb_detach_dom(struct xenfb *xenfb)
{
@@ -673,6 +503,8 @@ static int xenfb_kbd_event(struct xenfb
return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port);
}
+
+/* Send a keyboard (or mouse button) event */
static int xenfb_send_key(struct xenfb *xenfb, bool down, int keycode)
{
union xenkbd_in_event event;
@@ -685,10 +517,11 @@ static int xenfb_send_key(struct xenfb *
return xenfb_kbd_event(xenfb, &event);
}
+/* Send a relative mouse movement event */
static int xenfb_send_motion(struct xenfb *xenfb, int rel_x, int rel_y)
{
union xenkbd_in_event event;
-
+ LOGF("REL %d %d\n", rel_x, rel_y);
memset(&event, 0, XENKBD_IN_EVENT_SIZE);
event.type = XENKBD_TYPE_MOTION;
event.motion.rel_x = rel_x;
@@ -697,10 +530,11 @@ static int xenfb_send_motion(struct xenf
return xenfb_kbd_event(xenfb, &event);
}
+/* Send an absolute mouse movement event */
static int xenfb_send_position(struct xenfb *xenfb, int abs_x, int abs_y)
{
union xenkbd_in_event event;
-
+ LOGF("ABS %d %d\n", abs_x, abs_y);
memset(&event, 0, XENKBD_IN_EVENT_SIZE);
event.type = XENKBD_TYPE_POS;
event.pos.abs_x = abs_x;
@@ -753,161 +587,459 @@ static void xenfb_update(void *opaque)
/* QEMU display state changed, so refresh the framebuffer copy */
static void xenfb_invalidate(void *opaque)
{
- struct xenfb *xenfb = (struct xenfb *)opaque;
- xenfb_guest_copy(xenfb, 0, 0, xenfb->data.width, xenfb->data.height);
+ xenfb_update(opaque);
}
/* Screen dump is not used in Xen, so no need to impl this ? */
static void xenfb_screen_dump(void *opaque, const char *name) { }
-
+/* Process events from the frontend event channel */
static void xenfb_dispatch_channel(void *opaque)
{
struct xenfb *xenfb = (struct xenfb *)opaque;
evtchn_port_t port;
port = xc_evtchn_pending(xenfb->evt_xch);
- if (port == -1)
+ if (port == -1) {
+ xenfb_shutdown(xenfb);
exit(1);
+ }
if (port == xenfb->fb.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)
+ if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1) {
+ xenfb_shutdown(xenfb);
exit(1);
-}
-
-static void xenfb_dispatch_store(void *opaque)
-{
- struct xenfb *xenfb = (struct xenfb *)opaque;
- unsigned dummy;
- char **vec;
- int r;
-
- vec = xs_read_watch(xenfb->xsh, &dummy);
- free(vec);
- r = xenfb_on_state_change(&xenfb->fb);
- if (r == 0)
- r = xenfb_on_state_change(&xenfb->kbd);
- if (r == -1)
- exit(1);
-}
-
-
-int xenfb_attach_dom(struct xenfb *xenfb, int domid, DisplayState *ds)
-{
- struct xs_handle *xsh = xenfb->xsh;
- int val, serrno;
+ }
+}
+
+
+/* Process ongoing events from the frontend devices */
+static void xenfb_frontend_disconnected_kbd(void *opaque)
+{
+ struct xenfb_device *dev = (struct xenfb_device *)opaque;
+ unsigned dummy;
+ char **vec;
+ int r;
+ vec = xs_read_watch(dev->xenfb->xsh, &dummy);
+ free(vec);
+
+ r = xenfb_on_state_change(&dev->xenfb->kbd);
+ if (r >= 0)
+ r = xenfb_on_state_change(&dev->xenfb->fb);
+
+ if (r < 0) {
+ xs_unwatch(dev->xenfb->xsh, dev->otherend, "");
+ xenfb_shutdown(dev->xenfb);
+ }
+}
+
+
+/* Register a QEMU console & input handlers */
+static void xenfb_register_console(struct xenfb *xenfb) {
+ /* Register our keyboard & mouse handlers */
+ qemu_add_kbd_event_handler(xenfb_put_keycode, xenfb);
+ qemu_add_mouse_event_handler(xenfb_mouse_event, xenfb,
+ xenfb->data.abs_pointer_wanted,
+ "Xen PVFB Mouse");
+
+ /* Tell QEMU to allocate a graphical console even though
+ * we're not connected - so user at least has a black screen
+ * to look at ;-) */
+ graphic_console_init(xenfb->ds,
+ xenfb_update,
+ xenfb_invalidate,
+ xenfb_screen_dump,
+ xenfb);
+
+ LOGF("FB: Connected, resizing framebuffer\n");
+ dpy_resize(xenfb->ds, xenfb->data.width, xenfb->data.height);
+}
+
+/* Process the frontend framebuffer config */
+static int xenfb_read_frontend_fb_config(struct xenfb *xenfb) {
struct xenfb_page *fb_page;
-
- xenfb_detach_dom(xenfb);
-
- xenfb_device_set_domain(&xenfb->fb, domid);
- xenfb_device_set_domain(&xenfb->kbd, domid);
-
- if (xenfb_wait_for_backend_creation(&xenfb->fb) < 0)
- goto error;
- if (xenfb_wait_for_backend_creation(&xenfb->kbd) < 0)
- goto error;
-
- if (xenfb_xs_printf(xsh, xenfb->kbd.nodename, "feature-abs-pointer",
"1"))
- goto error;
- if (xenfb_switch_state(&xenfb->fb, XenbusStateInitWait))
- goto error;
- if (xenfb_switch_state(&xenfb->kbd, XenbusStateInitWait))
- goto error;
-
- if (xenfb_hotplug(&xenfb->fb) < 0)
- goto error;
- if (xenfb_hotplug(&xenfb->kbd) < 0)
- goto error;
-
- if (!xs_watch(xsh, xenfb->fb.otherend, ""))
- goto error;
- if (!xs_watch(xsh, xenfb->kbd.otherend, ""))
- goto error;
-
- if (xenfb_wait_for_frontend_initialised(&xenfb->fb) < 0)
- goto error;
- if (xenfb_wait_for_frontend_initialised(&xenfb->kbd) < 0)
- goto error;
-
- if (xenfb_bind(&xenfb->fb) < 0)
- goto error;
- if (xenfb_bind(&xenfb->kbd) < 0)
- goto error;
-
- if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "feature-update",
- "%d", &val) < 0)
- val = 0;
- if (!val) {
- errno = ENOTSUP;
- goto error;
- }
- if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "protocol", "%63s",
- xenfb->protocol) < 0)
- xenfb->protocol[0] = '\0';
- xenfb_xs_printf(xsh, xenfb->fb.nodename, "request-update", "1");
-
- /* TODO check for permitted ranges */
- fb_page = xenfb->fb.page;
- xenfb->data.depth = fb_page->depth;
- xenfb->data.width = fb_page->width;
- xenfb->data.height = fb_page->height;
- /* TODO check for consistency with the above */
- xenfb->data.len = fb_page->mem_length;
- xenfb->data.row_stride = fb_page->line_length;
-
- if (xenfb_map_fb(xenfb, domid) < 0)
- goto error;
-
- if (xenfb_switch_state(&xenfb->fb, XenbusStateConnected))
- goto error;
- if (xenfb_switch_state(&xenfb->kbd, XenbusStateConnected))
- goto error;
-
- if (xenfb_wait_for_frontend_connected(&xenfb->kbd) < 0)
- goto error;
- if (xenfb_xs_scanf1(xsh, xenfb->kbd.otherend, "request-abs-pointer",
+ int val;
+
+ if (xenfb_xs_scanf1(xenfb->xsh, xenfb->fb.otherend, "feature-update",
+ "%d", &val) < 0)
+ val = 0;
+ if (!val) {
+ LOGF("feature-update not supported\n");
+ errno = ENOTSUP;
+ return -1;
+ }
+ if (xenfb_xs_scanf1(xenfb->xsh, xenfb->fb.otherend, "protocol", "%63s",
+ xenfb->protocol) < 0)
+ xenfb->protocol[0] = '\0';
+ xenfb_xs_printf(xenfb->xsh, xenfb->fb.nodename, "request-update", "1");
+
+ /* TODO check for permitted ranges */
+ fb_page = xenfb->fb.page;
+ xenfb->data.depth = fb_page->depth;
+ xenfb->data.width = fb_page->width;
+ xenfb->data.height = fb_page->height;
+ /* TODO check for consistency with the above */
+ xenfb->data.len = fb_page->mem_length;
+ xenfb->data.row_stride = fb_page->line_length;
+ LOGF("Framebuffer depth %d width %d height %d line %d\n",
+ fb_page->depth, fb_page->width, fb_page->height,
fb_page->line_length);
+ if (xenfb_map_fb(xenfb, xenfb->fb.otherend_id) < 0)
+ return -1;
+
+ if (xenfb_switch_state(&xenfb->fb, XenbusStateConnected))
+ return -1;
+ if (xenfb_switch_state(&xenfb->kbd, XenbusStateConnected))
+ return -1;
+
+ return 0;
+}
+
+/* Process the frontend keyboard config */
+static int xenfb_read_frontend_kbd_config(struct xenfb *xenfb)
+{
+ int val;
+
+ if (xenfb_xs_scanf1(xenfb->xsh, xenfb->kbd.otherend,
"request-abs-pointer",
"%d", &val) < 0)
val = 0;
xenfb->data.abs_pointer_wanted = val;
- /* Listen for events from xenstore */
- if (qemu_set_fd_handler2(xs_fileno(xenfb->xsh), NULL,
xenfb_dispatch_store, NULL, xenfb) < 0)
- goto error;
-
- /* Listen for events from the event channel */
- 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_put_keycode, xenfb);
- qemu_add_mouse_event_handler(xenfb_mouse_event, xenfb,
- xenfb->data.abs_pointer_wanted,
- "Xen PVFB Mouse");
-
+ return 0;
+}
+
+/* Register a watch against a frontend device, and setup
+ * QEMU event loop to poll the xenstore FD for notification */
+static int xenfb_wait_for_frontend(struct xenfb_device *dev, IOHandler
*handler)
+{
+ LOGF("Doing frontend watch on %s\n", dev->otherend);
+ if (!xs_watch(dev->xenfb->xsh, dev->otherend, "")) {
+ LOGF("Watch for dev failed\n");
+ return -1;
+ }
+
+ if (qemu_set_fd_handler2(xs_fileno(dev->xenfb->xsh), NULL, handler,
NULL, dev) < 0)
+ return -1;
+
+ return 0;
+}
+
+/* Register a watch against a backend device, and setup
+ * QEMU event loop to poll the xenstore FD for notification */
+static int xenfb_wait_for_backend(struct xenfb_device *dev, IOHandler *handler)
+{
+ LOGF("Doing backend watch on %s\n", dev->nodename);
+ if (!xs_watch(dev->xenfb->xsh, dev->nodename, "")) {
+ LOGF("Watch for dev failed\n");
+ return -1;
+ }
+
+ if (qemu_set_fd_handler2(xs_fileno(dev->xenfb->xsh), NULL, handler,
NULL, dev) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+/* Helper to determine if a frontend device is in Connected state */
+static int xenfb_frontend_connected(struct xenfb_device *dev)
+{
+ unsigned int state;
+ unsigned int dummy;
+ char **vec;
+ vec = xs_read_watch(dev->xenfb->xsh, &dummy);
+ if (!vec) {
+ xs_unwatch(dev->xenfb->xsh, dev->otherend, "");
+ return -1;
+ }
+ free(vec);
+
+ state = xenfb_read_state(dev->xenfb->xsh, dev->otherend);
+ if (!((1 <<state) & ((1 << XenbusStateUnknown) |
+ (1 << XenbusStateConnected)))) {
+ LOGF("FB: Carry on waiting\n");
+ return 1;
+ }
+
+ xs_unwatch(dev->xenfb->xsh, dev->otherend, "");
+
+ switch (state) {
+ case XenbusStateConnected:
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+
+/* Helper to determine if a frontend device is in Initialized state */
+static int xenfb_frontend_initialized(struct xenfb_device *dev)
+{
+ unsigned int state;
+ unsigned int dummy;
+ char **vec;
+ vec = xs_read_watch(dev->xenfb->xsh, &dummy);
+ if (!vec) {
+ xs_unwatch(dev->xenfb->xsh, dev->otherend, "");
+ return -1;
+ }
+ free(vec);
+
+ state = xenfb_read_state(dev->xenfb->xsh, dev->otherend);
+
+ if (!((1 << state) & ((1 << XenbusStateUnknown)
+ | (1 << XenbusStateInitialised)
+#if 1 /* TODO fudging state to permit restarting; to be removed */
+ | (1 << XenbusStateConnected)
+#endif
+ ))) {
+ LOGF("FB: Carry on waiting\n");
+ return 1;
+ }
+
+ xs_unwatch(dev->xenfb->xsh, dev->otherend, "");
+
+ switch (state) {
+#if 1
+ case XenbusStateConnected:
+ LOGF("Fudging state to %d\n", XenbusStateInitialised); /*
FIXME */
+#endif
+ case XenbusStateInitialised:
+ break;
+ default:
+ return -1;
+ }
+
+ if (xenfb_bind(dev) < 0)
+ return -1;
+
+ return 0;
+}
+
+/* Helper to determine if a backend device is in Created state */
+int xenfb_backend_created(struct xenfb_device *dev)
+{
+ unsigned int state;
+ unsigned int dummy;
+ char **vec;
+ vec = xs_read_watch(dev->xenfb->xsh, &dummy);
+ if (!vec) {
+ xs_unwatch(dev->xenfb->xsh, dev->nodename, "");
+ return -1;
+ }
+ free(vec);
+
+ state = xenfb_read_state(dev->xenfb->xsh, dev->nodename);
+
+ if (!((1 <<state) & ((1 << XenbusStateUnknown)
+ | (1 << XenbusStateInitialising)
+ | (1 << XenbusStateClosed)
+#if 1 /* TODO fudging state to permit restarting; to be removed */
+ | (1 << XenbusStateInitWait)
+ | (1 << XenbusStateConnected)
+ | (1 << XenbusStateClosing)
+#endif
+ ))) {
+ LOGF("FB: Carry on waiting\n");
+ return 1;
+ }
+
+ xs_unwatch(dev->xenfb->xsh, dev->nodename, "");
+
+ switch (state) {
+#if 1
+ case XenbusStateInitWait:
+ case XenbusStateConnected:
+ LOGF("FB: Fudging state to %d\n", XenbusStateInitialising); /*
FIXME */
+#endif
+ case XenbusStateInitialising:
+ case XenbusStateClosing:
+ case XenbusStateClosed:
+ break;
+ default:
+ LOGF("FB: Wrong state %d\n", state);
+ return -1;
+ }
+ xenfb_switch_state(dev, XenbusStateInitWait);
+ if (xenfb_hotplug(dev) < 0)
+ return -1;
+
+ return 0;
+}
+
+/* Callback invoked while waiting for KBD frontend to change
+ * to the connected state */
+void xenfb_frontend_connected_kbd(void *opaque)
+{
+ struct xenfb_device *dev = (struct xenfb_device *)opaque;
+ int ret = xenfb_frontend_connected(dev);
+ if (ret < 0) {
+ xenfb_shutdown(dev->xenfb);
+ return;
+ }
+ if (ret)
+ return; /* Still waiting */
+
+ if (xenfb_read_frontend_kbd_config(dev->xenfb) < 0) {
+ xenfb_shutdown(dev->xenfb);
+ return;
+ }
+
+ xenfb_register_console(dev->xenfb);
+
+ if (qemu_set_fd_handler2(dev->xenfb->evt_xch, NULL,
xenfb_dispatch_channel, NULL, dev->xenfb) < 0) {
+ xenfb_shutdown(dev->xenfb);
+ return;
+ }
+
+ LOGF("FB: Waiting for KBD frontend disconnection\n");
+ xenfb_wait_for_frontend(&dev->xenfb->kbd,
xenfb_frontend_disconnected_kbd);
+}
+
+/* Callback invoked while waiting for FB frontend to change
+ * to the initialized state */
+void xenfb_frontend_initialized_fb(void *opaque)
+{
+ struct xenfb_device *dev = (struct xenfb_device *)opaque;
+ int ret = xenfb_frontend_initialized(dev);
+ if (ret < 0) {
+ xenfb_shutdown(dev->xenfb);
+ return;
+ }
+ if (ret)
+ return; /* Still waiting */
+
+
+ if (xenfb_read_frontend_fb_config(dev->xenfb)) {
+ xenfb_shutdown(dev->xenfb);
+ return;
+ }
+
+ LOGF("FB: Waiting for KBD frontend connection\n");
+ xenfb_wait_for_frontend(&dev->xenfb->kbd, xenfb_frontend_connected_kbd);
+}
+
+/* Callback invoked while waiting for KBD frontend to change
+ * to the initialized state */
+void xenfb_frontend_initialized_kbd(void *opaque)
+{
+ struct xenfb_device *dev = (struct xenfb_device *)opaque;
+ int ret = xenfb_frontend_initialized(dev);
+ if (ret < 0) {
+ xenfb_shutdown(dev->xenfb);
+ return;
+ }
+ if (ret)
+ return; /* Still waiting */
+
+
+ LOGF("FB: Waiting for FB frontend initialization\n");
+ xenfb_wait_for_frontend(&dev->xenfb->fb, xenfb_frontend_initialized_fb);
+}
+
+/* Callback invoked while waiting for FB backend to change
+ * to the created state */
+void xenfb_backend_created_fb(void *opaque)
+{
+ struct xenfb_device *dev = (struct xenfb_device *)opaque;
+ int ret = xenfb_backend_created(dev);
+ if (ret < 0) {
+ xenfb_shutdown(dev->xenfb);
+ return;
+ }
+ if (ret)
+ return; /* Still waiting */
+
+ LOGF("FB: Waiting for KBD frontend initialization\n");
+ xenfb_wait_for_frontend(&dev->xenfb->kbd,
xenfb_frontend_initialized_kbd);
+}
+
+/* Callback invoked while waiting for KBD backend to change
+ * to the created state */
+void xenfb_backend_created_kbd(void *opaque)
+{
+ struct xenfb_device *dev = (struct xenfb_device *)opaque;
+ int ret = xenfb_backend_created(dev);
+ if (ret < 0) {
+ xenfb_shutdown(dev->xenfb);
+ return;
+ }
+ if (ret)
+ return; /* Still waiting */
+
+ if (xenfb_xs_printf(dev->xenfb->xsh, dev->nodename,
"feature-abs-pointer", "1")) {
+ xenfb_shutdown(dev->xenfb);
+ return;
+ }
+
+ LOGF("FB: Waiting for FB backend creation\n");
+ xenfb_wait_for_backend(&dev->xenfb->fb, xenfb_backend_created_fb);
+}
+
+
+/* Create a new Xen FB associated with QEMU DisplayState,
+ * wait for domid to appear and connect to its frontend */
+struct xenfb *xenfb_new(int domid, DisplayState *ds)
+{
+ int serrno;
+ struct xenfb *xenfb = qemu_malloc(sizeof(struct xenfb));
+
+ if (xenfb == NULL)
+ return NULL;
+
+ memset(xenfb, 0, sizeof(*xenfb));
xenfb->ds = ds;
-
- /* Tell QEMU to allocate a graphical console */
- graphic_console_init(ds,
- xenfb_update,
- xenfb_invalidate,
- xenfb_screen_dump,
- xenfb);
- dpy_resize(ds, xenfb->data.width, xenfb->data.height);
-
- return 0;
-
- error:
- serrno = errno;
- xenfb_detach_dom(xenfb);
- xenfb_dev_fatal(&xenfb->fb, serrno, "on fire");
- xenfb_dev_fatal(&xenfb->kbd, serrno, "on fire");
- errno = serrno;
- return -1;
+ xenfb->evt_xch = xenfb->xc = -1;
+ xenfb_device_init(&xenfb->fb, "vfb", xenfb);
+ xenfb_device_init(&xenfb->kbd, "vkbd", xenfb);
+
+ xenfb->evt_xch = xc_evtchn_open();
+ if (xenfb->evt_xch == -1)
+ goto fail;
+
+ xenfb->xc = xc_interface_open();
+ if (xenfb->xc == -1)
+ goto fail;
+
+ xenfb->xsh = xs_daemon_open();
+ if (!xenfb->xsh)
+ goto fail;
+
+ xenfb_device_set_domain(&xenfb->fb, domid);
+ xenfb_device_set_domain(&xenfb->kbd, domid);
+
+ LOGF("FB: Waiting for KBD backend creation\n");
+ xenfb_wait_for_backend(&xenfb->kbd, xenfb_backend_created_kbd);
+
+ return xenfb;
+
+ fail:
+ serrno = errno;
+ xenfb_shutdown(xenfb);
+ errno = serrno;
+ return NULL;
+}
+
+/* Remove the backend area in xenbus since the framebuffer really is
+ going away. */
+void xenfb_shutdown(struct xenfb *xenfb)
+{
+ LOGF("FB: Shutting down backend\n");
+ xs_rm(xenfb->xsh, XBT_NULL, xenfb->fb.nodename);
+ xs_rm(xenfb->xsh, XBT_NULL, xenfb->kbd.nodename);
+
+ xenfb_detach_dom(xenfb);
+ if (xenfb->xc >= 0)
+ xc_interface_close(xenfb->xc);
+ if (xenfb->evt_xch >= 0)
+ xc_evtchn_close(xenfb->evt_xch);
+ if (xenfb->xsh)
+ xs_daemon_close(xenfb->xsh);
+ free(xenfb);
}
/*
diff -r 829464d36542 tools/ioemu/hw/xenfb.h
--- a/tools/ioemu/hw/xenfb.h Tue Aug 21 22:07:47 2007 -0400
+++ b/tools/ioemu/hw/xenfb.h Tue Aug 21 22:08:24 2007 -0400
@@ -7,10 +7,7 @@
struct xenfb;
-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, DisplayState *ds);
+struct xenfb *xenfb_new(int domid, DisplayState *ds);
+void xenfb_shutdown(struct xenfb *xenfb);
#endif
--
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=|
|=- Perl modules: http://search.cpan.org/~danberr/ -=|
|=- Projects: http://freshmeat.net/~danielpb/ -=|
|=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|