Subversion Repositories HelenOS

Rev

Rev 4538 | Rev 4571 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4538 Rev 4542
1
/*
1
/*
2
 * Copyright (c) 2006 Josef Cejka
2
 * Copyright (c) 2006 Josef Cejka
3
 * All rights reserved.
3
 * All rights reserved.
4
 *
4
 *
5
 * Redistribution and use in source and binary forms, with or without
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
6
 * modification, are permitted provided that the following conditions
7
 * are met:
7
 * are met:
8
 *
8
 *
9
 * - Redistributions of source code must retain the above copyright
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
13
 *   documentation and/or other materials provided with the distribution.
14
 * - The name of the author may not be used to endorse or promote products
14
 * - The name of the author may not be used to endorse or promote products
15
 *   derived from this software without specific prior written permission.
15
 *   derived from this software without specific prior written permission.
16
 *
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
27
 */
28
 
28
 
29
/** @addtogroup console
29
/** @addtogroup console
30
 * @{
30
 * @{
31
 */
31
 */
32
/** @file
32
/** @file
33
 */
33
 */
34
 
34
 
35
#include <libc.h>
35
#include <libc.h>
36
#include <fb.h>
36
#include <fb.h>
37
#include <ipc/ipc.h>
37
#include <ipc/ipc.h>
38
#include <kbd.h>
38
#include <kbd.h>
39
#include <io/keycode.h>
39
#include <io/keycode.h>
40
#include <ipc/fb.h>
40
#include <ipc/fb.h>
41
#include <ipc/services.h>
41
#include <ipc/services.h>
42
#include <errno.h>
42
#include <errno.h>
43
#include <keybuffer.h>
43
#include <keybuffer.h>
44
#include <ipc/console.h>
44
#include <ipc/console.h>
45
#include <unistd.h>
45
#include <unistd.h>
46
#include <async.h>
46
#include <async.h>
47
#include <adt/fifo.h>
47
#include <adt/fifo.h>
48
#include <sys/mman.h>
48
#include <sys/mman.h>
49
#include <stdio.h>
49
#include <stdio.h>
50
#include <string.h>
50
#include <string.h>
51
#include <sysinfo.h>
51
#include <sysinfo.h>
52
#include <event.h>
52
#include <event.h>
53
#include <devmap.h>
53
#include <devmap.h>
-
 
54
#include <assert.h>
-
 
55
#include <fibril_sync.h>
54
 
56
 
55
#include "console.h"
57
#include "console.h"
56
#include "gcons.h"
58
#include "gcons.h"
57
#include "screenbuffer.h"
59
#include "screenbuffer.h"
58
 
60
 
59
#define NAME  "console"
61
#define NAME  "console"
60
 
62
 
61
#define MAX_DEVICE_NAME  32
63
#define MAX_DEVICE_NAME  32
62
 
64
 
63
/** Phone to the keyboard driver. */
65
/** Phone to the keyboard driver. */
64
static int kbd_phone;
66
static int kbd_phone;
65
 
67
 
66
/** Information about framebuffer */
68
/** Information about framebuffer */
67
struct {
69
struct {
68
    int phone;      /**< Framebuffer phone */
70
    int phone;      /**< Framebuffer phone */
69
    ipcarg_t cols;  /**< Framebuffer columns */
71
    ipcarg_t cols;  /**< Framebuffer columns */
70
    ipcarg_t rows;  /**< Framebuffer rows */
72
    ipcarg_t rows;  /**< Framebuffer rows */
71
} fb_info;
73
} fb_info;
72
 
74
 
73
typedef struct {
75
typedef struct {
74
    size_t index;             /**< Console index */
76
    size_t index;             /**< Console index */
75
    size_t refcount;          /**< Connection reference count */
77
    size_t refcount;          /**< Connection reference count */
76
    dev_handle_t dev_handle;  /**< Device handle */
78
    dev_handle_t dev_handle;  /**< Device handle */
77
    keybuffer_t keybuffer;    /**< Buffer for incoming keys. */
79
    keybuffer_t keybuffer;    /**< Buffer for incoming keys. */
78
    screenbuffer_t scr;       /**< Screenbuffer for saving screen
80
    screenbuffer_t scr;       /**< Screenbuffer for saving screen
79
                                   contents and related settings. */
81
                                   contents and related settings. */
80
} console_t;
82
} console_t;
81
 
83
 
82
/** Array of data for virtual consoles */
84
/** Array of data for virtual consoles */
83
static console_t consoles[CONSOLE_COUNT];
85
static console_t consoles[CONSOLE_COUNT];
84
 
86
 
85
static console_t *active_console = &consoles[0];
87
static console_t *active_console = &consoles[0];
86
static console_t *prev_console = &consoles[0];
88
static console_t *prev_console = &consoles[0];
87
static console_t *kernel_console = &consoles[KERNEL_CONSOLE];
89
static console_t *kernel_console = &consoles[KERNEL_CONSOLE];
88
 
90
 
89
/** Pointer to memory shared with framebufer used for
91
/** Pointer to memory shared with framebufer used for
90
    faster virtual console switching */
92
    faster virtual console switching */
91
static keyfield_t *interbuffer = NULL;
93
static keyfield_t *interbuffer = NULL;
92
 
94
 
93
/** Information on row-span yet unsent to FB driver. */
95
/** Information on row-span yet unsent to FB driver. */
94
struct {
96
struct {
95
    size_t col;  /**< Leftmost column of the span. */
97
    size_t col;  /**< Leftmost column of the span. */
96
    size_t row;  /**< Row where the span lies. */
98
    size_t row;  /**< Row where the span lies. */
97
    size_t cnt;  /**< Width of the span. */
99
    size_t cnt;  /**< Width of the span. */
98
} fb_pending;
100
} fb_pending;
99
 
101
 
100
/** Pending input structure. */
102
/** Pending input structure. */
101
typedef struct {
103
typedef struct {
102
    link_t link;
104
    link_t link;
103
    console_t *cons;      /**< Console waiting for input */
105
    console_t *cons;      /**< Console waiting for input */
104
    ipc_callid_t rid;     /**< Call ID waiting for input */
106
    ipc_callid_t rid;     /**< Call ID waiting for input */
105
    ipc_callid_t callid;  /**< Call ID waiting for IPC_DATA_READ */
107
    ipc_callid_t callid;  /**< Call ID waiting for IPC_DATA_READ */
106
   
108
   
107
    size_t pos;           /**< Position of the last stored data */
109
    size_t pos;           /**< Position of the last stored data */
108
    size_t size;          /**< Size of ther buffer */
110
    size_t size;          /**< Size of ther buffer */
109
    char *data;           /**< Already stored data */
111
    char *data;           /**< Already stored data */
110
} pending_input_t;
112
} pending_input_t;
111
 
113
 
112
LIST_INITIALIZE(pending_input);
114
LIST_INITIALIZE(pending_input);
113
 
115
 
-
 
116
static FIBRIL_MUTEX_INITIALIZE(input_mutex);
-
 
117
static FIBRIL_CONDVAR_INITIALIZE(input_cv);
-
 
118
static input_flag = false;
-
 
119
 
114
/** Process pending input requests */
120
/** Process pending input requests */
115
static void process_pending_input(void)
121
static void process_pending_input(void)
116
{
122
{
117
    async_serialize_start();
-
 
118
   
-
 
119
    link_t *cur;
123
    link_t *cur;
120
   
124
   
121
loop:
125
loop:
-
 
126
    fibril_mutex_lock(&input_mutex);
-
 
127
    while (!input_flag)
-
 
128
        fibril_condvar_wait(&input_cv, &input_mutex);
-
 
129
rescan:
122
    for (cur = pending_input.next; cur != &pending_input; cur = cur->next) {
130
    for (cur = pending_input.next; cur != &pending_input; cur = cur->next) {
123
        pending_input_t *pr = list_get_instance(cur, pending_input_t, link);
131
        pending_input_t *pr = list_get_instance(cur, pending_input_t, link);
124
       
132
       
125
        console_event_t ev;
133
        console_event_t ev;
126
        if (keybuffer_pop(&pr->cons->keybuffer, &ev)) {
134
        if (keybuffer_pop(&pr->cons->keybuffer, &ev)) {
127
           
135
           
128
            if (pr->data != NULL) {
136
            if (pr->data != NULL) {
129
                if (ev.type == KEY_PRESS) {
137
                if (ev.type == KEY_PRESS) {
130
                    pr->data[pr->pos] = ev.c;
138
                    pr->data[pr->pos] = ev.c;
131
                    pr->pos++;
139
                    pr->pos++;
132
                }
140
                }
133
            } else {
141
            } else {
134
                ipc_answer_4(pr->rid, EOK, ev.type, ev.key, ev.mods, ev.c);
142
                ipc_answer_4(pr->rid, EOK, ev.type, ev.key, ev.mods, ev.c);
135
               
-
 
136
                list_remove(cur);
143
                list_remove(cur);
137
                free(pr);
144
                free(pr);
138
               
-
 
139
                goto loop;
145
                goto rescan;
140
            }
146
            }
141
        }
147
        }
142
       
148
       
143
        if ((pr->data != NULL) && (pr->pos == pr->size)) {
149
        if ((pr->data != NULL) && (pr->pos == pr->size)) {
144
            (void) ipc_data_read_finalize(pr->callid, pr->data, pr->size);
150
            (void) ipc_data_read_finalize(pr->callid, pr->data, pr->size);
145
            ipc_answer_1(pr->rid, EOK, pr->size);
151
            ipc_answer_1(pr->rid, EOK, pr->size);
146
           
152
 
147
            free(pr->data);
153
            free(pr->data);
148
            list_remove(cur);
154
            list_remove(cur);
149
            free(pr);
155
            free(pr);
150
           
-
 
151
            goto loop;
156
            goto rescan;
152
        }
157
        }
153
    }
158
    }
154
   
159
    input_flag = false;
155
    async_serialize_end();
160
    fibril_mutex_unlock(&input_mutex);
-
 
161
    goto loop;
156
}
162
}
157
 
163
 
158
static void curs_visibility(bool visible)
164
static void curs_visibility(bool visible)
159
{
165
{
160
    async_msg_1(fb_info.phone, FB_CURSOR_VISIBILITY, visible);
166
    async_msg_1(fb_info.phone, FB_CURSOR_VISIBILITY, visible);
161
}
167
}
162
 
168
 
163
static void curs_hide_sync(void)
169
static void curs_hide_sync(void)
164
{
170
{
165
    ipc_call_sync_1_0(fb_info.phone, FB_CURSOR_VISIBILITY, false);
171
    ipc_call_sync_1_0(fb_info.phone, FB_CURSOR_VISIBILITY, false);
166
}
172
}
167
 
173
 
168
static void curs_goto(size_t x, size_t y)
174
static void curs_goto(size_t x, size_t y)
169
{
175
{
170
    async_msg_2(fb_info.phone, FB_CURSOR_GOTO, x, y);
176
    async_msg_2(fb_info.phone, FB_CURSOR_GOTO, x, y);
171
}
177
}
172
 
178
 
173
static void screen_clear(void)
179
static void screen_clear(void)
174
{
180
{
175
    async_msg_0(fb_info.phone, FB_CLEAR);
181
    async_msg_0(fb_info.phone, FB_CLEAR);
176
}
182
}
177
 
183
 
178
static void screen_yield(void)
184
static void screen_yield(void)
179
{
185
{
180
    ipc_call_sync_0_0(fb_info.phone, FB_SCREEN_YIELD);
186
    ipc_call_sync_0_0(fb_info.phone, FB_SCREEN_YIELD);
181
}
187
}
182
 
188
 
183
static void screen_reclaim(void)
189
static void screen_reclaim(void)
184
{
190
{
185
    ipc_call_sync_0_0(fb_info.phone, FB_SCREEN_RECLAIM);
191
    ipc_call_sync_0_0(fb_info.phone, FB_SCREEN_RECLAIM);
186
}
192
}
187
 
193
 
188
static void kbd_yield(void)
194
static void kbd_yield(void)
189
{
195
{
190
    ipc_call_sync_0_0(kbd_phone, KBD_YIELD);
196
    ipc_call_sync_0_0(kbd_phone, KBD_YIELD);
191
}
197
}
192
 
198
 
193
static void kbd_reclaim(void)
199
static void kbd_reclaim(void)
194
{
200
{
195
    ipc_call_sync_0_0(kbd_phone, KBD_RECLAIM);
201
    ipc_call_sync_0_0(kbd_phone, KBD_RECLAIM);
196
}
202
}
197
 
203
 
198
static void set_style(int style)
204
static void set_style(int style)
199
{
205
{
200
    async_msg_1(fb_info.phone, FB_SET_STYLE, style);
206
    async_msg_1(fb_info.phone, FB_SET_STYLE, style);
201
}
207
}
202
 
208
 
203
static void set_color(int fgcolor, int bgcolor, int flags)
209
static void set_color(int fgcolor, int bgcolor, int flags)
204
{
210
{
205
    async_msg_3(fb_info.phone, FB_SET_COLOR, fgcolor, bgcolor, flags);
211
    async_msg_3(fb_info.phone, FB_SET_COLOR, fgcolor, bgcolor, flags);
206
}
212
}
207
 
213
 
208
static void set_rgb_color(int fgcolor, int bgcolor)
214
static void set_rgb_color(int fgcolor, int bgcolor)
209
{
215
{
210
    async_msg_2(fb_info.phone, FB_SET_RGB_COLOR, fgcolor, bgcolor);
216
    async_msg_2(fb_info.phone, FB_SET_RGB_COLOR, fgcolor, bgcolor);
211
}
217
}
212
 
218
 
213
static void set_attrs(attrs_t *attrs)
219
static void set_attrs(attrs_t *attrs)
214
{
220
{
215
    switch (attrs->t) {
221
    switch (attrs->t) {
216
    case at_style:
222
    case at_style:
217
        set_style(attrs->a.s.style);
223
        set_style(attrs->a.s.style);
218
        break;
224
        break;
219
    case at_idx:
225
    case at_idx:
220
        set_color(attrs->a.i.fg_color, attrs->a.i.bg_color,
226
        set_color(attrs->a.i.fg_color, attrs->a.i.bg_color,
221
            attrs->a.i.flags);
227
            attrs->a.i.flags);
222
        break;
228
        break;
223
    case at_rgb:
229
    case at_rgb:
224
        set_rgb_color(attrs->a.r.fg_color, attrs->a.r.bg_color);
230
        set_rgb_color(attrs->a.r.fg_color, attrs->a.r.bg_color);
225
        break;
231
        break;
226
    }
232
    }
227
}
233
}
228
 
234
 
229
/** Send an area of screenbuffer to the FB driver. */
235
/** Send an area of screenbuffer to the FB driver. */
230
static void fb_update_area(console_t *cons, ipcarg_t x0, ipcarg_t y0, ipcarg_t width, ipcarg_t height)
236
static void fb_update_area(console_t *cons, ipcarg_t x0, ipcarg_t y0, ipcarg_t width, ipcarg_t height)
231
{
237
{
232
    if (interbuffer) {
238
    if (interbuffer) {
233
        ipcarg_t x;
239
        ipcarg_t x;
234
        ipcarg_t y;
240
        ipcarg_t y;
235
       
241
       
236
        for (y = 0; y < height; y++) {
242
        for (y = 0; y < height; y++) {
237
            for (x = 0; x < width; x++) {
243
            for (x = 0; x < width; x++) {
238
                interbuffer[y * width + x] =
244
                interbuffer[y * width + x] =
239
                    *get_field_at(&cons->scr, x0 + x, y0 + y);
245
                    *get_field_at(&cons->scr, x0 + x, y0 + y);
240
            }
246
            }
241
        }
247
        }
242
       
248
       
243
        async_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA,
249
        async_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA,
244
            x0, y0, width, height);
250
            x0, y0, width, height);
245
    }
251
    }
246
}
252
}
247
 
253
 
248
/** Flush pending cells to FB. */
254
/** Flush pending cells to FB. */
249
static void fb_pending_flush(void)
255
static void fb_pending_flush(void)
250
{
256
{
251
    if (fb_pending.cnt > 0) {
257
    if (fb_pending.cnt > 0) {
252
        fb_update_area(active_console, fb_pending.col,
258
        fb_update_area(active_console, fb_pending.col,
253
            fb_pending.row, fb_pending.cnt, 1);
259
            fb_pending.row, fb_pending.cnt, 1);
254
        fb_pending.cnt = 0;
260
        fb_pending.cnt = 0;
255
    }
261
    }
256
}
262
}
257
 
263
 
258
/** Mark a character cell as changed.
264
/** Mark a character cell as changed.
259
 *
265
 *
260
 * This adds the cell to the pending rowspan if possible. Otherwise
266
 * This adds the cell to the pending rowspan if possible. Otherwise
261
 * the old span is flushed first.
267
 * the old span is flushed first.
262
 *
268
 *
263
 */
269
 */
264
static void cell_mark_changed(size_t col, size_t row)
270
static void cell_mark_changed(size_t col, size_t row)
265
{
271
{
266
    if (fb_pending.cnt != 0) {
272
    if (fb_pending.cnt != 0) {
267
        if ((col != fb_pending.col + fb_pending.cnt)
273
        if ((col != fb_pending.col + fb_pending.cnt)
268
            || (row != fb_pending.row)) {
274
            || (row != fb_pending.row)) {
269
            fb_pending_flush();
275
            fb_pending_flush();
270
        }
276
        }
271
    }
277
    }
272
   
278
   
273
    if (fb_pending.cnt == 0) {
279
    if (fb_pending.cnt == 0) {
274
        fb_pending.col = col;
280
        fb_pending.col = col;
275
        fb_pending.row = row;
281
        fb_pending.row = row;
276
    }
282
    }
277
   
283
   
278
    fb_pending.cnt++;
284
    fb_pending.cnt++;
279
}
285
}
280
 
286
 
281
/** Print a character to the active VC with buffering. */
287
/** Print a character to the active VC with buffering. */
282
static void fb_putchar(wchar_t c, ipcarg_t col, ipcarg_t row)
288
static void fb_putchar(wchar_t c, ipcarg_t col, ipcarg_t row)
283
{
289
{
284
    async_msg_3(fb_info.phone, FB_PUTCHAR, c, col, row);
290
    async_msg_3(fb_info.phone, FB_PUTCHAR, c, col, row);
285
}
291
}
286
 
292
 
287
/** Process a character from the client (TTY emulation). */
293
/** Process a character from the client (TTY emulation). */
288
static void write_char(console_t *cons, wchar_t ch)
294
static void write_char(console_t *cons, wchar_t ch)
289
{
295
{
290
    bool flush_cursor = false;
296
    bool flush_cursor = false;
291
 
297
 
292
    switch (ch) {
298
    switch (ch) {
293
    case '\n':
299
    case '\n':
294
        fb_pending_flush();
300
        fb_pending_flush();
295
        flush_cursor = true;
301
        flush_cursor = true;
296
        cons->scr.position_y++;
302
        cons->scr.position_y++;
297
        cons->scr.position_x = 0;
303
        cons->scr.position_x = 0;
298
        break;
304
        break;
299
    case '\r':
305
    case '\r':
300
        break;
306
        break;
301
    case '\t':
307
    case '\t':
302
        cons->scr.position_x += 8;
308
        cons->scr.position_x += 8;
303
        cons->scr.position_x -= cons->scr.position_x % 8;
309
        cons->scr.position_x -= cons->scr.position_x % 8;
304
        break;
310
        break;
305
    case '\b':
311
    case '\b':
306
        if (cons->scr.position_x == 0)
312
        if (cons->scr.position_x == 0)
307
            break;
313
            break;
308
        cons->scr.position_x--;
314
        cons->scr.position_x--;
309
        if (cons == active_console)
315
        if (cons == active_console)
310
            cell_mark_changed(cons->scr.position_x, cons->scr.position_y);
316
            cell_mark_changed(cons->scr.position_x, cons->scr.position_y);
311
        screenbuffer_putchar(&cons->scr, ' ');
317
        screenbuffer_putchar(&cons->scr, ' ');
312
        break;
318
        break;
313
    default:
319
    default:
314
        if (cons == active_console)
320
        if (cons == active_console)
315
            cell_mark_changed(cons->scr.position_x, cons->scr.position_y);
321
            cell_mark_changed(cons->scr.position_x, cons->scr.position_y);
316
       
322
       
317
        screenbuffer_putchar(&cons->scr, ch);
323
        screenbuffer_putchar(&cons->scr, ch);
318
        cons->scr.position_x++;
324
        cons->scr.position_x++;
319
    }
325
    }
320
   
326
   
321
    if (cons->scr.position_x >= cons->scr.size_x) {
327
    if (cons->scr.position_x >= cons->scr.size_x) {
322
        flush_cursor = true;
328
        flush_cursor = true;
323
        cons->scr.position_y++;
329
        cons->scr.position_y++;
324
    }
330
    }
325
   
331
   
326
    if (cons->scr.position_y >= cons->scr.size_y) {
332
    if (cons->scr.position_y >= cons->scr.size_y) {
327
        fb_pending_flush();
333
        fb_pending_flush();
328
        cons->scr.position_y = cons->scr.size_y - 1;
334
        cons->scr.position_y = cons->scr.size_y - 1;
329
        screenbuffer_clear_line(&cons->scr, cons->scr.top_line);
335
        screenbuffer_clear_line(&cons->scr, cons->scr.top_line);
330
        cons->scr.top_line = (cons->scr.top_line + 1) % cons->scr.size_y;
336
        cons->scr.top_line = (cons->scr.top_line + 1) % cons->scr.size_y;
331
       
337
       
332
        if (cons == active_console)
338
        if (cons == active_console)
333
            async_msg_1(fb_info.phone, FB_SCROLL, 1);
339
            async_msg_1(fb_info.phone, FB_SCROLL, 1);
334
    }
340
    }
335
 
341
 
336
    if (cons == active_console && flush_cursor)
342
    if (cons == active_console && flush_cursor)
337
        curs_goto(cons->scr.position_x, cons->scr.position_y);
343
        curs_goto(cons->scr.position_x, cons->scr.position_y);
338
    cons->scr.position_x = cons->scr.position_x % cons->scr.size_x;
344
    cons->scr.position_x = cons->scr.position_x % cons->scr.size_x;
339
}
345
}
340
 
346
 
341
/** Switch to new console */
347
/** Switch to new console */
342
static void change_console(console_t *cons)
348
static void change_console(console_t *cons)
343
{
349
{
344
    if (cons == active_console)
350
    if (cons == active_console)
345
        return;
351
        return;
346
   
352
   
347
    fb_pending_flush();
353
    fb_pending_flush();
348
   
354
   
349
    if (cons == kernel_console) {
355
    if (cons == kernel_console) {
350
        async_serialize_start();
356
        async_serialize_start();
351
        curs_hide_sync();
357
        curs_hide_sync();
352
        gcons_in_kernel();
358
        gcons_in_kernel();
353
        screen_yield();
359
        screen_yield();
354
        kbd_yield();
360
        kbd_yield();
355
        async_serialize_end();
361
        async_serialize_end();
356
       
362
       
357
        if (__SYSCALL0(SYS_DEBUG_ENABLE_CONSOLE)) {
363
        if (__SYSCALL0(SYS_DEBUG_ENABLE_CONSOLE)) {
358
            prev_console = active_console;
364
            prev_console = active_console;
359
            active_console = kernel_console;
365
            active_console = kernel_console;
360
        } else
366
        } else
361
            cons = active_console;
367
            cons = active_console;
362
    }
368
    }
363
   
369
   
364
    if (cons != kernel_console) {
370
    if (cons != kernel_console) {
365
        size_t x;
371
        size_t x;
366
        size_t y;
372
        size_t y;
367
        int rc = 0;
373
        int rc = 0;
368
       
374
       
369
        async_serialize_start();
375
        async_serialize_start();
370
       
376
       
371
        if (active_console == kernel_console) {
377
        if (active_console == kernel_console) {
372
            screen_reclaim();
378
            screen_reclaim();
373
            kbd_reclaim();
379
            kbd_reclaim();
374
            gcons_redraw_console();
380
            gcons_redraw_console();
375
        }
381
        }
376
       
382
       
377
        active_console = cons;
383
        active_console = cons;
378
        gcons_change_console(cons->index);
384
        gcons_change_console(cons->index);
379
       
385
       
380
        set_attrs(&cons->scr.attrs);
386
        set_attrs(&cons->scr.attrs);
381
        curs_visibility(false);
387
        curs_visibility(false);
382
        if (interbuffer) {
388
        if (interbuffer) {
383
            for (y = 0; y < cons->scr.size_y; y++) {
389
            for (y = 0; y < cons->scr.size_y; y++) {
384
                for (x = 0; x < cons->scr.size_x; x++) {
390
                for (x = 0; x < cons->scr.size_x; x++) {
385
                    interbuffer[y * cons->scr.size_x + x] =
391
                    interbuffer[y * cons->scr.size_x + x] =
386
                        *get_field_at(&cons->scr, x, y);
392
                        *get_field_at(&cons->scr, x, y);
387
                }
393
                }
388
            }
394
            }
389
           
395
           
390
            /* This call can preempt, but we are already at the end */
396
            /* This call can preempt, but we are already at the end */
391
            rc = async_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA,
397
            rc = async_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA,
392
                0, 0, cons->scr.size_x,
398
                0, 0, cons->scr.size_x,
393
                cons->scr.size_y);
399
                cons->scr.size_y);
394
        }
400
        }
395
       
401
       
396
        if ((!interbuffer) || (rc != 0)) {
402
        if ((!interbuffer) || (rc != 0)) {
397
            set_attrs(&cons->scr.attrs);
403
            set_attrs(&cons->scr.attrs);
398
            screen_clear();
404
            screen_clear();
399
           
405
           
400
            for (y = 0; y < cons->scr.size_y; y++)
406
            for (y = 0; y < cons->scr.size_y; y++)
401
                for (x = 0; x < cons->scr.size_x; x++) {
407
                for (x = 0; x < cons->scr.size_x; x++) {
402
                    keyfield_t *field = get_field_at(&cons->scr, x, y);
408
                    keyfield_t *field = get_field_at(&cons->scr, x, y);
403
                   
409
                   
404
                    if (!attrs_same(cons->scr.attrs, field->attrs))
410
                    if (!attrs_same(cons->scr.attrs, field->attrs))
405
                        set_attrs(&field->attrs);
411
                        set_attrs(&field->attrs);
406
                   
412
                   
407
                    cons->scr.attrs = field->attrs;
413
                    cons->scr.attrs = field->attrs;
408
                    if ((field->character == ' ') &&
414
                    if ((field->character == ' ') &&
409
                        (attrs_same(field->attrs, cons->scr.attrs)))
415
                        (attrs_same(field->attrs, cons->scr.attrs)))
410
                        continue;
416
                        continue;
411
                   
417
                   
412
                    fb_putchar(field->character, x, y);
418
                    fb_putchar(field->character, x, y);
413
                }
419
                }
414
        }
420
        }
415
       
421
       
416
        curs_goto(cons->scr.position_x, cons->scr.position_y);
422
        curs_goto(cons->scr.position_x, cons->scr.position_y);
417
        curs_visibility(cons->scr.is_cursor_visible);
423
        curs_visibility(cons->scr.is_cursor_visible);
418
       
424
       
419
        async_serialize_end();
425
        async_serialize_end();
420
    }
426
    }
421
}
427
}
422
 
428
 
423
/** Handler for keyboard */
429
/** Handler for keyboard */
424
static void keyboard_events(ipc_callid_t iid, ipc_call_t *icall)
430
static void keyboard_events(ipc_callid_t iid, ipc_call_t *icall)
425
{
431
{
426
    /* Ignore parameters, the connection is already opened */
432
    /* Ignore parameters, the connection is already opened */
427
    while (true) {
433
    while (true) {
428
       
434
       
429
        ipc_call_t call;
435
        ipc_call_t call;
430
        ipc_callid_t callid = async_get_call(&call);
436
        ipc_callid_t callid = async_get_call(&call);
431
       
437
       
432
        int retval;
438
        int retval;
433
        console_event_t ev;
439
        console_event_t ev;
434
       
440
       
435
        switch (IPC_GET_METHOD(call)) {
441
        switch (IPC_GET_METHOD(call)) {
436
        case IPC_M_PHONE_HUNGUP:
442
        case IPC_M_PHONE_HUNGUP:
437
            /* TODO: Handle hangup */
443
            /* TODO: Handle hangup */
438
            return;
444
            return;
439
        case KBD_EVENT:
445
        case KBD_EVENT:
440
            /* Got event from keyboard driver. */
446
            /* Got event from keyboard driver. */
441
            retval = 0;
447
            retval = 0;
442
            ev.type = IPC_GET_ARG1(call);
448
            ev.type = IPC_GET_ARG1(call);
443
            ev.key = IPC_GET_ARG2(call);
449
            ev.key = IPC_GET_ARG2(call);
444
            ev.mods = IPC_GET_ARG3(call);
450
            ev.mods = IPC_GET_ARG3(call);
445
            ev.c = IPC_GET_ARG4(call);
451
            ev.c = IPC_GET_ARG4(call);
446
           
452
           
447
            if ((ev.key >= KC_F1) && (ev.key < KC_F1 +
453
            if ((ev.key >= KC_F1) && (ev.key < KC_F1 +
448
                CONSOLE_COUNT) && ((ev.mods & KM_CTRL) == 0)) {
454
                CONSOLE_COUNT) && ((ev.mods & KM_CTRL) == 0)) {
449
                if (ev.key == KC_F1 + KERNEL_CONSOLE)
455
                if (ev.key == KC_F1 + KERNEL_CONSOLE)
450
                    change_console(kernel_console);
456
                    change_console(kernel_console);
451
                else
457
                else
452
                    change_console(&consoles[ev.key - KC_F1]);
458
                    change_console(&consoles[ev.key - KC_F1]);
453
                break;
459
                break;
454
            }
460
            }
455
           
461
           
-
 
462
            fibril_mutex_lock(&input_mutex);
456
            keybuffer_push(&active_console->keybuffer, &ev);
463
            keybuffer_push(&active_console->keybuffer, &ev);
-
 
464
            input_flag = true;
-
 
465
            fibril_condvar_signal(&input_cv);
-
 
466
            fibril_mutex_unlock(&input_mutex);
457
            break;
467
            break;
458
        default:
468
        default:
459
            retval = ENOENT;
469
            retval = ENOENT;
460
        }
470
        }
461
        ipc_answer_0(callid, retval);
471
        ipc_answer_0(callid, retval);
462
    }
472
    }
463
}
473
}
464
 
474
 
465
static void cons_write(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
475
static void cons_write(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
466
{
476
{
467
    ipc_callid_t callid;
477
    ipc_callid_t callid;
468
    size_t size;
478
    size_t size;
469
    if (!ipc_data_write_receive(&callid, &size)) {
479
    if (!ipc_data_write_receive(&callid, &size)) {
470
        ipc_answer_0(callid, EINVAL);
480
        ipc_answer_0(callid, EINVAL);
471
        ipc_answer_0(rid, EINVAL);
481
        ipc_answer_0(rid, EINVAL);
472
        return;
482
        return;
473
    }
483
    }
474
   
484
   
475
    char *buf = (char *) malloc(size);
485
    char *buf = (char *) malloc(size);
476
    if (buf == NULL) {
486
    if (buf == NULL) {
477
        ipc_answer_0(callid, ENOMEM);
487
        ipc_answer_0(callid, ENOMEM);
478
        ipc_answer_0(rid, ENOMEM);
488
        ipc_answer_0(rid, ENOMEM);
479
        return;
489
        return;
480
    }
490
    }
481
   
491
   
482
    (void) ipc_data_write_finalize(callid, buf, size);
492
    (void) ipc_data_write_finalize(callid, buf, size);
483
   
493
   
484
    async_serialize_start();
494
    async_serialize_start();
485
   
495
   
486
    size_t off = 0;
496
    size_t off = 0;
487
    while (off < size) {
497
    while (off < size) {
488
        wchar_t ch = str_decode(buf, &off, size);
498
        wchar_t ch = str_decode(buf, &off, size);
489
        write_char(cons, ch);
499
        write_char(cons, ch);
490
    }
500
    }
491
   
501
   
492
    async_serialize_end();
502
    async_serialize_end();
493
   
503
   
494
    gcons_notify_char(cons->index);
504
    gcons_notify_char(cons->index);
495
    ipc_answer_1(rid, EOK, size);
505
    ipc_answer_1(rid, EOK, size);
496
   
506
   
497
    free(buf);
507
    free(buf);
498
}
508
}
499
 
509
 
500
static void cons_read(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
510
static void cons_read(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
501
{
511
{
502
    ipc_callid_t callid;
512
    ipc_callid_t callid;
503
    size_t size;
513
    size_t size;
504
    if (!ipc_data_read_receive(&callid, &size)) {
514
    if (!ipc_data_read_receive(&callid, &size)) {
505
        ipc_answer_0(callid, EINVAL);
515
        ipc_answer_0(callid, EINVAL);
506
        ipc_answer_0(rid, EINVAL);
516
        ipc_answer_0(rid, EINVAL);
507
        return;
517
        return;
508
    }
518
    }
509
   
519
   
510
    char *buf = (char *) malloc(size);
520
    char *buf = (char *) malloc(size);
511
    if (buf == NULL) {
521
    if (buf == NULL) {
512
        ipc_answer_0(callid, ENOMEM);
522
        ipc_answer_0(callid, ENOMEM);
513
        ipc_answer_0(rid, ENOMEM);
523
        ipc_answer_0(rid, ENOMEM);
514
        return;
524
        return;
515
    }
525
    }
516
   
526
   
517
    async_serialize_start();
-
 
518
   
-
 
519
    size_t pos = 0;
527
    size_t pos = 0;
520
    console_event_t ev;
528
    console_event_t ev;
-
 
529
    fibril_mutex_lock(&input_mutex);
521
    while ((keybuffer_pop(&cons->keybuffer, &ev)) && (pos < size)) {
530
    while ((keybuffer_pop(&cons->keybuffer, &ev)) && (pos < size)) {
522
        if (ev.type == KEY_PRESS) {
531
        if (ev.type == KEY_PRESS) {
523
            buf[pos] = ev.c;
532
            buf[pos] = ev.c;
524
            pos++;
533
            pos++;
525
        }
534
        }
526
    }
535
    }
527
   
536
   
528
    if (pos == size) {
537
    if (pos == size) {
529
        (void) ipc_data_read_finalize(callid, buf, size);
538
        (void) ipc_data_read_finalize(callid, buf, size);
530
        ipc_answer_1(rid, EOK, size);
539
        ipc_answer_1(rid, EOK, size);
531
        free(buf);
540
        free(buf);
532
    } else {
541
    } else {
533
        pending_input_t *pr = (pending_input_t *) malloc(sizeof(pending_input_t));
542
        pending_input_t *pr = (pending_input_t *) malloc(sizeof(pending_input_t));
534
        if (!pr) {
543
        if (!pr) {
-
 
544
            fibril_mutex_unlock(&input_mutex);
535
            ipc_answer_0(callid, ENOMEM);
545
            ipc_answer_0(callid, ENOMEM);
536
            ipc_answer_0(rid, ENOMEM);
546
            ipc_answer_0(rid, ENOMEM);
537
            free(buf);
547
            free(buf);
538
            async_serialize_end();
-
 
539
            return;
548
            return;
540
        }
549
        }
541
       
550
       
542
        pr->cons = cons;
551
        pr->cons = cons;
543
        pr->rid = rid;
552
        pr->rid = rid;
544
        pr->callid = callid;
553
        pr->callid = callid;
545
        pr->pos = pos;
554
        pr->pos = pos;
546
        pr->size = size;
555
        pr->size = size;
547
        pr->data = buf;
556
        pr->data = buf;
548
        list_append(&pr->link, &pending_input);
557
        list_append(&pr->link, &pending_input);
549
    }
558
    }
550
   
-
 
551
    async_serialize_end();
559
    fibril_mutex_unlock(&input_mutex);
552
}
560
}
553
 
561
 
554
static void cons_get_event(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
562
static void cons_get_event(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
555
{
563
{
556
    async_serialize_start();
-
 
557
   
-
 
558
    console_event_t ev;
564
    console_event_t ev;
-
 
565
 
-
 
566
    fibril_mutex_lock(&input_mutex);
559
    if (keybuffer_pop(&cons->keybuffer, &ev)) {
567
    if (keybuffer_pop(&cons->keybuffer, &ev)) {
560
        ipc_answer_4(rid, EOK, ev.type, ev.key, ev.mods, ev.c);
568
        ipc_answer_4(rid, EOK, ev.type, ev.key, ev.mods, ev.c);
561
    } else {
569
    } else {
562
        pending_input_t *pr = (pending_input_t *) malloc(sizeof(pending_input_t));
570
        pending_input_t *pr = (pending_input_t *) malloc(sizeof(pending_input_t));
563
        if (!pr) {
571
        if (!pr) {
-
 
572
            fibril_mutex_unlock(&input_mutex);
564
            ipc_answer_0(rid, ENOMEM);
573
            ipc_answer_0(rid, ENOMEM);
565
            async_serialize_end();
-
 
566
            return;
574
            return;
567
        }
575
        }
568
       
576
       
569
        pr->cons = cons;
577
        pr->cons = cons;
570
        pr->rid = rid;
578
        pr->rid = rid;
571
        pr->callid = 0;
579
        pr->callid = 0;
572
        pr->data = NULL;
580
        pr->data = NULL;
573
        list_append(&pr->link, &pending_input);
581
        list_append(&pr->link, &pending_input);
574
    }
582
    }
575
   
-
 
576
    async_serialize_end();
583
    fibril_mutex_unlock(&input_mutex);
577
}
584
}
578
 
585
 
579
/** Default thread for new connections */
586
/** Default thread for new connections */
580
static void client_connection(ipc_callid_t iid, ipc_call_t *icall)
587
static void client_connection(ipc_callid_t iid, ipc_call_t *icall)
581
{
588
{
582
    console_t *cons = NULL;
589
    console_t *cons = NULL;
583
   
590
   
584
    size_t i;
591
    size_t i;
585
    for (i = 0; i < CONSOLE_COUNT; i++) {
592
    for (i = 0; i < CONSOLE_COUNT; i++) {
586
        if (i == KERNEL_CONSOLE)
593
        if (i == KERNEL_CONSOLE)
587
            continue;
594
            continue;
588
       
595
       
589
        if (consoles[i].dev_handle == (dev_handle_t) IPC_GET_ARG1(*icall)) {
596
        if (consoles[i].dev_handle == (dev_handle_t) IPC_GET_ARG1(*icall)) {
590
            cons = &consoles[i];
597
            cons = &consoles[i];
591
            break;
598
            break;
592
        }
599
        }
593
    }
600
    }
594
   
601
   
595
    if (cons == NULL) {
602
    if (cons == NULL) {
596
        ipc_answer_0(iid, ENOENT);
603
        ipc_answer_0(iid, ENOENT);
597
        return;
604
        return;
598
    }
605
    }
599
   
606
   
600
    ipc_callid_t callid;
607
    ipc_callid_t callid;
601
    ipc_call_t call;
608
    ipc_call_t call;
602
    ipcarg_t arg1;
609
    ipcarg_t arg1;
603
    ipcarg_t arg2;
610
    ipcarg_t arg2;
604
    ipcarg_t arg3;
611
    ipcarg_t arg3;
605
   
612
   
606
    async_serialize_start();
613
    async_serialize_start();
607
    if (cons->refcount == 0)
614
    if (cons->refcount == 0)
608
        gcons_notify_connect(cons->index);
615
        gcons_notify_connect(cons->index);
609
   
616
   
610
    cons->refcount++;
617
    cons->refcount++;
611
   
618
   
612
    /* Accept the connection */
619
    /* Accept the connection */
613
    ipc_answer_0(iid, EOK);
620
    ipc_answer_0(iid, EOK);
614
   
621
   
615
    while (true) {
622
    while (true) {
616
        async_serialize_end();
623
        async_serialize_end();
617
        callid = async_get_call(&call);
624
        callid = async_get_call(&call);
618
        async_serialize_start();
625
        async_serialize_start();
619
       
626
       
620
        arg1 = 0;
627
        arg1 = 0;
621
        arg2 = 0;
628
        arg2 = 0;
622
        arg3 = 0;
629
        arg3 = 0;
623
       
630
       
624
        switch (IPC_GET_METHOD(call)) {
631
        switch (IPC_GET_METHOD(call)) {
625
        case IPC_M_PHONE_HUNGUP:
632
        case IPC_M_PHONE_HUNGUP:
626
            cons->refcount--;
633
            cons->refcount--;
627
            if (cons->refcount == 0)
634
            if (cons->refcount == 0)
628
                gcons_notify_disconnect(cons->index);
635
                gcons_notify_disconnect(cons->index);
629
            return;
636
            return;
630
        case VFS_READ:
637
        case VFS_READ:
631
            async_serialize_end();
638
            async_serialize_end();
632
            cons_read(cons, callid, &call);
639
            cons_read(cons, callid, &call);
633
            async_serialize_start();
640
            async_serialize_start();
634
            continue;
641
            continue;
635
        case VFS_WRITE:
642
        case VFS_WRITE:
636
            async_serialize_end();
643
            async_serialize_end();
637
            cons_write(cons, callid, &call);
644
            cons_write(cons, callid, &call);
638
            async_serialize_start();
645
            async_serialize_start();
639
            continue;
646
            continue;
640
        case VFS_SYNC:
647
        case VFS_SYNC:
641
            fb_pending_flush();
648
            fb_pending_flush();
642
            if (cons == active_console) {
649
            if (cons == active_console) {
643
                async_req_0_0(fb_info.phone, FB_FLUSH);
650
                async_req_0_0(fb_info.phone, FB_FLUSH);
644
               
651
               
645
                curs_goto(cons->scr.position_x, cons->scr.position_y);
652
                curs_goto(cons->scr.position_x, cons->scr.position_y);
646
            }
653
            }
647
            break;
654
            break;
648
        case CONSOLE_CLEAR:
655
        case CONSOLE_CLEAR:
649
            /* Send message to fb */
656
            /* Send message to fb */
650
            if (cons == active_console)
657
            if (cons == active_console)
651
                async_msg_0(fb_info.phone, FB_CLEAR);
658
                async_msg_0(fb_info.phone, FB_CLEAR);
652
           
659
           
653
            screenbuffer_clear(&cons->scr);
660
            screenbuffer_clear(&cons->scr);
654
           
661
           
655
            break;
662
            break;
656
        case CONSOLE_GOTO:
663
        case CONSOLE_GOTO:
657
            screenbuffer_goto(&cons->scr,
664
            screenbuffer_goto(&cons->scr,
658
                IPC_GET_ARG1(call), IPC_GET_ARG2(call));
665
                IPC_GET_ARG1(call), IPC_GET_ARG2(call));
659
            if (cons == active_console)
666
            if (cons == active_console)
660
                curs_goto(IPC_GET_ARG1(call),
667
                curs_goto(IPC_GET_ARG1(call),
661
                    IPC_GET_ARG2(call));
668
                    IPC_GET_ARG2(call));
662
            break;
669
            break;
663
        case CONSOLE_GET_SIZE:
670
        case CONSOLE_GET_SIZE:
664
            arg1 = fb_info.cols;
671
            arg1 = fb_info.cols;
665
            arg2 = fb_info.rows;
672
            arg2 = fb_info.rows;
666
            break;
673
            break;
667
        case CONSOLE_SET_STYLE:
674
        case CONSOLE_SET_STYLE:
668
            fb_pending_flush();
675
            fb_pending_flush();
669
            arg1 = IPC_GET_ARG1(call);
676
            arg1 = IPC_GET_ARG1(call);
670
            screenbuffer_set_style(&cons->scr, arg1);
677
            screenbuffer_set_style(&cons->scr, arg1);
671
            if (cons == active_console)
678
            if (cons == active_console)
672
                set_style(arg1);
679
                set_style(arg1);
673
            break;
680
            break;
674
        case CONSOLE_SET_COLOR:
681
        case CONSOLE_SET_COLOR:
675
            fb_pending_flush();
682
            fb_pending_flush();
676
            arg1 = IPC_GET_ARG1(call);
683
            arg1 = IPC_GET_ARG1(call);
677
            arg2 = IPC_GET_ARG2(call);
684
            arg2 = IPC_GET_ARG2(call);
678
            arg3 = IPC_GET_ARG3(call);
685
            arg3 = IPC_GET_ARG3(call);
679
            screenbuffer_set_color(&cons->scr, arg1, arg2, arg3);
686
            screenbuffer_set_color(&cons->scr, arg1, arg2, arg3);
680
            if (cons == active_console)
687
            if (cons == active_console)
681
                set_color(arg1, arg2, arg3);
688
                set_color(arg1, arg2, arg3);
682
            break;
689
            break;
683
        case CONSOLE_SET_RGB_COLOR:
690
        case CONSOLE_SET_RGB_COLOR:
684
            fb_pending_flush();
691
            fb_pending_flush();
685
            arg1 = IPC_GET_ARG1(call);
692
            arg1 = IPC_GET_ARG1(call);
686
            arg2 = IPC_GET_ARG2(call);
693
            arg2 = IPC_GET_ARG2(call);
687
            screenbuffer_set_rgb_color(&cons->scr, arg1, arg2);
694
            screenbuffer_set_rgb_color(&cons->scr, arg1, arg2);
688
            if (cons == active_console)
695
            if (cons == active_console)
689
                set_rgb_color(arg1, arg2);
696
                set_rgb_color(arg1, arg2);
690
            break;
697
            break;
691
        case CONSOLE_CURSOR_VISIBILITY:
698
        case CONSOLE_CURSOR_VISIBILITY:
692
            fb_pending_flush();
699
            fb_pending_flush();
693
            arg1 = IPC_GET_ARG1(call);
700
            arg1 = IPC_GET_ARG1(call);
694
            cons->scr.is_cursor_visible = arg1;
701
            cons->scr.is_cursor_visible = arg1;
695
            if (cons == active_console)
702
            if (cons == active_console)
696
                curs_visibility(arg1);
703
                curs_visibility(arg1);
697
            break;
704
            break;
698
        case CONSOLE_GET_EVENT:
705
        case CONSOLE_GET_EVENT:
699
            async_serialize_end();
706
            async_serialize_end();
700
            cons_get_event(cons, callid, &call);
707
            cons_get_event(cons, callid, &call);
701
            async_serialize_start();
708
            async_serialize_start();
702
            continue;
709
            continue;
703
        case CONSOLE_KCON_ENABLE:
710
        case CONSOLE_KCON_ENABLE:
704
            change_console(kernel_console);
711
            change_console(kernel_console);
705
            break;
712
            break;
706
        }
713
        }
707
        ipc_answer_3(callid, EOK, arg1, arg2, arg3);
714
        ipc_answer_3(callid, EOK, arg1, arg2, arg3);
708
    }
715
    }
709
}
716
}
710
 
717
 
711
static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
718
static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
712
{
719
{
713
    change_console(prev_console);
720
    change_console(prev_console);
714
}
721
}
715
 
722
 
716
static bool console_init(void)
723
static bool console_init(void)
717
{
724
{
718
    async_serialize_start();
-
 
719
   
-
 
720
    /* Connect to keyboard driver */
725
    /* Connect to keyboard driver */
721
    kbd_phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_KEYBOARD, 0, 0);
726
    kbd_phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_KEYBOARD, 0, 0);
722
    if (kbd_phone < 0) {
727
    if (kbd_phone < 0) {
723
        printf(NAME ": Failed to connect to keyboard service\n");
728
        printf(NAME ": Failed to connect to keyboard service\n");
724
        async_serialize_end();
-
 
725
        return false;
729
        return false;
726
    }
730
    }
727
   
731
   
728
    ipcarg_t phonehash;
732
    ipcarg_t phonehash;
729
    if (ipc_connect_to_me(kbd_phone, SERVICE_CONSOLE, 0, 0, &phonehash) != 0) {
733
    if (ipc_connect_to_me(kbd_phone, SERVICE_CONSOLE, 0, 0, &phonehash) != 0) {
730
        printf(NAME ": Failed to create callback from keyboard service\n");
734
        printf(NAME ": Failed to create callback from keyboard service\n");
731
        async_serialize_end();
-
 
732
        return false;
735
        return false;
733
    }
736
    }
734
   
737
   
735
    async_set_pending(process_pending_input);
-
 
736
    async_new_connection(phonehash, 0, NULL, keyboard_events);
738
    async_new_connection(phonehash, 0, NULL, keyboard_events);
-
 
739
 
-
 
740
    fid_t fid = fibril_create(process_pending_input, NULL);
-
 
741
    if (!fid) {
-
 
742
        printf(NAME ": Failed to create fibril for handling pending "
-
 
743
            "input\n");
-
 
744
        return -1;
-
 
745
    }
-
 
746
    fibril_add_ready(fid);
737
   
747
   
738
    /* Connect to framebuffer driver */
748
    /* Connect to framebuffer driver */
739
    fb_info.phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_VIDEO, 0, 0);
749
    fb_info.phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_VIDEO, 0, 0);
740
    if (fb_info.phone < 0) {
750
    if (fb_info.phone < 0) {
741
        printf(NAME ": Failed to connect to video service\n");
751
        printf(NAME ": Failed to connect to video service\n");
742
        async_serialize_end();
-
 
743
        return -1;
752
        return -1;
744
    }
753
    }
745
   
754
   
746
    /* Register driver */
755
    /* Register driver */
747
    int rc = devmap_driver_register(NAME, client_connection);
756
    int rc = devmap_driver_register(NAME, client_connection);
748
    if (rc < 0) {
757
    if (rc < 0) {
749
        printf(NAME ": Unable to register driver (%d)\n", rc);
758
        printf(NAME ": Unable to register driver (%d)\n", rc);
750
        async_serialize_end();
-
 
751
        return false;
759
        return false;
752
    }
760
    }
753
   
761
   
754
    /* Initialize gcons */
762
    /* Initialize gcons */
755
    gcons_init(fb_info.phone);
763
    gcons_init(fb_info.phone);
756
   
764
   
757
    /* Synchronize, the gcons could put something in queue */
765
    /* Synchronize, the gcons could put something in queue */
758
    async_req_0_0(fb_info.phone, FB_FLUSH);
766
    async_req_0_0(fb_info.phone, FB_FLUSH);
759
    async_req_0_2(fb_info.phone, FB_GET_CSIZE, &fb_info.cols, &fb_info.rows);
767
    async_req_0_2(fb_info.phone, FB_GET_CSIZE, &fb_info.cols, &fb_info.rows);
760
   
768
   
761
    /* Set up shared memory buffer. */
769
    /* Set up shared memory buffer. */
762
    size_t ib_size = sizeof(keyfield_t) * fb_info.cols * fb_info.rows;
770
    size_t ib_size = sizeof(keyfield_t) * fb_info.cols * fb_info.rows;
763
    interbuffer = as_get_mappable_page(ib_size);
771
    interbuffer = as_get_mappable_page(ib_size);
764
   
772
   
765
    if (as_area_create(interbuffer, ib_size, AS_AREA_READ |
773
    if (as_area_create(interbuffer, ib_size, AS_AREA_READ |
766
        AS_AREA_WRITE | AS_AREA_CACHEABLE) != interbuffer)
774
        AS_AREA_WRITE | AS_AREA_CACHEABLE) != interbuffer)
767
        interbuffer = NULL;
775
        interbuffer = NULL;
768
   
776
   
769
    if (interbuffer) {
777
    if (interbuffer) {
770
        if (ipc_share_out_start(fb_info.phone, interbuffer,
778
        if (ipc_share_out_start(fb_info.phone, interbuffer,
771
            AS_AREA_READ) != EOK) {
779
            AS_AREA_READ) != EOK) {
772
            as_area_destroy(interbuffer);
780
            as_area_destroy(interbuffer);
773
            interbuffer = NULL;
781
            interbuffer = NULL;
774
        }
782
        }
775
    }
783
    }
776
   
784
   
777
    fb_pending.cnt = 0;
785
    fb_pending.cnt = 0;
778
   
786
   
779
    /* Inititalize consoles */
787
    /* Inititalize consoles */
780
    size_t i;
788
    size_t i;
781
    for (i = 0; i < CONSOLE_COUNT; i++) {
789
    for (i = 0; i < CONSOLE_COUNT; i++) {
782
        if (i != KERNEL_CONSOLE) {
790
        if (i != KERNEL_CONSOLE) {
783
            if (screenbuffer_init(&consoles[i].scr,
791
            if (screenbuffer_init(&consoles[i].scr,
784
                fb_info.cols, fb_info.rows) == NULL) {
792
                fb_info.cols, fb_info.rows) == NULL) {
785
                printf(NAME ": Unable to allocate screen buffer %u\n", i);
793
                printf(NAME ": Unable to allocate screen buffer %u\n", i);
786
                async_serialize_end();
-
 
787
                return false;
794
                return false;
788
            }
795
            }
789
            screenbuffer_clear(&consoles[i].scr);
796
            screenbuffer_clear(&consoles[i].scr);
790
            keybuffer_init(&consoles[i].keybuffer);
797
            keybuffer_init(&consoles[i].keybuffer);
791
            consoles[i].index = i;
798
            consoles[i].index = i;
792
            consoles[i].refcount = 0;
799
            consoles[i].refcount = 0;
793
           
800
           
794
            char vc[MAX_DEVICE_NAME];
801
            char vc[MAX_DEVICE_NAME];
795
            snprintf(vc, MAX_DEVICE_NAME, "vc%u", i);
802
            snprintf(vc, MAX_DEVICE_NAME, "vc%u", i);
796
           
803
           
797
            if (devmap_device_register(vc, &consoles[i].dev_handle) != EOK) {
804
            if (devmap_device_register(vc, &consoles[i].dev_handle) != EOK) {
798
                devmap_hangup_phone(DEVMAP_DRIVER);
805
                devmap_hangup_phone(DEVMAP_DRIVER);
799
                printf(NAME ": Unable to register device %s\n", vc);
806
                printf(NAME ": Unable to register device %s\n", vc);
800
                async_serialize_end();
-
 
801
                return false;
807
                return false;
802
            }
808
            }
803
        }
809
        }
804
    }
810
    }
805
   
811
   
806
    /* Disable kernel output to the console */
812
    /* Disable kernel output to the console */
807
    __SYSCALL0(SYS_DEBUG_DISABLE_CONSOLE);
813
    __SYSCALL0(SYS_DEBUG_DISABLE_CONSOLE);
808
   
814
   
809
    /* Initialize the screen */
815
    /* Initialize the screen */
-
 
816
    async_serialize_start();
810
    gcons_redraw_console();
817
    gcons_redraw_console();
811
    set_rgb_color(DEFAULT_FOREGROUND, DEFAULT_BACKGROUND);
818
    set_rgb_color(DEFAULT_FOREGROUND, DEFAULT_BACKGROUND);
812
    screen_clear();
819
    screen_clear();
813
    curs_goto(0, 0);
820
    curs_goto(0, 0);
814
    curs_visibility(active_console->scr.is_cursor_visible);
821
    curs_visibility(active_console->scr.is_cursor_visible);
-
 
822
    async_serialize_end();
815
   
823
   
816
    /* Receive kernel notifications */
824
    /* Receive kernel notifications */
817
    if (event_subscribe(EVENT_KCONSOLE, 0) != EOK)
825
    if (event_subscribe(EVENT_KCONSOLE, 0) != EOK)
818
        printf(NAME ": Error registering kconsole notifications\n");
826
        printf(NAME ": Error registering kconsole notifications\n");
819
   
827
   
820
    async_set_interrupt_received(interrupt_received);
828
    async_set_interrupt_received(interrupt_received);
821
   
829
   
822
    async_serialize_end();
-
 
823
    return true;
830
    return true;
824
}
831
}
825
 
832
 
826
int main(int argc, char *argv[])
833
int main(int argc, char *argv[])
827
{
834
{
828
    printf(NAME ": HelenOS Console service\n");
835
    printf(NAME ": HelenOS Console service\n");
829
   
836
   
830
    if (!console_init())
837
    if (!console_init())
831
        return -1;
838
        return -1;
832
   
839
   
833
    printf(NAME ": Accepting connections\n");
840
    printf(NAME ": Accepting connections\n");
834
    async_manager();
841
    async_manager();
835
   
842
   
836
    return 0;
843
    return 0;
837
}
844
}
838
 
845
 
839
/** @}
846
/** @}
840
 */
847
 */
841
 
848