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

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

Stop userspace kbd driver from polling when switching to kcon. Also, fix swapped reversed enabling/disabling of polling in kernel sgcn and ski drivers.

  • Property mode set to 100644
File size: 18.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
[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);
506 }
507
[171f9a1]508 if (size > CWRITE_BUF_SIZE)
509 size = CWRITE_BUF_SIZE;
[d2cc7e1]510
[171f9a1]511 (void) ipc_data_write_finalize(callid, cwrite_buf, size);
[d2cc7e1]512
[171f9a1]513 off = 0;
514 while (off < size) {
515 ch = str_decode(cwrite_buf, &off, size);
516 write_char(consnum, ch);
[d2cc7e1]517 }
518
519 gcons_notify_char(consnum);
[171f9a1]520 ipc_answer_1(rid, EOK, size);
[d2cc7e1]521}
522
[eaf34f7]523/** Default thread for new connections */
[b1f51f0]524static void client_connection(ipc_callid_t iid, ipc_call_t *icall)
[eaf34f7]525{
[51c1b003]526 ipc_callid_t callid;
[eaf34f7]527 ipc_call_t call;
528 int consnum;
[fa09449]529 ipcarg_t arg1, arg2, arg3, arg4;
[e9073f2]530 connection_t *conn;
[dc033a1]531 screenbuffer_t *scr;
[3ad953c]532
[d32af35]533 if ((consnum = find_free_connection()) == -1) {
[b74959bd]534 ipc_answer_0(iid, ELIMIT);
[eaf34f7]535 return;
536 }
[e9073f2]537 conn = &connections[consnum];
[085bd54]538 conn->used = 1;
[a7d2d78]539
[085bd54]540 async_serialize_start();
[a7d2d78]541 gcons_notify_connect(consnum);
[38c706cc]542 conn->client_phone = IPC_GET_ARG5(*icall);
[e9073f2]543 screenbuffer_clear(&conn->screenbuffer);
[700dcb5]544 if (consnum == active_console)
545 clrscr();
[10569b1]546
[eaf34f7]547 /* Accept the connection */
[b74959bd]548 ipc_answer_0(iid, EOK);
[3ad953c]549
[eaf34f7]550 while (1) {
[085bd54]551 async_serialize_end();
[eaf34f7]552 callid = async_get_call(&call);
[085bd54]553 async_serialize_start();
[3ad953c]554
[96858e8]555 arg1 = 0;
556 arg2 = 0;
[fa09449]557 arg3 = 0;
558 arg4 = 0;
559
[eaf34f7]560 switch (IPC_GET_METHOD(call)) {
561 case IPC_M_PHONE_HUNGUP:
[e9073f2]562 gcons_notify_disconnect(consnum);
[085bd54]563
[e9073f2]564 /* Answer all pending requests */
[3ad953c]565 while (conn->keyrequest_counter > 0) {
[e9073f2]566 conn->keyrequest_counter--;
[b74959bd]567 ipc_answer_0(fifo_pop(conn->keyrequests),
568 ENOENT);
[e9073f2]569 break;
570 }
[0d11fc1c]571 conn->used = 0;
[eaf34f7]572 return;
573 case CONSOLE_PUTCHAR:
[10569b1]574 write_char(consnum, IPC_GET_ARG1(call));
[d6cc453]575 gcons_notify_char(consnum);
[ad123964]576 break;
[d2cc7e1]577 case CONSOLE_WRITE:
578 cons_write(consnum, callid, &call);
579 continue;
[ad123964]580 case CONSOLE_CLEAR:
[3993b3d]581 /* Send message to fb */
582 if (consnum == active_console) {
[0cc4313]583 async_msg_0(fb_info.phone, FB_CLEAR);
[3993b3d]584 }
585
[e9073f2]586 screenbuffer_clear(&conn->screenbuffer);
[3993b3d]587
[eaf34f7]588 break;
[ad123964]589 case CONSOLE_GOTO:
[00bb6965]590 screenbuffer_goto(&conn->screenbuffer,
[01f5e17]591 IPC_GET_ARG2(call), IPC_GET_ARG1(call));
[6118e5f6]592 if (consnum == active_console)
[00bb6965]593 curs_goto(IPC_GET_ARG1(call),
[01f5e17]594 IPC_GET_ARG2(call));
[ad123964]595 break;
[3756912]596 case CONSOLE_GETSIZE:
[d6cc453]597 arg1 = fb_info.rows;
598 arg2 = fb_info.cols;
[3756912]599 break;
[0c6984e]600 case CONSOLE_FLUSH:
[dc033a1]601 fb_pending_flush();
602 if (consnum == active_console) {
[0cc4313]603 async_req_0_0(fb_info.phone, FB_FLUSH);
[dc033a1]604
605 scr = &(connections[consnum].screenbuffer);
606 curs_goto(scr->position_y, scr->position_x);
607 }
[a9bd960c]608 break;
609 case CONSOLE_SET_STYLE:
[dc033a1]610 fb_pending_flush();
[9805cde]611 arg1 = IPC_GET_ARG1(call);
612 screenbuffer_set_style(&conn->screenbuffer, arg1);
613 if (consnum == active_console)
614 set_style(arg1);
615 break;
616 case CONSOLE_SET_COLOR:
[dc033a1]617 fb_pending_flush();
[9805cde]618 arg1 = IPC_GET_ARG1(call);
619 arg2 = IPC_GET_ARG2(call);
620 arg3 = IPC_GET_ARG3(call);
621 screenbuffer_set_color(&conn->screenbuffer, arg1,
622 arg2, arg3);
623 if (consnum == active_console)
624 set_color(arg1, arg2, arg3);
625 break;
626 case CONSOLE_SET_RGB_COLOR:
[dc033a1]627 fb_pending_flush();
[a9bd960c]628 arg1 = IPC_GET_ARG1(call);
629 arg2 = IPC_GET_ARG2(call);
[9805cde]630 screenbuffer_set_rgb_color(&conn->screenbuffer, arg1,
[01f5e17]631 arg2);
[a9bd960c]632 if (consnum == active_console)
[9805cde]633 set_rgb_color(arg1, arg2);
[0c6984e]634 break;
[a8b2b5b2]635 case CONSOLE_CURSOR_VISIBILITY:
[dc033a1]636 fb_pending_flush();
[a8b2b5b2]637 arg1 = IPC_GET_ARG1(call);
[e9073f2]638 conn->screenbuffer.is_cursor_visible = arg1;
[a8b2b5b2]639 if (consnum == active_console)
640 curs_visibility(arg1);
641 break;
[fa09449]642 case CONSOLE_GETKEY:
[e9073f2]643 if (keybuffer_empty(&conn->keybuffer)) {
[cf28036c]644 /* buffer is empty -> store request */
[00bb6965]645 if (conn->keyrequest_counter <
646 MAX_KEYREQUESTS_BUFFERED) {
[e9073f2]647 fifo_push(conn->keyrequests, callid);
648 conn->keyrequest_counter++;
[cf28036c]649 } else {
[00bb6965]650 /*
651 * No key available and too many
652 * requests => fail.
653 */
[b74959bd]654 ipc_answer_0(callid, ELIMIT);
[cf28036c]655 }
656 continue;
[00bb6965]657 }
[fa09449]658 kbd_event_t ev;
659 keybuffer_pop(&conn->keybuffer, &ev);
660 arg1 = ev.type;
661 arg2 = ev.key;
662 arg3 = ev.mods;
663 arg4 = ev.c;
[eaf34f7]664 break;
[3fe00ee]665 case CONSOLE_KCON_ENABLE:
666 change_console(KERNEL_CONSOLE);
667 break;
[eaf34f7]668 }
[fa09449]669 ipc_answer_4(callid, EOK, arg1, arg2, arg3, arg4);
[eaf34f7]670 }
671}
672
[3ad953c]673static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
674{
675 change_console(prev_console);
676}
677
[eaf34f7]678int main(int argc, char *argv[])
679{
[271b540]680 printf(NAME ": HelenOS Console service\n");
681
[eaf34f7]682 ipcarg_t phonehash;
[7447572]683 size_t ib_size;
[79460ae]684 int i;
[3ad953c]685
[da0c91e7]686 async_set_client_connection(client_connection);
[51c1b003]687
688 /* Connect to keyboard driver */
[4904de8]689 kbd_phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_KEYBOARD, 0, 0);
690 if (kbd_phone < 0) {
691 printf(NAME ": Failed to connect to keyboard service\n");
692 return -1;
[00bb6965]693 }
[51c1b003]694
[4904de8]695 if (ipc_connect_to_me(kbd_phone, SERVICE_CONSOLE, 0, 0, &phonehash) != 0) {
696 printf(NAME ": Failed to create callback from keyboard service\n");
[51c1b003]697 return -1;
[4904de8]698 }
699
[290c0db]700 async_new_connection(phonehash, 0, NULL, keyboard_events);
701
[51c1b003]702 /* Connect to framebuffer driver */
[4904de8]703 fb_info.phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_VIDEO, 0, 0);
704 if (fb_info.phone < 0) {
705 printf(NAME ": Failed to connect to video service\n");
706 return -1;
[3993b3d]707 }
[429acb9]708
[516ff92]709 /* Disable kernel output to the console */
710 __SYSCALL0(SYS_DEBUG_DISABLE_CONSOLE);
711
[e1c4849]712 /* Initialize gcons */
713 gcons_init(fb_info.phone);
714 /* Synchronize, the gcons can have something in queue */
[0cc4313]715 async_req_0_0(fb_info.phone, FB_FLUSH);
[3993b3d]716
[0cc4313]717 async_req_0_2(fb_info.phone, FB_GET_CSIZE, &fb_info.rows,
[01f5e17]718 &fb_info.cols);
[9805cde]719 set_rgb_color(DEFAULT_FOREGROUND, DEFAULT_BACKGROUND);
[429acb9]720 clrscr();
[3993b3d]721
722 /* Init virtual consoles */
[79460ae]723 for (i = 0; i < CONSOLE_COUNT; i++) {
724 connections[i].used = 0;
[01f5e17]725 keybuffer_init(&connections[i].keybuffer);
[cf28036c]726
[01f5e17]727 connections[i].keyrequests.head = 0;
728 connections[i].keyrequests.tail = 0;
[cf28036c]729 connections[i].keyrequests.items = MAX_KEYREQUESTS_BUFFERED;
730 connections[i].keyrequest_counter = 0;
[3993b3d]731
[01f5e17]732 if (screenbuffer_init(&connections[i].screenbuffer,
733 fb_info.cols, fb_info.rows) == NULL) {
[c738d65]734 /* FIXME: handle error */
[3993b3d]735 return -1;
736 }
[79460ae]737 }
[d32af35]738 connections[KERNEL_CONSOLE].used = 1;
[7447572]739
740 /* Set up shared memory buffer. */
741 ib_size = sizeof(keyfield_t) * fb_info.cols * fb_info.rows;
742 interbuffer = as_get_mappable_page(ib_size);
743
[dc033a1]744 fb_pending.n = 0;
745
[7447572]746 if (as_area_create(interbuffer, ib_size, AS_AREA_READ |
747 AS_AREA_WRITE | AS_AREA_CACHEABLE) != interbuffer) {
748 interbuffer = NULL;
749 }
750
751 if (interbuffer) {
[215e375]752 if (ipc_share_out_start(fb_info.phone, interbuffer,
[27d293a]753 AS_AREA_READ) != EOK) {
[7447572]754 as_area_destroy(interbuffer);
[390a678]755 interbuffer = NULL;
756 }
757 }
[3ad953c]758
[c738d65]759 curs_goto(0, 0);
[01f5e17]760 curs_visibility(
761 connections[active_console].screenbuffer.is_cursor_visible);
[3ad953c]762
[b1f51f0]763 /* Register at NS */
[271b540]764 if (ipc_connect_to_me(PHONE_NS, SERVICE_CONSOLE, 0, 0, &phonehash) != 0)
[51c1b003]765 return -1;
766
[3ad953c]767 /* Receive kernel notifications */
[05641a9e]768 if (event_subscribe(EVENT_KCONSOLE, 0) != EOK)
769 printf(NAME ": Error registering kconsole notifications\n");
770
771 async_set_interrupt_received(interrupt_received);
[3ad953c]772
[271b540]773 // FIXME: avoid connectiong to itself, keep using klog
774 // printf(NAME ": Accepting connections\n");
[eaf34f7]775 async_manager();
[3ad953c]776
777 return 0;
[51c1b003]778}
[516ff92]779
[ce5bcb4]780/** @}
781 */
Note: See TracBrowser for help on using the repository browser.