summaryrefslogtreecommitdiff
path: root/kern/console.c
diff options
context:
space:
mode:
authorRichard Braun <rbraun@sceen.net>2017-05-28 17:03:27 +0200
committerRichard Braun <rbraun@sceen.net>2017-05-28 17:54:08 +0200
commitc5680f01485f35c1735cdae08b16b63e300b9f6d (patch)
tree4210d0975efb8a3aac56930473055e2c14314dac /kern/console.c
parentdf6e8f87ad6800ecb348f11b01a42db48237b371 (diff)
kern/console: implement input handling
Diffstat (limited to 'kern/console.c')
-rw-r--r--kern/console.c89
1 files changed, 85 insertions, 4 deletions
diff --git a/kern/console.c b/kern/console.c
index eb1306f8..c82e7dc9 100644
--- a/kern/console.c
+++ b/kern/console.c
@@ -22,10 +22,14 @@
#include <kern/arg.h>
#include <kern/assert.h>
+#include <kern/error.h>
#include <kern/init.h>
#include <kern/console.h>
#include <kern/list.h>
+#include <kern/mutex.h>
#include <kern/spinlock.h>
+#include <kern/thread.h>
+#include <machine/cpu.h>
/*
* Registered consoles.
@@ -51,10 +55,14 @@ console_name_match(const char *name)
void __init
console_init(struct console *console, const char *name,
- console_putc_fn putc)
+ const struct console_ops *ops)
{
+ assert(ops != NULL);
+
spinlock_init(&console->lock);
- console->putc = putc;
+ console->ops = ops;
+ cbuf_init(&console->recvbuf, console->buffer, sizeof(console->buffer));
+ console->waiter = NULL;
strlcpy(console->name, name, sizeof(console->name));
}
@@ -64,10 +72,44 @@ console_putc(struct console *console, char c)
unsigned long flags;
spinlock_lock_intr_save(&console->lock, &flags);
- console->putc(console, c);
+ console->ops->putc(console_dev, c);
spinlock_unlock_intr_restore(&console->lock, flags);
}
+static char
+console_getc(struct console *console)
+{
+ unsigned long flags;
+ int error;
+ char c;
+
+ spinlock_lock_intr_save(&console->lock, &flags);
+
+ if (console->waiter != NULL) {
+ c = EOF;
+ goto out;
+ }
+
+ console->waiter = thread_self();
+
+ for (;;) {
+ error = cbuf_pop(&console->recvbuf, &c);
+
+ if (!error) {
+ break;
+ }
+
+ thread_sleep(&console->lock, console, "consgetc");
+ }
+
+ console->waiter = NULL;
+
+out:
+ spinlock_unlock_intr_restore(&console->lock, flags);
+
+ return c;
+}
+
void __init
console_setup(void)
{
@@ -78,6 +120,8 @@ console_setup(void)
void __init
console_register(struct console *console)
{
+ assert(console->ops != NULL);
+
list_insert_tail(&console_devs, &console->node);
if ((console_dev == NULL) && console_name_match(console->name)) {
@@ -92,7 +136,28 @@ console_register(struct console *console)
}
void
-console_write_char(char c)
+console_intr(struct console *console, char c)
+{
+ assert(!cpu_intr_enabled());
+
+ spinlock_lock(&console->lock);
+
+ if (cbuf_size(&console->recvbuf) == cbuf_capacity(&console->recvbuf)) {
+ goto out;
+ }
+
+ cbuf_push(&console->recvbuf, c);
+
+ if ((console->waiter != NULL) && (console->waiter != thread_self())) {
+ thread_wakeup(console->waiter);
+ }
+
+out:
+ spinlock_unlock(&console->lock);
+}
+
+void
+console_putchar(char c)
{
if (console_dev == NULL) {
return;
@@ -100,3 +165,19 @@ console_write_char(char c)
console_putc(console_dev, c);
}
+
+char
+console_getchar(void)
+{
+ char c;
+
+ if (console_dev == NULL) {
+ c = EOF;
+ goto out;
+ }
+
+ c = console_getc(console_dev);
+
+out:
+ return c;
+}