]> xenbits.xensource.com Git - people/liuw/mini-os.git/commitdiff
pvfb/ioemu: transmit refresh interval advice from backend to frontend
authorKeir Fraser <keir.fraser@citrix.com>
Mon, 12 May 2008 09:10:03 +0000 (10:10 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Mon, 12 May 2008 09:10:03 +0000 (10:10 +0100)
which permits the frontend to avoid useless polls.

Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
fbfront.c
include/fbfront.h
include/lib.h
kernel.c
lib/sys.c

index 3a361b829c9badbd64bfcfbc23450fe0ea14acd8..d5acadf0851ba25f928d93339aa870e0f6677efe 100644 (file)
--- a/fbfront.c
+++ b/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
+
index 70b2f2a681d6d0c845e89c1e98de8587e8465d6a..1e4d7ac6d9c9533491e6df695dac137851a75a23 100644 (file)
@@ -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);
 
index 0acb0fc4e2ca81501058b65bebc5975016ca36d2..b26a5eda39f81dd5260fb1fe97ef083c08c7bb2d 100644 (file)
@@ -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.  */
index c37644bf4fa48681d5a9045d19442b1e328825a3..662acb0b0082ae4c4bbbd15021d8b35d9f5ad7aa 100644 (file)
--- a/kernel.c
+++ b/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();
     }
 }
 
index efa02e5af4a323ddbe5be3e6b2debfeaf5fe1a6a..730caab552c07ad429284ddf9125e2c89c9a5ce2 100644 (file)
--- a/lib/sys.c
+++ b/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++;