source: mainline/uspace/srv/hid/console/console.c@ e435537

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

cstyle

  • Property mode set to 100644
File size: 25.8 KB
Line 
1/*
2 * Copyright (c) 2011 Martin Decky
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 <async.h>
36#include <stdio.h>
37#include <adt/prodcons.h>
38#include <ipc/input.h>
39#include <ipc/console.h>
40#include <ipc/vfs.h>
41#include <errno.h>
42#include <str_error.h>
43#include <loc.h>
44#include <event.h>
45#include <io/keycode.h>
46#include <screenbuffer.h>
47#include <fb.h>
48#include <imgmap.h>
49#include <align.h>
50#include <malloc.h>
51#include <as.h>
52#include <fibril_synch.h>
53#include "images.h"
54#include "console.h"
55
56#define NAME "console"
57#define NAMESPACE "term"
58
59#define CONSOLE_TOP 66
60#define CONSOLE_MARGIN 12
61
62#define STATE_START 100
63#define STATE_TOP 8
64#define STATE_SPACE 4
65#define STATE_WIDTH 48
66#define STATE_HEIGHT 48
67
68typedef enum {
69 CONS_DISCONNECTED = 0,
70 CONS_DISCONNECTED_SELECTED,
71 CONS_SELECTED,
72 CONS_IDLE,
73 CONS_DATA,
74 CONS_KERNEL,
75 CONS_LAST
76} console_state_t;
77
78#define UTF8_CHAR_BUFFER_SIZE (STR_BOUNDS(1) + 1)
79
80typedef struct {
81 atomic_t refcnt; /**< Connection reference count */
82 prodcons_t input_pc; /**< Incoming keyboard events */
83 char char_remains[UTF8_CHAR_BUFFER_SIZE]; /**< Not yet sent bytes of last char event. */
84 size_t char_remains_len; /**< Number of not yet sent bytes. */
85
86 fibril_mutex_t mtx; /**< Lock protecting mutable fields */
87
88 size_t index; /**< Console index */
89 console_state_t state; /**< Console state */
90 service_id_t dsid; /**< Service handle */
91
92 vp_handle_t state_vp; /**< State icon viewport */
93 sysarg_t cols; /**< Number of columns */
94 sysarg_t rows; /**< Number of rows */
95 console_caps_t ccaps; /**< Console capabilities */
96
97 screenbuffer_t *frontbuf; /**< Front buffer */
98 frontbuf_handle_t fbid; /**< Front buffer handle */
99} console_t;
100
101typedef enum {
102 GRAPHICS_NONE = 0,
103 GRAPHICS_BASIC = 1,
104 GRAPHICS_FULL = 2
105} graphics_state_t;
106
107/** Current console state */
108static graphics_state_t graphics_state = GRAPHICS_NONE;
109
110/** State icons */
111static imagemap_handle_t state_icons[CONS_LAST];
112
113/** Session to the input server */
114static async_sess_t *input_sess;
115
116/** Session to the framebuffer server */
117static async_sess_t *fb_sess;
118
119/** Framebuffer resolution */
120static sysarg_t xres;
121static sysarg_t yres;
122
123/** Array of data for virtual consoles */
124static console_t consoles[CONSOLE_COUNT];
125
126/** Mutex for console switching */
127static FIBRIL_MUTEX_INITIALIZE(switch_mtx);
128
129static console_t *prev_console = &consoles[0];
130static console_t *active_console = &consoles[0];
131static console_t *kernel_console = &consoles[KERNEL_CONSOLE];
132
133static imgmap_t *logo_img;
134static imgmap_t *nameic_img;
135
136static imgmap_t *anim_1_img;
137static imgmap_t *anim_2_img;
138static imgmap_t *anim_3_img;
139static imgmap_t *anim_4_img;
140
141static imagemap_handle_t anim_1;
142static imagemap_handle_t anim_2;
143static imagemap_handle_t anim_3;
144static imagemap_handle_t anim_4;
145
146static sequence_handle_t anim_seq;
147
148static imgmap_t *cons_data_img;
149static imgmap_t *cons_dis_img;
150static imgmap_t *cons_dis_sel_img;
151static imgmap_t *cons_idle_img;
152static imgmap_t *cons_kernel_img;
153static imgmap_t *cons_sel_img;
154
155static vp_handle_t logo_vp;
156static imagemap_handle_t logo_handle;
157
158static vp_handle_t nameic_vp;
159static imagemap_handle_t nameic_handle;
160
161static vp_handle_t screen_vp;
162static vp_handle_t console_vp;
163
164struct {
165 sysarg_t x;
166 sysarg_t y;
167
168 sysarg_t btn_x;
169 sysarg_t btn_y;
170
171 bool pressed;
172} mouse;
173
174static void cons_redraw_state(console_t *cons)
175{
176 if (graphics_state == GRAPHICS_FULL) {
177 fibril_mutex_lock(&cons->mtx);
178
179 fb_vp_imagemap_damage(fb_sess, cons->state_vp,
180 state_icons[cons->state], 0, 0, STATE_WIDTH, STATE_HEIGHT);
181
182 if ((cons->state != CONS_DISCONNECTED) &&
183 (cons->state != CONS_KERNEL) &&
184 (cons->state != CONS_DISCONNECTED_SELECTED)) {
185 char data[5];
186 snprintf(data, 5, "%zu", cons->index + 1);
187
188 for (size_t i = 0; data[i] != 0; i++)
189 fb_vp_putchar(fb_sess, cons->state_vp, i + 2, 1, data[i]);
190 }
191
192 fibril_mutex_unlock(&cons->mtx);
193 }
194}
195
196static void cons_kernel_sequence_start(console_t *cons)
197{
198 if (graphics_state == GRAPHICS_FULL) {
199 fibril_mutex_lock(&cons->mtx);
200
201 fb_vp_sequence_start(fb_sess, cons->state_vp, anim_seq);
202 fb_vp_imagemap_damage(fb_sess, cons->state_vp,
203 state_icons[cons->state], 0, 0, STATE_WIDTH, STATE_HEIGHT);
204
205 fibril_mutex_unlock(&cons->mtx);
206 }
207}
208
209static void cons_update_state(console_t *cons, console_state_t state)
210{
211 bool update = false;
212
213 fibril_mutex_lock(&cons->mtx);
214
215 if (cons->state != state) {
216 cons->state = state;
217 update = true;
218 }
219
220 fibril_mutex_unlock(&cons->mtx);
221
222 if (update)
223 cons_redraw_state(cons);
224}
225
226static void cons_notify_data(console_t *cons)
227{
228 fibril_mutex_lock(&switch_mtx);
229
230 if (cons != active_console)
231 cons_update_state(cons, CONS_DATA);
232
233 fibril_mutex_unlock(&switch_mtx);
234}
235
236static void cons_notify_connect(console_t *cons)
237{
238 fibril_mutex_lock(&switch_mtx);
239
240 if (cons == active_console)
241 cons_update_state(cons, CONS_SELECTED);
242 else
243 cons_update_state(cons, CONS_IDLE);
244
245 fibril_mutex_unlock(&switch_mtx);
246}
247
248static void cons_notify_disconnect(console_t *cons)
249{
250 fibril_mutex_lock(&switch_mtx);
251
252 if (cons == active_console)
253 cons_update_state(cons, CONS_DISCONNECTED_SELECTED);
254 else
255 cons_update_state(cons, CONS_DISCONNECTED);
256
257 fibril_mutex_unlock(&switch_mtx);
258}
259
260static void cons_update(console_t *cons)
261{
262 fibril_mutex_lock(&switch_mtx);
263 fibril_mutex_lock(&cons->mtx);
264
265 if ((cons == active_console) && (active_console != kernel_console)) {
266 fb_vp_update(fb_sess, console_vp, cons->fbid);
267 fb_vp_cursor_update(fb_sess, console_vp, cons->fbid);
268 }
269
270 fibril_mutex_unlock(&cons->mtx);
271 fibril_mutex_unlock(&switch_mtx);
272}
273
274static void cons_update_cursor(console_t *cons)
275{
276 fibril_mutex_lock(&switch_mtx);
277 fibril_mutex_lock(&cons->mtx);
278
279 if ((cons == active_console) && (active_console != kernel_console))
280 fb_vp_cursor_update(fb_sess, console_vp, cons->fbid);
281
282 fibril_mutex_unlock(&cons->mtx);
283 fibril_mutex_unlock(&switch_mtx);
284}
285
286static void cons_clear(console_t *cons)
287{
288 fibril_mutex_lock(&cons->mtx);
289 screenbuffer_clear(cons->frontbuf);
290 fibril_mutex_unlock(&cons->mtx);
291
292 cons_update(cons);
293}
294
295static void cons_damage_all(console_t *cons)
296{
297 fibril_mutex_lock(&switch_mtx);
298 fibril_mutex_lock(&cons->mtx);
299
300 if ((cons == active_console) && (active_console != kernel_console)) {
301 fb_vp_damage(fb_sess, console_vp, cons->fbid, 0, 0, cons->cols,
302 cons->rows);
303 fb_vp_cursor_update(fb_sess, console_vp, cons->fbid);
304 }
305
306 fibril_mutex_unlock(&cons->mtx);
307 fibril_mutex_unlock(&switch_mtx);
308}
309
310static void cons_switch(console_t *cons)
311{
312 fibril_mutex_lock(&switch_mtx);
313
314 if (cons == active_console) {
315 fibril_mutex_unlock(&switch_mtx);
316 return;
317 }
318
319 if (cons == kernel_console) {
320 fb_yield(fb_sess);
321 if (!console_kcon()) {
322 fb_claim(fb_sess);
323 fibril_mutex_unlock(&switch_mtx);
324 return;
325 }
326 }
327
328 if (active_console == kernel_console)
329 fb_claim(fb_sess);
330
331 prev_console = active_console;
332 active_console = cons;
333
334 if (prev_console->state == CONS_DISCONNECTED_SELECTED)
335 cons_update_state(prev_console, CONS_DISCONNECTED);
336 else
337 cons_update_state(prev_console, CONS_IDLE);
338
339 if ((cons->state == CONS_DISCONNECTED) ||
340 (cons->state == CONS_DISCONNECTED_SELECTED))
341 cons_update_state(cons, CONS_DISCONNECTED_SELECTED);
342 else
343 cons_update_state(cons, CONS_SELECTED);
344
345 fibril_mutex_unlock(&switch_mtx);
346
347 cons_damage_all(cons);
348}
349
350static console_t *cons_get_active_uspace(void)
351{
352 fibril_mutex_lock(&switch_mtx);
353
354 console_t *active_uspace = active_console;
355 if (active_uspace == kernel_console) {
356 active_uspace = prev_console;
357 }
358 assert(active_uspace != kernel_console);
359
360 fibril_mutex_unlock(&switch_mtx);
361
362 return active_uspace;
363}
364
365static ssize_t limit(ssize_t val, ssize_t lo, ssize_t hi)
366{
367 if (val > hi)
368 return hi;
369
370 if (val < lo)
371 return lo;
372
373 return val;
374}
375
376static void cons_mouse_move(sysarg_t dx, sysarg_t dy)
377{
378 ssize_t sx = (ssize_t) dx;
379 ssize_t sy = (ssize_t) dy;
380
381 mouse.x = limit(mouse.x + sx, 0, xres);
382 mouse.y = limit(mouse.y + sy, 0, yres);
383
384 fb_pointer_update(fb_sess, mouse.x, mouse.y, true);
385}
386
387static console_t *cons_find_icon(sysarg_t x, sysarg_t y)
388{
389 sysarg_t status_start =
390 STATE_START + (xres - 800) / 2 + CONSOLE_MARGIN;
391
392 if ((y < STATE_TOP) || (y >= STATE_TOP + STATE_HEIGHT))
393 return NULL;
394
395 if (x < status_start)
396 return NULL;
397
398 if (x >= status_start + (STATE_WIDTH + STATE_SPACE) * CONSOLE_COUNT)
399 return NULL;
400
401 if (((x - status_start) % (STATE_WIDTH + STATE_SPACE)) >= STATE_WIDTH)
402 return NULL;
403
404 sysarg_t btn = (x - status_start) / (STATE_WIDTH + STATE_SPACE);
405
406 if (btn < CONSOLE_COUNT)
407 return consoles + btn;
408
409 return NULL;
410}
411
412/** Handle mouse click
413 *
414 * @param state Button state (true - pressed, false - depressed)
415 *
416 */
417static console_t *cons_mouse_button(bool state)
418{
419 if (graphics_state != GRAPHICS_FULL)
420 return NULL;
421
422 if (state) {
423 console_t *cons = cons_find_icon(mouse.x, mouse.y);
424 if (cons != NULL) {
425 mouse.btn_x = mouse.x;
426 mouse.btn_y = mouse.y;
427 mouse.pressed = true;
428 }
429
430 return NULL;
431 }
432
433 if ((!state) && (!mouse.pressed))
434 return NULL;
435
436 console_t *cons = cons_find_icon(mouse.x, mouse.y);
437 if (cons == cons_find_icon(mouse.btn_x, mouse.btn_y))
438 return cons;
439
440 mouse.pressed = false;
441 return NULL;
442}
443
444static void input_events(ipc_callid_t iid, ipc_call_t *icall, void *arg)
445{
446 /* Ignore parameters, the connection is already opened */
447 while (true) {
448 ipc_call_t call;
449 ipc_callid_t callid = async_get_call(&call);
450
451 if (!IPC_GET_IMETHOD(call)) {
452 /* TODO: Handle hangup */
453 async_hangup(input_sess);
454 return;
455 }
456
457 kbd_event_type_t type;
458 keycode_t key;
459 keymod_t mods;
460 wchar_t c;
461
462 switch (IPC_GET_IMETHOD(call)) {
463 case INPUT_EVENT_KEY:
464 type = IPC_GET_ARG1(call);
465 key = IPC_GET_ARG2(call);
466 mods = IPC_GET_ARG3(call);
467 c = IPC_GET_ARG4(call);
468
469 if ((key >= KC_F1) && (key < KC_F1 + CONSOLE_COUNT) &&
470 ((mods & KM_CTRL) == 0))
471 cons_switch(&consoles[key - KC_F1]);
472 else {
473 /* Got key press/release event */
474 kbd_event_t *event =
475 (kbd_event_t *) malloc(sizeof(kbd_event_t));
476 if (event == NULL) {
477 async_answer_0(callid, ENOMEM);
478 break;
479 }
480
481 link_initialize(&event->link);
482 event->type = type;
483 event->key = key;
484 event->mods = mods;
485 event->c = c;
486
487 /*
488 * Kernel console does not read events
489 * from us, so we will redirect them
490 * to the (last) active userspace console
491 * if necessary.
492 */
493 console_t *target_console = cons_get_active_uspace();
494
495 prodcons_produce(&target_console->input_pc,
496 &event->link);
497 }
498
499 async_answer_0(callid, EOK);
500 break;
501 case INPUT_EVENT_MOVE:
502 cons_mouse_move(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
503 async_answer_0(callid, EOK);
504 break;
505 case INPUT_EVENT_BUTTON:
506 /* Got pointer button press/release event */
507 if (IPC_GET_ARG1(call) == 1) {
508 console_t *cons =
509 cons_mouse_button((bool) IPC_GET_ARG2(call));
510 if (cons != NULL)
511 cons_switch(cons);
512 }
513 async_answer_0(callid, EOK);
514 break;
515 default:
516 async_answer_0(callid, EINVAL);
517 }
518 }
519}
520
521/** Process a character from the client (TTY emulation). */
522static void cons_write_char(console_t *cons, wchar_t ch)
523{
524 sysarg_t updated = 0;
525
526 fibril_mutex_lock(&cons->mtx);
527
528 switch (ch) {
529 case '\n':
530 updated = screenbuffer_newline(cons->frontbuf);
531 break;
532 case '\r':
533 break;
534 case '\t':
535 updated = screenbuffer_tabstop(cons->frontbuf, 8);
536 break;
537 case '\b':
538 updated = screenbuffer_backspace(cons->frontbuf);
539 break;
540 default:
541 updated = screenbuffer_putchar(cons->frontbuf, ch, true);
542 }
543
544 fibril_mutex_unlock(&cons->mtx);
545
546 if (updated > 1)
547 cons_update(cons);
548}
549
550static void cons_set_cursor(console_t *cons, sysarg_t col, sysarg_t row)
551{
552 fibril_mutex_lock(&cons->mtx);
553 screenbuffer_set_cursor(cons->frontbuf, col, row);
554 fibril_mutex_unlock(&cons->mtx);
555
556 cons_update_cursor(cons);
557}
558
559static void cons_set_cursor_visibility(console_t *cons, bool visible)
560{
561 fibril_mutex_lock(&cons->mtx);
562 screenbuffer_set_cursor_visibility(cons->frontbuf, visible);
563 fibril_mutex_unlock(&cons->mtx);
564
565 cons_update_cursor(cons);
566}
567
568static void cons_get_cursor(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
569{
570 sysarg_t col;
571 sysarg_t row;
572
573 fibril_mutex_lock(&cons->mtx);
574 screenbuffer_get_cursor(cons->frontbuf, &col, &row);
575 fibril_mutex_unlock(&cons->mtx);
576
577 async_answer_2(iid, EOK, col, row);
578}
579
580static void cons_write(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
581{
582 void *buf;
583 size_t size;
584 int rc = async_data_write_accept(&buf, false, 0, 0, 0, &size);
585
586 if (rc != EOK) {
587 async_answer_0(iid, rc);
588 return;
589 }
590
591 size_t off = 0;
592 while (off < size)
593 cons_write_char(cons, str_decode(buf, &off, size));
594
595 async_answer_1(iid, EOK, size);
596 free(buf);
597
598 cons_notify_data(cons);
599}
600
601static void cons_read(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
602{
603 ipc_callid_t callid;
604 size_t size;
605 if (!async_data_read_receive(&callid, &size)) {
606 async_answer_0(callid, EINVAL);
607 async_answer_0(iid, EINVAL);
608 return;
609 }
610
611 char *buf = (char *) malloc(size);
612 if (buf == NULL) {
613 async_answer_0(callid, ENOMEM);
614 async_answer_0(iid, ENOMEM);
615 return;
616 }
617
618 size_t pos = 0;
619
620 /*
621 * Read input from keyboard and copy it to the buffer.
622 * We need to handle situation when wchar is split by 2 following
623 * reads.
624 */
625 while (pos < size) {
626 /* Copy to the buffer remaining characters. */
627 while ((pos < size) && (cons->char_remains_len > 0)) {
628 buf[pos] = cons->char_remains[0];
629 pos++;
630
631 /* Unshift the array. */
632 for (size_t i = 1; i < cons->char_remains_len; i++)
633 cons->char_remains[i - 1] = cons->char_remains[i];
634
635 cons->char_remains_len--;
636 }
637
638 /* Still not enough? Then get another key from the queue. */
639 if (pos < size) {
640 link_t *link = prodcons_consume(&cons->input_pc);
641 kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
642
643 /* Accept key presses of printable chars only. */
644 if ((event->type == KEY_PRESS) && (event->c != 0)) {
645 wchar_t tmp[2] = { event->c, 0 };
646 wstr_to_str(cons->char_remains, UTF8_CHAR_BUFFER_SIZE, tmp);
647 cons->char_remains_len = str_size(cons->char_remains);
648 }
649
650 free(event);
651 }
652 }
653
654 (void) async_data_read_finalize(callid, buf, size);
655 async_answer_1(iid, EOK, size);
656 free(buf);
657}
658
659static void cons_set_style(console_t *cons, console_style_t style)
660{
661 fibril_mutex_lock(&cons->mtx);
662 screenbuffer_set_style(cons->frontbuf, style);
663 fibril_mutex_unlock(&cons->mtx);
664}
665
666static void cons_set_color(console_t *cons, console_color_t bgcolor,
667 console_color_t fgcolor, console_color_attr_t attr)
668{
669 fibril_mutex_lock(&cons->mtx);
670 screenbuffer_set_color(cons->frontbuf, bgcolor, fgcolor, attr);
671 fibril_mutex_unlock(&cons->mtx);
672}
673
674static void cons_set_rgb_color(console_t *cons, pixel_t bgcolor,
675 pixel_t fgcolor)
676{
677 fibril_mutex_lock(&cons->mtx);
678 screenbuffer_set_rgb_color(cons->frontbuf, bgcolor, fgcolor);
679 fibril_mutex_unlock(&cons->mtx);
680}
681
682static void cons_get_event(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
683{
684 link_t *link = prodcons_consume(&cons->input_pc);
685 kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
686
687 async_answer_4(iid, EOK, event->type, event->key, event->mods, event->c);
688 free(event);
689}
690
691static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
692{
693 console_t *cons = NULL;
694
695 for (size_t i = 0; i < CONSOLE_COUNT; i++) {
696 if (i == KERNEL_CONSOLE)
697 continue;
698
699 if (consoles[i].dsid == (service_id_t) IPC_GET_ARG1(*icall)) {
700 cons = &consoles[i];
701 break;
702 }
703 }
704
705 if (cons == NULL) {
706 async_answer_0(iid, ENOENT);
707 return;
708 }
709
710 if (atomic_postinc(&cons->refcnt) == 0) {
711 cons_set_cursor_visibility(cons, true);
712 cons_notify_connect(cons);
713 }
714
715 /* Accept the connection */
716 async_answer_0(iid, EOK);
717
718 while (true) {
719 ipc_call_t call;
720 ipc_callid_t callid = async_get_call(&call);
721
722 if (!IPC_GET_IMETHOD(call)) {
723 if (atomic_postdec(&cons->refcnt) == 1)
724 cons_notify_disconnect(cons);
725
726 return;
727 }
728
729 switch (IPC_GET_IMETHOD(call)) {
730 case VFS_OUT_READ:
731 cons_read(cons, callid, &call);
732 break;
733 case VFS_OUT_WRITE:
734 cons_write(cons, callid, &call);
735 break;
736 case VFS_OUT_SYNC:
737 cons_update(cons);
738 async_answer_0(callid, EOK);
739 break;
740 case CONSOLE_CLEAR:
741 cons_clear(cons);
742 async_answer_0(callid, EOK);
743 break;
744 case CONSOLE_GOTO:
745 cons_set_cursor(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
746 async_answer_0(callid, EOK);
747 break;
748 case CONSOLE_GET_POS:
749 cons_get_cursor(cons, callid, &call);
750 break;
751 case CONSOLE_GET_SIZE:
752 async_answer_2(callid, EOK, cons->cols, cons->rows);
753 break;
754 case CONSOLE_GET_COLOR_CAP:
755 async_answer_1(callid, EOK, cons->ccaps);
756 break;
757 case CONSOLE_SET_STYLE:
758 cons_set_style(cons, IPC_GET_ARG1(call));
759 async_answer_0(callid, EOK);
760 break;
761 case CONSOLE_SET_COLOR:
762 cons_set_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call),
763 IPC_GET_ARG3(call));
764 async_answer_0(callid, EOK);
765 break;
766 case CONSOLE_SET_RGB_COLOR:
767 cons_set_rgb_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
768 async_answer_0(callid, EOK);
769 break;
770 case CONSOLE_CURSOR_VISIBILITY:
771 cons_set_cursor_visibility(cons, IPC_GET_ARG1(call));
772 async_answer_0(callid, EOK);
773 break;
774 case CONSOLE_GET_EVENT:
775 cons_get_event(cons, callid, &call);
776 break;
777 default:
778 async_answer_0(callid, EINVAL);
779 }
780 }
781}
782
783static async_sess_t *input_connect(const char *svc)
784{
785 async_sess_t *sess;
786 service_id_t dsid;
787
788 int rc = loc_service_get_id(svc, &dsid, 0);
789 if (rc == EOK) {
790 sess = loc_service_connect(EXCHANGE_ATOMIC, dsid, 0);
791 if (sess == NULL) {
792 printf("%s: Unable to connect to input service %s\n", NAME,
793 svc);
794 return NULL;
795 }
796 } else
797 return NULL;
798
799 async_exch_t *exch = async_exchange_begin(sess);
800 rc = async_connect_to_me(exch, 0, 0, 0, input_events, NULL);
801 async_exchange_end(exch);
802
803 if (rc != EOK) {
804 async_hangup(sess);
805 printf("%s: Unable to create callback connection to service %s (%s)\n",
806 NAME, svc, str_error(rc));
807 return NULL;
808 }
809
810 return sess;
811}
812
813static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
814{
815 cons_switch(prev_console);
816}
817
818static async_sess_t *fb_connect(const char *svc)
819{
820 async_sess_t *sess;
821 service_id_t dsid;
822
823 int rc = loc_service_get_id(svc, &dsid, 0);
824 if (rc == EOK) {
825 sess = loc_service_connect(EXCHANGE_SERIALIZE, dsid, 0);
826 if (sess == NULL) {
827 printf("%s: Unable to connect to framebuffer service %s\n",
828 NAME, svc);
829 return NULL;
830 }
831 } else
832 return NULL;
833
834 return sess;
835}
836
837static bool console_srv_init(char *input_svc, char *fb_svc)
838{
839 /* Avoid double initialization */
840 if (graphics_state != GRAPHICS_NONE)
841 return false;
842
843 /* Connect to input service */
844 input_sess = input_connect(input_svc);
845 if (input_sess == NULL)
846 return false;
847
848 /* Connect to framebuffer service */
849 fb_sess = fb_connect(fb_svc);
850 if (fb_sess == NULL)
851 return false;
852
853 /* Register server */
854 async_set_client_connection(client_connection);
855 int rc = loc_server_register(NAME);
856 if (rc != EOK) {
857 printf("%s: Unable to register server (%s)\n", NAME,
858 str_error(rc));
859 return false;
860 }
861
862 fb_get_resolution(fb_sess, &xres, &yres);
863
864 /* Initialize the screen */
865 screen_vp = fb_vp_create(fb_sess, 0, 0, xres, yres);
866
867 if ((xres >= 800) && (yres >= 600)) {
868 logo_vp = fb_vp_create(fb_sess, xres - 66, 2, 64, 60);
869 logo_img = imgmap_decode_tga((void *) helenos_tga,
870 helenos_tga_size, IMGMAP_FLAG_SHARED);
871 logo_handle = fb_imagemap_create(fb_sess, logo_img);
872
873 nameic_vp = fb_vp_create(fb_sess, 5, 17, 100, 26);
874 nameic_img = imgmap_decode_tga((void *) nameic_tga,
875 nameic_tga_size, IMGMAP_FLAG_SHARED);
876 nameic_handle = fb_imagemap_create(fb_sess, nameic_img);
877
878 cons_data_img = imgmap_decode_tga((void *) cons_data_tga,
879 cons_data_tga_size, IMGMAP_FLAG_SHARED);
880 cons_dis_img = imgmap_decode_tga((void *) cons_dis_tga,
881 cons_dis_tga_size, IMGMAP_FLAG_SHARED);
882 cons_dis_sel_img = imgmap_decode_tga((void *) cons_dis_sel_tga,
883 cons_dis_sel_tga_size, IMGMAP_FLAG_SHARED);
884 cons_idle_img = imgmap_decode_tga((void *) cons_idle_tga,
885 cons_idle_tga_size, IMGMAP_FLAG_SHARED);
886 cons_kernel_img = imgmap_decode_tga((void *) cons_kernel_tga,
887 cons_kernel_tga_size, IMGMAP_FLAG_SHARED);
888 cons_sel_img = imgmap_decode_tga((void *) cons_sel_tga,
889 cons_sel_tga_size, IMGMAP_FLAG_SHARED);
890
891 state_icons[CONS_DISCONNECTED] =
892 fb_imagemap_create(fb_sess, cons_dis_img);
893 state_icons[CONS_DISCONNECTED_SELECTED] =
894 fb_imagemap_create(fb_sess, cons_dis_sel_img);
895 state_icons[CONS_SELECTED] =
896 fb_imagemap_create(fb_sess, cons_sel_img);
897 state_icons[CONS_IDLE] =
898 fb_imagemap_create(fb_sess, cons_idle_img);
899 state_icons[CONS_DATA] =
900 fb_imagemap_create(fb_sess, cons_data_img);
901 state_icons[CONS_KERNEL] =
902 fb_imagemap_create(fb_sess, cons_kernel_img);
903
904 anim_1_img = imgmap_decode_tga((void *) anim_1_tga,
905 anim_1_tga_size, IMGMAP_FLAG_SHARED);
906 anim_2_img = imgmap_decode_tga((void *) anim_2_tga,
907 anim_2_tga_size, IMGMAP_FLAG_SHARED);
908 anim_3_img = imgmap_decode_tga((void *) anim_3_tga,
909 anim_3_tga_size, IMGMAP_FLAG_SHARED);
910 anim_4_img = imgmap_decode_tga((void *) anim_4_tga,
911 anim_4_tga_size, IMGMAP_FLAG_SHARED);
912
913 anim_1 = fb_imagemap_create(fb_sess, anim_1_img);
914 anim_2 = fb_imagemap_create(fb_sess, anim_2_img);
915 anim_3 = fb_imagemap_create(fb_sess, anim_3_img);
916 anim_4 = fb_imagemap_create(fb_sess, anim_4_img);
917
918 anim_seq = fb_sequence_create(fb_sess);
919 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_1);
920 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_2);
921 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_3);
922 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_4);
923
924 console_vp = fb_vp_create(fb_sess, CONSOLE_MARGIN, CONSOLE_TOP,
925 xres - 2 * CONSOLE_MARGIN, yres - (CONSOLE_TOP + CONSOLE_MARGIN));
926
927 fb_vp_clear(fb_sess, screen_vp);
928 fb_vp_imagemap_damage(fb_sess, logo_vp, logo_handle,
929 0, 0, 64, 60);
930 fb_vp_imagemap_damage(fb_sess, nameic_vp, nameic_handle,
931 0, 0, 100, 26);
932
933 graphics_state = GRAPHICS_FULL;
934 } else {
935 console_vp = screen_vp;
936 graphics_state = GRAPHICS_BASIC;
937 }
938
939 fb_vp_set_style(fb_sess, console_vp, STYLE_NORMAL);
940 fb_vp_clear(fb_sess, console_vp);
941
942 sysarg_t cols;
943 sysarg_t rows;
944 fb_vp_get_dimensions(fb_sess, console_vp, &cols, &rows);
945
946 console_caps_t ccaps;
947 fb_vp_get_caps(fb_sess, console_vp, &ccaps);
948
949 mouse.x = xres / 2;
950 mouse.y = yres / 2;
951 mouse.pressed = false;
952
953 /* Inititalize consoles */
954 for (size_t i = 0; i < CONSOLE_COUNT; i++) {
955 consoles[i].index = i;
956 atomic_set(&consoles[i].refcnt, 0);
957 fibril_mutex_initialize(&consoles[i].mtx);
958 prodcons_initialize(&consoles[i].input_pc);
959 consoles[i].char_remains_len = 0;
960
961 if (graphics_state == GRAPHICS_FULL) {
962 /* Create state buttons */
963 consoles[i].state_vp =
964 fb_vp_create(fb_sess, STATE_START + (xres - 800) / 2 +
965 CONSOLE_MARGIN + i * (STATE_WIDTH + STATE_SPACE),
966 STATE_TOP, STATE_WIDTH, STATE_HEIGHT);
967 }
968
969 if (i == KERNEL_CONSOLE) {
970 consoles[i].state = CONS_KERNEL;
971 cons_redraw_state(&consoles[i]);
972 cons_kernel_sequence_start(&consoles[i]);
973 continue;
974 }
975
976 if (i == 0)
977 consoles[i].state = CONS_DISCONNECTED_SELECTED;
978 else
979 consoles[i].state = CONS_DISCONNECTED;
980
981 consoles[i].cols = cols;
982 consoles[i].rows = rows;
983 consoles[i].ccaps = ccaps;
984 consoles[i].frontbuf =
985 screenbuffer_create(cols, rows, SCREENBUFFER_FLAG_SHARED);
986
987 if (consoles[i].frontbuf == NULL) {
988 printf("%s: Unable to allocate frontbuffer %zu\n", NAME, i);
989 return false;
990 }
991
992 consoles[i].fbid = fb_frontbuf_create(fb_sess, consoles[i].frontbuf);
993 if (consoles[i].fbid == 0) {
994 printf("%s: Unable to create frontbuffer %zu\n", NAME, i);
995 return false;
996 }
997
998 cons_redraw_state(&consoles[i]);
999
1000 char vc[LOC_NAME_MAXLEN + 1];
1001 snprintf(vc, LOC_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i);
1002
1003 if (loc_service_register(vc, &consoles[i].dsid) != EOK) {
1004 printf("%s: Unable to register device %s\n", NAME, vc);
1005 return false;
1006 }
1007 }
1008
1009 /* Receive kernel notifications */
1010 async_set_interrupt_received(interrupt_received);
1011 rc = event_subscribe(EVENT_KCONSOLE, 0);
1012 if (rc != EOK)
1013 printf("%s: Failed to register kconsole notifications (%s)\n",
1014 NAME, str_error(rc));
1015
1016 return true;
1017}
1018
1019static void usage(void)
1020{
1021 printf("Usage: console <input_dev> <framebuffer_dev>\n");
1022}
1023
1024int main(int argc, char *argv[])
1025{
1026 if (argc < 3) {
1027 usage();
1028 return -1;
1029 }
1030
1031 printf("%s: HelenOS Console service\n", NAME);
1032
1033 if (!console_srv_init(argv[1], argv[2]))
1034 return -1;
1035
1036 printf("%s: Accepting connections\n", NAME);
1037 task_retval(0);
1038 async_manager();
1039
1040 return 0;
1041}
1042
1043/** @}
1044 */
Note: See TracBrowser for help on using the repository browser.