diff options
-rw-r--r-- | arch/x86/machine/cga.c | 6 | ||||
-rw-r--r-- | arch/x86/machine/uart.c | 6 | ||||
-rw-r--r-- | include/stdio.h | 4 | ||||
-rw-r--r-- | kern/console.c | 89 | ||||
-rw-r--r-- | kern/console.h | 35 | ||||
-rw-r--r-- | kern/printf.c | 2 |
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); |