source: mainline/uspace/srv/console/console.c@ 50cfa6c

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 50cfa6c was 50cfa6c, checked in by Jiri Svoboda <jirik.svoboda@…>, 16 years ago

Method for getting console color capabilities. Use to fix invisible tetris pieces.

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