source: mainline/uspace/srv/console/console.c@ 1090b8c

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

Fix incorrect serialization in console, which could lead to the console server getting stuck.

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