summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cmd/init/driver/ps2.c125
-rw-r--r--src/cmd/init/driver/termcook.c8
-rw-r--r--src/cmd/init/init.c2
3 files changed, 78 insertions, 57 deletions
diff --git a/src/cmd/init/driver/ps2.c b/src/cmd/init/driver/ps2.c
index 5470249..874e672 100644
--- a/src/cmd/init/driver/ps2.c
+++ b/src/cmd/init/driver/ps2.c
@@ -2,6 +2,7 @@
#include <assert.h>
#include <camellia/compat.h>
#include <camellia/syscalls.h>
+#include <err.h>
#include <errno.h>
#include <shared/ring.h>
#include <stdbool.h>
@@ -31,12 +32,9 @@ static const char keymap_upper[] = {
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
};
-
static volatile uint8_t backlog_buf[16];
static volatile ring_t backlog = {(void*)backlog_buf, sizeof backlog_buf, 0, 0};
-static hid_t fd;
-
static bool keys[0x80] = {0};
static void parse_scancode(uint8_t s) {
@@ -54,76 +52,93 @@ static void parse_scancode(uint8_t s) {
}
-/** Is a thread waiting for /kdev/ps2/kb? */
-static volatile bool blocked = false;
-/* for use in read_thread */
-static hid_t rt_reqh;
-static size_t rt_cap;
+#define QSIZE 16
+static hid_t queue[QSIZE] = {0};
+
+static void enqueue(hid_t h) {
+ for (int i = 0; i < QSIZE; i++) {
+ if (queue[i] == 0) {
+ queue[i] = h;
+ return;
+ }
+ }
+ _sys_fs_respond(h, NULL, -EAGAIN, 0);
+}
-static void read_thread(void *unused) {
- char buf[512];
+static void fulfill(void) {
+ int ret;
+ char c;
+ bool queued = false;
+ for (int i = 0; i < QSIZE; i++) {
+ if (queue[i] != 0) {
+ queued = true;
+ break;
+ }
+ }
+ if (!queued) return;
+
+ // only reading a single char at a time because that's easier
+ ret = ring_get((void*)&backlog, &c, 1);
+ if (ret == 0) return;
+ for (int i = 0; i < QSIZE; i++) {
+ if (queue[i] != 0) {
+ _sys_fs_respond(queue[i], &c, 1, 0);
+ queue[i] = 0;
+ break;
+ }
+ }
+}
+
+static void kb_thread(void *unused) {
+ static char buf[512];
+ int fd;
(void)unused;
- assert(blocked);
- while (ring_used((void*)&backlog) == 0) {
- /* read raw input until we have something to output */
- int len = _sys_read(fd, buf, sizeof buf, 0);
- if (len == 0) break;
- for (int i = 0; i < len; i++)
+ fd = _sys_open("/kdev/ps2/kb", 12, 0);
+ if (fd < 0) err(1, "open");
+
+ while (true) {
+ int ret = _sys_read(fd, buf, sizeof buf, -1);
+ if (ret < 0) break;
+ for (int i = 0; i < ret; i++) {
parse_scancode(buf[i]);
+ }
+ fulfill();
}
- if (ring_used((void*)&backlog) > 0) {
- int ret = ring_get((void*)&backlog, buf, rt_cap);
- _sys_fs_respond(rt_reqh, buf, ret, 0);
- } else {
- _sys_fs_respond(rt_reqh, 0, -EGENERIC, 0);
- }
- blocked = false;
}
-static void fs_loop(void) {
+static void fs_thread(void *unused) {
static char buf[512];
- int ret;
+ (void)unused;
for (;;) {
struct ufs_request res;
hid_t reqh = _sys_fs_wait(buf, sizeof buf, &res);
if (reqh < 0) return;
switch (res.op) {
- case VFSOP_OPEN:
- if (res.len == 0) {
- _sys_fs_respond(reqh, NULL, 1, 0);
- } else {
- _sys_fs_respond(reqh, NULL, -ENOENT, 0);
- }
- break;
-
- case VFSOP_READ:
- if (blocked) {
- _sys_fs_respond(reqh, NULL, -EAGAIN, 0);
- break;
- } else if (ring_used((void*)&backlog) > 0) {
- ret = ring_get((void*)&backlog, buf, res.capacity);
- _sys_fs_respond(reqh, buf, ret, 0);
- } else {
- blocked = true;
- rt_reqh = reqh;
- rt_cap = res.capacity;
- thread_create(0, read_thread, 0);
- }
- break;
-
- default:
- _sys_fs_respond(reqh, NULL, -1, 0);
- break;
+ case VFSOP_OPEN:
+ if (res.len == 0) {
+ _sys_fs_respond(reqh, NULL, 1, 0);
+ } else {
+ _sys_fs_respond(reqh, NULL, -ENOENT, 0);
+ }
+ break;
+
+ case VFSOP_READ:
+ enqueue(reqh);
+ fulfill();
+ break;
+
+ default:
+ _sys_fs_respond(reqh, NULL, -1, 0);
+ break;
}
}
}
void ps2_drv(void) {
- fd = _sys_open("/kdev/ps2/kb", 12, 0);
- if (fd < 0) exit(1);
-
- fs_loop();
+ thread_create(0, kb_thread, NULL);
+ thread_create(0, fs_thread, NULL);
+ _sys_await();
exit(0);
}
diff --git a/src/cmd/init/driver/termcook.c b/src/cmd/init/driver/termcook.c
index a76f3a8..68b5746 100644
--- a/src/cmd/init/driver/termcook.c
+++ b/src/cmd/init/driver/termcook.c
@@ -1,5 +1,7 @@
#include "driver.h"
#include <camellia/syscalls.h>
+#include <err.h>
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -25,7 +27,11 @@ static void line_editor(hid_t input, hid_t output) {
enum tstate state = Normal;
for (;;) {
int readlen = _sys_read(input, readbuf, sizeof readbuf, -1);
- if (readlen < 0) return;
+ if (readlen < 0) {
+ errno = -readlen;
+ err(1, "read");
+ return;
+ }
for (int i = 0; i < readlen; i++) {
char c = readbuf[i];
switch (state) {
diff --git a/src/cmd/init/init.c b/src/cmd/init/init.c
index fcebfc7..d221a7f 100644
--- a/src/cmd/init/init.c
+++ b/src/cmd/init/init.c
@@ -31,11 +31,11 @@ void redirect(const char *exe, const char *out, const char *in) {
termcook();
execv(exe, (void*)argv);
fprintf(stderr, "init: couldn't start %s\n", exe);
- _sys_sleep(5000);
exit(1);
}
_sys_await();
_sys_intr();
+ _sys_sleep(1000);
}
}
}