ia64/xen-unstable

changeset 17625:3b20e543b52d

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>
author Keir Fraser <keir.fraser@citrix.com>
date Mon May 12 10:10:03 2008 +0100 (2008-05-12)
parents e3be00bd6aa9
children 4c3140455620
files extras/mini-os/fbfront.c extras/mini-os/include/fbfront.h extras/mini-os/include/lib.h extras/mini-os/kernel.c extras/mini-os/lib/sys.c tools/ioemu/hw/xenfb.c tools/ioemu/sdl.c tools/ioemu/vl.c tools/ioemu/vl.h tools/ioemu/vnc.c xen/include/public/io/fbif.h
line diff
     1.1 --- a/extras/mini-os/fbfront.c	Mon May 12 10:09:12 2008 +0100
     1.2 +++ b/extras/mini-os/fbfront.c	Mon May 12 10:10:03 2008 +0100
     1.3 @@ -255,13 +255,57 @@ struct fbfront_dev {
     1.4      int offset;
     1.5  
     1.6      xenbus_event_queue events;
     1.7 +
     1.8 +#ifdef HAVE_LIBC
     1.9 +    int fd;
    1.10 +#endif
    1.11  };
    1.12  
    1.13  void fbfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
    1.14  {
    1.15 +#ifdef HAVE_LIBC
    1.16 +    struct fbfront_dev *dev = data;
    1.17 +    int fd = dev->fd;
    1.18 +
    1.19 +    files[fd].read = 1;
    1.20 +#endif
    1.21      wake_up(&fbfront_queue);
    1.22  }
    1.23  
    1.24 +int fbfront_receive(struct fbfront_dev *dev, union xenfb_in_event *buf, int n)
    1.25 +{
    1.26 +    struct xenfb_page *page = dev->page;
    1.27 +    uint32_t prod, cons;
    1.28 +    int i;
    1.29 +
    1.30 +#ifdef HAVE_LIBC
    1.31 +    files[dev->fd].read = 0;
    1.32 +    mb(); /* Make sure to let the handler set read to 1 before we start looking at the ring */
    1.33 +#endif
    1.34 +
    1.35 +    prod = page->in_prod;
    1.36 +
    1.37 +    if (prod == page->in_cons)
    1.38 +        return 0;
    1.39 +
    1.40 +    rmb();      /* ensure we see ring contents up to prod */
    1.41 +
    1.42 +    for (i = 0, cons = page->in_cons; i < n && cons != prod; i++, cons++)
    1.43 +        memcpy(buf + i, &XENFB_IN_RING_REF(page, cons), sizeof(*buf));
    1.44 +
    1.45 +    mb();       /* ensure we got ring contents */
    1.46 +    page->in_cons = cons;
    1.47 +    notify_remote_via_evtchn(dev->evtchn);
    1.48 +
    1.49 +#ifdef HAVE_LIBC
    1.50 +    if (cons != prod)
    1.51 +        /* still some events to read */
    1.52 +        files[dev->fd].read = 1;
    1.53 +#endif
    1.54 +
    1.55 +    return i;
    1.56 +}
    1.57 +
    1.58  struct fbfront_dev *init_fbfront(char *nodename, unsigned long *mfns, int width, int height, int depth, int stride, int n)
    1.59  {
    1.60      xenbus_transaction_t xbt;
    1.61 @@ -482,3 +526,14 @@ void shutdown_fbfront(struct fbfront_dev
    1.62      free(dev->backend);
    1.63      free(dev);
    1.64  }
    1.65 +
    1.66 +#ifdef HAVE_LIBC
    1.67 +int fbfront_open(struct fbfront_dev *dev)
    1.68 +{
    1.69 +    dev->fd = alloc_fd(FTYPE_FB);
    1.70 +    printk("fb_open(%s) -> %d\n", dev->nodename, dev->fd);
    1.71 +    files[dev->fd].fb.dev = dev;
    1.72 +    return dev->fd;
    1.73 +}
    1.74 +#endif
    1.75 +
     2.1 --- a/extras/mini-os/include/fbfront.h	Mon May 12 10:09:12 2008 +0100
     2.2 +++ b/extras/mini-os/include/fbfront.h	Mon May 12 10:10:03 2008 +0100
     2.3 @@ -1,4 +1,5 @@
     2.4  #include <xen/io/kbdif.h>
     2.5 +#include <xen/io/fbif.h>
     2.6  #include <wait.h>
     2.7  
     2.8  /* from <linux/input.h> */
     2.9 @@ -36,6 +37,8 @@ struct fbfront_dev *init_fbfront(char *n
    2.10  int fbfront_open(struct fbfront_dev *dev);
    2.11  #endif
    2.12  
    2.13 +int fbfront_receive(struct fbfront_dev *dev, union xenfb_in_event *buf, int n);
    2.14 +extern struct wait_queue_head fbfront_queue;
    2.15  void fbfront_update(struct fbfront_dev *dev, int x, int y, int width, int height);
    2.16  void fbfront_resize(struct fbfront_dev *dev, int width, int height, int stride, int depth, int offset);
    2.17  
     3.1 --- a/extras/mini-os/include/lib.h	Mon May 12 10:09:12 2008 +0100
     3.2 +++ b/extras/mini-os/include/lib.h	Mon May 12 10:10:03 2008 +0100
     3.3 @@ -141,6 +141,7 @@ enum fd_type {
     3.4      FTYPE_TAP,
     3.5      FTYPE_BLK,
     3.6      FTYPE_KBD,
     3.7 +    FTYPE_FB,
     3.8  };
     3.9  
    3.10  #define MAX_EVTCHN_PORTS 16
    3.11 @@ -175,6 +176,9 @@ extern struct file {
    3.12  	struct {
    3.13  	    struct kbdfront_dev *dev;
    3.14  	} kbd;
    3.15 +	struct {
    3.16 +	    struct fbfront_dev *dev;
    3.17 +	} fb;
    3.18          struct {
    3.19              /* To each xenbus FD is associated a queue of watch events for this
    3.20               * FD.  */
     4.1 --- a/extras/mini-os/kernel.c	Mon May 12 10:09:12 2008 +0100
     4.2 +++ b/extras/mini-os/kernel.c	Mon May 12 10:10:03 2008 +0100
     4.3 @@ -260,6 +260,7 @@ static void blkfront_thread(void *p)
     4.4  #define DEPTH 32
     4.5  
     4.6  static uint32_t *fb;
     4.7 +static int refresh_period = 50;
     4.8  static struct fbfront_dev *fb_dev;
     4.9  static struct semaphore fbfront_sem = __SEMAPHORE_INITIALIZER(fbfront_sem, 0);
    4.10  
    4.11 @@ -333,6 +334,10 @@ static void clip_cursor(int *x, int *y)
    4.12  static void refresh_cursor(int new_x, int new_y)
    4.13  {
    4.14      static int old_x = -1, old_y = -1;
    4.15 +
    4.16 +    if (!refresh_period)
    4.17 +        return;
    4.18 +
    4.19      if (old_x != -1 && old_y != -1) {
    4.20          fbfront_drawvert(old_x, old_y + 1, old_y + 8, 0xffffffff);
    4.21          fbfront_drawhoriz(old_x + 1, old_x + 8, old_y, 0xffffffff);
    4.22 @@ -358,43 +363,46 @@ static void kbdfront_thread(void *p)
    4.23      down(&fbfront_sem);
    4.24      refresh_cursor(x, y);
    4.25      while (1) {
    4.26 -        union xenkbd_in_event event;
    4.27 +        union xenkbd_in_event kbdevent;
    4.28 +        union xenfb_in_event fbevent;
    4.29 +        int sleep = 1;
    4.30  
    4.31          add_waiter(w, kbdfront_queue);
    4.32 +        add_waiter(w, fbfront_queue);
    4.33  
    4.34 -        if (kbdfront_receive(kbd_dev, &event, 1) == 0)
    4.35 -            schedule();
    4.36 -        else switch(event.type) {
    4.37 +        while (kbdfront_receive(kbd_dev, &kbdevent, 1) != 0) {
    4.38 +            sleep = 0;
    4.39 +            switch(kbdevent.type) {
    4.40              case XENKBD_TYPE_MOTION:
    4.41                  printk("motion x:%d y:%d z:%d\n",
    4.42 -                        event.motion.rel_x,
    4.43 -                        event.motion.rel_y,
    4.44 -                        event.motion.rel_z);
    4.45 -                x += event.motion.rel_x;
    4.46 -                y += event.motion.rel_y;
    4.47 -                z += event.motion.rel_z;
    4.48 +                        kbdevent.motion.rel_x,
    4.49 +                        kbdevent.motion.rel_y,
    4.50 +                        kbdevent.motion.rel_z);
    4.51 +                x += kbdevent.motion.rel_x;
    4.52 +                y += kbdevent.motion.rel_y;
    4.53 +                z += kbdevent.motion.rel_z;
    4.54                  clip_cursor(&x, &y);
    4.55                  refresh_cursor(x, y);
    4.56                  break;
    4.57              case XENKBD_TYPE_POS:
    4.58                  printk("pos x:%d y:%d dz:%d\n",
    4.59 -                        event.pos.abs_x,
    4.60 -                        event.pos.abs_y,
    4.61 -                        event.pos.rel_z);
    4.62 -                x = event.pos.abs_x;
    4.63 -                y = event.pos.abs_y;
    4.64 -                z = event.pos.rel_z;
    4.65 +                        kbdevent.pos.abs_x,
    4.66 +                        kbdevent.pos.abs_y,
    4.67 +                        kbdevent.pos.rel_z);
    4.68 +                x = kbdevent.pos.abs_x;
    4.69 +                y = kbdevent.pos.abs_y;
    4.70 +                z = kbdevent.pos.rel_z;
    4.71                  clip_cursor(&x, &y);
    4.72                  refresh_cursor(x, y);
    4.73                  break;
    4.74              case XENKBD_TYPE_KEY:
    4.75                  printk("key %d %s\n",
    4.76 -                        event.key.keycode,
    4.77 -                        event.key.pressed ? "pressed" : "released");
    4.78 -                if (event.key.keycode == BTN_LEFT) {
    4.79 +                        kbdevent.key.keycode,
    4.80 +                        kbdevent.key.pressed ? "pressed" : "released");
    4.81 +                if (kbdevent.key.keycode == BTN_LEFT) {
    4.82                      printk("mouse %s at (%d,%d,%d)\n",
    4.83 -                            event.key.pressed ? "clic" : "release", x, y, z);
    4.84 -                    if (event.key.pressed) {
    4.85 +                            kbdevent.key.pressed ? "clic" : "release", x, y, z);
    4.86 +                    if (kbdevent.key.pressed) {
    4.87                          uint32_t color = rand();
    4.88                          fbfront_drawvert(x - 16, y - 16, y + 15, color);
    4.89                          fbfront_drawhoriz(x - 16, x + 15, y + 16, color);
    4.90 @@ -402,13 +410,26 @@ static void kbdfront_thread(void *p)
    4.91                          fbfront_drawhoriz(x - 15, x + 16, y - 16, color);
    4.92                          fbfront_update(fb_dev, x - 16, y - 16, 33, 33);
    4.93                      }
    4.94 -                } else if (event.key.keycode == KEY_Q) {
    4.95 +                } else if (kbdevent.key.keycode == KEY_Q) {
    4.96                      struct sched_shutdown sched_shutdown = { .reason = SHUTDOWN_poweroff };
    4.97                      HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown);
    4.98                      do_exit();
    4.99                  }
   4.100                  break;
   4.101 +            }
   4.102          }
   4.103 +        while (fbfront_receive(fb_dev, &fbevent, 1) != 0) {
   4.104 +            sleep = 0;
   4.105 +            switch(fbevent.type) {
   4.106 +            case XENFB_TYPE_REFRESH_PERIOD:
   4.107 +                refresh_period = fbevent.refresh_period.period;
   4.108 +                printk("refresh period %d\n", refresh_period);
   4.109 +                refresh_cursor(x, y);
   4.110 +                break;
   4.111 +            }
   4.112 +        }
   4.113 +        if (sleep)
   4.114 +            schedule();
   4.115      }
   4.116  }
   4.117  
     5.1 --- a/extras/mini-os/lib/sys.c	Mon May 12 10:09:12 2008 +0100
     5.2 +++ b/extras/mini-os/lib/sys.c	Mon May 12 10:10:03 2008 +0100
     5.3 @@ -249,6 +249,16 @@ int read(int fd, void *buf, size_t nbyte
     5.4  	    }
     5.5  	    return ret * sizeof(union xenkbd_in_event);
     5.6          }
     5.7 +        case FTYPE_FB: {
     5.8 +            int ret, n;
     5.9 +            n = nbytes / sizeof(union xenfb_in_event);
    5.10 +            ret = fbfront_receive(files[fd].fb.dev, buf, n);
    5.11 +	    if (ret <= 0) {
    5.12 +		errno = EAGAIN;
    5.13 +		return -1;
    5.14 +	    }
    5.15 +	    return ret * sizeof(union xenfb_in_event);
    5.16 +        }
    5.17  	case FTYPE_NONE:
    5.18  	case FTYPE_XENBUS:
    5.19  	case FTYPE_EVTCHN:
    5.20 @@ -290,6 +300,7 @@ int write(int fd, const void *buf, size_
    5.21  	case FTYPE_EVTCHN:
    5.22  	case FTYPE_BLK:
    5.23  	case FTYPE_KBD:
    5.24 +	case FTYPE_FB:
    5.25  	    break;
    5.26      }
    5.27      printk("write(%d): Bad descriptor\n", fd);
    5.28 @@ -348,6 +359,7 @@ int fsync(int fd) {
    5.29  	case FTYPE_TAP:
    5.30  	case FTYPE_BLK:
    5.31  	case FTYPE_KBD:
    5.32 +	case FTYPE_FB:
    5.33  	    break;
    5.34      }
    5.35      printk("fsync(%d): Bad descriptor\n", fd);
    5.36 @@ -394,6 +406,10 @@ int close(int fd)
    5.37              shutdown_kbdfront(files[fd].kbd.dev);
    5.38              files[fd].type = FTYPE_NONE;
    5.39              return 0;
    5.40 +	case FTYPE_FB:
    5.41 +            shutdown_fbfront(files[fd].fb.dev);
    5.42 +            files[fd].type = FTYPE_NONE;
    5.43 +            return 0;
    5.44  	case FTYPE_NONE:
    5.45  	    break;
    5.46      }
    5.47 @@ -485,6 +501,7 @@ int fstat(int fd, struct stat *buf)
    5.48  	case FTYPE_TAP:
    5.49  	case FTYPE_BLK:
    5.50  	case FTYPE_KBD:
    5.51 +	case FTYPE_FB:
    5.52  	    break;
    5.53      }
    5.54  
    5.55 @@ -513,6 +530,7 @@ int ftruncate(int fd, off_t length)
    5.56  	case FTYPE_TAP:
    5.57  	case FTYPE_BLK:
    5.58  	case FTYPE_KBD:
    5.59 +	case FTYPE_FB:
    5.60  	    break;
    5.61      }
    5.62  
    5.63 @@ -624,6 +642,7 @@ static const char file_types[] = {
    5.64      [FTYPE_TAP]		= 'T',
    5.65      [FTYPE_BLK]		= 'B',
    5.66      [FTYPE_KBD]		= 'K',
    5.67 +    [FTYPE_FB]		= 'G',
    5.68  };
    5.69  #ifdef LIBC_DEBUG
    5.70  static void dump_set(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
    5.71 @@ -732,6 +751,7 @@ static int select_poll(int nfds, fd_set 
    5.72  	case FTYPE_TAP:
    5.73  	case FTYPE_BLK:
    5.74  	case FTYPE_KBD:
    5.75 +	case FTYPE_FB:
    5.76  	    if (FD_ISSET(i, readfds)) {
    5.77  		if (files[i].read)
    5.78  		    n++;
     6.1 --- a/tools/ioemu/hw/xenfb.c	Mon May 12 10:09:12 2008 +0100
     6.2 +++ b/tools/ioemu/hw/xenfb.c	Mon May 12 10:10:03 2008 +0100
     6.3 @@ -59,6 +59,7 @@ struct xenfb {
     6.4  	int offset;             /* offset of the framebuffer */
     6.5  	int abs_pointer_wanted; /* Whether guest supports absolute pointer */
     6.6  	int button_state;       /* Last seen pointer button state */
     6.7 +	int refresh_period;     /* The refresh period we have advised */
     6.8  	char protocol[64];	/* frontend protocol */
     6.9  };
    6.10  
    6.11 @@ -536,6 +537,41 @@ static void xenfb_on_fb_event(struct xen
    6.12  	xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port);
    6.13  }
    6.14  
    6.15 +static int xenfb_queue_full(struct xenfb *xenfb)
    6.16 +{
    6.17 +	struct xenfb_page *page = xenfb->fb.page;
    6.18 +	uint32_t cons, prod;
    6.19 +
    6.20 +	prod = page->in_prod;
    6.21 +	cons = page->in_cons;
    6.22 +	return prod - cons == XENFB_IN_RING_LEN;
    6.23 +}
    6.24 +
    6.25 +static void xenfb_send_event(struct xenfb *xenfb, union xenfb_in_event *event)
    6.26 +{
    6.27 +	uint32_t prod;
    6.28 +	struct xenfb_page *page = xenfb->fb.page;
    6.29 +
    6.30 +	prod = page->in_prod;
    6.31 +	/* caller ensures !xenfb_queue_full() */
    6.32 +	xen_mb();                   /* ensure ring space available */
    6.33 +	XENFB_IN_RING_REF(page, prod) = *event;
    6.34 +	xen_wmb();                  /* ensure ring contents visible */
    6.35 +	page->in_prod = prod + 1;
    6.36 +
    6.37 +	xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port);
    6.38 +}
    6.39 +
    6.40 +static void xenfb_send_refresh_period(struct xenfb *xenfb, int period)
    6.41 +{
    6.42 +	union xenfb_in_event event;
    6.43 +
    6.44 +	memset(&event, 0, sizeof(event));
    6.45 +	event.type = XENFB_TYPE_REFRESH_PERIOD;
    6.46 +	event.refresh_period.period = period;
    6.47 +	xenfb_send_event(xenfb, &event);
    6.48 +}
    6.49 +
    6.50  static void xenfb_on_kbd_event(struct xenfb *xenfb)
    6.51  {
    6.52  	struct xenkbd_page *page = xenfb->kbd.page;
    6.53 @@ -707,6 +743,7 @@ static int xenfb_read_frontend_fb_config
    6.54                              xenfb->protocol) < 0)
    6.55                  xenfb->protocol[0] = '\0';
    6.56          xenfb_xs_printf(xenfb->xsh, xenfb->fb.nodename, "request-update", "1");
    6.57 +        xenfb->refresh_period = -1;
    6.58  
    6.59          /* TODO check for permitted ranges */
    6.60          fb_page = xenfb->fb.page;
    6.61 @@ -1185,10 +1222,28 @@ static void xenfb_guest_copy(struct xenf
    6.62      dpy_update(xenfb->ds, x, y, w, h);
    6.63  }
    6.64  
    6.65 -/* Periodic update of display, no need for any in our case */
    6.66 +/* Periodic update of display, transmit the refresh interval to the frontend */
    6.67  static void xenfb_update(void *opaque)
    6.68  {
    6.69      struct xenfb *xenfb = opaque;
    6.70 +    int period;
    6.71 +
    6.72 +    if (xenfb_queue_full(xenfb))
    6.73 +        return;
    6.74 +
    6.75 +    if (xenfb->ds->idle)
    6.76 +        period = XENFB_NO_REFRESH;
    6.77 +    else {
    6.78 +        period = xenfb->ds->gui_timer_interval;
    6.79 +        if (!period)
    6.80 +            period = GUI_REFRESH_INTERVAL;
    6.81 +    }
    6.82 +
    6.83 +    /* Will have to be disabled for frontends without feature-update */
    6.84 +    if (xenfb->refresh_period != period) {
    6.85 +        xenfb_send_refresh_period(xenfb, period);
    6.86 +        xenfb->refresh_period = period;
    6.87 +    }
    6.88  }
    6.89  
    6.90  /* QEMU display state changed, so refresh the framebuffer copy */
    6.91 @@ -1232,11 +1287,17 @@ static int xenfb_register_console(struct
    6.92  }
    6.93  
    6.94  #ifdef CONFIG_STUBDOM
    6.95 -static struct semaphore kbd_sem = __SEMAPHORE_INITIALIZER(kbd_sem, 0);
    6.96 -static struct kbdfront_dev *kbd_dev;
    6.97 +typedef struct XenFBState {
    6.98 +    struct semaphore kbd_sem;
    6.99 +    struct kbdfront_dev *kbd_dev;
   6.100 +    struct fbfront_dev *fb_dev;
   6.101 +    void *vga_vram, *nonshared_vram;
   6.102 +    DisplayState *ds;
   6.103 +} XenFBState;
   6.104 +
   6.105 +XenFBState *xs;
   6.106 +
   6.107  static char *kbd_path, *fb_path;
   6.108 -static void *vga_vram, *nonshared_vram;
   6.109 -static DisplayState *xenfb_ds;
   6.110  
   6.111  static unsigned char linux2scancode[KEY_MAX + 1];
   6.112  
   6.113 @@ -1254,7 +1315,8 @@ int xenfb_connect_vfb(const char *path)
   6.114  
   6.115  static void xenfb_pv_update(DisplayState *ds, int x, int y, int w, int h)
   6.116  {
   6.117 -    struct fbfront_dev *fb_dev = ds->opaque;
   6.118 +    XenFBState *xs = ds->opaque;
   6.119 +    struct fbfront_dev *fb_dev = xs->fb_dev;
   6.120      if (!fb_dev)
   6.121          return;
   6.122      fbfront_update(fb_dev, x, y, w, h);
   6.123 @@ -1262,7 +1324,8 @@ static void xenfb_pv_update(DisplayState
   6.124  
   6.125  static void xenfb_pv_resize(DisplayState *ds, int w, int h, int linesize)
   6.126  {
   6.127 -    struct fbfront_dev *fb_dev = ds->opaque;
   6.128 +    XenFBState *xs = ds->opaque;
   6.129 +    struct fbfront_dev *fb_dev = xs->fb_dev;
   6.130      fprintf(stderr,"resize to %dx%d, %d required\n", w, h, linesize);
   6.131      ds->width = w;
   6.132      ds->height = h;
   6.133 @@ -1276,14 +1339,15 @@ static void xenfb_pv_resize(DisplayState
   6.134      if (ds->shared_buf) {
   6.135          ds->data = NULL;
   6.136      } else {
   6.137 -        ds->data = nonshared_vram;
   6.138 +        ds->data = xs->nonshared_vram;
   6.139          fbfront_resize(fb_dev, w, h, linesize, ds->depth, VGA_RAM_SIZE);
   6.140      }
   6.141  }
   6.142  
   6.143  static void xenfb_pv_colourdepth(DisplayState *ds, int depth)
   6.144  {
   6.145 -    struct fbfront_dev *fb_dev = ds->opaque;
   6.146 +    XenFBState *xs = ds->opaque;
   6.147 +    struct fbfront_dev *fb_dev = xs->fb_dev;
   6.148      static int lastdepth = -1;
   6.149      if (!depth) {
   6.150          ds->shared_buf = 0;
   6.151 @@ -1301,15 +1365,16 @@ static void xenfb_pv_colourdepth(Display
   6.152      if (ds->shared_buf) {
   6.153          ds->data = NULL;
   6.154      } else {
   6.155 -        ds->data = nonshared_vram;
   6.156 +        ds->data = xs->nonshared_vram;
   6.157          fbfront_resize(fb_dev, ds->width, ds->height, ds->linesize, ds->depth, VGA_RAM_SIZE);
   6.158      }
   6.159  }
   6.160  
   6.161  static void xenfb_pv_setdata(DisplayState *ds, void *pixels)
   6.162  {
   6.163 -    struct fbfront_dev *fb_dev = ds->opaque;
   6.164 -    int offset = pixels - vga_vram;
   6.165 +    XenFBState *xs = ds->opaque;
   6.166 +    struct fbfront_dev *fb_dev = xs->fb_dev;
   6.167 +    int offset = pixels - xs->vga_vram;
   6.168      ds->data = pixels;
   6.169      if (!fb_dev)
   6.170          return;
   6.171 @@ -1321,16 +1386,45 @@ static void xenfb_pv_refresh(DisplayStat
   6.172      vga_hw_update();
   6.173  }
   6.174  
   6.175 +static void xenfb_fb_handler(void *opaque)
   6.176 +{
   6.177 +#define FB_NUM_BATCH 4
   6.178 +    union xenfb_in_event buf[FB_NUM_BATCH];
   6.179 +    int n, i;
   6.180 +    XenFBState *xs = opaque;
   6.181 +    DisplayState *ds = xs->ds;
   6.182 +
   6.183 +    n = fbfront_receive(xs->fb_dev, buf, FB_NUM_BATCH);
   6.184 +    for (i = 0; i < n; i++) {
   6.185 +        switch (buf[i].type) {
   6.186 +        case XENFB_TYPE_REFRESH_PERIOD:
   6.187 +            if (buf[i].refresh_period.period == XENFB_NO_REFRESH) {
   6.188 +                /* Sleeping interval */
   6.189 +                ds->idle = 1;
   6.190 +                ds->gui_timer_interval = 500;
   6.191 +            } else {
   6.192 +                /* Set interval */
   6.193 +                ds->idle = 0;
   6.194 +                ds->gui_timer_interval = buf[i].refresh_period.period;
   6.195 +            }
   6.196 +        default:
   6.197 +            /* ignore unknown events */
   6.198 +            break;
   6.199 +        }
   6.200 +    }
   6.201 +}
   6.202 +
   6.203  static void xenfb_kbd_handler(void *opaque)
   6.204  {
   6.205  #define KBD_NUM_BATCH 64
   6.206      union xenkbd_in_event buf[KBD_NUM_BATCH];
   6.207      int n, i;
   6.208 -    DisplayState *s = opaque;
   6.209 +    XenFBState *xs = opaque;
   6.210 +    DisplayState *s = xs->ds;
   6.211      static int buttons;
   6.212      static int x, y;
   6.213  
   6.214 -    n = kbdfront_receive(kbd_dev, buf, KBD_NUM_BATCH);
   6.215 +    n = kbdfront_receive(xs->kbd_dev, buf, KBD_NUM_BATCH);
   6.216      for (i = 0; i < n; i++) {
   6.217          switch (buf[i].type) {
   6.218  
   6.219 @@ -1412,12 +1506,13 @@ static void xenfb_kbd_handler(void *opaq
   6.220  static void kbdfront_thread(void *p)
   6.221  {
   6.222      int scancode, keycode;
   6.223 -    kbd_dev = init_kbdfront(p, 1);
   6.224 -    if (!kbd_dev) {
   6.225 +    XenFBState *xs = p;
   6.226 +    xs->kbd_dev = init_kbdfront(kbd_path, 1);
   6.227 +    if (!xs->kbd_dev) {
   6.228          fprintf(stderr,"can't open keyboard\n");
   6.229          exit(1);
   6.230      }
   6.231 -    up(&kbd_sem);
   6.232 +    up(&xs->kbd_sem);
   6.233      for (scancode = 0; scancode < 128; scancode++) {
   6.234          keycode = atkbd_set2_keycode[atkbd_unxlate_table[scancode]];
   6.235          linux2scancode[keycode] = scancode;
   6.236 @@ -1431,12 +1526,18 @@ int xenfb_pv_display_init(DisplayState *
   6.237      if (!fb_path || !kbd_path)
   6.238          return -1;
   6.239  
   6.240 -    create_thread("kbdfront", kbdfront_thread, (void*) kbd_path);
   6.241 +    xs = qemu_mallocz(sizeof(XenFBState));
   6.242 +    if (!xs)
   6.243 +        return -1;
   6.244  
   6.245 -    xenfb_ds = ds;
   6.246 +    init_SEMAPHORE(&xs->kbd_sem, 0);
   6.247 +    xs->ds = ds;
   6.248  
   6.249 -    ds->data = nonshared_vram = qemu_memalign(PAGE_SIZE, VGA_RAM_SIZE);
   6.250 +    create_thread("kbdfront", kbdfront_thread, (void*) xs);
   6.251 +
   6.252 +    ds->data = xs->nonshared_vram = qemu_memalign(PAGE_SIZE, VGA_RAM_SIZE);
   6.253      memset(ds->data, 0, VGA_RAM_SIZE);
   6.254 +    ds->opaque = xs;
   6.255      ds->depth = 32;
   6.256      ds->bgr = 0;
   6.257      ds->width = 640;
   6.258 @@ -1452,9 +1553,9 @@ int xenfb_pv_display_init(DisplayState *
   6.259  
   6.260  int xenfb_pv_display_start(void *data)
   6.261  {
   6.262 -    DisplayState *ds = xenfb_ds;
   6.263 +    DisplayState *ds;
   6.264      struct fbfront_dev *fb_dev;
   6.265 -    int kbd_fd;
   6.266 +    int kbd_fd, fb_fd;
   6.267      int offset = 0;
   6.268      unsigned long *mfns;
   6.269      int n = VGA_RAM_SIZE / PAGE_SIZE;
   6.270 @@ -1463,12 +1564,13 @@ int xenfb_pv_display_start(void *data)
   6.271      if (!fb_path || !kbd_path)
   6.272          return 0;
   6.273  
   6.274 -    vga_vram = data;
   6.275 +    ds = xs->ds;
   6.276 +    xs->vga_vram = data;
   6.277      mfns = malloc(2 * n * sizeof(*mfns));
   6.278      for (i = 0; i < n; i++)
   6.279 -        mfns[i] = virtual_to_mfn(vga_vram + i * PAGE_SIZE);
   6.280 +        mfns[i] = virtual_to_mfn(xs->vga_vram + i * PAGE_SIZE);
   6.281      for (i = 0; i < n; i++)
   6.282 -        mfns[n + i] = virtual_to_mfn(nonshared_vram + i * PAGE_SIZE);
   6.283 +        mfns[n + i] = virtual_to_mfn(xs->nonshared_vram + i * PAGE_SIZE);
   6.284  
   6.285      fb_dev = init_fbfront(fb_path, mfns, ds->width, ds->height, ds->depth, ds->linesize, 2 * n);
   6.286      free(mfns);
   6.287 @@ -1479,21 +1581,24 @@ int xenfb_pv_display_start(void *data)
   6.288      free(fb_path);
   6.289  
   6.290      if (ds->shared_buf) {
   6.291 -        offset = (void*) ds->data - vga_vram;
   6.292 +        offset = (void*) ds->data - xs->vga_vram;
   6.293      } else {
   6.294          offset = VGA_RAM_SIZE;
   6.295 -        ds->data = nonshared_vram;
   6.296 +        ds->data = xs->nonshared_vram;
   6.297      }
   6.298      if (offset)
   6.299          fbfront_resize(fb_dev, ds->width, ds->height, ds->linesize, ds->depth, offset);
   6.300  
   6.301 -    down(&kbd_sem);
   6.302 +    down(&xs->kbd_sem);
   6.303      free(kbd_path);
   6.304  
   6.305 -    kbd_fd = kbdfront_open(kbd_dev);
   6.306 -    qemu_set_fd_handler(kbd_fd, xenfb_kbd_handler, NULL, ds);
   6.307 +    kbd_fd = kbdfront_open(xs->kbd_dev);
   6.308 +    qemu_set_fd_handler(kbd_fd, xenfb_kbd_handler, NULL, xs);
   6.309  
   6.310 -    xenfb_ds->opaque = fb_dev;
   6.311 +    fb_fd = fbfront_open(fb_dev);
   6.312 +    qemu_set_fd_handler(fb_fd, xenfb_fb_handler, NULL, xs);
   6.313 +
   6.314 +    xs->fb_dev = fb_dev;
   6.315      return 0;
   6.316  }
   6.317  #endif
     7.1 --- a/tools/ioemu/sdl.c	Mon May 12 10:09:12 2008 +0100
     7.2 +++ b/tools/ioemu/sdl.c	Mon May 12 10:10:03 2008 +0100
     7.3 @@ -696,9 +696,11 @@ static void sdl_refresh(DisplayState *ds
     7.4  		if (ev->active.gain) {
     7.5  		    /* Back to default interval */
     7.6  		    ds->gui_timer_interval = 0;
     7.7 +		    ds->idle = 0;
     7.8  		} else {
     7.9  		    /* Sleeping interval */
    7.10  		    ds->gui_timer_interval = 500;
    7.11 +		    ds->idle = 1;
    7.12  		}
    7.13  	    }
    7.14              break;
     8.1 --- a/tools/ioemu/vl.c	Mon May 12 10:09:12 2008 +0100
     8.2 +++ b/tools/ioemu/vl.c	Mon May 12 10:10:03 2008 +0100
     8.3 @@ -130,8 +130,6 @@
     8.4  #else
     8.5  #define DEFAULT_RAM_SIZE 128
     8.6  #endif
     8.7 -/* in ms */
     8.8 -#define GUI_REFRESH_INTERVAL 30
     8.9  
    8.10  /* Max number of USB devices that can be specified on the commandline.  */
    8.11  #define MAX_USB_CMDLINE 8
    8.12 @@ -4467,6 +4465,8 @@ void dumb_display_init(DisplayState *ds)
    8.13      ds->dpy_resize = dumb_resize;
    8.14      ds->dpy_colourdepth = NULL;
    8.15      ds->dpy_refresh = dumb_refresh;
    8.16 +    ds->gui_timer_interval = 500;
    8.17 +    ds->idle = 1;
    8.18  }
    8.19  
    8.20  /***********************************************************/
     9.1 --- a/tools/ioemu/vl.h	Mon May 12 10:09:12 2008 +0100
     9.2 +++ b/tools/ioemu/vl.h	Mon May 12 10:10:03 2008 +0100
     9.3 @@ -929,6 +929,9 @@ extern struct soundhw soundhw[];
     9.4  
     9.5  #define VGA_RAM_SIZE (8192 * 1024)
     9.6  
     9.7 +/* in ms */
     9.8 +#define GUI_REFRESH_INTERVAL 30
     9.9 +
    9.10  struct DisplayState {
    9.11      uint8_t *data;
    9.12      int linesize;
    9.13 @@ -939,6 +942,7 @@ struct DisplayState {
    9.14      void *opaque;
    9.15      uint32_t *palette;
    9.16      uint64_t gui_timer_interval;
    9.17 +    int idle;
    9.18  
    9.19      int shared_buf;
    9.20      
    10.1 --- a/tools/ioemu/vnc.c	Mon May 12 10:09:12 2008 +0100
    10.2 +++ b/tools/ioemu/vnc.c	Mon May 12 10:10:03 2008 +0100
    10.3 @@ -778,6 +778,7 @@ static void _vnc_update_client(void *opa
    10.4      vs->has_update = 0;
    10.5      vnc_flush(vs);
    10.6      vs->last_update_time = now;
    10.7 +    vs->ds->idle = 0;
    10.8  
    10.9      vs->timer_interval /= 2;
   10.10      if (vs->timer_interval < VNC_REFRESH_INTERVAL_BASE)
   10.11 @@ -790,26 +791,29 @@ static void _vnc_update_client(void *opa
   10.12      vs->timer_interval += VNC_REFRESH_INTERVAL_INC;
   10.13      if (vs->timer_interval > VNC_REFRESH_INTERVAL_MAX) {
   10.14  	vs->timer_interval = VNC_REFRESH_INTERVAL_MAX;
   10.15 -	if (now - vs->last_update_time >= VNC_MAX_UPDATE_INTERVAL &&
   10.16 -            vs->update_requested) {
   10.17 -	    /* Send a null update.  If the client is no longer
   10.18 -	       interested (e.g. minimised) it'll ignore this, and we
   10.19 -	       can stop scanning the buffer until it sends another
   10.20 -	       update request. */
   10.21 -	    /* It turns out that there's a bug in realvncviewer 4.1.2
   10.22 -	       which means that if you send a proper null update (with
   10.23 -	       no update rectangles), it gets a bit out of sync and
   10.24 -	       never sends any further requests, regardless of whether
   10.25 -	       it needs one or not.  Fix this by sending a single 1x1
   10.26 -	       update rectangle instead. */
   10.27 -	    vnc_write_u8(vs, 0);
   10.28 -	    vnc_write_u8(vs, 0);
   10.29 -	    vnc_write_u16(vs, 1);
   10.30 -	    send_framebuffer_update(vs, 0, 0, 1, 1);
   10.31 -	    vnc_flush(vs);
   10.32 -	    vs->last_update_time = now;
   10.33 -            vs->update_requested--;
   10.34 -	    return;
   10.35 +	if (now - vs->last_update_time >= VNC_MAX_UPDATE_INTERVAL) {
   10.36 +            if (!vs->update_requested) {
   10.37 +                vs->ds->idle = 1;
   10.38 +            } else {
   10.39 +                /* Send a null update.  If the client is no longer
   10.40 +                   interested (e.g. minimised) it'll ignore this, and we
   10.41 +                   can stop scanning the buffer until it sends another
   10.42 +                   update request. */
   10.43 +                /* It turns out that there's a bug in realvncviewer 4.1.2
   10.44 +                   which means that if you send a proper null update (with
   10.45 +                   no update rectangles), it gets a bit out of sync and
   10.46 +                   never sends any further requests, regardless of whether
   10.47 +                   it needs one or not.  Fix this by sending a single 1x1
   10.48 +                   update rectangle instead. */
   10.49 +                vnc_write_u8(vs, 0);
   10.50 +                vnc_write_u8(vs, 0);
   10.51 +                vnc_write_u16(vs, 1);
   10.52 +                send_framebuffer_update(vs, 0, 0, 1, 1);
   10.53 +                vnc_flush(vs);
   10.54 +                vs->last_update_time = now;
   10.55 +                vs->update_requested--;
   10.56 +                return;
   10.57 +            }
   10.58  	}
   10.59      }
   10.60      qemu_mod_timer(vs->timer, now + vs->timer_interval);
   10.61 @@ -970,6 +974,7 @@ static int vnc_client_io_error(VncState 
   10.62  	qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
   10.63  	closesocket(vs->csock);
   10.64  	vs->csock = -1;
   10.65 +	vs->ds->idle = 1;
   10.66  	buffer_reset(&vs->input);
   10.67  	buffer_reset(&vs->output);
   10.68          free_queue(vs);
   10.69 @@ -2443,6 +2448,7 @@ static void vnc_listen_read(void *opaque
   10.70      vs->csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
   10.71      if (vs->csock != -1) {
   10.72  	VNC_DEBUG("New client on socket %d\n", vs->csock);
   10.73 +	vs->ds->idle = 0;
   10.74          socket_set_nonblock(vs->csock);
   10.75  	qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, opaque);
   10.76  	vnc_write(vs, "RFB 003.008\n", 12);
   10.77 @@ -2468,6 +2474,7 @@ void vnc_display_init(DisplayState *ds)
   10.78  	exit(1);
   10.79  
   10.80      ds->opaque = vs;
   10.81 +    ds->idle = 1;
   10.82      vnc_state = vs;
   10.83      vs->display = NULL;
   10.84      vs->password = NULL;
    11.1 --- a/xen/include/public/io/fbif.h	Mon May 12 10:09:12 2008 +0100
    11.2 +++ b/xen/include/public/io/fbif.h	Mon May 12 10:10:03 2008 +0100
    11.3 @@ -80,14 +80,33 @@ union xenfb_out_event
    11.4  
    11.5  /*
    11.6   * Frontends should ignore unknown in events.
    11.7 - * No in events currently defined.
    11.8   */
    11.9  
   11.10 +/*
   11.11 + * Framebuffer refresh period advice
   11.12 + * Backend sends it to advise the frontend their preferred period of
   11.13 + * refresh.  Frontends that keep the framebuffer constantly up-to-date
   11.14 + * just ignore it.  Frontends that use the advice should immediately
   11.15 + * refresh the framebuffer (and send an update notification event if
   11.16 + * those have been requested), then use the update frequency to guide
   11.17 + * their periodical refreshs.
   11.18 + */
   11.19 +#define XENFB_TYPE_REFRESH_PERIOD 1
   11.20 +#define XENFB_NO_REFRESH 0
   11.21 +
   11.22 +struct xenfb_refresh_period
   11.23 +{
   11.24 +    uint8_t type;    /* XENFB_TYPE_UPDATE_PERIOD */
   11.25 +    uint32_t period; /* period of refresh, in ms,
   11.26 +                      * XENFB_NO_REFRESH if no refresh is needed */
   11.27 +};
   11.28 +
   11.29  #define XENFB_IN_EVENT_SIZE 40
   11.30  
   11.31  union xenfb_in_event
   11.32  {
   11.33      uint8_t type;
   11.34 +    struct xenfb_refresh_period refresh_period;
   11.35      char pad[XENFB_IN_EVENT_SIZE];
   11.36  };
   11.37