source: mainline/kernel/generic/src/console/console.c@ cb3d641a

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since cb3d641a was a71c158, checked in by Martin Decky <martin@…>, 16 years ago

kernel output devices now suport multiple instances (except ski and sgcn, which respect the same interface, but behave as singletons)
if more than one output device gets initialized, the output is cloned to all of them
get rid of arch_grab_console() and arch_release_console() (output devices can implement a generic "redraw" method, input devices respect the "silent" global variable)
related cleanups and modifications

  • Property mode set to 100644
File size: 8.0 KB
Line 
1/*
2 * Copyright (c) 2003 Josef Cejka
3 * Copyright (c) 2005 Jakub Jermar
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup genericconsole
31 * @{
32 */
33/** @file
34 */
35
36#include <console/console.h>
37#include <console/chardev.h>
38#include <sysinfo/sysinfo.h>
39#include <synch/waitq.h>
40#include <synch/spinlock.h>
41#include <arch/types.h>
42#include <ddi/irq.h>
43#include <ddi/ddi.h>
44#include <ipc/event.h>
45#include <ipc/irq.h>
46#include <arch.h>
47#include <print.h>
48#include <putchar.h>
49#include <atomic.h>
50#include <syscall/copy.h>
51#include <errno.h>
52#include <string.h>
53
54#define KLOG_PAGES 4
55#define KLOG_LENGTH (KLOG_PAGES * PAGE_SIZE / sizeof(wchar_t))
56#define KLOG_LATENCY 8
57
58/** Kernel log cyclic buffer */
59static wchar_t klog[KLOG_LENGTH] __attribute__ ((aligned (PAGE_SIZE)));
60
61/** Kernel log initialized */
62static bool klog_inited = false;
63/** First kernel log characters */
64static size_t klog_start = 0;
65/** Number of valid kernel log characters */
66static size_t klog_len = 0;
67/** Number of stored (not printed) kernel log characters */
68static size_t klog_stored = 0;
69/** Number of stored kernel log characters for uspace */
70static size_t klog_uspace = 0;
71
72/** Kernel log spinlock */
73SPINLOCK_STATIC_INITIALIZE_NAME(klog_lock, "*klog_lock");
74
75/** Physical memory area used for klog buffer */
76static parea_t klog_parea;
77
78static indev_t stdin_sink;
79static outdev_t stdout_source;
80
81static indev_operations_t stdin_ops = {
82 .poll = NULL
83};
84
85static void stdout_write(outdev_t *dev, wchar_t ch, bool silent);
86static void stdout_redraw(outdev_t *dev);
87
88static outdev_operations_t stdout_ops = {
89 .write = stdout_write,
90 .redraw = stdout_redraw
91};
92
93/** Silence output */
94bool silent = false;
95
96/** Standard input and output character devices */
97indev_t *stdin = NULL;
98outdev_t *stdout = NULL;
99
100indev_t *stdin_wire(void)
101{
102 if (stdin == NULL) {
103 indev_initialize("stdin", &stdin_sink, &stdin_ops);
104 stdin = &stdin_sink;
105 }
106
107 return stdin;
108}
109
110void stdout_wire(outdev_t *outdev)
111{
112 if (stdout == NULL) {
113 outdev_initialize("stdout", &stdout_source, &stdout_ops);
114 stdout = &stdout_source;
115 }
116
117 list_append(&outdev->link, &stdout->list);
118}
119
120static void stdout_write(outdev_t *dev, wchar_t ch, bool silent)
121{
122 link_t *cur;
123
124 for (cur = dev->list.next; cur != &dev->list; cur = cur->next) {
125 outdev_t *sink = list_get_instance(cur, outdev_t, link);
126 if ((sink) && (sink->op->write))
127 sink->op->write(sink, ch, silent);
128 }
129}
130
131static void stdout_redraw(outdev_t *dev)
132{
133 link_t *cur;
134
135 for (cur = dev->list.next; cur != &dev->list; cur = cur->next) {
136 outdev_t *sink = list_get_instance(cur, outdev_t, link);
137 if ((sink) && (sink->op->redraw))
138 sink->op->redraw(sink);
139 }
140}
141
142/** Initialize kernel logging facility
143 *
144 * The shared area contains kernel cyclic buffer. Userspace application may
145 * be notified on new data with indication of position and size
146 * of the data within the circular buffer.
147 *
148 */
149void klog_init(void)
150{
151 void *faddr = (void *) KA2PA(klog);
152
153 ASSERT((uintptr_t) faddr % FRAME_SIZE == 0);
154
155 klog_parea.pbase = (uintptr_t) faddr;
156 klog_parea.frames = SIZE2FRAMES(sizeof(klog));
157 ddi_parea_register(&klog_parea);
158
159 sysinfo_set_item_val("klog.faddr", NULL, (unative_t) faddr);
160 sysinfo_set_item_val("klog.pages", NULL, KLOG_PAGES);
161
162 spinlock_lock(&klog_lock);
163 klog_inited = true;
164 spinlock_unlock(&klog_lock);
165}
166
167void grab_console(void)
168{
169 bool prev = silent;
170
171 silent = false;
172 if ((stdout) && (stdout->op->redraw))
173 stdout->op->redraw(stdout);
174
175 /* Force the console to print the prompt */
176 if ((stdin) && (prev))
177 indev_push_character(stdin, '\n');
178}
179
180void release_console(void)
181{
182 // FIXME arch_release_console
183 silent = true;
184}
185
186/** Tell kernel to get keyboard/console access again */
187unative_t sys_debug_enable_console(void)
188{
189#ifdef CONFIG_KCONSOLE
190 grab_console();
191 return true;
192#else
193 return false;
194#endif
195}
196
197/** Tell kernel to relinquish keyboard/console access */
198unative_t sys_debug_disable_console(void)
199{
200 release_console();
201 return true;
202}
203
204/** Get string from input character device.
205 *
206 * Read characters from input character device until first occurrence
207 * of newline character.
208 *
209 * @param indev Input character device.
210 * @param buf Buffer where to store string terminated by NULL.
211 * @param buflen Size of the buffer.
212 *
213 * @return Number of characters read.
214 *
215 */
216size_t gets(indev_t *indev, char *buf, size_t buflen)
217{
218 size_t offset = 0;
219 size_t count = 0;
220 buf[offset] = 0;
221
222 wchar_t ch;
223 while ((ch = indev_pop_character(indev)) != '\n') {
224 if (ch == '\b') {
225 if (count > 0) {
226 /* Space, backspace, space */
227 putchar('\b');
228 putchar(' ');
229 putchar('\b');
230
231 count--;
232 offset = str_lsize(buf, count);
233 buf[offset] = 0;
234 }
235 }
236 if (chr_encode(ch, buf, &offset, buflen - 1) == EOK) {
237 putchar(ch);
238 count++;
239 buf[offset] = 0;
240 }
241 }
242
243 return count;
244}
245
246/** Get character from input device & echo it to screen */
247wchar_t getc(indev_t *indev)
248{
249 wchar_t ch = indev_pop_character(indev);
250 putchar(ch);
251 return ch;
252}
253
254void klog_update(void)
255{
256 spinlock_lock(&klog_lock);
257
258 if ((klog_inited) && (event_is_subscribed(EVENT_KLOG)) && (klog_uspace > 0)) {
259 event_notify_3(EVENT_KLOG, klog_start, klog_len, klog_uspace);
260 klog_uspace = 0;
261 }
262
263 spinlock_unlock(&klog_lock);
264}
265
266void putchar(const wchar_t ch)
267{
268 spinlock_lock(&klog_lock);
269
270 if ((klog_stored > 0) && (stdout) && (stdout->op->write)) {
271 /* Print charaters stored in kernel log */
272 size_t i;
273 for (i = klog_len - klog_stored; i < klog_len; i++)
274 stdout->op->write(stdout, klog[(klog_start + i) % KLOG_LENGTH], silent);
275 klog_stored = 0;
276 }
277
278 /* Store character in the cyclic kernel log */
279 klog[(klog_start + klog_len) % KLOG_LENGTH] = ch;
280 if (klog_len < KLOG_LENGTH)
281 klog_len++;
282 else
283 klog_start = (klog_start + 1) % KLOG_LENGTH;
284
285 if ((stdout) && (stdout->op->write))
286 stdout->op->write(stdout, ch, silent);
287 else {
288 /* The character is just in the kernel log */
289 if (klog_stored < klog_len)
290 klog_stored++;
291 }
292
293 /* The character is stored for uspace */
294 if (klog_uspace < klog_len)
295 klog_uspace++;
296
297 /* Check notify uspace to update */
298 bool update;
299 if ((klog_uspace > KLOG_LATENCY) || (ch == '\n'))
300 update = true;
301 else
302 update = false;
303
304 spinlock_unlock(&klog_lock);
305
306 if (update)
307 klog_update();
308}
309
310/** Print using kernel facility
311 *
312 * Print to kernel log.
313 *
314 */
315unative_t sys_klog(int fd, const void *buf, size_t size)
316{
317 char *data;
318 int rc;
319
320 if (size > PAGE_SIZE)
321 return ELIMIT;
322
323 if (size > 0) {
324 data = (char *) malloc(size + 1, 0);
325 if (!data)
326 return ENOMEM;
327
328 rc = copy_from_uspace(data, buf, size);
329 if (rc) {
330 free(data);
331 return rc;
332 }
333 data[size] = 0;
334
335 printf("%s", data);
336 free(data);
337 } else
338 klog_update();
339
340 return size;
341}
342
343/** @}
344 */
Note: See TracBrowser for help on using the repository browser.