console.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  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. struct list node;
  35. struct thread *thread;
  36. };
  37. /*
  38. * Registered consoles.
  39. */
  40. static struct list console_devs;
  41. /*
  42. * Active console device.
  43. */
  44. static struct console *console_dev;
  45. static const char *console_name __initdata;
  46. static bool __init
  47. console_name_match(const char *name)
  48. {
  49. if (console_name == NULL) {
  50. return true;
  51. }
  52. return (strcmp(console_name, name) == 0);
  53. }
  54. void __init
  55. console_init(struct console *console, const char *name,
  56. const struct console_ops *ops)
  57. {
  58. assert(ops != NULL);
  59. spinlock_init(&console->lock);
  60. console->ops = ops;
  61. cbuf_init(&console->recvbuf, console->buffer, sizeof(console->buffer));
  62. list_init(&console->waiters);
  63. strlcpy(console->name, name, sizeof(console->name));
  64. }
  65. static int
  66. console_process_ctrl_char(struct console *console, char c)
  67. {
  68. switch (c) {
  69. case CONSOLE_SCROLL_UP:
  70. case CONSOLE_SCROLL_DOWN:
  71. break;
  72. default:
  73. return EINVAL;
  74. }
  75. console->ops->puts(console, &c, 1);
  76. return 0;
  77. }
  78. static size_t
  79. console_read_nolock(struct console *console, char *s, size_t size)
  80. {
  81. int error;
  82. struct console_waiter waiter;
  83. size_t i, nc;
  84. waiter.thread = thread_self();
  85. list_insert_tail(&console->waiters, &waiter.node);
  86. for (;;) {
  87. error = cbuf_pop(&console->recvbuf, s, &size);
  88. if (!error) {
  89. for (i = nc = 0; i < size; ++i) {
  90. error = console_process_ctrl_char(console, s[i]);
  91. if (!error) {
  92. nc++;
  93. }
  94. }
  95. size -= nc;
  96. if (size) {
  97. break;
  98. }
  99. }
  100. thread_sleep(&console->lock, console, "consgetc");
  101. }
  102. list_remove(&waiter.node);
  103. return size;
  104. }
  105. static int __init
  106. console_bootstrap(void)
  107. {
  108. list_init(&console_devs);
  109. console_name = arg_value("console");
  110. return 0;
  111. }
  112. INIT_OP_DEFINE(console_bootstrap,
  113. INIT_OP_DEP(arg_setup, true),
  114. INIT_OP_DEP(log_setup, true));
  115. static int __init
  116. console_setup(void)
  117. {
  118. return 0;
  119. }
  120. INIT_OP_DEFINE(console_setup,
  121. INIT_OP_DEP(boot_setup_console, true),
  122. INIT_OP_DEP(thread_setup, true));
  123. void __init
  124. console_register(struct console *console)
  125. {
  126. assert(console->ops != NULL);
  127. list_insert_tail(&console_devs, &console->node);
  128. if ((console_dev == NULL) && console_name_match(console->name)) {
  129. console_dev = console;
  130. }
  131. log_info("console: %s registered", console->name);
  132. if (console == console_dev) {
  133. log_info("console: %s selected as active console", console->name);
  134. }
  135. }
  136. void
  137. console_intr(struct console *console, const char *s)
  138. {
  139. struct list *node;
  140. assert(thread_check_intr_context());
  141. if (*s == '\0') {
  142. return;
  143. }
  144. spinlock_lock(&console->lock);
  145. while (*s != '\0') {
  146. if (cbuf_size(&console->recvbuf) == cbuf_capacity(&console->recvbuf)) {
  147. goto out;
  148. }
  149. cbuf_pushb(&console->recvbuf, *s, false);
  150. s++;
  151. }
  152. node = list_first(&console->waiters);
  153. if (node) {
  154. thread_wakeup(list_entry(node, struct console_waiter, node)->thread);
  155. }
  156. out:
  157. spinlock_unlock(&console->lock);
  158. }
  159. void
  160. console_putchar(char c)
  161. {
  162. console_puts(&c, 1);
  163. }
  164. char
  165. console_getchar(void)
  166. {
  167. char c;
  168. if (!console_gets(&c, 1)) {
  169. c = EOF;
  170. }
  171. return c;
  172. }
  173. void
  174. console_puts_nolock(const char *s, size_t size)
  175. {
  176. if (console_dev) {
  177. console_dev->ops->puts(console_dev, s, size);
  178. }
  179. }
  180. void
  181. console_puts(const char *s, size_t size)
  182. {
  183. unsigned long flags;
  184. console_lock(&flags);
  185. console_puts_nolock(s, size);
  186. console_unlock(flags);
  187. }
  188. size_t
  189. console_gets_nolock(char *s, size_t size)
  190. {
  191. if (!console_dev) {
  192. return 0;
  193. }
  194. return console_read_nolock(console_dev, s, size);
  195. }
  196. size_t
  197. console_gets(char *s, size_t size)
  198. {
  199. unsigned long flags;
  200. console_lock(&flags);
  201. size = console_gets_nolock(s, size);
  202. console_unlock(flags);
  203. return size;
  204. }
  205. void
  206. console_lock(unsigned long *flags)
  207. {
  208. if (console_dev) {
  209. spinlock_lock_intr_save(&console_dev->lock, flags);
  210. }
  211. }
  212. void
  213. console_unlock(unsigned long flags)
  214. {
  215. if (console_dev) {
  216. spinlock_unlock_intr_restore(&console_dev->lock, flags);
  217. }
  218. }