123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- /*
- * Copyright (c) 2017 Richard Braun.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #include <assert.h>
- #include <errno.h>
- #include <stdbool.h>
- #include <stddef.h>
- #include <stdio.h>
- #include <string.h>
- #include <kern/arg.h>
- #include <kern/init.h>
- #include <kern/console.h>
- #include <kern/list.h>
- #include <kern/log.h>
- #include <kern/mutex.h>
- #include <kern/spinlock.h>
- #include <kern/thread.h>
- #include <machine/boot.h>
- #include <machine/cpu.h>
- struct console_waiter {
- struct list node;
- struct thread *thread;
- };
- /*
- * Registered consoles.
- */
- static struct list console_devs;
- /*
- * Active console device.
- */
- static struct console *console_dev;
- static const char *console_name __initdata;
- static bool __init
- console_name_match(const char *name)
- {
- if (console_name == NULL) {
- return true;
- }
- return (strcmp(console_name, name) == 0);
- }
- void __init
- console_init(struct console *console, const char *name,
- const struct console_ops *ops)
- {
- assert(ops != NULL);
- spinlock_init(&console->lock);
- console->ops = ops;
- cbuf_init(&console->recvbuf, console->buffer, sizeof(console->buffer));
- list_init(&console->waiters);
- strlcpy(console->name, name, sizeof(console->name));
- }
- static int
- console_process_ctrl_char(struct console *console, char c)
- {
- switch (c) {
- case CONSOLE_SCROLL_UP:
- case CONSOLE_SCROLL_DOWN:
- break;
- default:
- return EINVAL;
- }
- console->ops->puts(console, &c, 1);
- return 0;
- }
- static size_t
- console_read_nolock(struct console *console, char *s, size_t size)
- {
- int error;
- struct console_waiter waiter;
- size_t i, nc;
- waiter.thread = thread_self();
- list_insert_tail(&console->waiters, &waiter.node);
- for (;;) {
- error = cbuf_pop(&console->recvbuf, s, &size);
- if (!error) {
- for (i = nc = 0; i < size; ++i) {
- error = console_process_ctrl_char(console, s[i]);
- if (!error) {
- nc++;
- }
- }
- size -= nc;
- if (size) {
- break;
- }
- }
- thread_sleep(&console->lock, console, "consgetc");
- }
- list_remove(&waiter.node);
- return size;
- }
- static int __init
- console_bootstrap(void)
- {
- list_init(&console_devs);
- console_name = arg_value("console");
- return 0;
- }
- INIT_OP_DEFINE(console_bootstrap,
- INIT_OP_DEP(arg_setup, true),
- INIT_OP_DEP(log_setup, true));
- static int __init
- console_setup(void)
- {
- return 0;
- }
- INIT_OP_DEFINE(console_setup,
- INIT_OP_DEP(boot_setup_console, true),
- INIT_OP_DEP(thread_setup, true));
- 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)) {
- console_dev = console;
- }
- log_info("console: %s registered", console->name);
- if (console == console_dev) {
- log_info("console: %s selected as active console", console->name);
- }
- }
- void
- console_intr(struct console *console, const char *s)
- {
- struct list *node;
- assert(thread_check_intr_context());
- if (*s == '\0') {
- return;
- }
- spinlock_lock(&console->lock);
- while (*s != '\0') {
- if (cbuf_size(&console->recvbuf) == cbuf_capacity(&console->recvbuf)) {
- goto out;
- }
- cbuf_pushb(&console->recvbuf, *s, false);
- s++;
- }
- node = list_first(&console->waiters);
- if (node) {
- thread_wakeup(list_entry(node, struct console_waiter, node)->thread);
- }
- out:
- spinlock_unlock(&console->lock);
- }
- void
- console_putchar(char c)
- {
- console_puts(&c, 1);
- }
- char
- console_getchar(void)
- {
- char c;
- if (!console_gets(&c, 1)) {
- c = EOF;
- }
- return c;
- }
- void
- console_puts_nolock(const char *s, size_t size)
- {
- if (console_dev) {
- console_dev->ops->puts(console_dev, s, size);
- }
- }
- void
- console_puts(const char *s, size_t size)
- {
- unsigned long flags;
- console_lock(&flags);
- console_puts_nolock(s, size);
- console_unlock(flags);
- }
- size_t
- console_gets_nolock(char *s, size_t size)
- {
- if (!console_dev) {
- return 0;
- }
- return console_read_nolock(console_dev, s, size);
- }
- size_t
- console_gets(char *s, size_t size)
- {
- unsigned long flags;
- console_lock(&flags);
- size = console_gets_nolock(s, size);
- console_unlock(flags);
- return size;
- }
- void
- console_lock(unsigned long *flags)
- {
- if (console_dev) {
- spinlock_lock_intr_save(&console_dev->lock, flags);
- }
- }
- void
- console_unlock(unsigned long flags)
- {
- if (console_dev) {
- spinlock_unlock_intr_restore(&console_dev->lock, flags);
- }
- }
|