source: mainline/uspace/srv/hid/console/console.c@ 68a552f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 68a552f was 68a552f, checked in by Jiri Svoboda <jiri@…>, 4 years ago

Efficient way of rendering to the console via shared buffer

Makes congfx reasonably fast

  • Property mode set to 100644
File size: 19.1 KB
Line 
1/*
2 * Copyright (c) 2021 Jiri Svoboda
3 * Copyright (c) 2011 Martin Decky
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup console
31 * @{
32 */
33/** @file
34 */
35
36#include <async.h>
37#include <stdio.h>
38#include <adt/prodcons.h>
39#include <io/input.h>
40#include <ipc/vfs.h>
41#include <errno.h>
42#include <str_error.h>
43#include <loc.h>
44#include <io/con_srv.h>
45#include <io/kbd_event.h>
46#include <io/keycode.h>
47#include <io/chargrid.h>
48#include <io/output.h>
49#include <align.h>
50#include <as.h>
51#include <task.h>
52#include <fibril_synch.h>
53#include <stdatomic.h>
54#include <stdlib.h>
55#include <str.h>
56#include "console.h"
57
58#define NAME "console"
59#define NAMESPACE "term"
60
61#define UTF8_CHAR_BUFFER_SIZE (STR_BOUNDS(1) + 1)
62
63typedef struct {
64 atomic_flag refcnt; /**< Connection reference count */
65 prodcons_t input_pc; /**< Incoming keyboard events */
66
67 /**
68 * Not yet sent bytes of last char event.
69 */
70 char char_remains[UTF8_CHAR_BUFFER_SIZE];
71 size_t char_remains_len; /**< Number of not yet sent bytes. */
72
73 fibril_mutex_t mtx; /**< Lock protecting mutable fields */
74
75 size_t index; /**< Console index */
76 service_id_t dsid; /**< Service handle */
77
78 sysarg_t cols; /**< Number of columns */
79 sysarg_t rows; /**< Number of rows */
80 console_caps_t ccaps; /**< Console capabilities */
81
82 sysarg_t ucols; /**< Number of columns in user buffer */
83 sysarg_t urows; /**< Number of rows in user buffer */
84 charfield_t *ubuf; /**< User buffer */
85
86 chargrid_t *frontbuf; /**< Front buffer */
87 frontbuf_handle_t fbid; /**< Front buffer handle */
88 con_srvs_t srvs; /**< Console service setup */
89} console_t;
90
91/** Input server proxy */
92static input_t *input;
93static bool active = false;
94
95/** Session to the output server */
96static async_sess_t *output_sess;
97
98/** Output dimensions */
99static sysarg_t cols;
100static sysarg_t rows;
101
102/** Array of data for virtual consoles */
103static console_t consoles[CONSOLE_COUNT];
104
105/** Mutex for console switching */
106static FIBRIL_MUTEX_INITIALIZE(switch_mtx);
107
108static console_t *active_console = &consoles[0];
109
110static errno_t input_ev_active(input_t *);
111static errno_t input_ev_deactive(input_t *);
112static errno_t input_ev_key(input_t *, kbd_event_type_t, keycode_t, keymod_t, char32_t);
113static errno_t input_ev_move(input_t *, int, int);
114static errno_t input_ev_abs_move(input_t *, unsigned, unsigned, unsigned, unsigned);
115static errno_t input_ev_button(input_t *, int, int);
116
117static input_ev_ops_t input_ev_ops = {
118 .active = input_ev_active,
119 .deactive = input_ev_deactive,
120 .key = input_ev_key,
121 .move = input_ev_move,
122 .abs_move = input_ev_abs_move,
123 .button = input_ev_button
124};
125
126static errno_t cons_open(con_srvs_t *, con_srv_t *);
127static errno_t cons_close(con_srv_t *);
128static errno_t cons_read(con_srv_t *, void *, size_t, size_t *);
129static errno_t cons_write(con_srv_t *, void *, size_t, size_t *);
130static void cons_sync(con_srv_t *);
131static void cons_clear(con_srv_t *);
132static void cons_set_pos(con_srv_t *, sysarg_t col, sysarg_t row);
133static errno_t cons_get_pos(con_srv_t *, sysarg_t *, sysarg_t *);
134static errno_t cons_get_size(con_srv_t *, sysarg_t *, sysarg_t *);
135static errno_t cons_get_color_cap(con_srv_t *, console_caps_t *);
136static void cons_set_style(con_srv_t *, console_style_t);
137static void cons_set_color(con_srv_t *, console_color_t, console_color_t,
138 console_color_attr_t);
139static void cons_set_rgb_color(con_srv_t *, pixel_t, pixel_t);
140static void cons_set_cursor_visibility(con_srv_t *, bool);
141static errno_t cons_get_event(con_srv_t *, cons_event_t *);
142static errno_t cons_map(con_srv_t *, sysarg_t, sysarg_t, charfield_t **);
143static void cons_unmap(con_srv_t *);
144static void cons_buf_update(con_srv_t *, sysarg_t, sysarg_t, sysarg_t,
145 sysarg_t);
146
147static con_ops_t con_ops = {
148 .open = cons_open,
149 .close = cons_close,
150 .read = cons_read,
151 .write = cons_write,
152 .sync = cons_sync,
153 .clear = cons_clear,
154 .set_pos = cons_set_pos,
155 .get_pos = cons_get_pos,
156 .get_size = cons_get_size,
157 .get_color_cap = cons_get_color_cap,
158 .set_style = cons_set_style,
159 .set_color = cons_set_color,
160 .set_rgb_color = cons_set_rgb_color,
161 .set_cursor_visibility = cons_set_cursor_visibility,
162 .get_event = cons_get_event,
163 .map = cons_map,
164 .unmap = cons_unmap,
165 .update = cons_buf_update
166};
167
168static console_t *srv_to_console(con_srv_t *srv)
169{
170 return srv->srvs->sarg;
171}
172
173static void cons_update(console_t *cons)
174{
175 fibril_mutex_lock(&switch_mtx);
176 fibril_mutex_lock(&cons->mtx);
177
178 if ((active) && (cons == active_console)) {
179 output_update(output_sess, cons->fbid);
180 output_cursor_update(output_sess, cons->fbid);
181 }
182
183 fibril_mutex_unlock(&cons->mtx);
184 fibril_mutex_unlock(&switch_mtx);
185}
186
187static void cons_update_cursor(console_t *cons)
188{
189 fibril_mutex_lock(&switch_mtx);
190 fibril_mutex_lock(&cons->mtx);
191
192 if ((active) && (cons == active_console))
193 output_cursor_update(output_sess, cons->fbid);
194
195 fibril_mutex_unlock(&cons->mtx);
196 fibril_mutex_unlock(&switch_mtx);
197}
198
199static void cons_damage(console_t *cons)
200{
201 fibril_mutex_lock(&switch_mtx);
202 fibril_mutex_lock(&cons->mtx);
203
204 if ((active) && (cons == active_console)) {
205 output_damage(output_sess, cons->fbid, 0, 0, cons->cols,
206 cons->rows);
207 output_cursor_update(output_sess, cons->fbid);
208 }
209
210 fibril_mutex_unlock(&cons->mtx);
211 fibril_mutex_unlock(&switch_mtx);
212}
213
214static void cons_switch(unsigned int index)
215{
216 /*
217 * The first undefined index is reserved
218 * for switching to the kernel console.
219 */
220 if (index == CONSOLE_COUNT) {
221 if (console_kcon())
222 active = false;
223
224 return;
225 }
226
227 if (index > CONSOLE_COUNT)
228 return;
229
230 console_t *cons = &consoles[index];
231
232 fibril_mutex_lock(&switch_mtx);
233
234 if (cons == active_console) {
235 fibril_mutex_unlock(&switch_mtx);
236 return;
237 }
238
239 active_console = cons;
240
241 fibril_mutex_unlock(&switch_mtx);
242
243 cons_damage(cons);
244}
245
246static errno_t input_ev_active(input_t *input)
247{
248 active = true;
249 output_claim(output_sess);
250 cons_damage(active_console);
251
252 return EOK;
253}
254
255static errno_t input_ev_deactive(input_t *input)
256{
257 active = false;
258 output_yield(output_sess);
259
260 return EOK;
261}
262
263static errno_t input_ev_key(input_t *input, kbd_event_type_t type, keycode_t key,
264 keymod_t mods, char32_t c)
265{
266 if ((key >= KC_F1) && (key <= KC_F1 + CONSOLE_COUNT) &&
267 ((mods & KM_CTRL) == 0)) {
268 cons_switch(key - KC_F1);
269 } else {
270 /* Got key press/release event */
271 kbd_event_t *event =
272 (kbd_event_t *) malloc(sizeof(kbd_event_t));
273 if (event == NULL) {
274 return ENOMEM;
275 }
276
277 link_initialize(&event->link);
278 event->type = type;
279 event->key = key;
280 event->mods = mods;
281 event->c = c;
282
283 prodcons_produce(&active_console->input_pc,
284 &event->link);
285 }
286
287 return EOK;
288}
289
290static errno_t input_ev_move(input_t *input, int dx, int dy)
291{
292 return EOK;
293}
294
295static errno_t input_ev_abs_move(input_t *input, unsigned x, unsigned y,
296 unsigned max_x, unsigned max_y)
297{
298 return EOK;
299}
300
301static errno_t input_ev_button(input_t *input, int bnum, int bpress)
302{
303 return EOK;
304}
305
306/** Process a character from the client (TTY emulation). */
307static void cons_write_char(console_t *cons, char32_t ch)
308{
309 sysarg_t updated = 0;
310
311 fibril_mutex_lock(&cons->mtx);
312
313 switch (ch) {
314 case '\n':
315 updated = chargrid_newline(cons->frontbuf);
316 break;
317 case '\r':
318 break;
319 case '\t':
320 updated = chargrid_tabstop(cons->frontbuf, 8);
321 break;
322 case '\b':
323 updated = chargrid_backspace(cons->frontbuf);
324 break;
325 default:
326 updated = chargrid_putuchar(cons->frontbuf, ch, true);
327 }
328
329 fibril_mutex_unlock(&cons->mtx);
330
331 if (updated > 1)
332 cons_update(cons);
333}
334
335static void cons_set_cursor_vis(console_t *cons, bool visible)
336{
337 fibril_mutex_lock(&cons->mtx);
338 chargrid_set_cursor_visibility(cons->frontbuf, visible);
339 fibril_mutex_unlock(&cons->mtx);
340
341 cons_update_cursor(cons);
342}
343
344static errno_t cons_open(con_srvs_t *srvs, con_srv_t *srv)
345{
346 return EOK;
347}
348
349static errno_t cons_close(con_srv_t *srv)
350{
351 return EOK;
352}
353
354static errno_t cons_read(con_srv_t *srv, void *buf, size_t size, size_t *nread)
355{
356 uint8_t *bbuf = buf;
357 console_t *cons = srv_to_console(srv);
358 size_t pos = 0;
359
360 /*
361 * Read input from keyboard and copy it to the buffer.
362 * We need to handle situation when wchar is split by 2 following
363 * reads.
364 */
365 while (pos < size) {
366 /* Copy to the buffer remaining characters. */
367 while ((pos < size) && (cons->char_remains_len > 0)) {
368 bbuf[pos] = cons->char_remains[0];
369 pos++;
370
371 /* Unshift the array. */
372 for (size_t i = 1; i < cons->char_remains_len; i++)
373 cons->char_remains[i - 1] = cons->char_remains[i];
374
375 cons->char_remains_len--;
376 }
377
378 /* Still not enough? Then get another key from the queue. */
379 if (pos < size) {
380 link_t *link = prodcons_consume(&cons->input_pc);
381 kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
382
383 /* Accept key presses of printable chars only. */
384 if ((event->type == KEY_PRESS) && (event->c != 0)) {
385 char32_t tmp[2] = { event->c, 0 };
386 wstr_to_str(cons->char_remains, UTF8_CHAR_BUFFER_SIZE, tmp);
387 cons->char_remains_len = str_size(cons->char_remains);
388 }
389
390 free(event);
391 }
392 }
393
394 *nread = size;
395 return EOK;
396}
397
398static errno_t cons_write(con_srv_t *srv, void *data, size_t size, size_t *nwritten)
399{
400 console_t *cons = srv_to_console(srv);
401
402 size_t off = 0;
403 while (off < size)
404 cons_write_char(cons, str_decode(data, &off, size));
405
406 *nwritten = size;
407 return EOK;
408}
409
410static void cons_sync(con_srv_t *srv)
411{
412 console_t *cons = srv_to_console(srv);
413
414 cons_update(cons);
415}
416
417static void cons_clear(con_srv_t *srv)
418{
419 console_t *cons = srv_to_console(srv);
420
421 fibril_mutex_lock(&cons->mtx);
422 chargrid_clear(cons->frontbuf);
423 fibril_mutex_unlock(&cons->mtx);
424
425 cons_update(cons);
426}
427
428static void cons_set_pos(con_srv_t *srv, sysarg_t col, sysarg_t row)
429{
430 console_t *cons = srv_to_console(srv);
431
432 fibril_mutex_lock(&cons->mtx);
433 chargrid_set_cursor(cons->frontbuf, col, row);
434 fibril_mutex_unlock(&cons->mtx);
435
436 cons_update_cursor(cons);
437}
438
439static errno_t cons_get_pos(con_srv_t *srv, sysarg_t *col, sysarg_t *row)
440{
441 console_t *cons = srv_to_console(srv);
442
443 fibril_mutex_lock(&cons->mtx);
444 chargrid_get_cursor(cons->frontbuf, col, row);
445 fibril_mutex_unlock(&cons->mtx);
446
447 return EOK;
448}
449
450static errno_t cons_get_size(con_srv_t *srv, sysarg_t *cols, sysarg_t *rows)
451{
452 console_t *cons = srv_to_console(srv);
453
454 fibril_mutex_lock(&cons->mtx);
455 *cols = cons->cols;
456 *rows = cons->rows;
457 fibril_mutex_unlock(&cons->mtx);
458
459 return EOK;
460}
461
462static errno_t cons_get_color_cap(con_srv_t *srv, console_caps_t *ccaps)
463{
464 console_t *cons = srv_to_console(srv);
465
466 fibril_mutex_lock(&cons->mtx);
467 *ccaps = cons->ccaps;
468 fibril_mutex_unlock(&cons->mtx);
469
470 return EOK;
471}
472
473static void cons_set_style(con_srv_t *srv, console_style_t style)
474{
475 console_t *cons = srv_to_console(srv);
476
477 fibril_mutex_lock(&cons->mtx);
478 chargrid_set_style(cons->frontbuf, style);
479 fibril_mutex_unlock(&cons->mtx);
480}
481
482static void cons_set_color(con_srv_t *srv, console_color_t bgcolor,
483 console_color_t fgcolor, console_color_attr_t attr)
484{
485 console_t *cons = srv_to_console(srv);
486
487 fibril_mutex_lock(&cons->mtx);
488 chargrid_set_color(cons->frontbuf, bgcolor, fgcolor, attr);
489 fibril_mutex_unlock(&cons->mtx);
490}
491
492static void cons_set_rgb_color(con_srv_t *srv, pixel_t bgcolor,
493 pixel_t fgcolor)
494{
495 console_t *cons = srv_to_console(srv);
496
497 fibril_mutex_lock(&cons->mtx);
498 chargrid_set_rgb_color(cons->frontbuf, bgcolor, fgcolor);
499 fibril_mutex_unlock(&cons->mtx);
500}
501
502static void cons_set_cursor_visibility(con_srv_t *srv, bool visible)
503{
504 console_t *cons = srv_to_console(srv);
505
506 cons_set_cursor_vis(cons, visible);
507}
508
509static errno_t cons_get_event(con_srv_t *srv, cons_event_t *event)
510{
511 console_t *cons = srv_to_console(srv);
512 link_t *link = prodcons_consume(&cons->input_pc);
513 kbd_event_t *kevent = list_get_instance(link, kbd_event_t, link);
514
515 event->type = CEV_KEY;
516 event->ev.key = *kevent;
517
518 free(kevent);
519 return EOK;
520}
521
522/** Create shared buffer for efficient rendering.
523 *
524 * @param srv Console server
525 * @param cols Number of columns in buffer
526 * @param rows Number of rows in buffer
527 * @param rbuf Place to store pointer to new sharable buffer
528 *
529 * @return EOK on sucess or an error code
530 */
531static errno_t cons_map(con_srv_t *srv, sysarg_t cols, sysarg_t rows,
532 charfield_t **rbuf)
533{
534 console_t *cons = srv_to_console(srv);
535 void *buf;
536
537 fibril_mutex_lock(&cons->mtx);
538
539 if (cons->ubuf != NULL) {
540 fibril_mutex_unlock(&cons->mtx);
541 return EBUSY;
542 }
543
544 buf = as_area_create(AS_AREA_ANY, cols * rows * sizeof(charfield_t),
545 AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE, AS_AREA_UNPAGED);
546 if (buf == AS_MAP_FAILED) {
547 fibril_mutex_unlock(&cons->mtx);
548 return ENOMEM;
549 }
550
551 cons->ucols = cols;
552 cons->urows = rows;
553 cons->ubuf = buf;
554 fibril_mutex_unlock(&cons->mtx);
555
556 *rbuf = buf;
557 return EOK;
558}
559
560/** Delete shared buffer.
561 *
562 * @param srv Console server
563 */
564static void cons_unmap(con_srv_t *srv)
565{
566 console_t *cons = srv_to_console(srv);
567 void *buf;
568
569 fibril_mutex_lock(&cons->mtx);
570
571 buf = cons->ubuf;
572 cons->ubuf = NULL;
573
574 if (buf != NULL)
575 as_area_destroy(buf);
576
577 fibril_mutex_unlock(&cons->mtx);
578}
579
580/** Update area of console from shared buffer.
581 *
582 * @param srv Console server
583 * @param c0 Column coordinate of top-left corner (inclusive)
584 * @param r0 Row coordinate of top-left corner (inclusive)
585 * @param c1 Column coordinate of bottom-right corner (exclusive)
586 * @param r1 Row coordinate of bottom-right corner (exclusive)
587 */
588static void cons_buf_update(con_srv_t *srv, sysarg_t c0, sysarg_t r0,
589 sysarg_t c1, sysarg_t r1)
590{
591 console_t *cons = srv_to_console(srv);
592 charfield_t *ch;
593 sysarg_t col, row;
594
595 fibril_mutex_lock(&cons->mtx);
596
597 if (cons->ubuf == NULL) {
598 fibril_mutex_unlock(&cons->mtx);
599 return;
600 }
601
602 /* Make sure we have meaningful coordinates, within bounds */
603
604 if (c1 > cons->ucols)
605 c1 = cons->ucols;
606 if (c1 > cons->cols)
607 c1 = cons->cols;
608 if (c0 >= c1) {
609 fibril_mutex_unlock(&cons->mtx);
610 return;
611 }
612 if (r1 > cons->urows)
613 r1 = cons->urows;
614 if (r1 > cons->rows)
615 r1 = cons->rows;
616 if (r0 >= r1) {
617 fibril_mutex_unlock(&cons->mtx);
618 return;
619 }
620
621 /* Update front buffer from user buffer */
622
623 for (row = r0; row < r1; row++) {
624 for (col = c0; col < c1; col++) {
625 ch = chargrid_charfield_at(cons->frontbuf, col, row);
626 *ch = cons->ubuf[row * cons->ucols + col];
627 }
628 }
629
630 fibril_mutex_unlock(&cons->mtx);
631
632 /* Update console */
633 cons_update(cons);
634}
635
636static void client_connection(ipc_call_t *icall, void *arg)
637{
638 console_t *cons = NULL;
639
640 for (size_t i = 0; i < CONSOLE_COUNT; i++) {
641 if (consoles[i].dsid == (service_id_t) ipc_get_arg2(icall)) {
642 cons = &consoles[i];
643 break;
644 }
645 }
646
647 if (cons == NULL) {
648 async_answer_0(icall, ENOENT);
649 return;
650 }
651
652 if (!atomic_flag_test_and_set(&cons->refcnt))
653 cons_set_cursor_vis(cons, true);
654
655 con_conn(icall, &cons->srvs);
656}
657
658static errno_t input_connect(const char *svc)
659{
660 async_sess_t *sess;
661 service_id_t dsid;
662
663 errno_t rc = loc_service_get_id(svc, &dsid, 0);
664 if (rc != EOK) {
665 printf("%s: Input service %s not found\n", NAME, svc);
666 return rc;
667 }
668
669 sess = loc_service_connect(dsid, INTERFACE_INPUT, 0);
670 if (sess == NULL) {
671 printf("%s: Unable to connect to input service %s\n", NAME,
672 svc);
673 return EIO;
674 }
675
676 rc = input_open(sess, &input_ev_ops, NULL, &input);
677 if (rc != EOK) {
678 async_hangup(sess);
679 printf("%s: Unable to communicate with service %s (%s)\n",
680 NAME, svc, str_error(rc));
681 return rc;
682 }
683
684 return EOK;
685}
686
687static async_sess_t *output_connect(const char *svc)
688{
689 async_sess_t *sess;
690 service_id_t dsid;
691
692 errno_t rc = loc_service_get_id(svc, &dsid, 0);
693 if (rc == EOK) {
694 sess = loc_service_connect(dsid, INTERFACE_OUTPUT, 0);
695 if (sess == NULL) {
696 printf("%s: Unable to connect to output service %s\n",
697 NAME, svc);
698 return NULL;
699 }
700 } else
701 return NULL;
702
703 return sess;
704}
705
706static bool console_srv_init(char *input_svc, char *output_svc)
707{
708 /* Connect to input service */
709 errno_t rc = input_connect(input_svc);
710 if (rc != EOK)
711 return false;
712
713 /* Connect to output service */
714 output_sess = output_connect(output_svc);
715 if (output_sess == NULL)
716 return false;
717
718 /* Register server */
719 async_set_fallback_port_handler(client_connection, NULL);
720 rc = loc_server_register(NAME);
721 if (rc != EOK) {
722 printf("%s: Unable to register server (%s)\n", NAME,
723 str_error(rc));
724 return false;
725 }
726
727 output_get_dimensions(output_sess, &cols, &rows);
728 output_set_style(output_sess, STYLE_NORMAL);
729
730 console_caps_t ccaps;
731 output_get_caps(output_sess, &ccaps);
732
733 /*
734 * Inititalize consoles only if there are
735 * actually some output devices.
736 */
737 if (ccaps != 0) {
738 for (size_t i = 0; i < CONSOLE_COUNT; i++) {
739 consoles[i].index = i;
740 atomic_flag_clear(&consoles[i].refcnt);
741 fibril_mutex_initialize(&consoles[i].mtx);
742 prodcons_initialize(&consoles[i].input_pc);
743 consoles[i].char_remains_len = 0;
744
745 consoles[i].cols = cols;
746 consoles[i].rows = rows;
747 consoles[i].ccaps = ccaps;
748 consoles[i].frontbuf =
749 chargrid_create(cols, rows, CHARGRID_FLAG_SHARED);
750
751 if (consoles[i].frontbuf == NULL) {
752 printf("%s: Unable to allocate frontbuffer %zu\n", NAME, i);
753 return false;
754 }
755
756 consoles[i].fbid = output_frontbuf_create(output_sess,
757 consoles[i].frontbuf);
758 if (consoles[i].fbid == 0) {
759 printf("%s: Unable to create frontbuffer %zu\n", NAME, i);
760 return false;
761 }
762
763 con_srvs_init(&consoles[i].srvs);
764 consoles[i].srvs.ops = &con_ops;
765 consoles[i].srvs.sarg = &consoles[i];
766
767 char vc[LOC_NAME_MAXLEN + 1];
768 snprintf(vc, LOC_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i);
769
770 if (loc_service_register(vc, &consoles[i].dsid) != EOK) {
771 printf("%s: Unable to register device %s\n", NAME, vc);
772 return false;
773 }
774 }
775
776 input_activate(input);
777 active = true;
778 cons_damage(active_console);
779 }
780
781 return true;
782}
783
784static void usage(char *name)
785{
786 printf("Usage: %s <input_dev> <output_dev>\n", name);
787}
788
789int main(int argc, char *argv[])
790{
791 if (argc < 3) {
792 usage(argv[0]);
793 return -1;
794 }
795
796 printf("%s: HelenOS Console service\n", NAME);
797
798 if (!console_srv_init(argv[1], argv[2]))
799 return -1;
800
801 printf("%s: Accepting connections\n", NAME);
802 task_retval(0);
803 async_manager();
804
805 /* Never reached */
806 return 0;
807}
808
809/** @}
810 */
Note: See TracBrowser for help on using the repository browser.