source: mainline/uspace/srv/hid/console/console.c@ 5bf76c1

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

improve button rendering and click detection

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