aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2008-05-12 10:10:03 +0100
committerKeir Fraser <keir.fraser@citrix.com>2008-05-12 10:10:03 +0100
commitde239d043fbfddbcb509e64186f963697127983e (patch)
tree572eae02c73c3850771a8895cc5712d14bccc8f0
parentaa7e17e11bb354d0cda598c7e6ccff29b210eb1c (diff)
downloadxen-de239d043fbfddbcb509e64186f963697127983e.tar.gz
xen-de239d043fbfddbcb509e64186f963697127983e.tar.bz2
xen-de239d043fbfddbcb509e64186f963697127983e.zip
pvfb/ioemu: transmit refresh interval advice from backend to frontend
which permits the frontend to avoid useless polls. Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
-rw-r--r--extras/mini-os/fbfront.c55
-rw-r--r--extras/mini-os/include/fbfront.h3
-rw-r--r--extras/mini-os/include/lib.h4
-rw-r--r--extras/mini-os/kernel.c65
-rw-r--r--extras/mini-os/lib/sys.c20
-rw-r--r--tools/ioemu/hw/xenfb.c167
-rw-r--r--tools/ioemu/sdl.c2
-rw-r--r--tools/ioemu/vl.c4
-rw-r--r--tools/ioemu/vl.h4
-rw-r--r--tools/ioemu/vnc.c47
-rw-r--r--xen/include/public/io/fbif.h21
11 files changed, 316 insertions, 76 deletions
diff --git a/extras/mini-os/fbfront.c b/extras/mini-os/fbfront.c
index 3a361b829c..d5acadf085 100644
--- a/extras/mini-os/fbfront.c
+++ b/extras/mini-os/fbfront.c
@@ -255,13 +255,57 @@ struct fbfront_dev {
int offset;
xenbus_event_queue events;
+
+#ifdef HAVE_LIBC
+ int fd;
+#endif
};
void fbfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
{
+#ifdef HAVE_LIBC
+ struct fbfront_dev *dev = data;
+ int fd = dev->fd;
+
+ files[fd].read = 1;
+#endif
wake_up(&fbfront_queue);
}
+int fbfront_receive(struct fbfront_dev *dev, union xenfb_in_event *buf, int n)
+{
+ struct xenfb_page *page = dev->page;
+ uint32_t prod, cons;
+ int i;
+
+#ifdef HAVE_LIBC
+ files[dev->fd].read = 0;
+ mb(); /* Make sure to let the handler set read to 1 before we start looking at the ring */
+#endif
+
+ prod = page->in_prod;
+
+ if (prod == page->in_cons)
+ return 0;
+
+ rmb(); /* ensure we see ring contents up to prod */
+
+ for (i = 0, cons = page->in_cons; i < n && cons != prod; i++, cons++)
+ memcpy(buf + i, &XENFB_IN_RING_REF(page, cons), sizeof(*buf));
+
+ mb(); /* ensure we got ring contents */
+ page->in_cons = cons;
+ notify_remote_via_evtchn(dev->evtchn);
+
+#ifdef HAVE_LIBC
+ if (cons != prod)
+ /* still some events to read */
+ files[dev->fd].read = 1;
+#endif
+
+ return i;
+}
+
struct fbfront_dev *init_fbfront(char *nodename, unsigned long *mfns, int width, int height, int depth, int stride, int n)
{
xenbus_transaction_t xbt;
@@ -482,3 +526,14 @@ void shutdown_fbfront(struct fbfront_dev *dev)
free(dev->backend);
free(dev);
}
+
+#ifdef HAVE_LIBC
+int fbfront_open(struct fbfront_dev *dev)
+{
+ dev->fd = alloc_fd(FTYPE_FB);
+ printk("fb_open(%s) -> %d\n", dev->nodename, dev->fd);
+ files[dev->fd].fb.dev = dev;
+ return dev->fd;
+}
+#endif
+
diff --git a/extras/mini-os/include/fbfront.h b/extras/mini-os/include/fbfront.h
index 70b2f2a681..1e4d7ac6d9 100644
--- a/extras/mini-os/include/fbfront.h
+++ b/extras/mini-os/include/fbfront.h
@@ -1,4 +1,5 @@
#include <xen/io/kbdif.h>
+#include <xen/io/fbif.h>
#include <wait.h>
/* from <linux/input.h> */
@@ -36,6 +37,8 @@ struct fbfront_dev *init_fbfront(char *nodename, unsigned long *mfns, int width,
int fbfront_open(struct fbfront_dev *dev);
#endif
+int fbfront_receive(struct fbfront_dev *dev, union xenfb_in_event *buf, int n);
+extern struct wait_queue_head fbfront_queue;
void fbfront_update(struct fbfront_dev *dev, int x, int y, int width, int height);
void fbfront_resize(struct fbfront_dev *dev, int width, int height, int stride, int depth, int offset);
diff --git a/extras/mini-os/include/lib.h b/extras/mini-os/include/lib.h
index 0acb0fc4e2..b26a5eda39 100644
--- a/extras/mini-os/include/lib.h
+++ b/extras/mini-os/include/lib.h
@@ -141,6 +141,7 @@ enum fd_type {
FTYPE_TAP,
FTYPE_BLK,
FTYPE_KBD,
+ FTYPE_FB,
};
#define MAX_EVTCHN_PORTS 16
@@ -175,6 +176,9 @@ extern struct file {
struct {
struct kbdfront_dev *dev;
} kbd;
+ struct {
+ struct fbfront_dev *dev;
+ } fb;
struct {
/* To each xenbus FD is associated a queue of watch events for this
* FD. */
diff --git a/extras/mini-os/kernel.c b/extras/mini-os/kernel.c
index c37644bf4f..662acb0b00 100644
--- a/extras/mini-os/kernel.c
+++ b/extras/mini-os/kernel.c
@@ -260,6 +260,7 @@ static void blkfront_thread(void *p)
#define DEPTH 32
static uint32_t *fb;
+static int refresh_period = 50;
static struct fbfront_dev *fb_dev;
static struct semaphore fbfront_sem = __SEMAPHORE_INITIALIZER(fbfront_sem, 0);
@@ -333,6 +334,10 @@ static void clip_cursor(int *x, int *y)
static void refresh_cursor(int new_x, int new_y)
{
static int old_x = -1, old_y = -1;
+
+ if (!refresh_period)
+ return;
+
if (old_x != -1 && old_y != -1) {
fbfront_drawvert(old_x, old_y + 1, old_y + 8, 0xffffffff);
fbfront_drawhoriz(old_x + 1, old_x + 8, old_y, 0xffffffff);
@@ -358,43 +363,46 @@ static void kbdfront_thread(void *p)
down(&fbfront_sem);
refresh_cursor(x, y);
while (1) {
- union xenkbd_in_event event;
+ union xenkbd_in_event kbdevent;
+ union xenfb_in_event fbevent;
+ int sleep = 1;
add_waiter(w, kbdfront_queue);
+ add_waiter(w, fbfront_queue);
- if (kbdfront_receive(kbd_dev, &event, 1) == 0)
- schedule();
- else switch(event.type) {
+ while (kbdfront_receive(kbd_dev, &kbdevent, 1) != 0) {
+ sleep = 0;
+ switch(kbdevent.type) {
case XENKBD_TYPE_MOTION:
printk("motion x:%d y:%d z:%d\n",
- event.motion.rel_x,
- event.motion.rel_y,
- event.motion.rel_z);
- x += event.motion.rel_x;
- y += event.motion.rel_y;
- z += event.motion.rel_z;
+ kbdevent.motion.rel_x,
+ kbdevent.motion.rel_y,
+ kbdevent.motion.rel_z);
+ x += kbdevent.motion.rel_x;
+ y += kbdevent.motion.rel_y;
+ z += kbdevent.motion.rel_z;
clip_cursor(&x, &y);
refresh_cursor(x, y);
break;
case XENKBD_TYPE_POS:
printk("pos x:%d y:%d dz:%d\n",
- event.pos.abs_x,
- event.pos.abs_y,
- event.pos.rel_z);
- x = event.pos.abs_x;
- y = event.pos.abs_y;
- z = event.pos.rel_z;
+ kbdevent.pos.abs_x,
+ kbdevent.pos.abs_y,
+ kbdevent.pos.rel_z);
+ x = kbdevent.pos.abs_x;
+ y = kbdevent.pos.abs_y;
+ z = kbdevent.pos.rel_z;
clip_cursor(&x, &y);
refresh_cursor(x, y);
break;
case XENKBD_TYPE_KEY:
printk("key %d %s\n",
- event.key.keycode,
- event.key.pressed ? "pressed" : "released");
- if (event.key.keycode == BTN_LEFT) {
+ kbdevent.key.keycode,
+ kbdevent.key.pressed ? "pressed" : "released");
+ if (kbdevent.key.keycode == BTN_LEFT) {
printk("mouse %s at (%d,%d,%d)\n",
- event.key.pressed ? "clic" : "release", x, y, z);
- if (event.key.pressed) {
+ kbdevent.key.pressed ? "clic" : "release", x, y, z);
+ if (kbdevent.key.pressed) {
uint32_t color = rand();
fbfront_drawvert(x - 16, y - 16, y + 15, color);
fbfront_drawhoriz(x - 16, x + 15, y + 16, color);
@@ -402,13 +410,26 @@ static void kbdfront_thread(void *p)
fbfront_drawhoriz(x - 15, x + 16, y - 16, color);
fbfront_update(fb_dev, x - 16, y - 16, 33, 33);
}
- } else if (event.key.keycode == KEY_Q) {
+ } else if (kbdevent.key.keycode == KEY_Q) {
struct sched_shutdown sched_shutdown = { .reason = SHUTDOWN_poweroff };
HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown);
do_exit();
}
break;
+ }
}
+ while (fbfront_receive(fb_dev, &fbevent, 1) != 0) {
+ sleep = 0;
+ switch(fbevent.type) {
+ case XENFB_TYPE_REFRESH_PERIOD:
+ refresh_period = fbevent.refresh_period.period;
+ printk("refresh period %d\n", refresh_period);
+ refresh_cursor(x, y);
+ break;
+ }
+ }
+ if (sleep)
+ schedule();
}
}
diff --git a/extras/mini-os/lib/sys.c b/extras/mini-os/lib/sys.c
index efa02e5af4..730caab552 100644
--- a/extras/mini-os/lib/sys.c
+++ b/extras/mini-os/lib/sys.c
@@ -249,6 +249,16 @@ int read(int fd, void *buf, size_t nbytes)
}
return ret * sizeof(union xenkbd_in_event);
}
+ case FTYPE_FB: {
+ int ret, n;
+ n = nbytes / sizeof(union xenfb_in_event);
+ ret = fbfront_receive(files[fd].fb.dev, buf, n);
+ if (ret <= 0) {
+ errno = EAGAIN;
+ return -1;
+ }
+ return ret * sizeof(union xenfb_in_event);
+ }
case FTYPE_NONE:
case FTYPE_XENBUS:
case FTYPE_EVTCHN:
@@ -290,6 +300,7 @@ int write(int fd, const void *buf, size_t nbytes)
case FTYPE_EVTCHN:
case FTYPE_BLK:
case FTYPE_KBD:
+ case FTYPE_FB:
break;
}
printk("write(%d): Bad descriptor\n", fd);
@@ -348,6 +359,7 @@ int fsync(int fd) {
case FTYPE_TAP:
case FTYPE_BLK:
case FTYPE_KBD:
+ case FTYPE_FB:
break;
}
printk("fsync(%d): Bad descriptor\n", fd);
@@ -394,6 +406,10 @@ int close(int fd)
shutdown_kbdfront(files[fd].kbd.dev);
files[fd].type = FTYPE_NONE;
return 0;
+ case FTYPE_FB:
+ shutdown_fbfront(files[fd].fb.dev);
+ files[fd].type = FTYPE_NONE;
+ return 0;
case FTYPE_NONE:
break;
}
@@ -485,6 +501,7 @@ int fstat(int fd, struct stat *buf)
case FTYPE_TAP:
case FTYPE_BLK:
case FTYPE_KBD:
+ case FTYPE_FB:
break;
}
@@ -513,6 +530,7 @@ int ftruncate(int fd, off_t length)
case FTYPE_TAP:
case FTYPE_BLK:
case FTYPE_KBD:
+ case FTYPE_FB:
break;
}
@@ -624,6 +642,7 @@ static const char file_types[] = {
[FTYPE_TAP] = 'T',
[FTYPE_BLK] = 'B',
[FTYPE_KBD] = 'K',
+ [FTYPE_FB] = 'G',
};
#ifdef LIBC_DEBUG
static void dump_set(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
@@ -732,6 +751,7 @@ static int select_poll(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exce
case FTYPE_TAP:
case FTYPE_BLK:
case FTYPE_KBD:
+ case FTYPE_FB:
if (FD_ISSET(i, readfds)) {
if (files[i].read)
n++;
diff --git a/tools/ioemu/hw/xenfb.c b/tools/ioemu/hw/xenfb.c
index ee75795a29..7307122980 100644
--- a/tools/ioemu/hw/xenfb.c
+++ b/tools/ioemu/hw/xenfb.c
@@ -59,6 +59,7 @@ struct xenfb {
int offset; /* offset of the framebuffer */
int abs_pointer_wanted; /* Whether guest supports absolute pointer */
int button_state; /* Last seen pointer button state */
+ int refresh_period; /* The refresh period we have advised */
char protocol[64]; /* frontend protocol */
};
@@ -536,6 +537,41 @@ static void xenfb_on_fb_event(struct xenfb *xenfb)
xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port);
}
+static int xenfb_queue_full(struct xenfb *xenfb)
+{
+ struct xenfb_page *page = xenfb->fb.page;
+ uint32_t cons, prod;
+
+ prod = page->in_prod;
+ cons = page->in_cons;
+ return prod - cons == XENFB_IN_RING_LEN;
+}
+
+static void xenfb_send_event(struct xenfb *xenfb, union xenfb_in_event *event)
+{
+ uint32_t prod;
+ struct xenfb_page *page = xenfb->fb.page;
+
+ prod = page->in_prod;
+ /* caller ensures !xenfb_queue_full() */
+ xen_mb(); /* ensure ring space available */
+ XENFB_IN_RING_REF(page, prod) = *event;
+ xen_wmb(); /* ensure ring contents visible */
+ page->in_prod = prod + 1;
+
+ xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port);
+}
+
+static void xenfb_send_refresh_period(struct xenfb *xenfb, int period)
+{
+ union xenfb_in_event event;
+
+ memset(&event, 0, sizeof(event));
+ event.type = XENFB_TYPE_REFRESH_PERIOD;
+ event.refresh_period.period = period;
+ xenfb_send_event(xenfb, &event);
+}
+
static void xenfb_on_kbd_event(struct xenfb *xenfb)
{
struct xenkbd_page *page = xenfb->kbd.page;
@@ -707,6 +743,7 @@ static int xenfb_read_frontend_fb_config(struct xenfb *xenfb) {
xenfb->protocol) < 0)
xenfb->protocol[0] = '\0';
xenfb_xs_printf(xenfb->xsh, xenfb->fb.nodename, "request-update", "1");
+ xenfb->refresh_period = -1;
/* TODO check for permitted ranges */
fb_page = xenfb->fb.page;
@@ -1185,10 +1222,28 @@ static void xenfb_guest_copy(struct xenfb *xenfb, int x, int y, int w, int h)
dpy_update(xenfb->ds, x, y, w, h);
}
-/* Periodic update of display, no need for any in our case */
+/* Periodic update of display, transmit the refresh interval to the frontend */
static void xenfb_update(void *opaque)
{
struct xenfb *xenfb = opaque;
+ int period;
+
+ if (xenfb_queue_full(xenfb))
+ return;
+
+ if (xenfb->ds->idle)
+ period = XENFB_NO_REFRESH;
+ else {
+ period = xenfb->ds->gui_timer_interval;
+ if (!period)
+ period = GUI_REFRESH_INTERVAL;
+ }
+
+ /* Will have to be disabled for frontends without feature-update */
+ if (xenfb->refresh_period != period) {
+ xenfb_send_refresh_period(xenfb, period);
+ xenfb->refresh_period = period;
+ }
}
/* QEMU display state changed, so refresh the framebuffer copy */
@@ -1232,11 +1287,17 @@ static int xenfb_register_console(struct xenfb *xenfb) {
}
#ifdef CONFIG_STUBDOM
-static struct semaphore kbd_sem = __SEMAPHORE_INITIALIZER(kbd_sem, 0);
-static struct kbdfront_dev *kbd_dev;
+typedef struct XenFBState {
+ struct semaphore kbd_sem;
+ struct kbdfront_dev *kbd_dev;
+ struct fbfront_dev *fb_dev;
+ void *vga_vram, *nonshared_vram;
+ DisplayState *ds;
+} XenFBState;
+
+XenFBState *xs;
+
static char *kbd_path, *fb_path;
-static void *vga_vram, *nonshared_vram;
-static DisplayState *xenfb_ds;
static unsigned char linux2scancode[KEY_MAX + 1];
@@ -1254,7 +1315,8 @@ int xenfb_connect_vfb(const char *path)
static void xenfb_pv_update(DisplayState *ds, int x, int y, int w, int h)
{
- struct fbfront_dev *fb_dev = ds->opaque;
+ XenFBState *xs = ds->opaque;
+ struct fbfront_dev *fb_dev = xs->fb_dev;
if (!fb_dev)
return;
fbfront_update(fb_dev, x, y, w, h);
@@ -1262,7 +1324,8 @@ static void xenfb_pv_update(DisplayState *ds, int x, int y, int w, int h)
static void xenfb_pv_resize(DisplayState *ds, int w, int h, int linesize)
{
- struct fbfront_dev *fb_dev = ds->opaque;
+ XenFBState *xs = ds->opaque;
+ struct fbfront_dev *fb_dev = xs->fb_dev;
fprintf(stderr,"resize to %dx%d, %d required\n", w, h, linesize);
ds->width = w;
ds->height = h;
@@ -1276,14 +1339,15 @@ static void xenfb_pv_resize(DisplayState *ds, int w, int h, int linesize)
if (ds->shared_buf) {
ds->data = NULL;
} else {
- ds->data = nonshared_vram;
+ ds->data = xs->nonshared_vram;
fbfront_resize(fb_dev, w, h, linesize, ds->depth, VGA_RAM_SIZE);
}
}
static void xenfb_pv_colourdepth(DisplayState *ds, int depth)
{
- struct fbfront_dev *fb_dev = ds->opaque;
+ XenFBState *xs = ds->opaque;
+ struct fbfront_dev *fb_dev = xs->fb_dev;
static int lastdepth = -1;
if (!depth) {
ds->shared_buf = 0;
@@ -1301,15 +1365,16 @@ static void xenfb_pv_colourdepth(DisplayState *ds, int depth)
if (ds->shared_buf) {
ds->data = NULL;
} else {
- ds->data = nonshared_vram;
+ ds->data = xs->nonshared_vram;
fbfront_resize(fb_dev, ds->width, ds->height, ds->linesize, ds->depth, VGA_RAM_SIZE);
}
}
static void xenfb_pv_setdata(DisplayState *ds, void *pixels)
{
- struct fbfront_dev *fb_dev = ds->opaque;
- int offset = pixels - vga_vram;
+ XenFBState *xs = ds->opaque;
+ struct fbfront_dev *fb_dev = xs->fb_dev;
+ int offset = pixels - xs->vga_vram;
ds->data = pixels;
if (!fb_dev)
return;
@@ -1321,16 +1386,45 @@ static void xenfb_pv_refresh(DisplayState *ds)
vga_hw_update();
}
+static void xenfb_fb_handler(void *opaque)
+{
+#define FB_NUM_BATCH 4
+ union xenfb_in_event buf[FB_NUM_BATCH];
+ int n, i;
+ XenFBState *xs = opaque;
+ DisplayState *ds = xs->ds;
+
+ n = fbfront_receive(xs->fb_dev, buf, FB_NUM_BATCH);
+ for (i = 0; i < n; i++) {
+ switch (buf[i].type) {
+ case XENFB_TYPE_REFRESH_PERIOD:
+ if (buf[i].refresh_period.period == XENFB_NO_REFRESH) {
+ /* Sleeping interval */
+ ds->idle = 1;
+ ds->gui_timer_interval = 500;
+ } else {
+ /* Set interval */
+ ds->idle = 0;
+ ds->gui_timer_interval = buf[i].refresh_period.period;
+ }
+ default:
+ /* ignore unknown events */
+ break;
+ }
+ }
+}
+
static void xenfb_kbd_handler(void *opaque)
{
#define KBD_NUM_BATCH 64
union xenkbd_in_event buf[KBD_NUM_BATCH];
int n, i;
- DisplayState *s = opaque;
+ XenFBState *xs = opaque;
+ DisplayState *s = xs->ds;
static int buttons;
static int x, y;
- n = kbdfront_receive(kbd_dev, buf, KBD_NUM_BATCH);
+ n = kbdfront_receive(xs->kbd_dev, buf, KBD_NUM_BATCH);
for (i = 0; i < n; i++) {
switch (buf[i].type) {
@@ -1412,12 +1506,13 @@ static void xenfb_kbd_handler(void *opaque)
static void kbdfront_thread(void *p)
{
int scancode, keycode;
- kbd_dev = init_kbdfront(p, 1);
- if (!kbd_dev) {
+ XenFBState *xs = p;
+ xs->kbd_dev = init_kbdfront(kbd_path, 1);
+ if (!xs->kbd_dev) {
fprintf(stderr,"can't open keyboard\n");
exit(1);
}
- up(&kbd_sem);
+ up(&xs->kbd_sem);
for (scancode = 0; scancode < 128; scancode++) {
keycode = atkbd_set2_keycode[atkbd_unxlate_table[scancode]];
linux2scancode[keycode] = scancode;
@@ -1431,12 +1526,18 @@ int xenfb_pv_display_init(DisplayState *ds)
if (!fb_path || !kbd_path)
return -1;
- create_thread("kbdfront", kbdfront_thread, (void*) kbd_path);
+ xs = qemu_mallocz(sizeof(XenFBState));
+ if (!xs)
+ return -1;
- xenfb_ds = ds;
+ init_SEMAPHORE(&xs->kbd_sem, 0);
+ xs->ds = ds;
- ds->data = nonshared_vram = qemu_memalign(PAGE_SIZE, VGA_RAM_SIZE);
+ create_thread("kbdfront", kbdfront_thread, (void*) xs);
+
+ ds->data = xs->nonshared_vram = qemu_memalign(PAGE_SIZE, VGA_RAM_SIZE);
memset(ds->data, 0, VGA_RAM_SIZE);
+ ds->opaque = xs;
ds->depth = 32;
ds->bgr = 0;
ds->width = 640;
@@ -1452,9 +1553,9 @@ int xenfb_pv_display_init(DisplayState *ds)
int xenfb_pv_display_start(void *data)
{
- DisplayState *ds = xenfb_ds;
+ DisplayState *ds;
struct fbfront_dev *fb_dev;
- int kbd_fd;
+ int kbd_fd, fb_fd;
int offset = 0;
unsigned long *mfns;
int n = VGA_RAM_SIZE / PAGE_SIZE;
@@ -1463,12 +1564,13 @@ int xenfb_pv_display_start(void *data)
if (!fb_path || !kbd_path)
return 0;
- vga_vram = data;
+ ds = xs->ds;
+ xs->vga_vram = data;
mfns = malloc(2 * n * sizeof(*mfns));
for (i = 0; i < n; i++)
- mfns[i] = virtual_to_mfn(vga_vram + i * PAGE_SIZE);
+ mfns[i] = virtual_to_mfn(xs->vga_vram + i * PAGE_SIZE);
for (i = 0; i < n; i++)
- mfns[n + i] = virtual_to_mfn(nonshared_vram + i * PAGE_SIZE);
+ mfns[n + i] = virtual_to_mfn(xs->nonshared_vram + i * PAGE_SIZE);
fb_dev = init_fbfront(fb_path, mfns, ds->width, ds->height, ds->depth, ds->linesize, 2 * n);
free(mfns);
@@ -1479,21 +1581,24 @@ int xenfb_pv_display_start(void *data)
free(fb_path);
if (ds->shared_buf) {
- offset = (void*) ds->data - vga_vram;
+ offset = (void*) ds->data - xs->vga_vram;
} else {
offset = VGA_RAM_SIZE;
- ds->data = nonshared_vram;
+ ds->data = xs->nonshared_vram;
}
if (offset)
fbfront_resize(fb_dev, ds->width, ds->height, ds->linesize, ds->depth, offset);
- down(&kbd_sem);
+ down(&xs->kbd_sem);
free(kbd_path);
- kbd_fd = kbdfront_open(kbd_dev);
- qemu_set_fd_handler(kbd_fd, xenfb_kbd_handler, NULL, ds);
+ kbd_fd = kbdfront_open(xs->kbd_dev);
+ qemu_set_fd_handler(kbd_fd, xenfb_kbd_handler, NULL, xs);
+
+ fb_fd = fbfront_open(fb_dev);
+ qemu_set_fd_handler(fb_fd, xenfb_fb_handler, NULL, xs);
- xenfb_ds->opaque = fb_dev;
+ xs->fb_dev = fb_dev;
return 0;
}
#endif
diff --git a/tools/ioemu/sdl.c b/tools/ioemu/sdl.c
index c70c3cb7ad..3384a9a894 100644
--- a/tools/ioemu/sdl.c
+++ b/tools/ioemu/sdl.c
@@ -696,9 +696,11 @@ static void sdl_refresh(DisplayState *ds)
if (ev->active.gain) {
/* Back to default interval */
ds->gui_timer_interval = 0;
+ ds->idle = 0;
} else {
/* Sleeping interval */
ds->gui_timer_interval = 500;
+ ds->idle = 1;
}
}
break;
diff --git a/tools/ioemu/vl.c b/tools/ioemu/vl.c
index 50e3f871f2..76fa9acf6d 100644
--- a/tools/ioemu/vl.c
+++ b/tools/ioemu/vl.c
@@ -130,8 +130,6 @@
#else
#define DEFAULT_RAM_SIZE 128
#endif
-/* in ms */
-#define GUI_REFRESH_INTERVAL 30
/* Max number of USB devices that can be specified on the commandline. */
#define MAX_USB_CMDLINE 8
@@ -4467,6 +4465,8 @@ void dumb_display_init(DisplayState *ds)
ds->dpy_resize = dumb_resize;
ds->dpy_colourdepth = NULL;
ds->dpy_refresh = dumb_refresh;
+ ds->gui_timer_interval = 500;
+ ds->idle = 1;
}
/***********************************************************/
diff --git a/tools/ioemu/vl.h b/tools/ioemu/vl.h
index 6b103e72a9..705878cba2 100644
--- a/tools/ioemu/vl.h
+++ b/tools/ioemu/vl.h
@@ -929,6 +929,9 @@ extern struct soundhw soundhw[];
#define VGA_RAM_SIZE (8192 * 1024)
+/* in ms */
+#define GUI_REFRESH_INTERVAL 30
+
struct DisplayState {
uint8_t *data;
int linesize;
@@ -939,6 +942,7 @@ struct DisplayState {
void *opaque;
uint32_t *palette;
uint64_t gui_timer_interval;
+ int idle;
int shared_buf;
diff --git a/tools/ioemu/vnc.c b/tools/ioemu/vnc.c
index 36c5f5749f..7ac3c4c2f5 100644
--- a/tools/ioemu/vnc.c
+++ b/tools/ioemu/vnc.c
@@ -778,6 +778,7 @@ static void _vnc_update_client(void *opaque)
vs->has_update = 0;
vnc_flush(vs);
vs->last_update_time = now;
+ vs->ds->idle = 0;
vs->timer_interval /= 2;
if (vs->timer_interval < VNC_REFRESH_INTERVAL_BASE)
@@ -790,26 +791,29 @@ static void _vnc_update_client(void *opaque)
vs->timer_interval += VNC_REFRESH_INTERVAL_INC;
if (vs->timer_interval > VNC_REFRESH_INTERVAL_MAX) {
vs->timer_interval = VNC_REFRESH_INTERVAL_MAX;
- if (now - vs->last_update_time >= VNC_MAX_UPDATE_INTERVAL &&
- vs->update_requested) {
- /* Send a null update. If the client is no longer
- interested (e.g. minimised) it'll ignore this, and we
- can stop scanning the buffer until it sends another
- update request. */
- /* It turns out that there's a bug in realvncviewer 4.1.2
- which means that if you send a proper null update (with
- no update rectangles), it gets a bit out of sync and
- never sends any further requests, regardless of whether
- it needs one or not. Fix this by sending a single 1x1
- update rectangle instead. */
- vnc_write_u8(vs, 0);
- vnc_write_u8(vs, 0);
- vnc_write_u16(vs, 1);
- send_framebuffer_update(vs, 0, 0, 1, 1);
- vnc_flush(vs);
- vs->last_update_time = now;
- vs->update_requested--;
- return;
+ if (now - vs->last_update_time >= VNC_MAX_UPDATE_INTERVAL) {
+ if (!vs->update_requested) {
+ vs->ds->idle = 1;
+ } else {
+ /* Send a null update. If the client is no longer
+ interested (e.g. minimised) it'll ignore this, and we
+ can stop scanning the buffer until it sends another
+ update request. */
+ /* It turns out that there's a bug in realvncviewer 4.1.2
+ which means that if you send a proper null update (with
+ no update rectangles), it gets a bit out of sync and
+ never sends any further requests, regardless of whether
+ it needs one or not. Fix this by sending a single 1x1
+ update rectangle instead. */
+ vnc_write_u8(vs, 0);
+ vnc_write_u8(vs, 0);
+ vnc_write_u16(vs, 1);
+ send_framebuffer_update(vs, 0, 0, 1, 1);
+ vnc_flush(vs);
+ vs->last_update_time = now;
+ vs->update_requested--;
+ return;
+ }
}
}
qemu_mod_timer(vs->timer, now + vs->timer_interval);
@@ -970,6 +974,7 @@ static int vnc_client_io_error(VncState *vs, int ret, int last_errno)
qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
closesocket(vs->csock);
vs->csock = -1;
+ vs->ds->idle = 1;
buffer_reset(&vs->input);
buffer_reset(&vs->output);
free_queue(vs);
@@ -2443,6 +2448,7 @@ static void vnc_listen_read(void *opaque)
vs->csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
if (vs->csock != -1) {
VNC_DEBUG("New client on socket %d\n", vs->csock);
+ vs->ds->idle = 0;
socket_set_nonblock(vs->csock);
qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, opaque);
vnc_write(vs, "RFB 003.008\n", 12);
@@ -2468,6 +2474,7 @@ void vnc_display_init(DisplayState *ds)
exit(1);
ds->opaque = vs;
+ ds->idle = 1;
vnc_state = vs;
vs->display = NULL;
vs->password = NULL;
diff --git a/xen/include/public/io/fbif.h b/xen/include/public/io/fbif.h
index aecd1cd810..95377a0e0f 100644
--- a/xen/include/public/io/fbif.h
+++ b/xen/include/public/io/fbif.h
@@ -80,14 +80,33 @@ union xenfb_out_event
/*
* Frontends should ignore unknown in events.
- * No in events currently defined.
*/
+/*
+ * Framebuffer refresh period advice
+ * Backend sends it to advise the frontend their preferred period of
+ * refresh. Frontends that keep the framebuffer constantly up-to-date
+ * just ignore it. Frontends that use the advice should immediately
+ * refresh the framebuffer (and send an update notification event if
+ * those have been requested), then use the update frequency to guide
+ * their periodical refreshs.
+ */
+#define XENFB_TYPE_REFRESH_PERIOD 1
+#define XENFB_NO_REFRESH 0
+
+struct xenfb_refresh_period
+{
+ uint8_t type; /* XENFB_TYPE_UPDATE_PERIOD */
+ uint32_t period; /* period of refresh, in ms,
+ * XENFB_NO_REFRESH if no refresh is needed */
+};
+
#define XENFB_IN_EVENT_SIZE 40
union xenfb_in_event
{
uint8_t type;
+ struct xenfb_refresh_period refresh_period;
char pad[XENFB_IN_EVENT_SIZE];
};