source: mainline/uspace/srv/hid/console/console.c@ 1924bd43

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1924bd43 was 024fcc5, checked in by Vojtech Horky <vojtechhorky@…>, 14 years ago

Do not discard input events when in kcon (#377)

  • Property mode set to 100644
File size: 24.7 KB
RevLine 
[51c1b003]1/*
[7c014d1]2 * Copyright (c) 2011 Martin Decky
[51c1b003]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 */
[ce5bcb4]28
[231a60a]29/** @addtogroup console
[1601f3c]30 * @{
[ce5bcb4]31 */
32/** @file
33 */
34
[7c014d1]35#include <async.h>
36#include <stdio.h>
37#include <adt/prodcons.h>
[5f88293]38#include <ipc/input.h>
[7c014d1]39#include <ipc/console.h>
40#include <ipc/vfs.h>
[51c1b003]41#include <errno.h>
[30db06c]42#include <str_error.h>
[15f3c3f]43#include <loc.h>
[7c014d1]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>
[1e4cada]52#include <fibril_synch.h>
[7c014d1]53#include "images.h"
[9805cde]54#include "console.h"
[369a5f8]55
[1313ee9]56#define NAME "console"
57#define NAMESPACE "term"
[79ae36dd]58
[7c014d1]59#define CONSOLE_TOP 66
60#define CONSOLE_MARGIN 12
61
[cccc091]62#define STATE_START 100
[7c014d1]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;
[3993b3d]77
[79460ae]78typedef struct {
[7c014d1]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 */
[424cd43]95} console_t;
[79460ae]96
[7c014d1]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
[1601f3c]119/** Array of data for virtual consoles */
[424cd43]120static console_t consoles[CONSOLE_COUNT];
121
[7c014d1]122/** Mutex for console switching */
123static FIBRIL_MUTEX_INITIALIZE(switch_mtx);
124
[424cd43]125static console_t *prev_console = &consoles[0];
[7c014d1]126static console_t *active_console = &consoles[0];
[424cd43]127static console_t *kernel_console = &consoles[KERNEL_CONSOLE];
[1601f3c]128
[7c014d1]129static imgmap_t *logo_img;
130static imgmap_t *nameic_img;
[d2cc7e1]131
[7c014d1]132static imgmap_t *anim_1_img;
133static imgmap_t *anim_2_img;
134static imgmap_t *anim_3_img;
135static imgmap_t *anim_4_img;
[d2cc7e1]136
[7c014d1]137static imagemap_handle_t anim_1;
138static imagemap_handle_t anim_2;
139static imagemap_handle_t anim_3;
140static imagemap_handle_t anim_4;
[429acb9]141
[7c014d1]142static sequence_handle_t anim_seq;
[a40dea3]143
[7c014d1]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;
[a40dea3]150
[7c014d1]151static vp_handle_t logo_vp;
152static imagemap_handle_t logo_handle;
[a40dea3]153
[7c014d1]154static vp_handle_t nameic_vp;
155static imagemap_handle_t nameic_handle;
[8c6337d]156
[7c014d1]157static vp_handle_t screen_vp;
158static vp_handle_t console_vp;
[424cd43]159
[7c014d1]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;
[429acb9]169
[7c014d1]170static void cons_redraw_state(console_t *cons)
[10270a8]171{
[7c014d1]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 }
[10270a8]190}
191
[7c014d1]192static void cons_kernel_sequence_start(console_t *cons)
[10270a8]193{
[7c014d1]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 }
[10270a8]203}
204
[7c014d1]205static void cons_update_state(console_t *cons, console_state_t state)
[ccd1a14]206{
[7c014d1]207 bool update = false;
208
209 fibril_mutex_lock(&cons->mtx);
210
211 if (cons->state != state) {
212 cons->state = state;
213 update = true;
[a40dea3]214 }
215
[7c014d1]216 fibril_mutex_unlock(&cons->mtx);
217
218 if (update)
219 cons_redraw_state(cons);
[ccd1a14]220}
221
[7c014d1]222static void cons_notify_data(console_t *cons)
[ccd1a14]223{
[7c014d1]224 fibril_mutex_lock(&switch_mtx);
[a40dea3]225
[7c014d1]226 if (cons != active_console)
227 cons_update_state(cons, CONS_DATA);
228
229 fibril_mutex_unlock(&switch_mtx);
[ccd1a14]230}
231
[7c014d1]232static void cons_notify_connect(console_t *cons)
[429acb9]233{
[7c014d1]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);
[429acb9]242}
243
[7c014d1]244static void cons_notify_disconnect(console_t *cons)
[429acb9]245{
[7c014d1]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);
[9805cde]254}
255
[7c014d1]256static void cons_update(console_t *cons)
[9805cde]257{
[7c014d1]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);
[9805cde]268}
269
[7c014d1]270static void cons_update_cursor(console_t *cons)
[9805cde]271{
[7c014d1]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);
[429acb9]280}
281
[7c014d1]282static void cons_clear(console_t *cons)
[50cfa6c]283{
[7c014d1]284 fibril_mutex_lock(&cons->mtx);
285 screenbuffer_clear(cons->frontbuf);
286 fibril_mutex_unlock(&cons->mtx);
[9f1362d4]287
[7c014d1]288 cons_update(cons);
[50cfa6c]289}
290
[7c014d1]291static void cons_damage_all(console_t *cons)
[d2cc7e1]292{
[7c014d1]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);
[dc033a1]300 }
[7c014d1]301
302 fibril_mutex_unlock(&cons->mtx);
303 fibril_mutex_unlock(&switch_mtx);
[d2cc7e1]304}
305
[7c014d1]306static void cons_switch(console_t *cons)
[d2cc7e1]307{
[7c014d1]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 }
[d2cc7e1]322 }
[7c014d1]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);
[d2cc7e1]344}
345
[024fcc5]346static console_t *cons_get_active_uspace(void)
347{
348 fibril_mutex_lock(&switch_mtx);
349
350 console_t *active_uspace = active_console;
351 if (active_uspace == kernel_console) {
352 active_uspace = prev_console;
353 }
354 assert(active_uspace != kernel_console);
355
356 fibril_mutex_unlock(&switch_mtx);
357
358 return active_uspace;
359}
360
[7c014d1]361static ssize_t limit(ssize_t val, ssize_t lo, ssize_t hi)
[429acb9]362{
[7c014d1]363 if (val > hi)
364 return hi;
[1601f3c]365
[7c014d1]366 if (val < lo)
367 return lo;
[1601f3c]368
[7c014d1]369 return val;
[429acb9]370}
371
[7c014d1]372static void cons_mouse_move(sysarg_t dx, sysarg_t dy)
[dc033a1]373{
[7c014d1]374 ssize_t sx = (ssize_t) dx;
375 ssize_t sy = (ssize_t) dy;
376
377 mouse.x = limit(mouse.x + sx, 0, xres);
378 mouse.y = limit(mouse.y + sy, 0, yres);
379
380 fb_pointer_update(fb_sess, mouse.x, mouse.y, true);
[dc033a1]381}
382
[7c014d1]383static console_t *cons_find_icon(sysarg_t x, sysarg_t y)
[10569b1]384{
[cccc091]385 sysarg_t status_start =
386 STATE_START + (xres - 800) / 2 + CONSOLE_MARGIN;
[9f1362d4]387
[7c014d1]388 if ((y < STATE_TOP) || (y >= STATE_TOP + STATE_HEIGHT))
389 return NULL;
[1601f3c]390
[7c014d1]391 if (x < status_start)
392 return NULL;
[10569b1]393
[7c014d1]394 if (x >= status_start + (STATE_WIDTH + STATE_SPACE) * CONSOLE_COUNT)
395 return NULL;
396
[cccc091]397 if (((x - status_start) % (STATE_WIDTH + STATE_SPACE)) >= STATE_WIDTH)
[7c014d1]398 return NULL;
399
400 sysarg_t btn = (x - status_start) / (STATE_WIDTH + STATE_SPACE);
401
402 if (btn < CONSOLE_COUNT)
403 return consoles + btn;
[9f1362d4]404
[7c014d1]405 return NULL;
[10569b1]406}
407
[7c014d1]408/** Handle mouse click
409 *
410 * @param state Button state (true - pressed, false - depressed)
411 *
412 */
413static console_t *cons_mouse_button(bool state)
[429acb9]414{
[7c014d1]415 if (graphics_state != GRAPHICS_FULL)
416 return NULL;
[6d5005c]417
[7c014d1]418 if (state) {
419 console_t *cons = cons_find_icon(mouse.x, mouse.y);
420 if (cons != NULL) {
421 mouse.btn_x = mouse.x;
422 mouse.btn_y = mouse.y;
423 mouse.pressed = true;
[10270a8]424 }
[76fca31]425
[7c014d1]426 return NULL;
[429acb9]427 }
[7c014d1]428
429 if ((!state) && (!mouse.pressed))
430 return NULL;
431
432 console_t *cons = cons_find_icon(mouse.x, mouse.y);
433 if (cons == cons_find_icon(mouse.btn_x, mouse.btn_y))
434 return cons;
435
436 mouse.pressed = false;
437 return NULL;
[429acb9]438}
[10569b1]439
[854eddd6]440static void input_events(ipc_callid_t iid, ipc_call_t *icall, void *arg)
[51c1b003]441{
[424cd43]442 /* Ignore parameters, the connection is already opened */
[1601f3c]443 while (true) {
[424cd43]444 ipc_call_t call;
445 ipc_callid_t callid = async_get_call(&call);
446
[79ae36dd]447 if (!IPC_GET_IMETHOD(call)) {
[eaf34f7]448 /* TODO: Handle hangup */
[a40dea3]449 async_hangup(input_sess);
[eaf34f7]450 return;
[79ae36dd]451 }
452
[7c014d1]453 kbd_event_type_t type;
454 keycode_t key;
455 keymod_t mods;
456 wchar_t c;
457
[79ae36dd]458 switch (IPC_GET_IMETHOD(call)) {
[854eddd6]459 case INPUT_EVENT_KEY:
[7c014d1]460 type = IPC_GET_ARG1(call);
461 key = IPC_GET_ARG2(call);
462 mods = IPC_GET_ARG3(call);
463 c = IPC_GET_ARG4(call);
[fa09449]464
[7c014d1]465 if ((key >= KC_F1) && (key < KC_F1 + CONSOLE_COUNT) &&
466 ((mods & KM_CTRL) == 0))
467 cons_switch(&consoles[key - KC_F1]);
468 else {
469 /* Got key press/release event */
470 kbd_event_t *event =
471 (kbd_event_t *) malloc(sizeof(kbd_event_t));
472 if (event == NULL) {
473 async_answer_0(callid, ENOMEM);
474 break;
475 }
476
477 link_initialize(&event->link);
478 event->type = type;
479 event->key = key;
480 event->mods = mods;
481 event->c = c;
482
[024fcc5]483 /* Kernel console does not read events
484 * from us, so we will redirect them
485 * to the (last) active userspace console
486 * if necessary.
487 */
488 console_t *target_console = cons_get_active_uspace();
489
490 prodcons_produce(&target_console->input_pc,
491 &event->link);
[eaf34f7]492 }
[cf28036c]493
[7c014d1]494 async_answer_0(callid, EOK);
[eaf34f7]495 break;
[854eddd6]496 case INPUT_EVENT_MOVE:
[7c014d1]497 cons_mouse_move(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
498 async_answer_0(callid, EOK);
[854eddd6]499 break;
500 case INPUT_EVENT_BUTTON:
501 /* Got pointer button press/release event */
[9f1362d4]502 if (IPC_GET_ARG1(call) == 1) {
[7c014d1]503 console_t *cons =
504 cons_mouse_button((bool) IPC_GET_ARG2(call));
505 if (cons != NULL)
506 cons_switch(cons);
[9f51afc]507 }
[7c014d1]508 async_answer_0(callid, EOK);
[9f51afc]509 break;
510 default:
[7c014d1]511 async_answer_0(callid, EINVAL);
[9f51afc]512 }
[7c014d1]513 }
514}
[1875a0c]515
[7c014d1]516/** Process a character from the client (TTY emulation). */
517static void cons_write_char(console_t *cons, wchar_t ch)
518{
519 sysarg_t updated = 0;
520
521 fibril_mutex_lock(&cons->mtx);
522
523 switch (ch) {
524 case '\n':
525 updated = screenbuffer_newline(cons->frontbuf);
526 break;
527 case '\r':
528 break;
529 case '\t':
530 updated = screenbuffer_tabstop(cons->frontbuf, 8);
531 break;
532 case '\b':
533 updated = screenbuffer_backspace(cons->frontbuf);
534 break;
535 default:
536 updated = screenbuffer_putchar(cons->frontbuf, ch, true);
[9f51afc]537 }
[7c014d1]538
539 fibril_mutex_unlock(&cons->mtx);
540
541 if (updated > 1)
542 cons_update(cons);
543}
544
545static void cons_set_cursor(console_t *cons, sysarg_t col, sysarg_t row)
546{
547 fibril_mutex_lock(&cons->mtx);
548 screenbuffer_set_cursor(cons->frontbuf, col, row);
549 fibril_mutex_unlock(&cons->mtx);
550
551 cons_update_cursor(cons);
552}
553
554static void cons_set_cursor_visibility(console_t *cons, bool visible)
555{
556 fibril_mutex_lock(&cons->mtx);
557 screenbuffer_set_cursor_visibility(cons->frontbuf, visible);
558 fibril_mutex_unlock(&cons->mtx);
559
560 cons_update_cursor(cons);
561}
562
563static void cons_get_cursor(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
564{
565 sysarg_t col;
566 sysarg_t row;
567
568 fibril_mutex_lock(&cons->mtx);
569 screenbuffer_get_cursor(cons->frontbuf, &col, &row);
570 fibril_mutex_unlock(&cons->mtx);
571
572 async_answer_2(iid, EOK, col, row);
[9f51afc]573}
574
[7c014d1]575static void cons_write(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
[d2cc7e1]576{
[472c09d]577 void *buf;
[171f9a1]578 size_t size;
[eda925a]579 int rc = async_data_write_accept(&buf, false, 0, 0, 0, &size);
[1601f3c]580
[472c09d]581 if (rc != EOK) {
[7c014d1]582 async_answer_0(iid, rc);
[424cd43]583 return;
584 }
[1601f3c]585
[424cd43]586 size_t off = 0;
[7c014d1]587 while (off < size)
588 cons_write_char(cons, str_decode(buf, &off, size));
[424cd43]589
[7c014d1]590 async_answer_1(iid, EOK, size);
[424cd43]591 free(buf);
[7c014d1]592
593 cons_notify_data(cons);
[424cd43]594}
595
[7c014d1]596static void cons_read(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
[424cd43]597{
598 ipc_callid_t callid;
599 size_t size;
[0da4e41]600 if (!async_data_read_receive(&callid, &size)) {
[ffa2c8ef]601 async_answer_0(callid, EINVAL);
[7c014d1]602 async_answer_0(iid, EINVAL);
[424cd43]603 return;
604 }
605
606 char *buf = (char *) malloc(size);
607 if (buf == NULL) {
[ffa2c8ef]608 async_answer_0(callid, ENOMEM);
[7c014d1]609 async_answer_0(iid, ENOMEM);
[424cd43]610 return;
611 }
612
613 size_t pos = 0;
[7c014d1]614 while (pos < size) {
615 link_t *link = prodcons_consume(&cons->input_pc);
616 kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
617
618 if (event->type == KEY_PRESS) {
619 buf[pos] = event->c;
[424cd43]620 pos++;
621 }
[7c014d1]622
623 free(event);
[424cd43]624 }
625
[7c014d1]626 (void) async_data_read_finalize(callid, buf, size);
627 async_answer_1(iid, EOK, size);
628 free(buf);
[424cd43]629}
630
[7c014d1]631static void cons_set_style(console_t *cons, console_style_t style)
[424cd43]632{
[7c014d1]633 fibril_mutex_lock(&cons->mtx);
634 screenbuffer_set_style(cons->frontbuf, style);
635 fibril_mutex_unlock(&cons->mtx);
636}
637
638static void cons_set_color(console_t *cons, console_color_t bgcolor,
639 console_color_t fgcolor, console_color_attr_t attr)
640{
641 fibril_mutex_lock(&cons->mtx);
642 screenbuffer_set_color(cons->frontbuf, bgcolor, fgcolor, attr);
643 fibril_mutex_unlock(&cons->mtx);
644}
645
646static void cons_set_rgb_color(console_t *cons, pixel_t bgcolor,
647 pixel_t fgcolor)
648{
649 fibril_mutex_lock(&cons->mtx);
650 screenbuffer_set_rgb_color(cons->frontbuf, bgcolor, fgcolor);
651 fibril_mutex_unlock(&cons->mtx);
652}
653
654static void cons_get_event(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
655{
656 link_t *link = prodcons_consume(&cons->input_pc);
657 kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
[9f1362d4]658
[7c014d1]659 async_answer_4(iid, EOK, event->type, event->key, event->mods, event->c);
660 free(event);
[d2cc7e1]661}
662
[9934f7d]663static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
[eaf34f7]664{
[424cd43]665 console_t *cons = NULL;
[3ad953c]666
[7c014d1]667 for (size_t i = 0; i < CONSOLE_COUNT; i++) {
[424cd43]668 if (i == KERNEL_CONSOLE)
669 continue;
670
[7c014d1]671 if (consoles[i].dsid == (service_id_t) IPC_GET_ARG1(*icall)) {
[424cd43]672 cons = &consoles[i];
673 break;
674 }
675 }
676
677 if (cons == NULL) {
[ffa2c8ef]678 async_answer_0(iid, ENOENT);
[eaf34f7]679 return;
680 }
[424cd43]681
[7c014d1]682 if (atomic_postinc(&cons->refcnt) == 0) {
683 cons_set_cursor_visibility(cons, true);
684 cons_notify_connect(cons);
685 }
[10569b1]686
[eaf34f7]687 /* Accept the connection */
[ffa2c8ef]688 async_answer_0(iid, EOK);
[3ad953c]689
[1601f3c]690 while (true) {
[7c014d1]691 ipc_call_t call;
692 ipc_callid_t callid = async_get_call(&call);
[1601f3c]693
[79ae36dd]694 if (!IPC_GET_IMETHOD(call)) {
[7c014d1]695 if (atomic_postdec(&cons->refcnt) == 1)
696 cons_notify_disconnect(cons);
697
[eaf34f7]698 return;
[79ae36dd]699 }
700
701 switch (IPC_GET_IMETHOD(call)) {
[4198f9c3]702 case VFS_OUT_READ:
[424cd43]703 cons_read(cons, callid, &call);
[7c014d1]704 break;
[4198f9c3]705 case VFS_OUT_WRITE:
[424cd43]706 cons_write(cons, callid, &call);
[7c014d1]707 break;
[4198f9c3]708 case VFS_OUT_SYNC:
[7c014d1]709 cons_update(cons);
710 async_answer_0(callid, EOK);
[424cd43]711 break;
[ad123964]712 case CONSOLE_CLEAR:
[7c014d1]713 cons_clear(cons);
714 async_answer_0(callid, EOK);
[eaf34f7]715 break;
[ad123964]716 case CONSOLE_GOTO:
[7c014d1]717 cons_set_cursor(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
718 async_answer_0(callid, EOK);
[ad123964]719 break;
[19528516]720 case CONSOLE_GET_POS:
[7c014d1]721 cons_get_cursor(cons, callid, &call);
[19528516]722 break;
[424cd43]723 case CONSOLE_GET_SIZE:
[7c014d1]724 async_answer_2(callid, EOK, cons->cols, cons->rows);
[a9bd960c]725 break;
[50cfa6c]726 case CONSOLE_GET_COLOR_CAP:
[7c014d1]727 async_answer_1(callid, EOK, cons->ccaps);
[50cfa6c]728 break;
[a9bd960c]729 case CONSOLE_SET_STYLE:
[7c014d1]730 cons_set_style(cons, IPC_GET_ARG1(call));
731 async_answer_0(callid, EOK);
[9805cde]732 break;
733 case CONSOLE_SET_COLOR:
[7c014d1]734 cons_set_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call),
735 IPC_GET_ARG3(call));
736 async_answer_0(callid, EOK);
[9805cde]737 break;
738 case CONSOLE_SET_RGB_COLOR:
[7c014d1]739 cons_set_rgb_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
740 async_answer_0(callid, EOK);
[0c6984e]741 break;
[a8b2b5b2]742 case CONSOLE_CURSOR_VISIBILITY:
[7c014d1]743 cons_set_cursor_visibility(cons, IPC_GET_ARG1(call));
744 async_answer_0(callid, EOK);
[a8b2b5b2]745 break;
[424cd43]746 case CONSOLE_GET_EVENT:
747 cons_get_event(cons, callid, &call);
[7c014d1]748 break;
749 default:
750 async_answer_0(callid, EINVAL);
[eaf34f7]751 }
752 }
753}
754
[7c014d1]755static async_sess_t *input_connect(const char *svc)
[eaf34f7]756{
[a40dea3]757 async_sess_t *sess;
[7c014d1]758 service_id_t dsid;
[9f1362d4]759
[7c014d1]760 int rc = loc_service_get_id(svc, &dsid, 0);
[79ae36dd]761 if (rc == EOK) {
[7c014d1]762 sess = loc_service_connect(EXCHANGE_ATOMIC, dsid, 0);
[a40dea3]763 if (sess == NULL) {
[7c014d1]764 printf("%s: Unable to connect to input service %s\n", NAME,
765 svc);
[a40dea3]766 return NULL;
[79ae36dd]767 }
[7c014d1]768 } else
[a40dea3]769 return NULL;
[9f1362d4]770
[7c014d1]771 async_exch_t *exch = async_exchange_begin(sess);
[3015f4d]772 rc = async_connect_to_me(exch, 0, 0, 0, input_events, NULL);
[a40dea3]773 async_exchange_end(exch);
[7c014d1]774
[700af62]775 if (rc != EOK) {
[a40dea3]776 async_hangup(sess);
[7c014d1]777 printf("%s: Unable to create callback connection to service %s (%s)\n",
778 NAME, svc, str_error(rc));
[a40dea3]779 return NULL;
[4904de8]780 }
[9f1362d4]781
[a40dea3]782 return sess;
[700af62]783}
784
[7c014d1]785static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
786{
787 cons_switch(prev_console);
788}
789
790static async_sess_t *fb_connect(const char *svc)
[700af62]791{
[7c014d1]792 async_sess_t *sess;
793 service_id_t dsid;
794
795 int rc = loc_service_get_id(svc, &dsid, 0);
796 if (rc == EOK) {
797 sess = loc_service_connect(EXCHANGE_SERIALIZE, dsid, 0);
798 if (sess == NULL) {
799 printf("%s: Unable to connect to framebuffer service %s\n",
800 NAME, svc);
801 return NULL;
802 }
803 } else
804 return NULL;
805
806 return sess;
807}
808
809static bool console_srv_init(char *input_svc, char *fb_svc)
810{
811 /* Avoid double initialization */
812 if (graphics_state != GRAPHICS_NONE)
813 return false;
814
815 /* Connect to input service */
816 input_sess = input_connect(input_svc);
[a40dea3]817 if (input_sess == NULL)
[700af62]818 return false;
[79ae36dd]819
[7c014d1]820 /* Connect to framebuffer service */
821 fb_sess = fb_connect(fb_svc);
822 if (fb_sess == NULL)
[79ae36dd]823 return false;
[9f1362d4]824
[15f3c3f]825 /* Register server */
826 int rc = loc_server_register(NAME, client_connection);
[424cd43]827 if (rc < 0) {
[7c014d1]828 printf("%s: Unable to register server (%s)\n", NAME,
829 str_error(rc));
[424cd43]830 return false;
831 }
[516ff92]832
[7c014d1]833 fb_get_resolution(fb_sess, &xres, &yres);
[3993b3d]834
[7c014d1]835 /* Initialize the screen */
836 screen_vp = fb_vp_create(fb_sess, 0, 0, xres, yres);
[1601f3c]837
[7c014d1]838 if ((xres >= 800) && (yres >= 600)) {
839 logo_vp = fb_vp_create(fb_sess, xres - 66, 2, 64, 60);
840 logo_img = imgmap_decode_tga((void *) helenos_tga,
841 helenos_tga_size, IMGMAP_FLAG_SHARED);
842 logo_handle = fb_imagemap_create(fb_sess, logo_img);
843
844 nameic_vp = fb_vp_create(fb_sess, 5, 17, 100, 26);
845 nameic_img = imgmap_decode_tga((void *) nameic_tga,
846 nameic_tga_size, IMGMAP_FLAG_SHARED);
847 nameic_handle = fb_imagemap_create(fb_sess, nameic_img);
848
849 cons_data_img = imgmap_decode_tga((void *) cons_data_tga,
850 cons_data_tga_size, IMGMAP_FLAG_SHARED);
851 cons_dis_img = imgmap_decode_tga((void *) cons_dis_tga,
852 cons_dis_tga_size, IMGMAP_FLAG_SHARED);
853 cons_dis_sel_img = imgmap_decode_tga((void *) cons_dis_sel_tga,
854 cons_dis_sel_tga_size, IMGMAP_FLAG_SHARED);
855 cons_idle_img = imgmap_decode_tga((void *) cons_idle_tga,
856 cons_idle_tga_size, IMGMAP_FLAG_SHARED);
857 cons_kernel_img = imgmap_decode_tga((void *) cons_kernel_tga,
858 cons_kernel_tga_size, IMGMAP_FLAG_SHARED);
859 cons_sel_img = imgmap_decode_tga((void *) cons_sel_tga,
860 cons_sel_tga_size, IMGMAP_FLAG_SHARED);
861
862 state_icons[CONS_DISCONNECTED] =
863 fb_imagemap_create(fb_sess, cons_dis_img);
864 state_icons[CONS_DISCONNECTED_SELECTED] =
865 fb_imagemap_create(fb_sess, cons_dis_sel_img);
866 state_icons[CONS_SELECTED] =
867 fb_imagemap_create(fb_sess, cons_sel_img);
868 state_icons[CONS_IDLE] =
869 fb_imagemap_create(fb_sess, cons_idle_img);
870 state_icons[CONS_DATA] =
871 fb_imagemap_create(fb_sess, cons_data_img);
872 state_icons[CONS_KERNEL] =
873 fb_imagemap_create(fb_sess, cons_kernel_img);
874
875 anim_1_img = imgmap_decode_tga((void *) anim_1_tga,
876 anim_1_tga_size, IMGMAP_FLAG_SHARED);
877 anim_2_img = imgmap_decode_tga((void *) anim_2_tga,
878 anim_2_tga_size, IMGMAP_FLAG_SHARED);
879 anim_3_img = imgmap_decode_tga((void *) anim_3_tga,
880 anim_3_tga_size, IMGMAP_FLAG_SHARED);
881 anim_4_img = imgmap_decode_tga((void *) anim_4_tga,
882 anim_4_tga_size, IMGMAP_FLAG_SHARED);
883
884 anim_1 = fb_imagemap_create(fb_sess, anim_1_img);
885 anim_2 = fb_imagemap_create(fb_sess, anim_2_img);
886 anim_3 = fb_imagemap_create(fb_sess, anim_3_img);
887 anim_4 = fb_imagemap_create(fb_sess, anim_4_img);
888
889 anim_seq = fb_sequence_create(fb_sess);
890 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_1);
891 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_2);
892 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_3);
893 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_4);
894
895 console_vp = fb_vp_create(fb_sess, CONSOLE_MARGIN, CONSOLE_TOP,
896 xres - 2 * CONSOLE_MARGIN, yres - (CONSOLE_TOP + CONSOLE_MARGIN));
897
898 fb_vp_clear(fb_sess, screen_vp);
899 fb_vp_imagemap_damage(fb_sess, logo_vp, logo_handle,
900 0, 0, 64, 60);
901 fb_vp_imagemap_damage(fb_sess, nameic_vp, nameic_handle,
902 0, 0, 100, 26);
903
904 graphics_state = GRAPHICS_FULL;
905 } else {
906 console_vp = screen_vp;
907 graphics_state = GRAPHICS_BASIC;
908 }
[1601f3c]909
[7c014d1]910 fb_vp_set_style(fb_sess, console_vp, STYLE_NORMAL);
911 fb_vp_clear(fb_sess, console_vp);
[1601f3c]912
[7c014d1]913 sysarg_t cols;
914 sysarg_t rows;
915 fb_vp_get_dimensions(fb_sess, console_vp, &cols, &rows);
916
917 console_caps_t ccaps;
918 fb_vp_get_caps(fb_sess, console_vp, &ccaps);
[3ad953c]919
[b7c33b0]920 mouse.x = xres / 2;
921 mouse.y = yres / 2;
[7c014d1]922 mouse.pressed = false;
[3ad953c]923
[424cd43]924 /* Inititalize consoles */
[7c014d1]925 for (size_t i = 0; i < CONSOLE_COUNT; i++) {
926 consoles[i].index = i;
927 atomic_set(&consoles[i].refcnt, 0);
928 fibril_mutex_initialize(&consoles[i].mtx);
[d03da17]929 prodcons_initialize(&consoles[i].input_pc);
[7c014d1]930
931 if (graphics_state == GRAPHICS_FULL) {
932 /* Create state buttons */
933 consoles[i].state_vp =
934 fb_vp_create(fb_sess, STATE_START + (xres - 800) / 2 +
935 CONSOLE_MARGIN + i * (STATE_WIDTH + STATE_SPACE),
936 STATE_TOP, STATE_WIDTH, STATE_HEIGHT);
937 }
938
939 if (i == KERNEL_CONSOLE) {
940 consoles[i].state = CONS_KERNEL;
941 cons_redraw_state(&consoles[i]);
942 cons_kernel_sequence_start(&consoles[i]);
943 continue;
944 }
945
946 if (i == 0)
947 consoles[i].state = CONS_DISCONNECTED_SELECTED;
948 else
949 consoles[i].state = CONS_DISCONNECTED;
950
951 consoles[i].cols = cols;
952 consoles[i].rows = rows;
953 consoles[i].ccaps = ccaps;
954 consoles[i].frontbuf =
955 screenbuffer_create(cols, rows, SCREENBUFFER_FLAG_SHARED);
956
957 if (consoles[i].frontbuf == NULL) {
958 printf("%s: Unable to allocate frontbuffer %zu\n", NAME, i);
959 return false;
960 }
961
962 consoles[i].fbid = fb_frontbuf_create(fb_sess, consoles[i].frontbuf);
963 if (consoles[i].fbid == 0) {
964 printf("%s: Unable to create frontbuffer %zu\n", NAME, i);
965 return false;
966 }
967
968 cons_redraw_state(&consoles[i]);
969
970 char vc[LOC_NAME_MAXLEN + 1];
971 snprintf(vc, LOC_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i);
972
973 if (loc_service_register(vc, &consoles[i].dsid) != EOK) {
974 printf("%s: Unable to register device %s\n", NAME, vc);
975 return false;
[424cd43]976 }
977 }
978
[3ad953c]979 /* Receive kernel notifications */
[007e6efa]980 async_set_interrupt_received(interrupt_received);
[7c014d1]981 rc = event_subscribe(EVENT_KCONSOLE, 0);
982 if (rc != EOK)
983 printf("%s: Failed to register kconsole notifications (%s)\n",
984 NAME, str_error(rc));
[1601f3c]985
[424cd43]986 return true;
987}
988
[47a350f]989static void usage(void)
990{
[7c014d1]991 printf("Usage: console <input_dev> <framebuffer_dev>\n");
[47a350f]992}
993
[424cd43]994int main(int argc, char *argv[])
995{
[7c014d1]996 if (argc < 3) {
[47a350f]997 usage();
998 return -1;
999 }
1000
[7c014d1]1001 printf("%s: HelenOS Console service\n", NAME);
[424cd43]1002
[7c014d1]1003 if (!console_srv_init(argv[1], argv[2]))
[424cd43]1004 return -1;
[79ae36dd]1005
[7c014d1]1006 printf("%s: Accepting connections\n", NAME);
1007 task_retval(0);
[eaf34f7]1008 async_manager();
[3ad953c]1009
1010 return 0;
[51c1b003]1011}
[516ff92]1012
[ce5bcb4]1013/** @}
1014 */
Note: See TracBrowser for help on using the repository browser.