1 | // SPDX-License-Identifier: GPL-3.0-or-later |
2 | |
3 | #include "mos/tasks/signal.hpp" |
4 | #include "mos/tasks/thread.hpp" |
5 | |
6 | #include <array> |
7 | #include <limits.h> |
8 | #include <mos/device/console.hpp> |
9 | #include <mos/io/io.hpp> |
10 | #include <mos/lib/structures/list.hpp> |
11 | #include <mos/lib/structures/ring_buffer.hpp> |
12 | #include <mos/syslog/printk.hpp> |
13 | #include <mos/tasks/schedule.hpp> |
14 | #include <mos/tasks/wait.hpp> |
15 | #include <mos_string.hpp> |
16 | |
17 | list_head consoles; |
18 | |
19 | std::array<Console *, 128> console_list = {}; |
20 | |
21 | void Console::putc(u8 c) |
22 | { |
23 | if (c == 0x3) |
24 | { |
25 | spinlock_acquire(&waitlist.lock); |
26 | list_foreach(waitable_list_entry_t, entry, waitlist.list) |
27 | { |
28 | Thread *thread = thread_get(id: entry->waiter); |
29 | if (thread) |
30 | signal_send_to_thread(target: thread, SIGINT); |
31 | } |
32 | spinlock_release(&waitlist.lock); |
33 | } |
34 | |
35 | ring_buffer_pos_push_back_byte(buffer: reader.buf, pos: &reader.pos, data: c); |
36 | waitlist_wake(list: &waitlist, INT_MAX); |
37 | } |
38 | |
39 | static size_t console_io_read(io_t *io, void *data, size_t size) |
40 | { |
41 | Console *con = container_of(io, Console, io); |
42 | |
43 | retry_read:; |
44 | size_t read = 0; |
45 | |
46 | spinlock_acquire(&con->reader.lock); |
47 | if (ring_buffer_pos_is_empty(pos: &con->reader.pos)) |
48 | { |
49 | spinlock_release(&con->reader.lock); |
50 | bool ok = reschedule_for_waitlist(waitlist: &con->waitlist); |
51 | if (!ok) |
52 | { |
53 | pr_emerg("console: '%s' closed" , con->name); |
54 | return -EIO; |
55 | } |
56 | spinlock_acquire(&con->reader.lock); |
57 | |
58 | if (signal_has_pending()) |
59 | { |
60 | spinlock_release(&con->reader.lock); |
61 | return -ERESTARTSYS; |
62 | } |
63 | } |
64 | else |
65 | { |
66 | read = ring_buffer_pos_pop_front(buffer: con->reader.buf, pos: &con->reader.pos, buf: (u8 *) data, size); |
67 | } |
68 | spinlock_release(&con->reader.lock); |
69 | |
70 | if (read == 0) |
71 | goto retry_read; |
72 | |
73 | return read; |
74 | } |
75 | |
76 | static size_t console_io_write(io_t *io, const void *data, size_t size) |
77 | { |
78 | Console *con = container_of(io, Console, io); |
79 | spinlock_acquire(&con->writer.lock); |
80 | if ((con->caps & CONSOLE_CAP_COLOR)) |
81 | con->set_color(fg: con->default_fg, bg: con->default_bg); |
82 | size_t ret = con->do_write(data: (const char *) data, size); |
83 | spinlock_release(&con->writer.lock); |
84 | return ret; |
85 | } |
86 | |
87 | static const io_op_t console_io_ops = { |
88 | .read = console_io_read, |
89 | .write = console_io_write, |
90 | }; |
91 | |
92 | void console_register(Console *con) |
93 | { |
94 | bool result = con->extra_setup(); |
95 | if (!result) |
96 | { |
97 | pr_emerg("console: failed to setup '%s'" , con->name); |
98 | return; |
99 | } |
100 | |
101 | MOS_ASSERT_X(con->name != NULL, "console: %p's name is NULL" , con); |
102 | |
103 | io_flags_t flags = IO_WRITABLE; |
104 | |
105 | if (con->caps & CONSOLE_CAP_READ) |
106 | { |
107 | MOS_ASSERT_X(con->reader.buf, "console: '%s' has no read buffer" , con->name); |
108 | ring_buffer_pos_init(pos: &con->reader.pos, capacity: con->reader.size); |
109 | flags |= IO_READABLE; |
110 | } |
111 | |
112 | io_init(io: &con->io, type: IO_CONSOLE, flags, ops: &console_io_ops); |
113 | list_node_append(head: &consoles, list_node(con)); |
114 | waitlist_init(list: &con->waitlist); |
115 | } |
116 | |
117 | Console *console_get(const char *name) |
118 | { |
119 | if (list_is_empty(head: &consoles)) |
120 | return NULL; |
121 | |
122 | list_foreach(Console, con, consoles) |
123 | { |
124 | if (strcmp(str1: con->name, str2: name) == 0) |
125 | return con; |
126 | } |
127 | return NULL; |
128 | } |
129 | |
130 | Console *console_get_by_prefix(const char *prefix) |
131 | { |
132 | list_foreach(Console, con, consoles) |
133 | { |
134 | if (strncmp(str1: con->name, str2: prefix, n: strlen(str: prefix)) == 0) |
135 | return con; |
136 | } |
137 | return NULL; |
138 | } |
139 | |