source: mainline/uspace/srv/console/console.c@ 1035437

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

keep the kernel console intact as long as it is possible (to be able to see any out-of-order errors)

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