console.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /*
  2. * Copyright (c) 2017 Richard Braun.
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <assert.h>
  18. #include <errno.h>
  19. #include <stdbool.h>
  20. #include <stddef.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <kern/arg.h>
  24. #include <kern/init.h>
  25. #include <kern/console.h>
  26. #include <kern/list.h>
  27. #include <kern/log.h>
  28. #include <kern/mutex.h>
  29. #include <kern/spinlock.h>
  30. #include <kern/thread.h>
  31. #include <machine/boot.h>
  32. #include <machine/cpu.h>
  33. struct console_waiter
  34. {
  35. struct list node;
  36. struct thread *thread;
  37. };
  38. // Registered consoles.
  39. static struct list console_devs;
  40. // Active console device.
  41. static struct console *console_dev;
  42. static const char *console_name __initdata;
  43. static bool __init
  44. console_name_match (const char *name)
  45. {
  46. return (!console_name || strcmp (console_name, name) == 0);
  47. }
  48. void __init
  49. console_init (struct console *console, const char *name,
  50. const struct console_ops *ops)
  51. {
  52. assert (ops);
  53. spinlock_init (&console->lock);
  54. console->ops = ops;
  55. cbuf_init (&console->recvbuf, console->buffer, sizeof (console->buffer));
  56. list_init (&console->waiters);
  57. strlcpy (console->name, name, sizeof (console->name));
  58. }
  59. static int
  60. console_process_ctrl_char (struct console *console, char c)
  61. {
  62. switch (c)
  63. {
  64. case CONSOLE_SCROLL_UP:
  65. case CONSOLE_SCROLL_DOWN:
  66. break;
  67. default:
  68. return (EINVAL);
  69. }
  70. console->ops->puts (console, &c, 1);
  71. return (0);
  72. }
  73. static size_t
  74. console_read_nolock (struct console *console, char *s, size_t size)
  75. {
  76. struct console_waiter waiter = { .thread = thread_self () };
  77. list_insert_tail (&console->waiters, &waiter.node);
  78. while (1)
  79. {
  80. int error = cbuf_pop (&console->recvbuf, s, &size);
  81. if (! error)
  82. {
  83. size_t nc = 0;
  84. for (size_t i = 0; i < size; ++i)
  85. if (console_process_ctrl_char (console, s[i]) == 0)
  86. nc++;
  87. size -= nc;
  88. if (size)
  89. break;
  90. }
  91. thread_timedsleep (&console->lock, console, "consgetc", 1000);
  92. }
  93. list_remove (&waiter.node);
  94. return (size);
  95. }
  96. static int __init
  97. console_bootstrap (void)
  98. {
  99. list_init (&console_devs);
  100. console_name = arg_value ("console");
  101. return (0);
  102. }
  103. INIT_OP_DEFINE (console_bootstrap,
  104. INIT_OP_DEP (arg_setup, true),
  105. INIT_OP_DEP (log_setup, true));
  106. static int __init
  107. console_setup (void)
  108. {
  109. return (0);
  110. }
  111. INIT_OP_DEFINE (console_setup,
  112. INIT_OP_DEP (boot_setup_console, true),
  113. INIT_OP_DEP (thread_setup, true));
  114. void __init
  115. console_register (struct console *console)
  116. {
  117. assert (console->ops);
  118. list_insert_tail (&console_devs, &console->node);
  119. if (!console_dev && console_name_match (console->name))
  120. console_dev = console;
  121. log_info ("console: %s registered", console->name);
  122. if (console == console_dev)
  123. log_info ("console: %s selected as active console", console->name);
  124. }
  125. void
  126. console_intr (struct console *console, const char *s)
  127. {
  128. assert (thread_check_intr_context ());
  129. if (*s == '\0')
  130. return;
  131. SPINLOCK_GUARD (&console->lock);
  132. for (; *s; ++s)
  133. {
  134. if (cbuf_size (&console->recvbuf) == cbuf_capacity (&console->recvbuf))
  135. return;
  136. cbuf_pushb (&console->recvbuf, *s, false);
  137. }
  138. if (list_empty (&console->waiters))
  139. return;
  140. _Auto waiter = list_first_entry (&console->waiters,
  141. struct console_waiter, node);
  142. thread_wakeup (waiter->thread);
  143. }
  144. void
  145. console_putchar (char c)
  146. {
  147. console_puts (&c, 1);
  148. }
  149. char
  150. console_getchar (void)
  151. {
  152. char c;
  153. if (!console_gets (&c, 1))
  154. c = EOF;
  155. return (c);
  156. }
  157. void
  158. console_puts_nolock (const char *s, size_t size)
  159. {
  160. if (console_dev)
  161. console_dev->ops->puts (console_dev, s, size);
  162. }
  163. void
  164. console_puts (const char *s, size_t size)
  165. {
  166. cpu_flags_t flags;
  167. console_lock (&flags);
  168. console_puts_nolock (s, size);
  169. console_unlock (flags);
  170. }
  171. size_t
  172. console_gets_nolock (char *s, size_t size)
  173. {
  174. return (console_dev ? console_read_nolock (console_dev, s, size) : 0);
  175. }
  176. size_t
  177. console_gets (char *s, size_t size)
  178. {
  179. cpu_flags_t flags;
  180. console_lock (&flags);
  181. size = console_gets_nolock (s, size);
  182. console_unlock (flags);
  183. return (size);
  184. }
  185. void
  186. console_lock (cpu_flags_t *flags)
  187. {
  188. if (console_dev)
  189. spinlock_lock_intr_save (&console_dev->lock, flags);
  190. }
  191. void
  192. console_unlock (cpu_flags_t flags)
  193. {
  194. if (console_dev)
  195. spinlock_unlock_intr_restore (&console_dev->lock, flags);
  196. }