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;
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
+
#include <xen/io/kbdif.h>
+#include <xen/io/fbif.h>
#include <wait.h>
/* from <linux/input.h> */
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);
#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);
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);
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);
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();
}
}
}
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:
case FTYPE_EVTCHN:
case FTYPE_BLK:
case FTYPE_KBD:
+ case FTYPE_FB:
break;
}
printk("write(%d): Bad descriptor\n", fd);
case FTYPE_TAP:
case FTYPE_BLK:
case FTYPE_KBD:
+ case FTYPE_FB:
break;
}
printk("fsync(%d): Bad descriptor\n", 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;
}
case FTYPE_TAP:
case FTYPE_BLK:
case FTYPE_KBD:
+ case FTYPE_FB:
break;
}
case FTYPE_TAP:
case FTYPE_BLK:
case FTYPE_KBD:
+ case FTYPE_FB:
break;
}
[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)
case FTYPE_TAP:
case FTYPE_BLK:
case FTYPE_KBD:
+ case FTYPE_FB:
if (FD_ISSET(i, readfds)) {
if (files[i].read)
n++;