aboutsummaryrefslogtreecommitdiffstats
path: root/extras
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2008-02-26 14:47:23 +0000
committerKeir Fraser <keir.fraser@citrix.com>2008-02-26 14:47:23 +0000
commit26a1b308f37898b744d3b38477edcfb0a23b93cc (patch)
tree568602b1e4b7c88b844a5758baccdaaacc4b64ea /extras
parent2e83dbdb929d8a553ffd2f82404e8169d1fe4134 (diff)
downloadxen-26a1b308f37898b744d3b38477edcfb0a23b93cc.tar.gz
xen-26a1b308f37898b744d3b38477edcfb0a23b93cc.tar.bz2
xen-26a1b308f37898b744d3b38477edcfb0a23b93cc.zip
minios: add PVFB support
Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
Diffstat (limited to 'extras')
-rw-r--r--extras/mini-os/fbfront.c468
-rw-r--r--extras/mini-os/include/fbfront.h38
-rw-r--r--extras/mini-os/include/lib.h4
-rw-r--r--extras/mini-os/kernel.c149
-rw-r--r--extras/mini-os/lib/sys.c24
5 files changed, 683 insertions, 0 deletions
diff --git a/extras/mini-os/fbfront.c b/extras/mini-os/fbfront.c
new file mode 100644
index 0000000000..bbe49b92a5
--- /dev/null
+++ b/extras/mini-os/fbfront.c
@@ -0,0 +1,468 @@
+/*
+ * Frame Buffer + Keyboard driver for Mini-OS.
+ * Samuel Thibault <samuel.thibault@eu.citrix.com>, 2008
+ * Based on blkfront.c.
+ */
+
+#include <os.h>
+#include <xenbus.h>
+#include <events.h>
+#include <xen/io/kbdif.h>
+#include <xen/io/fbif.h>
+#include <xen/io/protocols.h>
+#include <gnttab.h>
+#include <xmalloc.h>
+#include <fbfront.h>
+#include <lib.h>
+
+DECLARE_WAIT_QUEUE_HEAD(kbdfront_queue);
+
+
+
+
+
+
+struct kbdfront_dev {
+ domid_t dom;
+
+ struct xenkbd_page *page;
+ evtchn_port_t evtchn, local_port;
+
+ char *nodename;
+ char *backend;
+
+ char *data;
+ int width;
+ int height;
+ int depth;
+ int line_length;
+ int mem_length;
+
+#ifdef HAVE_LIBC
+ int fd;
+#endif
+};
+
+void kbdfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
+{
+#ifdef HAVE_LIBC
+ struct kbdfront_dev *dev = data;
+ int fd = dev->fd;
+
+ files[fd].read = 1;
+#endif
+ wake_up(&kbdfront_queue);
+}
+
+struct kbdfront_dev *init_kbdfront(char *nodename, int abs_pointer)
+{
+ xenbus_transaction_t xbt;
+ char* err;
+ char* message=NULL;
+ struct xenkbd_page *s;
+ int retry=0;
+ char* msg;
+
+ struct kbdfront_dev *dev;
+
+ if (!nodename)
+ nodename = "device/vkbd/0";
+
+ char path[strlen(nodename) + 1 + 10 + 1];
+
+ printk("******************* KBDFRONT for %s **********\n\n\n", nodename);
+
+ dev = malloc(sizeof(*dev));
+ dev->nodename = strdup(nodename);
+
+ evtchn_alloc_unbound_t op;
+ op.dom = DOMID_SELF;
+ snprintf(path, sizeof(path), "%s/backend-id", nodename);
+ dev->dom = op.remote_dom = xenbus_read_integer(path);
+ HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &op);
+ clear_evtchn(op.port); /* Without, handler gets invoked now! */
+ dev->local_port = bind_evtchn(op.port, kbdfront_handler, dev);
+ dev->evtchn=op.port;
+
+ dev->page = s = (struct xenkbd_page*) alloc_page();
+ memset(s,0,PAGE_SIZE);
+
+ s->in_cons = s->in_prod = 0;
+ s->out_cons = s->out_prod = 0;
+
+ // FIXME: proper frees on failures
+again:
+ err = xenbus_transaction_start(&xbt);
+ if (err) {
+ printk("starting transaction\n");
+ }
+
+ err = xenbus_printf(xbt, nodename, "page-ref","%u", virt_to_mfn(s));
+ if (err) {
+ message = "writing page-ref";
+ goto abort_transaction;
+ }
+ err = xenbus_printf(xbt, nodename, "event-channel", "%u", dev->evtchn);
+ if (err) {
+ message = "writing event-channel";
+ goto abort_transaction;
+ }
+ if (abs_pointer) {
+ err = xenbus_printf(xbt, nodename, "request-abs-pointer", "1");
+ if (err) {
+ message = "writing event-channel";
+ goto abort_transaction;
+ }
+ }
+
+ err = xenbus_printf(xbt, nodename, "state", "%u", 3); /* initialized */
+ if (err)
+ printk("error writing initialized: %s\n", err);
+
+
+ err = xenbus_transaction_end(xbt, 0, &retry);
+ if (retry) {
+ goto again;
+ printk("completing transaction\n");
+ }
+
+ goto done;
+
+abort_transaction:
+ xenbus_transaction_end(xbt, 1, &retry);
+ return NULL;
+
+done:
+
+ snprintf(path, sizeof(path), "%s/backend", nodename);
+ msg = xenbus_read(XBT_NIL, path, &dev->backend);
+ if (msg) {
+ printk("Error %s when reading the backend path %s\n", msg, path);
+ return NULL;
+ }
+
+ printk("backend at %s\n", dev->backend);
+
+ {
+ char path[strlen(dev->backend) + 1 + 6 + 1];
+
+ snprintf(path, sizeof(path), "%s/state", dev->backend);
+
+ xenbus_watch_path(XBT_NIL, path);
+
+ xenbus_wait_for_value(path,"4");
+
+ xenbus_unwatch_path(XBT_NIL, path);
+
+ printk("%s connected\n", dev->backend);
+
+ err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 4); /* connected */
+ }
+
+ printk("************************** KBDFRONT\n");
+
+ return dev;
+}
+
+int kbdfront_receive(struct kbdfront_dev *dev, union xenkbd_in_event *buf, int n)
+{
+ struct xenkbd_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, &XENKBD_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;
+}
+
+
+void shutdown_kbdfront(struct kbdfront_dev *dev)
+{
+ char* err;
+ char *nodename = dev->nodename;
+
+ char path[strlen(dev->backend) + 1 + 5 + 1];
+
+ printk("close kbd: backend at %s\n",dev->backend);
+
+ snprintf(path, sizeof(path), "%s/state", dev->backend);
+ err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 5); /* closing */
+ xenbus_wait_for_value(path,"5");
+
+ err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 6);
+ xenbus_wait_for_value(path,"6");
+
+ unbind_evtchn(dev->local_port);
+
+ free_pages(dev->page,0);
+ free(nodename);
+ free(dev->backend);
+ free(dev);
+}
+
+#ifdef HAVE_LIBC
+int kbdfront_open(struct kbdfront_dev *dev)
+{
+ dev->fd = alloc_fd(FTYPE_KBD);
+ printk("kbd_open(%s) -> %d\n", dev->nodename, dev->fd);
+ files[dev->fd].kbd.dev = dev;
+ return dev->fd;
+}
+#endif
+
+
+
+
+
+DECLARE_WAIT_QUEUE_HEAD(fbfront_queue);
+
+
+
+
+
+
+struct fbfront_dev {
+ domid_t dom;
+
+ struct xenfb_page *page;
+ evtchn_port_t evtchn, local_port;
+
+ char *nodename;
+ char *backend;
+
+ char *data;
+ int width;
+ int height;
+ int depth;
+ int line_length;
+ int mem_length;
+};
+
+void fbfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
+{
+ wake_up(&fbfront_queue);
+}
+
+struct fbfront_dev *init_fbfront(char *nodename, void *data, int width, int height, int depth, int line_length, int mem_length)
+{
+ xenbus_transaction_t xbt;
+ char* err;
+ char* message=NULL;
+ struct xenfb_page *s;
+ int retry=0;
+ char* msg;
+ int i, j;
+ struct fbfront_dev *dev;
+
+ if (!nodename)
+ nodename = "device/vfb/0";
+
+ char path[strlen(nodename) + 1 + 10 + 1];
+
+ printk("******************* FBFRONT for %s **********\n\n\n", nodename);
+
+ dev = malloc(sizeof(*dev));
+ dev->nodename = strdup(nodename);
+
+ evtchn_alloc_unbound_t op;
+ op.dom = DOMID_SELF;
+ snprintf(path, sizeof(path), "%s/backend-id", nodename);
+ dev->dom = op.remote_dom = xenbus_read_integer(path);
+ HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &op);
+ clear_evtchn(op.port); /* Without, handler gets invoked now! */
+ dev->local_port = bind_evtchn(op.port, fbfront_handler, dev);
+ dev->evtchn=op.port;
+
+ dev->page = s = (struct xenfb_page*) alloc_page();
+ memset(s,0,PAGE_SIZE);
+
+ s->in_cons = s->in_prod = 0;
+ s->out_cons = s->out_prod = 0;
+ dev->width = s->width = width;
+ dev->height = s->height = height;
+ dev->depth = s->depth = depth;
+ dev->line_length = s->line_length = line_length;
+ dev->mem_length = s->mem_length = mem_length;
+
+ ASSERT(!((unsigned long)data & ~PAGE_MASK));
+ dev->data = data;
+
+ const int max_pd = sizeof(s->pd) / sizeof(s->pd[0]);
+ unsigned long mapped = 0;
+
+ for (i = 0; mapped < mem_length && i < max_pd; i++) {
+ unsigned long *pd = (unsigned long *) alloc_page();
+ for (j = 0; mapped < mem_length && j < PAGE_SIZE / sizeof(unsigned long); j++) {
+ pd[j] = virt_to_mfn((unsigned long) data + mapped);
+ mapped += PAGE_SIZE;
+ }
+ for ( ; j < PAGE_SIZE / sizeof(unsigned long); j++)
+ pd[j] = 0;
+ s->pd[i] = virt_to_mfn(pd);
+ }
+ for ( ; i < max_pd; i++)
+ s->pd[i] = 0;
+
+
+ // FIXME: proper frees on failures
+again:
+ err = xenbus_transaction_start(&xbt);
+ if (err) {
+ printk("starting transaction\n");
+ }
+
+ err = xenbus_printf(xbt, nodename, "page-ref","%u", virt_to_mfn(s));
+ if (err) {
+ message = "writing page-ref";
+ goto abort_transaction;
+ }
+ err = xenbus_printf(xbt, nodename, "event-channel", "%u", dev->evtchn);
+ if (err) {
+ message = "writing event-channel";
+ goto abort_transaction;
+ }
+ err = xenbus_printf(xbt, nodename, "protocol", "%s",
+ XEN_IO_PROTO_ABI_NATIVE);
+ if (err) {
+ message = "writing event-channel";
+ goto abort_transaction;
+ }
+ err = xenbus_printf(xbt, nodename, "feature-update", "1");
+ if (err) {
+ message = "writing event-channel";
+ goto abort_transaction;
+ }
+
+ err = xenbus_printf(xbt, nodename, "state", "%u", 3); /* initialized */
+
+
+ err = xenbus_transaction_end(xbt, 0, &retry);
+ if (retry) {
+ goto again;
+ printk("completing transaction\n");
+ }
+
+ goto done;
+
+abort_transaction:
+ xenbus_transaction_end(xbt, 1, &retry);
+ return NULL;
+
+done:
+
+ snprintf(path, sizeof(path), "%s/backend", nodename);
+ msg = xenbus_read(XBT_NIL, path, &dev->backend);
+ if (msg) {
+ printk("Error %s when reading the backend path %s\n", msg, path);
+ return NULL;
+ }
+
+ printk("backend at %s\n", dev->backend);
+
+ {
+ char path[strlen(dev->backend) + 1 + 6 + 1];
+
+ snprintf(path, sizeof(path), "%s/state", dev->backend);
+
+ xenbus_watch_path(XBT_NIL, path);
+
+ xenbus_wait_for_value(path,"4");
+
+ printk("%s connected\n", dev->backend);
+
+ xenbus_unwatch_path(XBT_NIL, path);
+
+ err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 4); /* connected */
+ }
+
+ printk("************************** FBFRONT\n");
+
+ return dev;
+}
+
+void fbfront_update(struct fbfront_dev *dev, int x, int y, int width, int height)
+{
+ struct xenfb_page *page = dev->page;
+ uint32_t prod;
+ DEFINE_WAIT(w);
+
+ if (x < 0) {
+ width += x;
+ x = 0;
+ }
+ if (x + width > dev->width)
+ width = dev->width - x;
+
+ if (y < 0) {
+ height += y;
+ y = 0;
+ }
+ if (y + height > dev->height)
+ height = dev->height - y;
+
+ if (width <= 0 || height <= 0)
+ return;
+
+ add_waiter(w, fbfront_queue);
+ while (page->out_prod - page->out_cons == XENFB_OUT_RING_LEN)
+ schedule();
+ remove_waiter(w);
+
+ prod = page->out_prod;
+ mb(); /* ensure ring space available */
+ XENFB_OUT_RING_REF(page, prod).type = XENFB_TYPE_UPDATE;
+ XENFB_OUT_RING_REF(page, prod).update.x = x;
+ XENFB_OUT_RING_REF(page, prod).update.y = y;
+ XENFB_OUT_RING_REF(page, prod).update.width = width;
+ XENFB_OUT_RING_REF(page, prod).update.height = height;
+ wmb(); /* ensure ring contents visible */
+ page->out_prod = prod + 1;
+ notify_remote_via_evtchn(dev->evtchn);
+}
+
+void shutdown_fbfront(struct fbfront_dev *dev)
+{
+ char* err;
+ char *nodename = dev->nodename;
+
+ char path[strlen(dev->backend) + 1 + 5 + 1];
+
+ printk("close fb: backend at %s\n",dev->backend);
+
+ snprintf(path, sizeof(path), "%s/state", dev->backend);
+ err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 5); /* closing */
+ xenbus_wait_for_value(path,"5");
+
+ err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 6);
+ xenbus_wait_for_value(path,"6");
+
+ unbind_evtchn(dev->local_port);
+
+ free_pages(dev->page,0);
+ free(nodename);
+ free(dev->backend);
+ free(dev);
+}
diff --git a/extras/mini-os/include/fbfront.h b/extras/mini-os/include/fbfront.h
new file mode 100644
index 0000000000..502f0330a2
--- /dev/null
+++ b/extras/mini-os/include/fbfront.h
@@ -0,0 +1,38 @@
+#include <xen/io/kbdif.h>
+#include <wait.h>
+
+/* from <linux/input.h> */
+#ifndef BTN_LEFT
+#define BTN_LEFT 0x110
+#endif
+#ifndef BTN_RIGHT
+#define BTN_RIGHT 0x111
+#endif
+#ifndef BTN_MIDDLE
+#define BTN_MIDDLE 0x112
+#endif
+#ifndef KEY_Q
+#define KEY_Q 16
+#endif
+
+
+struct kbdfront_dev;
+struct kbdfront_dev *init_kbdfront(char *nodename, int abs_pointer);
+#ifdef HAVE_LIBC
+int kbdfront_open(struct kbdfront_dev *dev);
+#endif
+
+int kbdfront_receive(struct kbdfront_dev *dev, union xenkbd_in_event *buf, int n);
+extern struct wait_queue_head kbdfront_queue;
+
+void shutdown_kbdfront(struct kbdfront_dev *dev);
+
+
+struct fbfront_dev *init_fbfront(char *nodename, void *data, int width, int height, int depth, int line_length, int mem_length);
+#ifdef HAVE_LIBC
+int fbfront_open(struct fbfront_dev *dev);
+#endif
+
+void fbfront_update(struct fbfront_dev *dev, int x, int y, int width, int height);
+
+void shutdown_fbfront(struct fbfront_dev *dev);
diff --git a/extras/mini-os/include/lib.h b/extras/mini-os/include/lib.h
index 2ddb8d07c8..016af66670 100644
--- a/extras/mini-os/include/lib.h
+++ b/extras/mini-os/include/lib.h
@@ -140,6 +140,7 @@ enum fd_type {
FTYPE_SOCKET,
FTYPE_TAP,
FTYPE_BLK,
+ FTYPE_KBD,
};
#define MAX_EVTCHN_PORTS 16
@@ -171,6 +172,9 @@ extern struct file {
struct {
struct blkfront_dev *dev;
} blk;
+ struct {
+ struct kbdfront_dev *dev;
+ } kbd;
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 a94e743f63..107d0649a5 100644
--- a/extras/mini-os/kernel.c
+++ b/extras/mini-os/kernel.c
@@ -39,6 +39,7 @@
#include <gnttab.h>
#include <netfront.h>
#include <blkfront.h>
+#include <fbfront.h>
#include <fs.h>
#include <xmalloc.h>
#include <fcntl.h>
@@ -248,6 +249,152 @@ static void blkfront_thread(void *p)
}
}
+#define WIDTH 800
+#define HEIGHT 600
+#define DEPTH 32
+
+static uint32_t *fb;
+static struct fbfront_dev *fb_dev;
+static struct semaphore fbfront_sem = __SEMAPHORE_INITIALIZER(fbfront_sem, 0);
+
+static void fbfront_drawvert(int x, int y1, int y2, uint32_t color)
+{
+ int y;
+ if (x < 0)
+ return;
+ if (x >= WIDTH)
+ return;
+ if (y1 < 0)
+ y1 = 0;
+ if (y2 >= HEIGHT)
+ y2 = HEIGHT-1;
+ for (y = y1; y <= y2; y++)
+ fb[x + y*WIDTH] ^= color;
+}
+
+static void fbfront_drawhoriz(int x1, int x2, int y, uint32_t color)
+{
+ int x;
+ if (y < 0)
+ return;
+ if (y >= HEIGHT)
+ return;
+ if (x1 < 0)
+ x1 = 0;
+ if (x2 >= WIDTH)
+ x2 = WIDTH-1;
+ for (x = x1; x <= x2; x++)
+ fb[x + y*WIDTH] ^= color;
+}
+
+static void fbfront_thread(void *p)
+{
+ size_t line_length = WIDTH * (DEPTH / 8);
+ size_t memsize = HEIGHT * line_length;
+
+ fb = _xmalloc(memsize, PAGE_SIZE);
+ fb_dev = init_fbfront(NULL, fb, WIDTH, HEIGHT, DEPTH, line_length, memsize);
+ if (!fb_dev) {
+ xfree(fb);
+ return;
+ }
+ up(&fbfront_sem);
+}
+
+static void clip_cursor(int *x, int *y)
+{
+ if (*x < 0)
+ *x = 0;
+ if (*x >= WIDTH)
+ *x = WIDTH - 1;
+ if (*y < 0)
+ *y = 0;
+ if (*y >= HEIGHT)
+ *y = HEIGHT - 1;
+}
+
+static void refresh_cursor(int new_x, int new_y)
+{
+ static int old_x = -1, old_y = -1;
+ 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);
+ fbfront_update(fb_dev, old_x, old_y, 9, 9);
+ }
+ old_x = new_x;
+ old_y = new_y;
+ fbfront_drawvert(new_x, new_y + 1, new_y + 8, 0xffffffff);
+ fbfront_drawhoriz(new_x + 1, new_x + 8, new_y, 0xffffffff);
+ fbfront_update(fb_dev, new_x, new_y, 9, 9);
+}
+
+static void kbdfront_thread(void *p)
+{
+ struct kbdfront_dev *kbd_dev;
+ DEFINE_WAIT(w);
+ int x = WIDTH / 2, y = HEIGHT / 2, z;
+
+ kbd_dev = init_kbdfront(NULL, 1);
+ if (!kbd_dev)
+ return;
+
+ down(&fbfront_sem);
+ refresh_cursor(x, y);
+ while (1) {
+ union xenkbd_in_event event;
+
+ add_waiter(w, kbdfront_queue);
+
+ if (kbdfront_receive(kbd_dev, &event, 1) == 0)
+ schedule();
+ else switch(event.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;
+ clip_cursor(&x, &y);
+ refresh_cursor(x, y);
+ break;
+ case XENKBD_TYPE_POS:
+ printk("pos x:%d y:%d z:%d\n",
+ event.pos.abs_x,
+ event.pos.abs_y,
+ event.pos.abs_z);
+ x = event.pos.abs_x;
+ y = event.pos.abs_y;
+ z = event.pos.abs_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) {
+ printk("mouse %s at (%d,%d,%d)\n",
+ event.key.pressed ? "clic" : "release", x, y, z);
+ if (event.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_drawvert(x + 16, y - 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) {
+ struct sched_shutdown sched_shutdown = { .reason = SHUTDOWN_poweroff };
+ HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown);
+ do_exit();
+ }
+ break;
+ }
+ }
+}
+
static void fs_thread(void *p)
{
init_fs_frontend();
@@ -261,6 +408,8 @@ __attribute__((weak)) int app_main(start_info_t *si)
create_thread("periodic_thread", periodic_thread, si);
create_thread("netfront", netfront_thread, si);
create_thread("blkfront", blkfront_thread, si);
+ create_thread("fbfront", fbfront_thread, si);
+ create_thread("kbdfront", kbdfront_thread, si);
create_thread("fs-frontend", fs_thread, si);
return 0;
}
diff --git a/extras/mini-os/lib/sys.c b/extras/mini-os/lib/sys.c
index f71e6966bd..13096d1eca 100644
--- a/extras/mini-os/lib/sys.c
+++ b/extras/mini-os/lib/sys.c
@@ -26,6 +26,7 @@
#include <wait.h>
#include <netfront.h>
#include <blkfront.h>
+#include <fbfront.h>
#include <xenbus.h>
#include <xs.h>
@@ -221,6 +222,16 @@ int read(int fd, void *buf, size_t nbytes)
}
return ret;
}
+ case FTYPE_KBD: {
+ int ret, n;
+ n = nbytes / sizeof(union xenkbd_in_event);
+ ret = kbdfront_receive(files[fd].kbd.dev, buf, n);
+ if (ret <= 0) {
+ errno = EAGAIN;
+ return -1;
+ }
+ return ret * sizeof(union xenkbd_in_event);
+ }
case FTYPE_NONE:
case FTYPE_XENBUS:
case FTYPE_EVTCHN:
@@ -261,6 +272,7 @@ int write(int fd, const void *buf, size_t nbytes)
case FTYPE_XENBUS:
case FTYPE_EVTCHN:
case FTYPE_BLK:
+ case FTYPE_KBD:
break;
}
printk("write(%d): Bad descriptor\n", fd);
@@ -318,6 +330,7 @@ int fsync(int fd) {
case FTYPE_EVTCHN:
case FTYPE_TAP:
case FTYPE_BLK:
+ case FTYPE_KBD:
break;
}
printk("fsync(%d): Bad descriptor\n", fd);
@@ -360,6 +373,10 @@ int close(int fd)
shutdown_blkfront(files[fd].blk.dev);
files[fd].type = FTYPE_NONE;
return 0;
+ case FTYPE_KBD:
+ shutdown_kbdfront(files[fd].kbd.dev);
+ files[fd].type = FTYPE_NONE;
+ return 0;
case FTYPE_NONE:
break;
}
@@ -450,6 +467,7 @@ int fstat(int fd, struct stat *buf)
case FTYPE_EVTCHN:
case FTYPE_TAP:
case FTYPE_BLK:
+ case FTYPE_KBD:
break;
}
@@ -477,6 +495,7 @@ int ftruncate(int fd, off_t length)
case FTYPE_EVTCHN:
case FTYPE_TAP:
case FTYPE_BLK:
+ case FTYPE_KBD:
break;
}
@@ -587,6 +606,7 @@ static const char file_types[] = {
[FTYPE_SOCKET] = 'S',
[FTYPE_TAP] = 'T',
[FTYPE_BLK] = 'B',
+ [FTYPE_KBD] = 'K',
};
#ifdef LIBC_DEBUG
static void dump_set(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
@@ -694,6 +714,7 @@ static int select_poll(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exce
case FTYPE_EVTCHN:
case FTYPE_TAP:
case FTYPE_BLK:
+ case FTYPE_KBD:
if (FD_ISSET(i, readfds)) {
if (files[i].read)
n++;
@@ -775,6 +796,7 @@ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
DEFINE_WAIT(w2);
DEFINE_WAIT(w3);
DEFINE_WAIT(w4);
+ DEFINE_WAIT(w5);
assert(thread == main_thread);
@@ -795,6 +817,7 @@ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
add_waiter(w2, event_queue);
add_waiter(w3, blkfront_queue);
add_waiter(w4, xenbus_watch_queue);
+ add_waiter(w5, kbdfront_queue);
myread = *readfds;
mywrite = *writefds;
@@ -860,6 +883,7 @@ out:
remove_waiter(w2);
remove_waiter(w3);
remove_waiter(w4);
+ remove_waiter(w5);
return ret;
}