source: mainline/uspace/srv/console/console.c@ 50cfa6c

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

Method for getting console color capabilities. Use to fix invisible tetris pieces.

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