123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- /*
- * 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)
- {
- return (!console_name || strcmp (console_name, name) == 0);
- }
- void __init
- console_init (struct console *console, const char *name,
- const struct console_ops *ops)
- {
- assert (ops);
- 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)
- {
- struct console_waiter waiter = { .thread = thread_self () };
- list_insert_tail (&console->waiters, &waiter.node);
- while (1)
- {
- int error = cbuf_pop (&console->recvbuf, s, &size);
- if (! error)
- {
- size_t nc = 0;
- for (size_t i = 0; i < size; ++i)
- if (console_process_ctrl_char (console, s[i]) == 0)
- nc++;
- size -= nc;
- if (size)
- break;
- }
- thread_timedsleep (&console->lock, console, "consgetc", 1000);
- }
- 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);
- list_insert_tail (&console_devs, &console->node);
- if (!console_dev && 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)
- {
- assert (thread_check_intr_context ());
- if (*s == '\0')
- return;
- SPINLOCK_GUARD (&console->lock);
- for (; *s; ++s)
- {
- if (cbuf_size (&console->recvbuf) == cbuf_capacity (&console->recvbuf))
- return;
- cbuf_pushb (&console->recvbuf, *s, false);
- }
- if (list_empty (&console->waiters))
- return;
- _Auto waiter = list_first_entry (&console->waiters,
- struct console_waiter, node);
- thread_wakeup (waiter->thread);
- }
- 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)
- {
- cpu_flags_t flags;
- console_lock (&flags);
- console_puts_nolock (s, size);
- console_unlock (flags);
- }
- size_t
- console_gets_nolock (char *s, size_t size)
- {
- return (console_dev ? console_read_nolock (console_dev, s, size) : 0);
- }
- size_t
- console_gets (char *s, size_t size)
- {
- cpu_flags_t flags;
- console_lock (&flags);
- size = console_gets_nolock (s, size);
- console_unlock (flags);
- return (size);
- }
- void
- console_lock (cpu_flags_t *flags)
- {
- if (console_dev)
- spinlock_lock_intr_save (&console_dev->lock, flags);
- }
- void
- console_unlock (cpu_flags_t flags)
- {
- if (console_dev)
- spinlock_unlock_intr_restore (&console_dev->lock, flags);
- }
|