~galfy/helenos/bird-port-mainline

« back to all changes in this revision

Viewing changes to kernel/generic/src/console/console.c

  • Committer: Martin Decky
  • Date: 2009-08-04 11:19:19 UTC
  • Revision ID: martin@uranus.dsrg.hide.ms.mff.cuni.cz-20090804111919-evyclddlr3v5lhmp
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 */
 
59
static wchar_t klog[KLOG_LENGTH] __attribute__ ((aligned (PAGE_SIZE)));
 
60
 
 
61
/** Kernel log initialized */
 
62
static bool klog_inited = false;
 
63
/** First kernel log characters */
 
64
static size_t klog_start = 0;
 
65
/** Number of valid kernel log characters */
 
66
static size_t klog_len = 0;
 
67
/** Number of stored (not printed) kernel log characters */
 
68
static size_t klog_stored = 0;
 
69
/** Number of stored kernel log characters for uspace */
 
70
static size_t klog_uspace = 0;
 
71
 
 
72
/** Kernel log spinlock */
 
73
SPINLOCK_INITIALIZE(klog_lock);
 
74
 
 
75
/** Physical memory area used for klog buffer */
 
76
static parea_t klog_parea;
 
77
 
 
78
static indev_operations_t stdin_ops = {
 
79
        .poll = NULL
 
80
};
 
81
 
 
82
/** Silence output */
 
83
bool silent = false;
 
84
 
 
85
/** Standard input and output character devices */
 
86
indev_t *stdin = NULL;
 
87
outdev_t *stdout = NULL;
 
88
 
 
89
indev_t *stdin_wire(void)
 
90
{
 
91
        if (stdin == NULL) {
 
92
                stdin = malloc(sizeof(indev_t), FRAME_ATOMIC);
 
93
                if (stdin != NULL)
 
94
                        indev_initialize("stdin", stdin, &stdin_ops);
 
95
        }
 
96
        
 
97
        return stdin;
 
98
}
 
99
 
 
100
/** Initialize kernel logging facility
 
101
 *
 
102
 * The shared area contains kernel cyclic buffer. Userspace application may
 
103
 * be notified on new data with indication of position and size
 
104
 * of the data within the circular buffer.
 
105
 *
 
106
 */
 
107
void klog_init(void)
 
108
{
 
109
        void *faddr = (void *) KA2PA(klog);
 
110
        
 
111
        ASSERT((uintptr_t) faddr % FRAME_SIZE == 0);
 
112
        
 
113
        klog_parea.pbase = (uintptr_t) faddr;
 
114
        klog_parea.frames = SIZE2FRAMES(sizeof(klog));
 
115
        ddi_parea_register(&klog_parea);
 
116
        
 
117
        sysinfo_set_item_val("klog.faddr", NULL, (unative_t) faddr);
 
118
        sysinfo_set_item_val("klog.pages", NULL, KLOG_PAGES);
 
119
        
 
120
        spinlock_lock(&klog_lock);
 
121
        klog_inited = true;
 
122
        spinlock_unlock(&klog_lock);
 
123
}
 
124
 
 
125
void grab_console(void)
 
126
{
 
127
        bool prev = silent;
 
128
        
 
129
        silent = false;
 
130
        arch_grab_console();
 
131
        
 
132
        /* Force the console to print the prompt */
 
133
        if ((stdin) && (prev))
 
134
                indev_push_character(stdin, '\n');
 
135
}
 
136
 
 
137
void release_console(void)
 
138
{
 
139
        silent = true;
 
140
        arch_release_console();
 
141
}
 
142
 
 
143
/** Tell kernel to get keyboard/console access again */
 
144
unative_t sys_debug_enable_console(void)
 
145
{
 
146
#ifdef CONFIG_KCONSOLE
 
147
        grab_console();
 
148
        return true;
 
149
#else
 
150
        return false;
 
151
#endif
 
152
}
 
153
 
 
154
/** Tell kernel to relinquish keyboard/console access */
 
155
unative_t sys_debug_disable_console(void)
 
156
{
 
157
        release_console();
 
158
        return true;
 
159
}
 
160
 
 
161
/** Get string from input character device.
 
162
 *
 
163
 * Read characters from input character device until first occurrence
 
164
 * of newline character.
 
165
 *
 
166
 * @param indev  Input character device.
 
167
 * @param buf    Buffer where to store string terminated by NULL.
 
168
 * @param buflen Size of the buffer.
 
169
 *
 
170
 * @return Number of characters read.
 
171
 *
 
172
 */
 
173
size_t gets(indev_t *indev, char *buf, size_t buflen)
 
174
{
 
175
        size_t offset = 0;
 
176
        size_t count = 0;
 
177
        buf[offset] = 0;
 
178
        
 
179
        wchar_t ch;
 
180
        while ((ch = indev_pop_character(indev)) != '\n') {
 
181
                if (ch == '\b') {
 
182
                        if (count > 0) {
 
183
                                /* Space, backspace, space */
 
184
                                putchar('\b');
 
185
                                putchar(' ');
 
186
                                putchar('\b');
 
187
                                
 
188
                                count--;
 
189
                                offset = str_lsize(buf, count);
 
190
                                buf[offset] = 0;
 
191
                        }
 
192
                }
 
193
                if (chr_encode(ch, buf, &offset, buflen - 1) == EOK) {
 
194
                        putchar(ch);
 
195
                        count++;
 
196
                        buf[offset] = 0;
 
197
                }
 
198
        }
 
199
        
 
200
        return count;
 
201
}
 
202
 
 
203
/** Get character from input device & echo it to screen */
 
204
wchar_t getc(indev_t *indev)
 
205
{
 
206
        wchar_t ch = indev_pop_character(indev);
 
207
        putchar(ch);
 
208
        return ch;
 
209
}
 
210
 
 
211
void klog_update(void)
 
212
{
 
213
        spinlock_lock(&klog_lock);
 
214
        
 
215
        if ((klog_inited) && (event_is_subscribed(EVENT_KLOG)) && (klog_uspace > 0)) {
 
216
                event_notify_3(EVENT_KLOG, klog_start, klog_len, klog_uspace);
 
217
                klog_uspace = 0;
 
218
        }
 
219
        
 
220
        spinlock_unlock(&klog_lock);
 
221
}
 
222
 
 
223
void putchar(const wchar_t ch)
 
224
{
 
225
        spinlock_lock(&klog_lock);
 
226
        
 
227
        if ((klog_stored > 0) && (stdout) && (stdout->op->write)) {
 
228
                /* Print charaters stored in kernel log */
 
229
                size_t i;
 
230
                for (i = klog_len - klog_stored; i < klog_len; i++)
 
231
                        stdout->op->write(stdout, klog[(klog_start + i) % KLOG_LENGTH], silent);
 
232
                klog_stored = 0;
 
233
        }
 
234
        
 
235
        /* Store character in the cyclic kernel log */
 
236
        klog[(klog_start + klog_len) % KLOG_LENGTH] = ch;
 
237
        if (klog_len < KLOG_LENGTH)
 
238
                klog_len++;
 
239
        else
 
240
                klog_start = (klog_start + 1) % KLOG_LENGTH;
 
241
        
 
242
        if ((stdout) && (stdout->op->write))
 
243
                stdout->op->write(stdout, ch, silent);
 
244
        else {
 
245
                /* The character is just in the kernel log */
 
246
                if (klog_stored < klog_len)
 
247
                        klog_stored++;
 
248
        }
 
249
        
 
250
        /* The character is stored for uspace */
 
251
        if (klog_uspace < klog_len)
 
252
                klog_uspace++;
 
253
        
 
254
        /* Check notify uspace to update */
 
255
        bool update;
 
256
        if ((klog_uspace > KLOG_LATENCY) || (ch == '\n'))
 
257
                update = true;
 
258
        else
 
259
                update = false;
 
260
        
 
261
        spinlock_unlock(&klog_lock);
 
262
        
 
263
        if (update)
 
264
                klog_update();
 
265
}
 
266
 
 
267
/** Print using kernel facility
 
268
 *
 
269
 * Print to kernel log.
 
270
 *
 
271
 */
 
272
unative_t sys_klog(int fd, const void *buf, size_t size)
 
273
{
 
274
        char *data;
 
275
        int rc;
 
276
        
 
277
        if (size > PAGE_SIZE)
 
278
                return ELIMIT;
 
279
        
 
280
        if (size > 0) {
 
281
                data = (char *) malloc(size + 1, 0);
 
282
                if (!data)
 
283
                        return ENOMEM;
 
284
                
 
285
                rc = copy_from_uspace(data, buf, size);
 
286
                if (rc) {
 
287
                        free(data);
 
288
                        return rc;
 
289
                }
 
290
                data[size] = 0;
 
291
                
 
292
                printf("%s", data);
 
293
                free(data);
 
294
        } else
 
295
                klog_update();
 
296
        
 
297
        return size;
 
298
}
 
299
 
 
300
/** @}
 
301
 */