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

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

console: initialize event-queue of kconsole (#377)

When some kernel console not aware keyboard (such as USB) sends event
while in the kernel console, the console service will try to add it
to the event queue of kernel console. Prior this commit this queue
was not initialized and thus the operation caused page violation.

  • Property mode set to 100644
File size: 24.2 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
[7c014d1]346static ssize_t limit(ssize_t val, ssize_t lo, ssize_t hi)
[429acb9]347{
[7c014d1]348 if (val > hi)
349 return hi;
[1601f3c]350
[7c014d1]351 if (val < lo)
352 return lo;
[1601f3c]353
[7c014d1]354 return val;
[429acb9]355}
356
[7c014d1]357static void cons_mouse_move(sysarg_t dx, sysarg_t dy)
[dc033a1]358{
[7c014d1]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);
[dc033a1]366}
367
[7c014d1]368static console_t *cons_find_icon(sysarg_t x, sysarg_t y)
[10569b1]369{
[cccc091]370 sysarg_t status_start =
371 STATE_START + (xres - 800) / 2 + CONSOLE_MARGIN;
[9f1362d4]372
[7c014d1]373 if ((y < STATE_TOP) || (y >= STATE_TOP + STATE_HEIGHT))
374 return NULL;
[1601f3c]375
[7c014d1]376 if (x < status_start)
377 return NULL;
[10569b1]378
[7c014d1]379 if (x >= status_start + (STATE_WIDTH + STATE_SPACE) * CONSOLE_COUNT)
380 return NULL;
381
[cccc091]382 if (((x - status_start) % (STATE_WIDTH + STATE_SPACE)) >= STATE_WIDTH)
[7c014d1]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;
[9f1362d4]389
[7c014d1]390 return NULL;
[10569b1]391}
392
[7c014d1]393/** Handle mouse click
394 *
395 * @param state Button state (true - pressed, false - depressed)
396 *
397 */
398static console_t *cons_mouse_button(bool state)
[429acb9]399{
[7c014d1]400 if (graphics_state != GRAPHICS_FULL)
401 return NULL;
[6d5005c]402
[7c014d1]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;
[10270a8]409 }
[76fca31]410
[7c014d1]411 return NULL;
[429acb9]412 }
[7c014d1]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;
[429acb9]423}
[10569b1]424
[854eddd6]425static void input_events(ipc_callid_t iid, ipc_call_t *icall, void *arg)
[51c1b003]426{
[424cd43]427 /* Ignore parameters, the connection is already opened */
[1601f3c]428 while (true) {
[424cd43]429 ipc_call_t call;
430 ipc_callid_t callid = async_get_call(&call);
431
[79ae36dd]432 if (!IPC_GET_IMETHOD(call)) {
[eaf34f7]433 /* TODO: Handle hangup */
[a40dea3]434 async_hangup(input_sess);
[eaf34f7]435 return;
[79ae36dd]436 }
437
[7c014d1]438 kbd_event_type_t type;
439 keycode_t key;
440 keymod_t mods;
441 wchar_t c;
442
[79ae36dd]443 switch (IPC_GET_IMETHOD(call)) {
[854eddd6]444 case INPUT_EVENT_KEY:
[7c014d1]445 type = IPC_GET_ARG1(call);
446 key = IPC_GET_ARG2(call);
447 mods = IPC_GET_ARG3(call);
448 c = IPC_GET_ARG4(call);
[fa09449]449
[7c014d1]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);
[eaf34f7]469 }
[cf28036c]470
[7c014d1]471 async_answer_0(callid, EOK);
[eaf34f7]472 break;
[854eddd6]473 case INPUT_EVENT_MOVE:
[7c014d1]474 cons_mouse_move(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
475 async_answer_0(callid, EOK);
[854eddd6]476 break;
477 case INPUT_EVENT_BUTTON:
478 /* Got pointer button press/release event */
[9f1362d4]479 if (IPC_GET_ARG1(call) == 1) {
[7c014d1]480 console_t *cons =
481 cons_mouse_button((bool) IPC_GET_ARG2(call));
482 if (cons != NULL)
483 cons_switch(cons);
[9f51afc]484 }
[7c014d1]485 async_answer_0(callid, EOK);
[9f51afc]486 break;
487 default:
[7c014d1]488 async_answer_0(callid, EINVAL);
[9f51afc]489 }
[7c014d1]490 }
491}
[1875a0c]492
[7c014d1]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);
[9f51afc]514 }
[7c014d1]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);
[9f51afc]550}
551
[7c014d1]552static void cons_write(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
[d2cc7e1]553{
[472c09d]554 void *buf;
[171f9a1]555 size_t size;
[eda925a]556 int rc = async_data_write_accept(&buf, false, 0, 0, 0, &size);
[1601f3c]557
[472c09d]558 if (rc != EOK) {
[7c014d1]559 async_answer_0(iid, rc);
[424cd43]560 return;
561 }
[1601f3c]562
[424cd43]563 size_t off = 0;
[7c014d1]564 while (off < size)
565 cons_write_char(cons, str_decode(buf, &off, size));
[424cd43]566
[7c014d1]567 async_answer_1(iid, EOK, size);
[424cd43]568 free(buf);
[7c014d1]569
570 cons_notify_data(cons);
[424cd43]571}
572
[7c014d1]573static void cons_read(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
[424cd43]574{
575 ipc_callid_t callid;
576 size_t size;
[0da4e41]577 if (!async_data_read_receive(&callid, &size)) {
[ffa2c8ef]578 async_answer_0(callid, EINVAL);
[7c014d1]579 async_answer_0(iid, EINVAL);
[424cd43]580 return;
581 }
582
583 char *buf = (char *) malloc(size);
584 if (buf == NULL) {
[ffa2c8ef]585 async_answer_0(callid, ENOMEM);
[7c014d1]586 async_answer_0(iid, ENOMEM);
[424cd43]587 return;
588 }
589
590 size_t pos = 0;
[7c014d1]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;
[424cd43]597 pos++;
598 }
[7c014d1]599
600 free(event);
[424cd43]601 }
602
[7c014d1]603 (void) async_data_read_finalize(callid, buf, size);
604 async_answer_1(iid, EOK, size);
605 free(buf);
[424cd43]606}
607
[7c014d1]608static void cons_set_style(console_t *cons, console_style_t style)
[424cd43]609{
[7c014d1]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);
[9f1362d4]635
[7c014d1]636 async_answer_4(iid, EOK, event->type, event->key, event->mods, event->c);
637 free(event);
[d2cc7e1]638}
639
[9934f7d]640static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
[eaf34f7]641{
[424cd43]642 console_t *cons = NULL;
[3ad953c]643
[7c014d1]644 for (size_t i = 0; i < CONSOLE_COUNT; i++) {
[424cd43]645 if (i == KERNEL_CONSOLE)
646 continue;
647
[7c014d1]648 if (consoles[i].dsid == (service_id_t) IPC_GET_ARG1(*icall)) {
[424cd43]649 cons = &consoles[i];
650 break;
651 }
652 }
653
654 if (cons == NULL) {
[ffa2c8ef]655 async_answer_0(iid, ENOENT);
[eaf34f7]656 return;
657 }
[424cd43]658
[7c014d1]659 if (atomic_postinc(&cons->refcnt) == 0) {
660 cons_set_cursor_visibility(cons, true);
661 cons_notify_connect(cons);
662 }
[10569b1]663
[eaf34f7]664 /* Accept the connection */
[ffa2c8ef]665 async_answer_0(iid, EOK);
[3ad953c]666
[1601f3c]667 while (true) {
[7c014d1]668 ipc_call_t call;
669 ipc_callid_t callid = async_get_call(&call);
[1601f3c]670
[79ae36dd]671 if (!IPC_GET_IMETHOD(call)) {
[7c014d1]672 if (atomic_postdec(&cons->refcnt) == 1)
673 cons_notify_disconnect(cons);
674
[eaf34f7]675 return;
[79ae36dd]676 }
677
678 switch (IPC_GET_IMETHOD(call)) {
[4198f9c3]679 case VFS_OUT_READ:
[424cd43]680 cons_read(cons, callid, &call);
[7c014d1]681 break;
[4198f9c3]682 case VFS_OUT_WRITE:
[424cd43]683 cons_write(cons, callid, &call);
[7c014d1]684 break;
[4198f9c3]685 case VFS_OUT_SYNC:
[7c014d1]686 cons_update(cons);
687 async_answer_0(callid, EOK);
[424cd43]688 break;
[ad123964]689 case CONSOLE_CLEAR:
[7c014d1]690 cons_clear(cons);
691 async_answer_0(callid, EOK);
[eaf34f7]692 break;
[ad123964]693 case CONSOLE_GOTO:
[7c014d1]694 cons_set_cursor(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
695 async_answer_0(callid, EOK);
[ad123964]696 break;
[19528516]697 case CONSOLE_GET_POS:
[7c014d1]698 cons_get_cursor(cons, callid, &call);
[19528516]699 break;
[424cd43]700 case CONSOLE_GET_SIZE:
[7c014d1]701 async_answer_2(callid, EOK, cons->cols, cons->rows);
[a9bd960c]702 break;
[50cfa6c]703 case CONSOLE_GET_COLOR_CAP:
[7c014d1]704 async_answer_1(callid, EOK, cons->ccaps);
[50cfa6c]705 break;
[a9bd960c]706 case CONSOLE_SET_STYLE:
[7c014d1]707 cons_set_style(cons, IPC_GET_ARG1(call));
708 async_answer_0(callid, EOK);
[9805cde]709 break;
710 case CONSOLE_SET_COLOR:
[7c014d1]711 cons_set_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call),
712 IPC_GET_ARG3(call));
713 async_answer_0(callid, EOK);
[9805cde]714 break;
715 case CONSOLE_SET_RGB_COLOR:
[7c014d1]716 cons_set_rgb_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
717 async_answer_0(callid, EOK);
[0c6984e]718 break;
[a8b2b5b2]719 case CONSOLE_CURSOR_VISIBILITY:
[7c014d1]720 cons_set_cursor_visibility(cons, IPC_GET_ARG1(call));
721 async_answer_0(callid, EOK);
[a8b2b5b2]722 break;
[424cd43]723 case CONSOLE_GET_EVENT:
724 cons_get_event(cons, callid, &call);
[7c014d1]725 break;
726 default:
727 async_answer_0(callid, EINVAL);
[eaf34f7]728 }
729 }
730}
731
[7c014d1]732static async_sess_t *input_connect(const char *svc)
[eaf34f7]733{
[a40dea3]734 async_sess_t *sess;
[7c014d1]735 service_id_t dsid;
[9f1362d4]736
[7c014d1]737 int rc = loc_service_get_id(svc, &dsid, 0);
[79ae36dd]738 if (rc == EOK) {
[7c014d1]739 sess = loc_service_connect(EXCHANGE_ATOMIC, dsid, 0);
[a40dea3]740 if (sess == NULL) {
[7c014d1]741 printf("%s: Unable to connect to input service %s\n", NAME,
742 svc);
[a40dea3]743 return NULL;
[79ae36dd]744 }
[7c014d1]745 } else
[a40dea3]746 return NULL;
[9f1362d4]747
[7c014d1]748 async_exch_t *exch = async_exchange_begin(sess);
[3015f4d]749 rc = async_connect_to_me(exch, 0, 0, 0, input_events, NULL);
[a40dea3]750 async_exchange_end(exch);
[7c014d1]751
[700af62]752 if (rc != EOK) {
[a40dea3]753 async_hangup(sess);
[7c014d1]754 printf("%s: Unable to create callback connection to service %s (%s)\n",
755 NAME, svc, str_error(rc));
[a40dea3]756 return NULL;
[4904de8]757 }
[9f1362d4]758
[a40dea3]759 return sess;
[700af62]760}
761
[7c014d1]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)
[700af62]768{
[7c014d1]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);
[a40dea3]794 if (input_sess == NULL)
[700af62]795 return false;
[79ae36dd]796
[7c014d1]797 /* Connect to framebuffer service */
798 fb_sess = fb_connect(fb_svc);
799 if (fb_sess == NULL)
[79ae36dd]800 return false;
[9f1362d4]801
[15f3c3f]802 /* Register server */
803 int rc = loc_server_register(NAME, client_connection);
[424cd43]804 if (rc < 0) {
[7c014d1]805 printf("%s: Unable to register server (%s)\n", NAME,
806 str_error(rc));
[424cd43]807 return false;
808 }
[516ff92]809
[7c014d1]810 fb_get_resolution(fb_sess, &xres, &yres);
[3993b3d]811
[7c014d1]812 /* Initialize the screen */
813 screen_vp = fb_vp_create(fb_sess, 0, 0, xres, yres);
[1601f3c]814
[7c014d1]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 }
[1601f3c]886
[7c014d1]887 fb_vp_set_style(fb_sess, console_vp, STYLE_NORMAL);
888 fb_vp_clear(fb_sess, console_vp);
[1601f3c]889
[7c014d1]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);
[3ad953c]896
[b7c33b0]897 mouse.x = xres / 2;
898 mouse.y = yres / 2;
[7c014d1]899 mouse.pressed = false;
[3ad953c]900
[424cd43]901 /* Inititalize consoles */
[7c014d1]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);
[d03da17]906 prodcons_initialize(&consoles[i].input_pc);
[7c014d1]907
908 if (graphics_state == GRAPHICS_FULL) {
909 /* Create state buttons */
910 consoles[i].state_vp =
911 fb_vp_create(fb_sess, STATE_START + (xres - 800) / 2 +
912 CONSOLE_MARGIN + i * (STATE_WIDTH + STATE_SPACE),
913 STATE_TOP, STATE_WIDTH, STATE_HEIGHT);
914 }
915
916 if (i == KERNEL_CONSOLE) {
917 consoles[i].state = CONS_KERNEL;
918 cons_redraw_state(&consoles[i]);
919 cons_kernel_sequence_start(&consoles[i]);
920 continue;
921 }
922
923 if (i == 0)
924 consoles[i].state = CONS_DISCONNECTED_SELECTED;
925 else
926 consoles[i].state = CONS_DISCONNECTED;
927
928 consoles[i].cols = cols;
929 consoles[i].rows = rows;
930 consoles[i].ccaps = ccaps;
931 consoles[i].frontbuf =
932 screenbuffer_create(cols, rows, SCREENBUFFER_FLAG_SHARED);
933
934 if (consoles[i].frontbuf == NULL) {
935 printf("%s: Unable to allocate frontbuffer %zu\n", NAME, i);
936 return false;
937 }
938
939 consoles[i].fbid = fb_frontbuf_create(fb_sess, consoles[i].frontbuf);
940 if (consoles[i].fbid == 0) {
941 printf("%s: Unable to create frontbuffer %zu\n", NAME, i);
942 return false;
943 }
944
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;
[424cd43]953 }
954 }
955
[3ad953c]956 /* Receive kernel notifications */
[007e6efa]957 async_set_interrupt_received(interrupt_received);
[7c014d1]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));
[1601f3c]962
[424cd43]963 return true;
964}
965
[47a350f]966static void usage(void)
967{
[7c014d1]968 printf("Usage: console <input_dev> <framebuffer_dev>\n");
[47a350f]969}
970
[424cd43]971int main(int argc, char *argv[])
972{
[7c014d1]973 if (argc < 3) {
[47a350f]974 usage();
975 return -1;
976 }
977
[7c014d1]978 printf("%s: HelenOS Console service\n", NAME);
[424cd43]979
[7c014d1]980 if (!console_srv_init(argv[1], argv[2]))
[424cd43]981 return -1;
[79ae36dd]982
[7c014d1]983 printf("%s: Accepting connections\n", NAME);
984 task_retval(0);
[eaf34f7]985 async_manager();
[3ad953c]986
987 return 0;
[51c1b003]988}
[516ff92]989
[ce5bcb4]990/** @}
991 */
Note: See TracBrowser for help on using the repository browser.