Subversion Repositories HelenOS

Rev

Rev 4263 | Rev 4581 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1445 cejka 1
/*
2071 jermar 2
 * Copyright (c) 2006 Josef Cejka
1445 cejka 3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 *
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
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
15
 *   derived from this software without specific prior written permission.
16
 *
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
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
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
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
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
1649 cejka 28
 
1740 jermar 29
/** @addtogroup console
1649 cejka 30
 * @{
31
 */
32
/** @file
33
 */
34
 
2618 jermar 35
#include <libc.h>
1451 cejka 36
#include <fb.h>
1445 cejka 37
#include <ipc/ipc.h>
4153 mejdrech 38
#include <kbd.h>
39
#include <kbd/keycode.h>
1451 cejka 40
#include <ipc/fb.h>
1445 cejka 41
#include <ipc/services.h>
42
#include <errno.h>
1451 cejka 43
#include <key_buffer.h>
4153 mejdrech 44
#include <ipc/console.h>
1453 palkovsky 45
#include <unistd.h>
46
#include <async.h>
1481 cejka 47
#include <libadt/fifo.h>
1487 cejka 48
#include <screenbuffer.h>
1867 jermar 49
#include <sys/mman.h>
3084 decky 50
#include <stdio.h>
4263 mejdrech 51
#include <string.h>
4153 mejdrech 52
#include <sysinfo.h>
4263 mejdrech 53
#include <event.h>
1445 cejka 54
 
4153 mejdrech 55
#include "console.h"
1522 palkovsky 56
#include "gcons.h"
57
 
1481 cejka 58
#define MAX_KEYREQUESTS_BUFFERED 32
1451 cejka 59
 
3084 decky 60
#define NAME "console"
1445 cejka 61
 
1526 cejka 62
/** Index of currently used virtual console.
63
 */
1512 cejka 64
int active_console = 0;
4153 mejdrech 65
int prev_console = 0;
1453 palkovsky 66
 
4263 mejdrech 67
/** Information about framebuffer */
1487 cejka 68
struct {
69
    int phone;      /**< Framebuffer phone */
1506 cejka 70
    ipcarg_t rows;      /**< Framebuffer rows */
71
    ipcarg_t cols;      /**< Framebuffer columns */
1487 cejka 72
} fb_info;
73
 
1451 cejka 74
typedef struct {
1526 cejka 75
    keybuffer_t keybuffer;      /**< Buffer for incoming keys. */
2025 jermar 76
    /** Buffer for unsatisfied request for keys. */
77
    FIFO_CREATE_STATIC(keyrequests, ipc_callid_t,
78
        MAX_KEYREQUESTS_BUFFERED); 
1526 cejka 79
    int keyrequest_counter;     /**< Number of requests in buffer. */
80
    int client_phone;       /**< Phone to connected client. */
2025 jermar 81
    int used;           /**< 1 if this virtual console is
82
                     * connected to some client.*/
83
    screenbuffer_t screenbuffer;    /**< Screenbuffer for saving screen
84
                     * contents and related settings. */
1451 cejka 85
} connection_t;
86
 
2025 jermar 87
static connection_t connections[CONSOLE_COUNT]; /**< Array of data for virtual
88
                         * consoles */
89
static keyfield_t *interbuffer = NULL;      /**< Pointer to memory shared
90
                         * with framebufer used for
91
                         * faster virtual console
2069 jermar 92
                         * switching */
1506 cejka 93
 
4263 mejdrech 94
/** Information on row-span yet unsent to FB driver. */
95
struct {
96
    int row;        /**< Row where the span lies. */
97
    int col;        /**< Leftmost column of the span. */
98
    int n;          /**< Width of the span. */
99
} fb_pending;
1506 cejka 100
 
4263 mejdrech 101
/** Size of cwrite_buf. */
102
#define CWRITE_BUF_SIZE 256
103
 
104
/** Buffer for receiving data via the CONSOLE_WRITE call from the client. */
105
static char cwrite_buf[CWRITE_BUF_SIZE];
106
 
107
static void fb_putchar(wchar_t c, int row, int col);
108
 
109
 
1526 cejka 110
/** Find unused virtual console.
111
 *
112
 */
1574 palkovsky 113
static int find_free_connection(void)
1451 cejka 114
{
2069 jermar 115
    int i;
1451 cejka 116
 
2069 jermar 117
    for (i = 0; i < CONSOLE_COUNT; i++) {
1574 palkovsky 118
        if (!connections[i].used)
1451 cejka 119
            return i;
120
    }
1574 palkovsky 121
    return -1;
1451 cejka 122
}
123
 
1552 palkovsky 124
static void clrscr(void)
125
{
2621 jermar 126
    async_msg_0(fb_info.phone, FB_CLEAR);
1552 palkovsky 127
}
128
 
4153 mejdrech 129
static void curs_visibility(bool visible)
1552 palkovsky 130
{
4153 mejdrech 131
    async_msg_1(fb_info.phone, FB_CURSOR_VISIBILITY, visible);
1552 palkovsky 132
}
133
 
4153 mejdrech 134
static void curs_hide_sync(void)
135
{
136
    ipc_call_sync_1_0(fb_info.phone, FB_CURSOR_VISIBILITY, false);
137
}
138
 
1552 palkovsky 139
static void curs_goto(int row, int col)
140
{
1610 palkovsky 141
    async_msg_2(fb_info.phone, FB_CURSOR_GOTO, row, col);
1552 palkovsky 142
}
143
 
4327 mejdrech 144
static void screen_yield(void)
145
{
146
    ipc_call_sync_0_0(fb_info.phone, FB_SCREEN_YIELD);
147
}
148
 
149
static void screen_reclaim(void)
150
{
151
    ipc_call_sync_0_0(fb_info.phone, FB_SCREEN_RECLAIM);
152
}
153
 
4153 mejdrech 154
static void set_style(int style)
1552 palkovsky 155
{
4153 mejdrech 156
    async_msg_1(fb_info.phone, FB_SET_STYLE, style);
1552 palkovsky 157
}
158
 
4153 mejdrech 159
static void set_color(int fgcolor, int bgcolor, int flags)
1552 palkovsky 160
{
4153 mejdrech 161
    async_msg_3(fb_info.phone, FB_SET_COLOR, fgcolor, bgcolor, flags);
1552 palkovsky 162
}
163
 
4153 mejdrech 164
static void set_rgb_color(int fgcolor, int bgcolor)
165
{
166
    async_msg_2(fb_info.phone, FB_SET_RGB_COLOR, fgcolor, bgcolor);
167
}
168
 
169
static void set_attrs(attrs_t *attrs)
170
{
171
    switch (attrs->t) {
172
    case at_style:
173
        set_style(attrs->a.s.style);
174
        break;
175
 
176
    case at_idx:
177
        set_color(attrs->a.i.fg_color, attrs->a.i.bg_color,
178
            attrs->a.i.flags);
179
        break;
180
 
181
    case at_rgb:
182
        set_rgb_color(attrs->a.r.fg_color, attrs->a.r.bg_color);
183
        break;
184
    }
185
}
186
 
4263 mejdrech 187
/** Send an area of screenbuffer to the FB driver. */
188
static void fb_update_area(connection_t *conn, int x, int y, int w, int h)
1552 palkovsky 189
{
4263 mejdrech 190
    int i, j;
191
    int rc;
192
    attrs_t *attrs;
193
    keyfield_t *field;
194
 
195
    if (interbuffer) {
196
        for (j = 0; j < h; j++) {
197
            for (i = 0; i < w; i++) {
198
                interbuffer[i + j * w] =
199
                    *get_field_at(&conn->screenbuffer,
200
                    x + i, y + j);
201
            }
202
        }
203
 
204
        rc = async_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA,
205
            x, y, w, h);
206
    } else {
207
        rc = ENOTSUP;
208
    }
209
 
210
    if (rc != 0) {
211
        /*
212
        attrs = &conn->screenbuffer.attrs;
213
 
214
        for (j = 0; j < h; j++) {
215
            for (i = 0; i < w; i++) {
216
                field = get_field_at(&conn->screenbuffer,
217
                    x + i, y + j);
218
                if (!attrs_same(*attrs, field->attrs))
219
                    set_attrs(&field->attrs);
220
                attrs = &field->attrs;
221
 
222
                fb_putchar(field->character, y + j, x + i);
223
            }
224
        }*/
225
    }
1552 palkovsky 226
}
227
 
4263 mejdrech 228
/** Flush pending cells to FB. */
229
static void fb_pending_flush(void)
230
{
231
    screenbuffer_t *scr;
232
 
233
    scr = &(connections[active_console].screenbuffer);
234
 
235
    if (fb_pending.n > 0) {
236
        fb_update_area(&connections[active_console], fb_pending.col,
237
            fb_pending.row, fb_pending.n, 1);
238
        fb_pending.n = 0;
239
    }
240
}
241
 
242
/** Mark a character cell as changed.
1497 cejka 243
 *
4263 mejdrech 244
 * This adds the cell to the pending rowspan if possible. Otherwise
245
 * the old span is flushed first.
2566 jermar 246
 */
4263 mejdrech 247
static void cell_mark_changed(int row, int col)
1497 cejka 248
{
4263 mejdrech 249
    if (fb_pending.n != 0) {
250
        if (row != fb_pending.row ||
251
            col != fb_pending.col + fb_pending.n) {
252
            fb_pending_flush();
253
        }
254
    }
255
 
256
    if (fb_pending.n == 0) {
257
        fb_pending.row = row;
258
        fb_pending.col = col;
259
    }
260
 
261
    ++fb_pending.n;
262
}
263
 
264
 
265
/** Print a character to the active VC with buffering. */
266
static void fb_putchar(wchar_t c, int row, int col)
267
{
268
    async_msg_3(fb_info.phone, FB_PUTCHAR, c, row, col);
269
}
270
 
271
/** Process a character from the client (TTY emulation). */
272
static void write_char(int console, wchar_t ch)
273
{
274
    bool flush_cursor = false;
1497 cejka 275
    screenbuffer_t *scr = &(connections[console].screenbuffer);
4263 mejdrech 276
 
277
    switch (ch) {
2025 jermar 278
    case '\n':
4263 mejdrech 279
        fb_pending_flush();
280
        flush_cursor = true;
2069 jermar 281
        scr->position_y++;
282
        scr->position_x = 0;
2025 jermar 283
        break;
284
    case '\r':
285
        break;
286
    case '\t':
287
        scr->position_x += 8;
288
        scr->position_x -= scr->position_x % 8;
289
        break;
290
    case '\b':
291
        if (scr->position_x == 0)
1497 cejka 292
            break;
2025 jermar 293
        scr->position_x--;
294
        if (console == active_console)
4263 mejdrech 295
            cell_mark_changed(scr->position_y, scr->position_x);
2025 jermar 296
        screenbuffer_putchar(scr, ' ');
297
        break;
298
    default:   
299
        if (console == active_console)
4263 mejdrech 300
            cell_mark_changed(scr->position_y, scr->position_x);
1497 cejka 301
 
4263 mejdrech 302
        screenbuffer_putchar(scr, ch);
2025 jermar 303
        scr->position_x++;
1497 cejka 304
    }
4263 mejdrech 305
 
306
    if (scr->position_x >= scr->size_x) {
307
        flush_cursor = true;
308
        scr->position_y++;
309
    }
1497 cejka 310
 
311
    if (scr->position_y >= scr->size_y) {
4263 mejdrech 312
        fb_pending_flush();
1497 cejka 313
        scr->position_y = scr->size_y - 1;
1674 palkovsky 314
        screenbuffer_clear_line(scr, scr->top_line);
2069 jermar 315
        scr->top_line = (scr->top_line + 1) % scr->size_y;
1518 palkovsky 316
        if (console == active_console)
2621 jermar 317
            async_msg_1(fb_info.phone, FB_SCROLL, 1);
1497 cejka 318
    }
4263 mejdrech 319
 
1497 cejka 320
    scr->position_x = scr->position_x % scr->size_x;
4263 mejdrech 321
 
322
    if (console == active_console && flush_cursor)
1552 palkovsky 323
        curs_goto(scr->position_y, scr->position_x);
1497 cejka 324
}
325
 
1552 palkovsky 326
/** Switch to new console */
327
static void change_console(int newcons)
328
{
329
    connection_t *conn;
1673 palkovsky 330
    int i, j, rc;
1578 cejka 331
    keyfield_t *field;
4153 mejdrech 332
    attrs_t *attrs;
333
 
1552 palkovsky 334
    if (newcons == active_console)
335
        return;
4263 mejdrech 336
 
337
    fb_pending_flush();
338
 
1555 palkovsky 339
    if (newcons == KERNEL_CONSOLE) {
1717 palkovsky 340
        async_serialize_start();
4153 mejdrech 341
        curs_hide_sync();
342
        gcons_in_kernel();
4327 mejdrech 343
        screen_yield();
1717 palkovsky 344
        async_serialize_end();
4327 mejdrech 345
 
4153 mejdrech 346
 
347
        if (__SYSCALL0(SYS_DEBUG_ENABLE_CONSOLE)) {
348
            prev_console = active_console;
349
            active_console = KERNEL_CONSOLE;
350
        } else
351
            newcons = active_console;
1552 palkovsky 352
    }
1578 cejka 353
 
4153 mejdrech 354
    if (newcons != KERNEL_CONSOLE) {
355
        async_serialize_start();
356
 
4327 mejdrech 357
        if (active_console == KERNEL_CONSOLE) {
358
            screen_reclaim();
4153 mejdrech 359
            gcons_redraw_console();
4327 mejdrech 360
        }
4153 mejdrech 361
 
362
        active_console = newcons;
363
        gcons_change_console(newcons);
364
        conn = &connections[active_console];
365
 
366
        set_attrs(&conn->screenbuffer.attrs);
367
        curs_visibility(false);
368
        if (interbuffer) {
4263 mejdrech 369
            for (j = 0; j < conn->screenbuffer.size_y; j++) {
370
                for (i = 0; i < conn->screenbuffer.size_x; i++) {
4153 mejdrech 371
                    unsigned int size_x;
372
 
373
                    size_x = conn->screenbuffer.size_x;
4263 mejdrech 374
                    interbuffer[j * size_x + i] =
4153 mejdrech 375
                        *get_field_at(&conn->screenbuffer, i, j);
376
                }
4263 mejdrech 377
            }
4153 mejdrech 378
            /* This call can preempt, but we are already at the end */
4263 mejdrech 379
            rc = async_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA,
380
                0, 0, conn->screenbuffer.size_x,
381
                conn->screenbuffer.size_y);
4153 mejdrech 382
        }
383
 
384
        if ((!interbuffer) || (rc != 0)) {
385
            set_attrs(&conn->screenbuffer.attrs);
386
            clrscr();
387
            attrs = &conn->screenbuffer.attrs;
388
 
389
            for (j = 0; j < conn->screenbuffer.size_y; j++)
390
                for (i = 0; i < conn->screenbuffer.size_x; i++) {
391
                    field = get_field_at(&conn->screenbuffer, i, j);
392
                    if (!attrs_same(*attrs, field->attrs))
393
                        set_attrs(&field->attrs);
394
                    attrs = &field->attrs;
395
                    if ((field->character == ' ') &&
396
                        (attrs_same(field->attrs,
397
                        conn->screenbuffer.attrs)))
398
                        continue;
1578 cejka 399
 
4263 mejdrech 400
                    fb_putchar(field->character, j, i);
4153 mejdrech 401
                }
402
        }
403
 
404
        curs_goto(conn->screenbuffer.position_y,
405
            conn->screenbuffer.position_x);
406
        curs_visibility(conn->screenbuffer.is_cursor_visible);
407
 
408
        async_serialize_end();
1552 palkovsky 409
    }
410
}
411
 
1526 cejka 412
/** Handler for keyboard */
1453 palkovsky 413
static void keyboard_events(ipc_callid_t iid, ipc_call_t *icall)
1445 cejka 414
{
1453 palkovsky 415
    ipc_callid_t callid;
1445 cejka 416
    ipc_call_t call;
1453 palkovsky 417
    int retval;
4153 mejdrech 418
    kbd_event_t ev;
1489 palkovsky 419
    connection_t *conn;
1717 palkovsky 420
    int newcon;
1506 cejka 421
 
1453 palkovsky 422
    /* Ignore parameters, the connection is alread opened */
423
    while (1) {
424
        callid = async_get_call(&call);
425
        switch (IPC_GET_METHOD(call)) {
426
        case IPC_M_PHONE_HUNGUP:
427
            /* TODO: Handle hangup */
428
            return;
1717 palkovsky 429
        case KBD_MS_LEFT:
430
            newcon = gcons_mouse_btn(IPC_GET_ARG1(call));
431
            if (newcon != -1)
432
                change_console(newcon);
1721 palkovsky 433
            retval = 0;
1717 palkovsky 434
            break;
1707 palkovsky 435
        case KBD_MS_MOVE:
2025 jermar 436
            gcons_mouse_move(IPC_GET_ARG1(call),
2539 jermar 437
                IPC_GET_ARG2(call));
1721 palkovsky 438
            retval = 0;
1707 palkovsky 439
            break;
4153 mejdrech 440
        case KBD_EVENT:
441
            /* Got event from keyboard driver. */
442
            retval = 0;
443
            ev.type = IPC_GET_ARG1(call);
444
            ev.key = IPC_GET_ARG2(call);
445
            ev.mods = IPC_GET_ARG3(call);
446
            ev.c = IPC_GET_ARG4(call);
1465 cejka 447
 
1453 palkovsky 448
            /* switch to another virtual console */
1481 cejka 449
 
1489 palkovsky 450
            conn = &connections[active_console];
4153 mejdrech 451
 
452
            if ((ev.key >= KC_F1) && (ev.key < KC_F1 +
4263 mejdrech 453
                CONSOLE_COUNT) && ((ev.mods & KM_CTRL) == 0)) {
4153 mejdrech 454
                if (ev.key == KC_F12)
1555 palkovsky 455
                    change_console(KERNEL_CONSOLE);
1552 palkovsky 456
                else
4153 mejdrech 457
                    change_console(ev.key - KC_F1);
1453 palkovsky 458
                break;
459
            }
1481 cejka 460
 
461
            /* if client is awaiting key, send it */
1489 palkovsky 462
            if (conn->keyrequest_counter > 0) {    
463
                conn->keyrequest_counter--;
4153 mejdrech 464
                ipc_answer_4(fifo_pop(conn->keyrequests), EOK,
465
                    ev.type, ev.key, ev.mods, ev.c);
1481 cejka 466
                break;
467
            }
4153 mejdrech 468
 
469
            keybuffer_push(&conn->keybuffer, &ev);
1721 palkovsky 470
            retval = 0;
4153 mejdrech 471
 
1453 palkovsky 472
            break;
473
        default:
1459 palkovsky 474
            retval = ENOENT;
1610 palkovsky 475
        }
2619 jermar 476
        ipc_answer_0(callid, retval);
1453 palkovsky 477
    }
478
}
479
 
4263 mejdrech 480
/** Handle CONSOLE_WRITE call. */
481
static void cons_write(int consnum, ipc_callid_t rid, ipc_call_t *request)
482
{
483
    ipc_callid_t callid;
484
    size_t size;
485
    wchar_t ch;
486
    size_t off;
487
 
488
    if (!ipc_data_write_receive(&callid, &size)) {
489
        ipc_answer_0(callid, EINVAL);
490
        ipc_answer_0(rid, EINVAL);
491
    }
492
 
493
    if (size > CWRITE_BUF_SIZE)
494
        size = CWRITE_BUF_SIZE;
495
 
496
    (void) ipc_data_write_finalize(callid, cwrite_buf, size);
497
 
498
    off = 0;
499
    while (off < size) {
500
        ch = str_decode(cwrite_buf, &off, size);
501
        write_char(consnum, ch);
502
    }
503
 
504
    gcons_notify_char(consnum);
505
    ipc_answer_1(rid, EOK, size);
506
}
507
 
1453 palkovsky 508
/** Default thread for new connections */
1518 palkovsky 509
static void client_connection(ipc_callid_t iid, ipc_call_t *icall)
1453 palkovsky 510
{
1445 cejka 511
    ipc_callid_t callid;
1453 palkovsky 512
    ipc_call_t call;
513
    int consnum;
4153 mejdrech 514
    ipcarg_t arg1, arg2, arg3, arg4;
1592 palkovsky 515
    connection_t *conn;
4263 mejdrech 516
    screenbuffer_t *scr;
4153 mejdrech 517
 
1574 palkovsky 518
    if ((consnum = find_free_connection()) == -1) {
2619 jermar 519
        ipc_answer_0(iid, ELIMIT);
1453 palkovsky 520
        return;
521
    }
1592 palkovsky 522
    conn = &connections[consnum];
1610 palkovsky 523
    conn->used = 1;
1555 palkovsky 524
 
1610 palkovsky 525
    async_serialize_start();
1555 palkovsky 526
    gcons_notify_connect(consnum);
2637 cejka 527
    conn->client_phone = IPC_GET_ARG5(*icall);
1592 palkovsky 528
    screenbuffer_clear(&conn->screenbuffer);
4327 mejdrech 529
    if (consnum == active_console)
530
        clrscr();
1497 cejka 531
 
1453 palkovsky 532
    /* Accept the connection */
2619 jermar 533
    ipc_answer_0(iid, EOK);
4153 mejdrech 534
 
1453 palkovsky 535
    while (1) {
1610 palkovsky 536
        async_serialize_end();
1453 palkovsky 537
        callid = async_get_call(&call);
1610 palkovsky 538
        async_serialize_start();
4153 mejdrech 539
 
2566 jermar 540
        arg1 = 0;
541
        arg2 = 0;
4153 mejdrech 542
        arg3 = 0;
543
        arg4 = 0;
544
 
1453 palkovsky 545
        switch (IPC_GET_METHOD(call)) {
546
        case IPC_M_PHONE_HUNGUP:
1592 palkovsky 547
            gcons_notify_disconnect(consnum);
1610 palkovsky 548
 
1592 palkovsky 549
            /* Answer all pending requests */
4153 mejdrech 550
            while (conn->keyrequest_counter > 0) {
1592 palkovsky 551
                conn->keyrequest_counter--;
2619 jermar 552
                ipc_answer_0(fifo_pop(conn->keyrequests),
553
                    ENOENT);
1592 palkovsky 554
                break;
555
            }
1616 palkovsky 556
            conn->used = 0;
1453 palkovsky 557
            return;
558
        case CONSOLE_PUTCHAR:
1497 cejka 559
            write_char(consnum, IPC_GET_ARG1(call));
1528 palkovsky 560
            gcons_notify_char(consnum);
1453 palkovsky 561
            break;
4263 mejdrech 562
        case CONSOLE_WRITE:
563
            cons_write(consnum, callid, &call);
564
            continue;
1476 cejka 565
        case CONSOLE_CLEAR:
1487 cejka 566
            /* Send message to fb */
567
            if (consnum == active_console) {
2621 jermar 568
                async_msg_0(fb_info.phone, FB_CLEAR);
1487 cejka 569
            }
570
 
1592 palkovsky 571
            screenbuffer_clear(&conn->screenbuffer);
1487 cejka 572
 
1476 cejka 573
            break;
574
        case CONSOLE_GOTO:
2025 jermar 575
            screenbuffer_goto(&conn->screenbuffer,
2539 jermar 576
                IPC_GET_ARG2(call), IPC_GET_ARG1(call));
1567 palkovsky 577
            if (consnum == active_console)
2025 jermar 578
                curs_goto(IPC_GET_ARG1(call),
2539 jermar 579
                    IPC_GET_ARG2(call));
1476 cejka 580
            break;
1521 cejka 581
        case CONSOLE_GETSIZE:
1528 palkovsky 582
            arg1 = fb_info.rows;
583
            arg2 = fb_info.cols;
1521 cejka 584
            break;
1523 cejka 585
        case CONSOLE_FLUSH:
4263 mejdrech 586
            fb_pending_flush();
587
            if (consnum == active_console) {
2621 jermar 588
                async_req_0_0(fb_info.phone, FB_FLUSH);
4263 mejdrech 589
 
590
                scr = &(connections[consnum].screenbuffer);
591
                curs_goto(scr->position_y, scr->position_x);
592
            }
1523 cejka 593
            break;
1525 cejka 594
        case CONSOLE_SET_STYLE:
4263 mejdrech 595
            fb_pending_flush();
1525 cejka 596
            arg1 = IPC_GET_ARG1(call);
4153 mejdrech 597
            screenbuffer_set_style(&conn->screenbuffer, arg1);
598
            if (consnum == active_console)
599
                set_style(arg1);
600
            break;
601
        case CONSOLE_SET_COLOR:
4263 mejdrech 602
            fb_pending_flush();
4153 mejdrech 603
            arg1 = IPC_GET_ARG1(call);
1525 cejka 604
            arg2 = IPC_GET_ARG2(call);
4153 mejdrech 605
            arg3 = IPC_GET_ARG3(call);
606
            screenbuffer_set_color(&conn->screenbuffer, arg1,
607
                arg2, arg3);
608
            if (consnum == active_console)
609
                set_color(arg1, arg2, arg3);
610
            break;
611
        case CONSOLE_SET_RGB_COLOR:
4263 mejdrech 612
            fb_pending_flush();
4153 mejdrech 613
            arg1 = IPC_GET_ARG1(call);
614
            arg2 = IPC_GET_ARG2(call);
615
            screenbuffer_set_rgb_color(&conn->screenbuffer, arg1,
2539 jermar 616
                arg2);
1525 cejka 617
            if (consnum == active_console)
4153 mejdrech 618
                set_rgb_color(arg1, arg2);
1525 cejka 619
            break;
1575 cejka 620
        case CONSOLE_CURSOR_VISIBILITY:
4263 mejdrech 621
            fb_pending_flush();
1575 cejka 622
            arg1 = IPC_GET_ARG1(call);
1592 palkovsky 623
            conn->screenbuffer.is_cursor_visible = arg1;
1575 cejka 624
            if (consnum == active_console)
625
                curs_visibility(arg1);
626
            break;
4153 mejdrech 627
        case CONSOLE_GETKEY:
1592 palkovsky 628
            if (keybuffer_empty(&conn->keybuffer)) {
1481 cejka 629
                /* buffer is empty -> store request */
2025 jermar 630
                if (conn->keyrequest_counter <
631
                    MAX_KEYREQUESTS_BUFFERED) {
1592 palkovsky 632
                    fifo_push(conn->keyrequests, callid);
633
                    conn->keyrequest_counter++;
1481 cejka 634
                } else {
2025 jermar 635
                    /*
636
                     * No key available and too many
637
                     * requests => fail.
638
                    */
2619 jermar 639
                    ipc_answer_0(callid, ELIMIT);
1481 cejka 640
                }
641
                continue;
2025 jermar 642
            }
4153 mejdrech 643
            kbd_event_t ev;
644
            keybuffer_pop(&conn->keybuffer, &ev);
645
            arg1 = ev.type;
646
            arg2 = ev.key;
647
            arg3 = ev.mods;
648
            arg4 = ev.c;
1453 palkovsky 649
            break;
4263 mejdrech 650
        case CONSOLE_KCON_ENABLE:
651
            change_console(KERNEL_CONSOLE);
652
            break;
1453 palkovsky 653
        }
4153 mejdrech 654
        ipc_answer_4(callid, EOK, arg1, arg2, arg3, arg4);
1453 palkovsky 655
    }
656
}
657
 
4153 mejdrech 658
static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
659
{
660
    change_console(prev_console);
661
}
662
 
1453 palkovsky 663
int main(int argc, char *argv[])
664
{
3084 decky 665
    printf(NAME ": HelenOS Console service\n");
666
 
1453 palkovsky 667
    ipcarg_t phonehash;
1721 palkovsky 668
    int kbd_phone;
4153 mejdrech 669
    size_t ib_size;
1451 cejka 670
    int i;
4153 mejdrech 671
 
1490 palkovsky 672
    async_set_client_connection(client_connection);
1445 cejka 673
 
674
    /* Connect to keyboard driver */
4153 mejdrech 675
    kbd_phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_KEYBOARD, 0, 0);
676
    if (kbd_phone < 0) {
677
        printf(NAME ": Failed to connect to keyboard service\n");
678
        return -1;
2025 jermar 679
    }
1445 cejka 680
 
4153 mejdrech 681
    if (ipc_connect_to_me(kbd_phone, SERVICE_CONSOLE, 0, 0, &phonehash) != 0) {
682
        printf(NAME ": Failed to create callback from keyboard service\n");
1445 cejka 683
        return -1;
4153 mejdrech 684
    }
685
 
1689 palkovsky 686
    async_new_connection(phonehash, 0, NULL, keyboard_events);
687
 
1445 cejka 688
    /* Connect to framebuffer driver */
4153 mejdrech 689
    fb_info.phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_VIDEO, 0, 0);
690
    if (fb_info.phone < 0) {
691
        printf(NAME ": Failed to connect to video service\n");
692
        return -1;
1487 cejka 693
    }
1552 palkovsky 694
 
4153 mejdrech 695
    /* Disable kernel output to the console */
696
    __SYSCALL0(SYS_DEBUG_DISABLE_CONSOLE);
697
 
1522 palkovsky 698
    /* Initialize gcons */
699
    gcons_init(fb_info.phone);
700
    /* Synchronize, the gcons can have something in queue */
2621 jermar 701
    async_req_0_0(fb_info.phone, FB_FLUSH);
1487 cejka 702
 
2621 jermar 703
    async_req_0_2(fb_info.phone, FB_GET_CSIZE, &fb_info.rows,
2539 jermar 704
        &fb_info.cols);
4153 mejdrech 705
    set_rgb_color(DEFAULT_FOREGROUND, DEFAULT_BACKGROUND);
1552 palkovsky 706
    clrscr();
1487 cejka 707
 
708
    /* Init virtual consoles */
1451 cejka 709
    for (i = 0; i < CONSOLE_COUNT; i++) {
710
        connections[i].used = 0;
2539 jermar 711
        keybuffer_init(&connections[i].keybuffer);
1481 cejka 712
 
2539 jermar 713
        connections[i].keyrequests.head = 0;
714
        connections[i].keyrequests.tail = 0;
1481 cejka 715
        connections[i].keyrequests.items = MAX_KEYREQUESTS_BUFFERED;
716
        connections[i].keyrequest_counter = 0;
1487 cejka 717
 
2539 jermar 718
        if (screenbuffer_init(&connections[i].screenbuffer,
719
            fb_info.cols, fb_info.rows) == NULL) {
2069 jermar 720
            /* FIXME: handle error */
1487 cejka 721
            return -1;
722
        }
1451 cejka 723
    }
1574 palkovsky 724
    connections[KERNEL_CONSOLE].used = 1;
4153 mejdrech 725
 
726
    /* Set up shared memory buffer. */
727
    ib_size = sizeof(keyfield_t) * fb_info.cols * fb_info.rows;
728
    interbuffer = as_get_mappable_page(ib_size);
729
 
4263 mejdrech 730
    fb_pending.n = 0;
731
 
4153 mejdrech 732
    if (as_area_create(interbuffer, ib_size, AS_AREA_READ |
733
        AS_AREA_WRITE | AS_AREA_CACHEABLE) != interbuffer) {
734
        interbuffer = NULL;
735
    }
736
 
737
    if (interbuffer) {
2678 jermar 738
        if (ipc_share_out_start(fb_info.phone, interbuffer,
2677 jermar 739
            AS_AREA_READ) != EOK) {
4153 mejdrech 740
            as_area_destroy(interbuffer);
1512 cejka 741
            interbuffer = NULL;
742
        }
743
    }
4153 mejdrech 744
 
2069 jermar 745
    curs_goto(0, 0);
2539 jermar 746
    curs_visibility(
747
        connections[active_console].screenbuffer.is_cursor_visible);
4153 mejdrech 748
 
1518 palkovsky 749
    /* Register at NS */
3084 decky 750
    if (ipc_connect_to_me(PHONE_NS, SERVICE_CONSOLE, 0, 0, &phonehash) != 0)
1445 cejka 751
        return -1;
752
 
4153 mejdrech 753
    /* Receive kernel notifications */
4263 mejdrech 754
    if (event_subscribe(EVENT_KCONSOLE, 0) != EOK)
755
        printf(NAME ": Error registering kconsole notifications\n");
756
 
757
    async_set_interrupt_received(interrupt_received);
4153 mejdrech 758
 
3084 decky 759
    // FIXME: avoid connectiong to itself, keep using klog
760
    // printf(NAME ": Accepting connections\n");
1453 palkovsky 761
    async_manager();
4153 mejdrech 762
 
763
    return 0;
764
}
1451 cejka 765
 
1649 cejka 766
/** @}
767
 */