source: mainline/uspace/srv/console/console.c@ 99272a3

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

console server rewrite: use VFS_READ/VFS_WRITE for generic I/O, register separate virtual consoles using device mapper

  • 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) {
531 ipc_answer_0(rid, ENOMEM);
532 free(buf);
533 async_serialize_end();
534 return;
535 }
536
537 pr->cons = cons;
538 pr->rid = rid;
539 pr->callid = callid;
540 pr->pos = pos;
541 pr->size = size;
542 pr->data = buf;
543 list_append(&pr->link, &pending_input);
544 }
545
546 async_serialize_end();
547}
548
549static void cons_get_event(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
550{
551 async_serialize_start();
552
553 console_event_t ev;
554 if (keybuffer_pop(&cons->keybuffer, &ev)) {
555 ipc_answer_4(rid, EOK, ev.type, ev.key, ev.mods, ev.c);
556 } else {
557 pending_input_t *pr = (pending_input_t *) malloc(sizeof(pending_input_t));
558 if (!pr) {
559 ipc_answer_0(rid, ENOMEM);
560 async_serialize_end();
561 return;
562 }
563
564 pr->cons = cons;
565 pr->rid = rid;
566 pr->callid = 0;
567 pr->data = NULL;
568 list_append(&pr->link, &pending_input);
569 }
570
571 async_serialize_end();
[d2cc7e1]572}
573
[eaf34f7]574/** Default thread for new connections */
[b1f51f0]575static void client_connection(ipc_callid_t iid, ipc_call_t *icall)
[eaf34f7]576{
[424cd43]577 console_t *cons = NULL;
[3ad953c]578
[424cd43]579 size_t i;
580 for (i = 0; i < CONSOLE_COUNT; i++) {
581 if (i == KERNEL_CONSOLE)
582 continue;
583
584 if (consoles[i].dev_handle == (dev_handle_t) IPC_GET_ARG1(*icall)) {
585 cons = &consoles[i];
586 break;
587 }
588 }
589
590 if (cons == NULL) {
591 ipc_answer_0(iid, ENOENT);
[eaf34f7]592 return;
593 }
[424cd43]594
595 ipc_callid_t callid;
596 ipc_call_t call;
597 ipcarg_t arg1;
598 ipcarg_t arg2;
599 ipcarg_t arg3;
[a7d2d78]600
[085bd54]601 async_serialize_start();
[424cd43]602 if (cons->refcount == 0)
603 gcons_notify_connect(cons->index);
604
605 cons->refcount++;
[10569b1]606
[eaf34f7]607 /* Accept the connection */
[b74959bd]608 ipc_answer_0(iid, EOK);
[3ad953c]609
[1601f3c]610 while (true) {
[085bd54]611 async_serialize_end();
[eaf34f7]612 callid = async_get_call(&call);
[085bd54]613 async_serialize_start();
[3ad953c]614
[96858e8]615 arg1 = 0;
616 arg2 = 0;
[fa09449]617 arg3 = 0;
[1601f3c]618
[eaf34f7]619 switch (IPC_GET_METHOD(call)) {
620 case IPC_M_PHONE_HUNGUP:
[424cd43]621 cons->refcount--;
622 if (cons->refcount == 0)
623 gcons_notify_disconnect(cons->index);
[eaf34f7]624 return;
[424cd43]625 case VFS_READ:
626 async_serialize_end();
627 cons_read(cons, callid, &call);
628 async_serialize_start();
629 continue;
630 case VFS_WRITE:
[6568225]631 async_serialize_end();
[424cd43]632 cons_write(cons, callid, &call);
[6568225]633 async_serialize_start();
[d2cc7e1]634 continue;
[424cd43]635 case VFS_SYNC:
636 fb_pending_flush();
637 if (cons == active_console) {
638 async_req_0_0(fb_info.phone, FB_FLUSH);
639
640 curs_goto(cons->scr.position_x, cons->scr.position_y);
641 }
642 break;
[ad123964]643 case CONSOLE_CLEAR:
[3993b3d]644 /* Send message to fb */
[424cd43]645 if (cons == active_console)
646 async_msg_0(fb_info.phone, FB_CLEAR);
[3993b3d]647
[424cd43]648 screenbuffer_clear(&cons->scr);
[3993b3d]649
[eaf34f7]650 break;
[ad123964]651 case CONSOLE_GOTO:
[424cd43]652 screenbuffer_goto(&cons->scr,
653 IPC_GET_ARG1(call), IPC_GET_ARG2(call));
654 if (cons == active_console)
[00bb6965]655 curs_goto(IPC_GET_ARG1(call),
[01f5e17]656 IPC_GET_ARG2(call));
[ad123964]657 break;
[424cd43]658 case CONSOLE_GET_SIZE:
659 arg1 = fb_info.cols;
660 arg2 = fb_info.rows;
[a9bd960c]661 break;
662 case CONSOLE_SET_STYLE:
[dc033a1]663 fb_pending_flush();
[9805cde]664 arg1 = IPC_GET_ARG1(call);
[424cd43]665 screenbuffer_set_style(&cons->scr, arg1);
666 if (cons == active_console)
[9805cde]667 set_style(arg1);
668 break;
669 case CONSOLE_SET_COLOR:
[dc033a1]670 fb_pending_flush();
[9805cde]671 arg1 = IPC_GET_ARG1(call);
672 arg2 = IPC_GET_ARG2(call);
673 arg3 = IPC_GET_ARG3(call);
[424cd43]674 screenbuffer_set_color(&cons->scr, arg1, arg2, arg3);
675 if (cons == active_console)
[9805cde]676 set_color(arg1, arg2, arg3);
677 break;
678 case CONSOLE_SET_RGB_COLOR:
[dc033a1]679 fb_pending_flush();
[a9bd960c]680 arg1 = IPC_GET_ARG1(call);
681 arg2 = IPC_GET_ARG2(call);
[424cd43]682 screenbuffer_set_rgb_color(&cons->scr, arg1, arg2);
683 if (cons == active_console)
[9805cde]684 set_rgb_color(arg1, arg2);
[0c6984e]685 break;
[a8b2b5b2]686 case CONSOLE_CURSOR_VISIBILITY:
[dc033a1]687 fb_pending_flush();
[a8b2b5b2]688 arg1 = IPC_GET_ARG1(call);
[424cd43]689 cons->scr.is_cursor_visible = arg1;
690 if (cons == active_console)
[a8b2b5b2]691 curs_visibility(arg1);
692 break;
[424cd43]693 case CONSOLE_GET_EVENT:
694 async_serialize_end();
695 cons_get_event(cons, callid, &call);
696 async_serialize_start();
697 continue;
[3fe00ee]698 case CONSOLE_KCON_ENABLE:
[424cd43]699 change_console(kernel_console);
[3fe00ee]700 break;
[eaf34f7]701 }
[424cd43]702 ipc_answer_3(callid, EOK, arg1, arg2, arg3);
[eaf34f7]703 }
704}
705
[3ad953c]706static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
707{
708 change_console(prev_console);
709}
710
[424cd43]711static bool console_init(void)
[eaf34f7]712{
[51c1b003]713 /* Connect to keyboard driver */
[424cd43]714
[4904de8]715 kbd_phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_KEYBOARD, 0, 0);
716 if (kbd_phone < 0) {
717 printf(NAME ": Failed to connect to keyboard service\n");
[424cd43]718 return false;
[00bb6965]719 }
[51c1b003]720
[424cd43]721 ipcarg_t phonehash;
[4904de8]722 if (ipc_connect_to_me(kbd_phone, SERVICE_CONSOLE, 0, 0, &phonehash) != 0) {
723 printf(NAME ": Failed to create callback from keyboard service\n");
[424cd43]724 return false;
[4904de8]725 }
726
[424cd43]727 async_set_pending(process_pending_input);
[290c0db]728 async_new_connection(phonehash, 0, NULL, keyboard_events);
729
[51c1b003]730 /* Connect to framebuffer driver */
[4904de8]731 fb_info.phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_VIDEO, 0, 0);
732 if (fb_info.phone < 0) {
733 printf(NAME ": Failed to connect to video service\n");
734 return -1;
[3993b3d]735 }
[429acb9]736
[424cd43]737 /* Register driver */
738 int rc = devmap_driver_register(NAME, client_connection);
739 if (rc < 0) {
740 printf(NAME ": Unable to register driver (%d)\n", rc);
741 return false;
742 }
[516ff92]743
[e1c4849]744 /* Initialize gcons */
745 gcons_init(fb_info.phone);
[3993b3d]746
[424cd43]747 /* Synchronize, the gcons could put something in queue */
748 async_req_0_0(fb_info.phone, FB_FLUSH);
749 async_req_0_2(fb_info.phone, FB_GET_CSIZE, &fb_info.cols, &fb_info.rows);
[1601f3c]750
[7447572]751 /* Set up shared memory buffer. */
[424cd43]752 size_t ib_size = sizeof(keyfield_t) * fb_info.cols * fb_info.rows;
[7447572]753 interbuffer = as_get_mappable_page(ib_size);
[1601f3c]754
[7447572]755 if (as_area_create(interbuffer, ib_size, AS_AREA_READ |
[424cd43]756 AS_AREA_WRITE | AS_AREA_CACHEABLE) != interbuffer)
[7447572]757 interbuffer = NULL;
[1601f3c]758
[7447572]759 if (interbuffer) {
[215e375]760 if (ipc_share_out_start(fb_info.phone, interbuffer,
[27d293a]761 AS_AREA_READ) != EOK) {
[7447572]762 as_area_destroy(interbuffer);
[390a678]763 interbuffer = NULL;
764 }
765 }
[3ad953c]766
[424cd43]767 fb_pending.cnt = 0;
[3ad953c]768
[424cd43]769 /* Inititalize consoles */
770 size_t i;
771 for (i = 0; i < CONSOLE_COUNT; i++) {
772 if (i != KERNEL_CONSOLE) {
773 if (screenbuffer_init(&consoles[i].scr,
774 fb_info.cols, fb_info.rows) == NULL) {
775 printf(NAME ": Unable to allocate screen buffer %u\n", i);
776 return false;
777 }
778 screenbuffer_clear(&consoles[i].scr);
779 keybuffer_init(&consoles[i].keybuffer);
780 consoles[i].index = i;
781 consoles[i].refcount = 0;
782
783 char vc[MAX_DEVICE_NAME];
784 snprintf(vc, MAX_DEVICE_NAME, "vc%u", i);
785
786 if (devmap_device_register(vc, &consoles[i].dev_handle) != EOK) {
787 devmap_hangup_phone(DEVMAP_DRIVER);
788 printf(NAME ": Unable to register device %s\n", vc);
789 return false;
790 }
791 }
792 }
793
794 /* Initialize the screen */
795 set_rgb_color(DEFAULT_FOREGROUND, DEFAULT_BACKGROUND);
796 screen_clear();
797 curs_goto(0, 0);
798 curs_visibility(active_console->scr.is_cursor_visible);
[51c1b003]799
[3ad953c]800 /* Receive kernel notifications */
[05641a9e]801 if (event_subscribe(EVENT_KCONSOLE, 0) != EOK)
802 printf(NAME ": Error registering kconsole notifications\n");
[1601f3c]803
[05641a9e]804 async_set_interrupt_received(interrupt_received);
[3ad953c]805
[424cd43]806 return true;
807}
808
809int main(int argc, char *argv[])
810{
811 printf(NAME ": HelenOS Console service\n");
812
813 /* Disable kernel output to the console */
814 __SYSCALL0(SYS_DEBUG_DISABLE_CONSOLE);
815
816 if (!console_init()) {
817 __SYSCALL0(SYS_DEBUG_ENABLE_CONSOLE);
818 return -1;
819 }
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.