summaryrefslogtreecommitdiff
path: root/src/user/app/init/driver
diff options
context:
space:
mode:
authordzwdz2023-07-19 21:27:15 +0200
committerdzwdz2023-07-19 21:27:15 +0200
commit2d7da42acbf2782636e481ebd79f30700fb7dc9e (patch)
treece818cbd3e8240b5d9c55147b21f2196f0b4e59b /src/user/app/init/driver
parent6b085892a0e99c21ccb2d94a2edab91cc4f87ad1 (diff)
user /keyboard: handle open()s instantly even if waiting for kb
fixes e.g. `echo */*` in dash
Diffstat (limited to 'src/user/app/init/driver')
-rw-r--r--src/user/app/init/driver/ps2.c66
1 files changed, 50 insertions, 16 deletions
diff --git a/src/user/app/init/driver/ps2.c b/src/user/app/init/driver/ps2.c
index 2752238..5470249 100644
--- a/src/user/app/init/driver/ps2.c
+++ b/src/user/app/init/driver/ps2.c
@@ -1,10 +1,12 @@
#include "driver.h"
+#include <assert.h>
#include <camellia/compat.h>
#include <camellia/syscalls.h>
#include <errno.h>
#include <shared/ring.h>
#include <stdbool.h>
#include <stdlib.h>
+#include <thread.h>
static const char keymap_lower[] = {
@@ -51,36 +53,68 @@ static void parse_scancode(uint8_t s) {
if (down && c) ring_put1b((void*)&backlog, c);
}
-static void main_loop(void) {
+
+/** 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;
+
+static void read_thread(void *unused) {
+ char buf[512];
+ (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++)
+ parse_scancode(buf[i]);
+ }
+ 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 char buf[512];
- struct ufs_request res;
int ret;
- while (!c0_fs_wait(buf, sizeof buf, &res)) {
- // TODO don't hang on ps2 reads
+ 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) {
- c0_fs_respond(NULL, 1, 0);
+ _sys_fs_respond(reqh, NULL, 1, 0);
} else {
- c0_fs_respond(NULL, -ENOENT, 0);
+ _sys_fs_respond(reqh, NULL, -ENOENT, 0);
}
break;
case VFSOP_READ:
- 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++)
- parse_scancode(buf[i]);
+ 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);
}
- ret = ring_get((void*)&backlog, buf, res.capacity);
- c0_fs_respond(buf, ret, 0);
break;
default:
- c0_fs_respond(NULL, -1, 0);
+ _sys_fs_respond(reqh, NULL, -1, 0);
break;
}
}
@@ -90,6 +124,6 @@ void ps2_drv(void) {
fd = _sys_open("/kdev/ps2/kb", 12, 0);
if (fd < 0) exit(1);
- main_loop();
+ fs_loop();
exit(0);
}