source: mainline/uspace/srv/console/console.c@ 0c0b800

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

console cleanup (no functional changes)

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