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

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

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

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