Subversion Repositories HelenOS

Rev

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