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

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

Revert clandestine removal of delayed cursor position update by c4456.

  • Property mode set to 100644
File size: 19.8 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 <adt/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 bool flush_cursor = false;
291
292 switch (ch) {
293 case '\n':
294 fb_pending_flush();
295 flush_cursor = true;
296 cons->scr.position_y++;
297 cons->scr.position_x = 0;
298 break;
299 case '\r':
300 break;
301 case '\t':
302 cons->scr.position_x += 8;
303 cons->scr.position_x -= cons->scr.position_x % 8;
304 break;
305 case '\b':
306 if (cons->scr.position_x == 0)
307 break;
308 cons->scr.position_x--;
309 if (cons == active_console)
310 cell_mark_changed(cons->scr.position_x, cons->scr.position_y);
311 screenbuffer_putchar(&cons->scr, ' ');
312 break;
313 default:
314 if (cons == active_console)
315 cell_mark_changed(cons->scr.position_x, cons->scr.position_y);
316
317 screenbuffer_putchar(&cons->scr, ch);
318 cons->scr.position_x++;
319 }
320
321 if (cons->scr.position_x >= cons->scr.size_x) {
322 flush_cursor = true;
323 cons->scr.position_y++;
324 }
325
326 if (cons->scr.position_y >= cons->scr.size_y) {
327 fb_pending_flush();
328 cons->scr.position_y = cons->scr.size_y - 1;
329 screenbuffer_clear_line(&cons->scr, cons->scr.top_line);
330 cons->scr.top_line = (cons->scr.top_line + 1) % cons->scr.size_y;
331
332 if (cons == active_console)
333 async_msg_1(fb_info.phone, FB_SCROLL, 1);
334 }
335
336 if (cons == active_console && flush_cursor)
337 curs_goto(cons->scr.position_x, cons->scr.position_y);
338 cons->scr.position_x = cons->scr.position_x % cons->scr.size_x;
339}
340
341/** Switch to new console */
342static void change_console(console_t *cons)
343{
344 if (cons == active_console)
345 return;
346
347 fb_pending_flush();
348
349 if (cons == kernel_console) {
350 async_serialize_start();
351 curs_hide_sync();
352 gcons_in_kernel();
353 screen_yield();
354 kbd_yield();
355 async_serialize_end();
356
357 if (__SYSCALL0(SYS_DEBUG_ENABLE_CONSOLE)) {
358 prev_console = active_console;
359 active_console = kernel_console;
360 } else
361 cons = active_console;
362 }
363
364 if (cons != kernel_console) {
365 size_t x;
366 size_t y;
367 int rc = 0;
368
369 async_serialize_start();
370
371 if (active_console == kernel_console) {
372 screen_reclaim();
373 kbd_reclaim();
374 gcons_redraw_console();
375 }
376
377 active_console = cons;
378 gcons_change_console(cons->index);
379
380 set_attrs(&cons->scr.attrs);
381 curs_visibility(false);
382 if (interbuffer) {
383 for (y = 0; y < cons->scr.size_y; y++) {
384 for (x = 0; x < cons->scr.size_x; x++) {
385 interbuffer[y * cons->scr.size_x + x] =
386 *get_field_at(&cons->scr, x, y);
387 }
388 }
389
390 /* This call can preempt, but we are already at the end */
391 rc = async_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA,
392 0, 0, cons->scr.size_x,
393 cons->scr.size_y);
394 }
395
396 if ((!interbuffer) || (rc != 0)) {
397 set_attrs(&cons->scr.attrs);
398 screen_clear();
399
400 for (y = 0; y < cons->scr.size_y; y++)
401 for (x = 0; x < cons->scr.size_x; x++) {
402 keyfield_t *field = get_field_at(&cons->scr, x, y);
403
404 if (!attrs_same(cons->scr.attrs, field->attrs))
405 set_attrs(&field->attrs);
406
407 cons->scr.attrs = field->attrs;
408 if ((field->character == ' ') &&
409 (attrs_same(field->attrs, cons->scr.attrs)))
410 continue;
411
412 fb_putchar(field->character, x, y);
413 }
414 }
415
416 curs_goto(cons->scr.position_x, cons->scr.position_y);
417 curs_visibility(cons->scr.is_cursor_visible);
418
419 async_serialize_end();
420 }
421}
422
423/** Handler for keyboard */
424static void keyboard_events(ipc_callid_t iid, ipc_call_t *icall)
425{
426 /* Ignore parameters, the connection is already opened */
427 while (true) {
428
429 ipc_call_t call;
430 ipc_callid_t callid = async_get_call(&call);
431
432 int retval;
433 console_event_t ev;
434
435 switch (IPC_GET_METHOD(call)) {
436 case IPC_M_PHONE_HUNGUP:
437 /* TODO: Handle hangup */
438 return;
439 case KBD_EVENT:
440 /* Got event from keyboard driver. */
441 retval = 0;
442 ev.type = IPC_GET_ARG1(call);
443 ev.key = IPC_GET_ARG2(call);
444 ev.mods = IPC_GET_ARG3(call);
445 ev.c = IPC_GET_ARG4(call);
446
447 if ((ev.key >= KC_F1) && (ev.key < KC_F1 +
448 CONSOLE_COUNT) && ((ev.mods & KM_CTRL) == 0)) {
449 if (ev.key == KC_F1 + KERNEL_CONSOLE)
450 change_console(kernel_console);
451 else
452 change_console(&consoles[ev.key - KC_F1]);
453 break;
454 }
455
456 keybuffer_push(&active_console->keybuffer, &ev);
457 break;
458 default:
459 retval = ENOENT;
460 }
461 ipc_answer_0(callid, retval);
462 }
463}
464
465static void cons_write(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
466{
467 ipc_callid_t callid;
468 size_t size;
469 if (!ipc_data_write_receive(&callid, &size)) {
470 ipc_answer_0(callid, EINVAL);
471 ipc_answer_0(rid, EINVAL);
472 return;
473 }
474
475 char *buf = (char *) malloc(size);
476 if (buf == NULL) {
477 ipc_answer_0(callid, ENOMEM);
478 ipc_answer_0(rid, ENOMEM);
479 return;
480 }
481
482 (void) ipc_data_write_finalize(callid, buf, size);
483
484 async_serialize_start();
485
486 size_t off = 0;
487 while (off < size) {
488 wchar_t ch = str_decode(buf, &off, size);
489 write_char(cons, ch);
490 }
491
492 async_serialize_end();
493
494 gcons_notify_char(cons->index);
495 ipc_answer_1(rid, EOK, size);
496
497 free(buf);
498}
499
500static void cons_read(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
501{
502 ipc_callid_t callid;
503 size_t size;
504 if (!ipc_data_read_receive(&callid, &size)) {
505 ipc_answer_0(callid, EINVAL);
506 ipc_answer_0(rid, EINVAL);
507 return;
508 }
509
510 char *buf = (char *) malloc(size);
511 if (buf == NULL) {
512 ipc_answer_0(callid, ENOMEM);
513 ipc_answer_0(rid, ENOMEM);
514 return;
515 }
516
517 async_serialize_start();
518
519 size_t pos = 0;
520 console_event_t ev;
521 while ((keybuffer_pop(&cons->keybuffer, &ev)) && (pos < size)) {
522 if (ev.type == KEY_PRESS) {
523 buf[pos] = ev.c;
524 pos++;
525 }
526 }
527
528 if (pos == size) {
529 (void) ipc_data_read_finalize(callid, buf, size);
530 ipc_answer_1(rid, EOK, size);
531 free(buf);
532 } else {
533 pending_input_t *pr = (pending_input_t *) malloc(sizeof(pending_input_t));
534 if (!pr) {
535 ipc_answer_0(callid, ENOMEM);
536 ipc_answer_0(rid, ENOMEM);
537 free(buf);
538 async_serialize_end();
539 return;
540 }
541
542 pr->cons = cons;
543 pr->rid = rid;
544 pr->callid = callid;
545 pr->pos = pos;
546 pr->size = size;
547 pr->data = buf;
548 list_append(&pr->link, &pending_input);
549 }
550
551 async_serialize_end();
552}
553
554static void cons_get_event(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
555{
556 async_serialize_start();
557
558 console_event_t ev;
559 if (keybuffer_pop(&cons->keybuffer, &ev)) {
560 ipc_answer_4(rid, EOK, ev.type, ev.key, ev.mods, ev.c);
561 } else {
562 pending_input_t *pr = (pending_input_t *) malloc(sizeof(pending_input_t));
563 if (!pr) {
564 ipc_answer_0(rid, ENOMEM);
565 async_serialize_end();
566 return;
567 }
568
569 pr->cons = cons;
570 pr->rid = rid;
571 pr->callid = 0;
572 pr->data = NULL;
573 list_append(&pr->link, &pending_input);
574 }
575
576 async_serialize_end();
577}
578
579/** Default thread for new connections */
580static void client_connection(ipc_callid_t iid, ipc_call_t *icall)
581{
582 console_t *cons = NULL;
583
584 size_t i;
585 for (i = 0; i < CONSOLE_COUNT; i++) {
586 if (i == KERNEL_CONSOLE)
587 continue;
588
589 if (consoles[i].dev_handle == (dev_handle_t) IPC_GET_ARG1(*icall)) {
590 cons = &consoles[i];
591 break;
592 }
593 }
594
595 if (cons == NULL) {
596 ipc_answer_0(iid, ENOENT);
597 return;
598 }
599
600 ipc_callid_t callid;
601 ipc_call_t call;
602 ipcarg_t arg1;
603 ipcarg_t arg2;
604 ipcarg_t arg3;
605
606 async_serialize_start();
607 if (cons->refcount == 0)
608 gcons_notify_connect(cons->index);
609
610 cons->refcount++;
611
612 /* Accept the connection */
613 ipc_answer_0(iid, EOK);
614
615 while (true) {
616 async_serialize_end();
617 callid = async_get_call(&call);
618 async_serialize_start();
619
620 arg1 = 0;
621 arg2 = 0;
622 arg3 = 0;
623
624 switch (IPC_GET_METHOD(call)) {
625 case IPC_M_PHONE_HUNGUP:
626 cons->refcount--;
627 if (cons->refcount == 0)
628 gcons_notify_disconnect(cons->index);
629 return;
630 case VFS_READ:
631 async_serialize_end();
632 cons_read(cons, callid, &call);
633 async_serialize_start();
634 continue;
635 case VFS_WRITE:
636 async_serialize_end();
637 cons_write(cons, callid, &call);
638 async_serialize_start();
639 continue;
640 case VFS_SYNC:
641 fb_pending_flush();
642 if (cons == active_console) {
643 async_req_0_0(fb_info.phone, FB_FLUSH);
644
645 curs_goto(cons->scr.position_x, cons->scr.position_y);
646 }
647 break;
648 case CONSOLE_CLEAR:
649 /* Send message to fb */
650 if (cons == active_console)
651 async_msg_0(fb_info.phone, FB_CLEAR);
652
653 screenbuffer_clear(&cons->scr);
654
655 break;
656 case CONSOLE_GOTO:
657 screenbuffer_goto(&cons->scr,
658 IPC_GET_ARG1(call), IPC_GET_ARG2(call));
659 if (cons == active_console)
660 curs_goto(IPC_GET_ARG1(call),
661 IPC_GET_ARG2(call));
662 break;
663 case CONSOLE_GET_SIZE:
664 arg1 = fb_info.cols;
665 arg2 = fb_info.rows;
666 break;
667 case CONSOLE_SET_STYLE:
668 fb_pending_flush();
669 arg1 = IPC_GET_ARG1(call);
670 screenbuffer_set_style(&cons->scr, arg1);
671 if (cons == active_console)
672 set_style(arg1);
673 break;
674 case CONSOLE_SET_COLOR:
675 fb_pending_flush();
676 arg1 = IPC_GET_ARG1(call);
677 arg2 = IPC_GET_ARG2(call);
678 arg3 = IPC_GET_ARG3(call);
679 screenbuffer_set_color(&cons->scr, arg1, arg2, arg3);
680 if (cons == active_console)
681 set_color(arg1, arg2, arg3);
682 break;
683 case CONSOLE_SET_RGB_COLOR:
684 fb_pending_flush();
685 arg1 = IPC_GET_ARG1(call);
686 arg2 = IPC_GET_ARG2(call);
687 screenbuffer_set_rgb_color(&cons->scr, arg1, arg2);
688 if (cons == active_console)
689 set_rgb_color(arg1, arg2);
690 break;
691 case CONSOLE_CURSOR_VISIBILITY:
692 fb_pending_flush();
693 arg1 = IPC_GET_ARG1(call);
694 cons->scr.is_cursor_visible = arg1;
695 if (cons == active_console)
696 curs_visibility(arg1);
697 break;
698 case CONSOLE_GET_EVENT:
699 async_serialize_end();
700 cons_get_event(cons, callid, &call);
701 async_serialize_start();
702 continue;
703 case CONSOLE_KCON_ENABLE:
704 change_console(kernel_console);
705 break;
706 }
707 ipc_answer_3(callid, EOK, arg1, arg2, arg3);
708 }
709}
710
711static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
712{
713 change_console(prev_console);
714}
715
716static bool console_init(void)
717{
718 async_serialize_start();
719
720 /* Connect to keyboard driver */
721 kbd_phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_KEYBOARD, 0, 0);
722 if (kbd_phone < 0) {
723 printf(NAME ": Failed to connect to keyboard service\n");
724 async_serialize_end();
725 return false;
726 }
727
728 ipcarg_t phonehash;
729 if (ipc_connect_to_me(kbd_phone, SERVICE_CONSOLE, 0, 0, &phonehash) != 0) {
730 printf(NAME ": Failed to create callback from keyboard service\n");
731 async_serialize_end();
732 return false;
733 }
734
735 async_set_pending(process_pending_input);
736 async_new_connection(phonehash, 0, NULL, keyboard_events);
737
738 /* Connect to framebuffer driver */
739 fb_info.phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_VIDEO, 0, 0);
740 if (fb_info.phone < 0) {
741 printf(NAME ": Failed to connect to video service\n");
742 async_serialize_end();
743 return -1;
744 }
745
746 /* Register driver */
747 int rc = devmap_driver_register(NAME, client_connection);
748 if (rc < 0) {
749 printf(NAME ": Unable to register driver (%d)\n", rc);
750 async_serialize_end();
751 return false;
752 }
753
754 /* Initialize gcons */
755 gcons_init(fb_info.phone);
756
757 /* Synchronize, the gcons could put something in queue */
758 async_req_0_0(fb_info.phone, FB_FLUSH);
759 async_req_0_2(fb_info.phone, FB_GET_CSIZE, &fb_info.cols, &fb_info.rows);
760
761 /* Set up shared memory buffer. */
762 size_t ib_size = sizeof(keyfield_t) * fb_info.cols * fb_info.rows;
763 interbuffer = as_get_mappable_page(ib_size);
764
765 if (as_area_create(interbuffer, ib_size, AS_AREA_READ |
766 AS_AREA_WRITE | AS_AREA_CACHEABLE) != interbuffer)
767 interbuffer = NULL;
768
769 if (interbuffer) {
770 if (ipc_share_out_start(fb_info.phone, interbuffer,
771 AS_AREA_READ) != EOK) {
772 as_area_destroy(interbuffer);
773 interbuffer = NULL;
774 }
775 }
776
777 fb_pending.cnt = 0;
778
779 /* Inititalize consoles */
780 size_t i;
781 for (i = 0; i < CONSOLE_COUNT; i++) {
782 if (i != KERNEL_CONSOLE) {
783 if (screenbuffer_init(&consoles[i].scr,
784 fb_info.cols, fb_info.rows) == NULL) {
785 printf(NAME ": Unable to allocate screen buffer %u\n", i);
786 async_serialize_end();
787 return false;
788 }
789 screenbuffer_clear(&consoles[i].scr);
790 keybuffer_init(&consoles[i].keybuffer);
791 consoles[i].index = i;
792 consoles[i].refcount = 0;
793
794 char vc[MAX_DEVICE_NAME];
795 snprintf(vc, MAX_DEVICE_NAME, "vc%u", i);
796
797 if (devmap_device_register(vc, &consoles[i].dev_handle) != EOK) {
798 devmap_hangup_phone(DEVMAP_DRIVER);
799 printf(NAME ": Unable to register device %s\n", vc);
800 async_serialize_end();
801 return false;
802 }
803 }
804 }
805
806 /* Disable kernel output to the console */
807 __SYSCALL0(SYS_DEBUG_DISABLE_CONSOLE);
808
809 /* Initialize the screen */
810 gcons_redraw_console();
811 set_rgb_color(DEFAULT_FOREGROUND, DEFAULT_BACKGROUND);
812 screen_clear();
813 curs_goto(0, 0);
814 curs_visibility(active_console->scr.is_cursor_visible);
815
816 /* Receive kernel notifications */
817 if (event_subscribe(EVENT_KCONSOLE, 0) != EOK)
818 printf(NAME ": Error registering kconsole notifications\n");
819
820 async_set_interrupt_received(interrupt_received);
821
822 async_serialize_end();
823 return true;
824}
825
826int main(int argc, char *argv[])
827{
828 printf(NAME ": HelenOS Console service\n");
829
830 if (!console_init())
831 return -1;
832
833 printf(NAME ": Accepting connections\n");
834 async_manager();
835
836 return 0;
837}
838
839/** @}
840 */
Note: See TracBrowser for help on using the repository browser.