summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/x86/machine/cga.c6
-rw-r--r--arch/x86/machine/uart.c6
-rw-r--r--include/stdio.h4
-rw-r--r--kern/console.c89
-rw-r--r--kern/console.h35
-rw-r--r--kern/printf.c2
6 files changed, 127 insertions, 15 deletions
diff --git a/arch/x86/machine/cga.c b/arch/x86/machine/cga.c
index 3b217ca..3f1525c 100644
--- a/arch/x86/machine/cga.c
+++ b/arch/x86/machine/cga.c
@@ -165,6 +165,10 @@ cga_console_putc(struct console *console, char c)
cga_write_char(c);
}
+static const struct console_ops cga_console_ops = {
+ .putc = cga_console_putc,
+};
+
void __init
cga_setup(void)
{
@@ -191,6 +195,6 @@ cga_setup(void)
cga_cursor = cga_get_cursor_position();
- console_init(&cga_console, "cga", cga_console_putc);
+ console_init(&cga_console, "cga", &cga_console_ops);
console_register(&cga_console);
}
diff --git a/arch/x86/machine/uart.c b/arch/x86/machine/uart.c
index f17bc66..16b6d92 100644
--- a/arch/x86/machine/uart.c
+++ b/arch/x86/machine/uart.c
@@ -170,6 +170,10 @@ uart_console_putc(struct console *console, char c)
uart_write_char(uart_get_from_console(console), c);
}
+static struct console_ops uart_console_ops = {
+ .putc = uart_console_putc,
+};
+
static void __init
uart_init(struct uart *uart, uint16_t port, uint16_t intr)
{
@@ -191,7 +195,7 @@ uart_init(struct uart *uart, uint16_t port, uint16_t intr)
uart_write(uart, UART_REG_LCR, byte);
snprintf(name, sizeof(name), "uart%zu", uart_get_id(uart));
- console_init(&uart->console, name, uart_console_putc);
+ console_init(&uart->console, name, &uart_console_ops);
console_register(&uart->console);
}
diff --git a/include/stdio.h b/include/stdio.h
index a9aed9e..636304c 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -21,4 +21,8 @@
#include <kern/printf.h>
#include <kern/sprintf.h>
+#ifndef EOF
+#define EOF (-1)
+#endif
+
#endif /* _STDIO_H */
diff --git a/kern/console.c b/kern/console.c
index eb1306f..c82e7dc 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;
+}
diff --git a/kern/console.h b/kern/console.h
index 3087b71..b967c0d 100644
--- a/kern/console.h
+++ b/kern/console.h
@@ -21,16 +21,18 @@
#ifndef _KERN_CONSOLE_H
#define _KERN_CONSOLE_H
+#include <kern/cbuf.h>
#include <kern/list.h>
#include <kern/spinlock.h>
+#include <kern/thread.h>
struct console;
-/*
- * Type for character writing functions.
- */
-typedef void (*console_putc_fn)(struct console *console, char c);
+struct console_ops {
+ void (*putc)(struct console *console, char c);
+};
+#define CONSOLE_BUF_SIZE 64
#define CONSOLE_NAME_SIZE 16
/*
@@ -42,8 +44,11 @@ typedef void (*console_putc_fn)(struct console *console, char c);
*/
struct console {
struct spinlock lock;
+ const struct console_ops *ops;
+ char buffer[CONSOLE_BUF_SIZE];
+ struct cbuf recvbuf;
+ struct thread *waiter;
struct list node;
- console_putc_fn putc;
char name[CONSOLE_NAME_SIZE];
};
@@ -51,7 +56,7 @@ struct console {
* Console initialization.
*/
void console_init(struct console *console, const char *name,
- console_putc_fn putc);
+ const struct console_ops *ops);
/*
* Initialize the console module.
@@ -69,8 +74,22 @@ void console_setup(void);
void console_register(struct console *console);
/*
- * Write a single character to all registered console devices.
+ * Console interrupt handler.
+ *
+ * This function is meant to be used by low-level drivers to fill the
+ * receive buffer.
+ *
+ * Interrupts must be disabled when calling this function.
+ */
+void console_intr(struct console *console, char c);
+
+/*
+ * Write/read a single character to all registered console devices.
+ *
+ * Writing may not block in order to allow printf functions to be used in any
+ * context. Reading may block waiting for input.
*/
-void console_write_char(char c);
+void console_putchar(char c);
+char console_getchar(void);
#endif /* _KERN_CONSOLE_H */
diff --git a/kern/printf.c b/kern/printf.c
index d7a1d10..f657fdf 100644
--- a/kern/printf.c
+++ b/kern/printf.c
@@ -54,7 +54,7 @@ vprintf(const char *format, va_list ap)
length = vsnprintf(printf_buffer, sizeof(printf_buffer), format, ap);
for (ptr = printf_buffer; *ptr != '\0'; ptr++) {
- console_write_char(*ptr);
+ console_putchar(*ptr);
}
spinlock_unlock_intr_restore(&printf_lock, flags);