source: mainline/uspace/srv/hid/console/gcons.c@ f2f99ae

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

new async framework with integrated exchange tracking

  • strict isolation between low-level IPC and high-level async framework with integrated exchange tracking
    • each IPC connection is represented by an async_sess_t structure
    • each IPC exchange is represented by an async_exch_t structure
    • exchange management is either based on atomic messages (EXCHANGE_ATOMIC), locking (EXCHANGE_SERIALIZE) or connection cloning (EXCHANGE_CLONE)
  • async_obsolete: temporary compatibility layer to keep old async clients working (several pieces of code are currently broken, but only non-essential functionality)
  • IPC_M_PHONE_HANGUP is now method no. 0 (for elegant boolean evaluation)
  • IPC_M_DEBUG_ALL has been renamed to IPC_M_DEBUG
  • IPC_M_PING has been removed (VFS protocol now has VFS_IN_PING)
  • console routines in libc have been rewritten for better abstraction
  • additional use for libc-private header files (FILE structure opaque to the client)
  • various cstyle changes (typos, indentation, missing externs in header files, improved comments, etc.)
  • Property mode set to 100644
File size: 13.3 KB
Line 
1/*
2 * Copyright (c) 2006 Ondrej Palkovsky
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 <ipc/fb.h>
36#include <async.h>
37#include <async_obsolete.h>
38#include <stdio.h>
39#include <sys/mman.h>
40#include <str.h>
41#include <align.h>
42#include <bool.h>
43
44#include "console.h"
45#include "gcons.h"
46
47#define CONSOLE_TOP 66
48#define CONSOLE_MARGIN 6
49
50#define STATUS_START 110
51#define STATUS_TOP 8
52#define STATUS_SPACE 4
53#define STATUS_WIDTH 48
54#define STATUS_HEIGHT 48
55
56#define COLOR_MAIN 0xffffff
57#define COLOR_FOREGROUND 0x202020
58#define COLOR_BACKGROUND 0xffffff
59
60extern char _binary_gfx_helenos_ppm_start[0];
61extern int _binary_gfx_helenos_ppm_size;
62extern char _binary_gfx_nameic_ppm_start[0];
63extern int _binary_gfx_nameic_ppm_size;
64
65extern char _binary_gfx_anim_1_ppm_start[0];
66extern int _binary_gfx_anim_1_ppm_size;
67extern char _binary_gfx_anim_2_ppm_start[0];
68extern int _binary_gfx_anim_2_ppm_size;
69extern char _binary_gfx_anim_3_ppm_start[0];
70extern int _binary_gfx_anim_3_ppm_size;
71extern char _binary_gfx_anim_4_ppm_start[0];
72extern int _binary_gfx_anim_4_ppm_size;
73
74extern char _binary_gfx_cons_selected_ppm_start[0];
75extern int _binary_gfx_cons_selected_ppm_size;
76extern char _binary_gfx_cons_idle_ppm_start[0];
77extern int _binary_gfx_cons_idle_ppm_size;
78extern char _binary_gfx_cons_has_data_ppm_start[0];
79extern int _binary_gfx_cons_has_data_ppm_size;
80extern char _binary_gfx_cons_kernel_ppm_start[0];
81extern int _binary_gfx_cons_kernel_ppm_size;
82
83static bool use_gcons = false;
84static sysarg_t xres;
85static sysarg_t yres;
86
87enum butstate {
88 CONS_DISCONNECTED = 0,
89 CONS_SELECTED,
90 CONS_IDLE,
91 CONS_HAS_DATA,
92 CONS_KERNEL,
93 CONS_DISCONNECTED_SEL,
94 CONS_LAST
95};
96
97static int console_vp;
98static int cstatus_vp[CONSOLE_COUNT];
99static enum butstate console_state[CONSOLE_COUNT];
100
101static int fbphone;
102
103/** List of pixmaps identifying these icons */
104static int ic_pixmaps[CONS_LAST] = {-1, -1, -1, -1, -1, -1};
105static int animation = -1;
106
107static size_t active_console = 0;
108
109static sysarg_t mouse_x = 0;
110static sysarg_t mouse_y= 0;
111
112static bool btn_pressed = false;
113static sysarg_t btn_x = 0;
114static sysarg_t btn_y = 0;
115
116static void vp_switch(int vp)
117{
118 async_obsolete_msg_1(fbphone, FB_VIEWPORT_SWITCH, vp);
119}
120
121/** Create view port */
122static int vp_create(sysarg_t x, sysarg_t y, sysarg_t width, sysarg_t height)
123{
124 return async_obsolete_req_2_0(fbphone, FB_VIEWPORT_CREATE, (x << 16) | y,
125 (width << 16) | height);
126}
127
128static void clear(void)
129{
130 async_obsolete_msg_0(fbphone, FB_CLEAR);
131}
132
133static void set_rgb_color(uint32_t fgcolor, uint32_t bgcolor)
134{
135 async_obsolete_msg_2(fbphone, FB_SET_RGB_COLOR, fgcolor, bgcolor);
136}
137
138/** Transparent putchar */
139static void tran_putch(wchar_t ch, sysarg_t col, sysarg_t row)
140{
141 async_obsolete_msg_3(fbphone, FB_PUTCHAR, ch, col, row);
142}
143
144/** Redraw the button showing state of a given console */
145static void redraw_state(size_t index)
146{
147 vp_switch(cstatus_vp[index]);
148
149 enum butstate state = console_state[index];
150
151 if (ic_pixmaps[state] != -1)
152 async_obsolete_msg_2(fbphone, FB_VP_DRAW_PIXMAP, cstatus_vp[index],
153 ic_pixmaps[state]);
154
155 if ((state != CONS_DISCONNECTED) && (state != CONS_KERNEL)
156 && (state != CONS_DISCONNECTED_SEL)) {
157
158 char data[5];
159 snprintf(data, 5, "%zu", index + 1);
160
161 size_t i;
162 for (i = 0; data[i] != 0; i++)
163 tran_putch(data[i], 2 + i, 1);
164 }
165}
166
167/** Notification run on changing console (except kernel console) */
168void gcons_change_console(size_t index)
169{
170 if (!use_gcons)
171 return;
172
173 if (active_console == KERNEL_CONSOLE) {
174 size_t i;
175
176 for (i = 0; i < CONSOLE_COUNT; i++)
177 redraw_state(i);
178
179 if (animation != -1)
180 async_obsolete_msg_1(fbphone, FB_ANIM_START, animation);
181 } else {
182 if (console_state[active_console] == CONS_DISCONNECTED_SEL)
183 console_state[active_console] = CONS_DISCONNECTED;
184 else
185 console_state[active_console] = CONS_IDLE;
186
187 redraw_state(active_console);
188 }
189
190 active_console = index;
191
192 if ((console_state[index] == CONS_DISCONNECTED)
193 || (console_state[index] == CONS_DISCONNECTED_SEL))
194 console_state[index] = CONS_DISCONNECTED_SEL;
195 else
196 console_state[index] = CONS_SELECTED;
197
198 redraw_state(index);
199 vp_switch(console_vp);
200}
201
202/** Notification function that gets called on new output to virtual console */
203void gcons_notify_char(size_t index)
204{
205 if (!use_gcons)
206 return;
207
208 if ((index == active_console)
209 || (console_state[index] == CONS_HAS_DATA))
210 return;
211
212 console_state[index] = CONS_HAS_DATA;
213
214 if (active_console == KERNEL_CONSOLE)
215 return;
216
217 redraw_state(index);
218 vp_switch(console_vp);
219}
220
221/** Notification function called on service disconnect from console */
222void gcons_notify_disconnect(size_t index)
223{
224 if (!use_gcons)
225 return;
226
227 if (index == active_console)
228 console_state[index] = CONS_DISCONNECTED_SEL;
229 else
230 console_state[index] = CONS_DISCONNECTED;
231
232 if (active_console == KERNEL_CONSOLE)
233 return;
234
235 redraw_state(index);
236 vp_switch(console_vp);
237}
238
239/** Notification function called on console connect */
240void gcons_notify_connect(size_t index)
241{
242 if (!use_gcons)
243 return;
244
245 if (index == active_console)
246 console_state[index] = CONS_SELECTED;
247 else
248 console_state[index] = CONS_IDLE;
249
250 if (active_console == KERNEL_CONSOLE)
251 return;
252
253 redraw_state(index);
254 vp_switch(console_vp);
255}
256
257/** Change to kernel console */
258void gcons_in_kernel(void)
259{
260 if (animation != -1)
261 async_obsolete_msg_1(fbphone, FB_ANIM_STOP, animation);
262
263 active_console = KERNEL_CONSOLE;
264 vp_switch(0);
265}
266
267/** Return x, where left <= x <= right && |a-x| == min(|a-x|) is smallest */
268static inline ssize_t limit(ssize_t a, ssize_t left, ssize_t right)
269{
270 if (a < left)
271 a = left;
272
273 if (a >= right)
274 a = right - 1;
275
276 return a;
277}
278
279/** Handle mouse move
280 *
281 * @param dx Delta X of mouse move
282 * @param dy Delta Y of mouse move
283 */
284void gcons_mouse_move(ssize_t dx, ssize_t dy)
285{
286 ssize_t nx = (ssize_t) mouse_x + dx;
287 ssize_t ny = (ssize_t) mouse_y + dy;
288
289 /* Until gcons is initalized we don't have the screen resolution */
290 if (xres == 0 || yres == 0)
291 return;
292
293 mouse_x = (size_t) limit(nx, 0, xres);
294 mouse_y = (size_t) limit(ny, 0, yres);
295
296 if (active_console != KERNEL_CONSOLE)
297 async_obsolete_msg_2(fbphone, FB_POINTER_MOVE, mouse_x, mouse_y);
298}
299
300static int gcons_find_conbut(sysarg_t x, sysarg_t y)
301{
302 sysarg_t status_start = STATUS_START + (xres - 800) / 2;
303
304 if ((y < STATUS_TOP) || (y >= STATUS_TOP + STATUS_HEIGHT))
305 return -1;
306
307 if (x < status_start)
308 return -1;
309
310 if (x >= status_start + (STATUS_WIDTH + STATUS_SPACE) * CONSOLE_COUNT)
311 return -1;
312
313 if (((x - status_start) % (STATUS_WIDTH + STATUS_SPACE)) < STATUS_SPACE)
314 return -1;
315
316 sysarg_t btn = (x - status_start) / (STATUS_WIDTH + STATUS_SPACE);
317
318 if (btn < CONSOLE_COUNT)
319 return btn;
320
321 return -1;
322}
323
324/** Handle mouse click
325 *
326 * @param state New state (true - pressed, false - depressed)
327 *
328 */
329int gcons_mouse_btn(bool state)
330{
331 /* Ignore mouse clicks if no buttons
332 are drawn at all */
333 if (xres < 800)
334 return -1;
335
336 if (state) {
337 int conbut = gcons_find_conbut(mouse_x, mouse_y);
338 if (conbut != -1) {
339 btn_pressed = true;
340 btn_x = mouse_x;
341 btn_y = mouse_y;
342 }
343 return -1;
344 }
345
346 if ((!state) && (!btn_pressed))
347 return -1;
348
349 btn_pressed = false;
350
351 int conbut = gcons_find_conbut(mouse_x, mouse_y);
352 if (conbut == gcons_find_conbut(btn_x, btn_y))
353 return conbut;
354
355 return -1;
356}
357
358/** Draw a PPM pixmap to framebuffer
359 *
360 * @param logo Pointer to PPM data
361 * @param size Size of PPM data
362 * @param x Coordinate of upper left corner
363 * @param y Coordinate of upper left corner
364 *
365 */
366static void draw_pixmap(char *logo, size_t size, sysarg_t x, sysarg_t y)
367{
368 /* Create area */
369 char *shm = mmap(NULL, size, PROTO_READ | PROTO_WRITE, MAP_SHARED |
370 MAP_ANONYMOUS, 0, 0);
371 if (shm == MAP_FAILED)
372 return;
373
374 memcpy(shm, logo, size);
375
376 /* Send area */
377 int rc = async_obsolete_req_1_0(fbphone, FB_PREPARE_SHM, (sysarg_t) shm);
378 if (rc)
379 goto exit;
380
381 rc = async_obsolete_share_out_start(fbphone, shm, PROTO_READ);
382 if (rc)
383 goto drop;
384
385 /* Draw logo */
386 async_obsolete_msg_2(fbphone, FB_DRAW_PPM, x, y);
387
388drop:
389 /* Drop area */
390 async_obsolete_msg_0(fbphone, FB_DROP_SHM);
391
392exit:
393 /* Remove area */
394 munmap(shm, size);
395}
396
397/** Redraws console graphics */
398void gcons_redraw_console(void)
399{
400 if (!use_gcons)
401 return;
402
403 vp_switch(0);
404 set_rgb_color(COLOR_MAIN, COLOR_MAIN);
405 clear();
406 draw_pixmap(_binary_gfx_helenos_ppm_start,
407 (size_t) &_binary_gfx_helenos_ppm_size, xres - 66, 2);
408 draw_pixmap(_binary_gfx_nameic_ppm_start,
409 (size_t) &_binary_gfx_nameic_ppm_size, 5, 17);
410
411 unsigned int i;
412 for (i = 0; i < CONSOLE_COUNT; i++)
413 redraw_state(i);
414
415 vp_switch(console_vp);
416}
417
418/** Creates a pixmap on framebuffer
419 *
420 * @param data PPM data
421 * @param size PPM data size
422 *
423 * @return Pixmap identification
424 *
425 */
426static int make_pixmap(char *data, size_t size)
427{
428 /* Create area */
429 char *shm = mmap(NULL, size, PROTO_READ | PROTO_WRITE, MAP_SHARED |
430 MAP_ANONYMOUS, 0, 0);
431 if (shm == MAP_FAILED)
432 return -1;
433
434 memcpy(shm, data, size);
435
436 int pxid = -1;
437
438 /* Send area */
439 int rc = async_obsolete_req_1_0(fbphone, FB_PREPARE_SHM, (sysarg_t) shm);
440 if (rc)
441 goto exit;
442
443 rc = async_obsolete_share_out_start(fbphone, shm, PROTO_READ);
444 if (rc)
445 goto drop;
446
447 /* Obtain pixmap */
448 rc = async_obsolete_req_0_0(fbphone, FB_SHM2PIXMAP);
449 if (rc < 0)
450 goto drop;
451
452 pxid = rc;
453
454drop:
455 /* Drop area */
456 async_obsolete_msg_0(fbphone, FB_DROP_SHM);
457
458exit:
459 /* Remove area */
460 munmap(shm, size);
461
462 return pxid;
463}
464
465static void make_anim(void)
466{
467 int an = async_obsolete_req_1_0(fbphone, FB_ANIM_CREATE,
468 cstatus_vp[KERNEL_CONSOLE]);
469 if (an < 0)
470 return;
471
472 int pm = make_pixmap(_binary_gfx_anim_1_ppm_start,
473 (size_t) &_binary_gfx_anim_1_ppm_size);
474 async_obsolete_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
475
476 pm = make_pixmap(_binary_gfx_anim_2_ppm_start,
477 (size_t) &_binary_gfx_anim_2_ppm_size);
478 async_obsolete_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
479
480 pm = make_pixmap(_binary_gfx_anim_3_ppm_start,
481 (size_t) &_binary_gfx_anim_3_ppm_size);
482 async_obsolete_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
483
484 pm = make_pixmap(_binary_gfx_anim_4_ppm_start,
485 (size_t) &_binary_gfx_anim_4_ppm_size);
486 async_obsolete_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
487
488 async_obsolete_msg_1(fbphone, FB_ANIM_START, an);
489
490 animation = an;
491}
492
493/** Initialize nice graphical console environment */
494void gcons_init(int phone)
495{
496 fbphone = phone;
497
498 int rc = async_obsolete_req_0_2(phone, FB_GET_RESOLUTION, &xres, &yres);
499 if (rc)
500 return;
501
502 if ((xres < 800) || (yres < 600))
503 return;
504
505 /* Create console viewport */
506
507 /* Align width & height to character size */
508 console_vp = vp_create(CONSOLE_MARGIN, CONSOLE_TOP,
509 ALIGN_DOWN(xres - 2 * CONSOLE_MARGIN, 8),
510 ALIGN_DOWN(yres - (CONSOLE_TOP + CONSOLE_MARGIN), 16));
511
512 if (console_vp < 0)
513 return;
514
515 /* Create status buttons */
516 sysarg_t status_start = STATUS_START + (xres - 800) / 2;
517 size_t i;
518 for (i = 0; i < CONSOLE_COUNT; i++) {
519 cstatus_vp[i] = vp_create(status_start + CONSOLE_MARGIN +
520 i * (STATUS_WIDTH + STATUS_SPACE), STATUS_TOP,
521 STATUS_WIDTH, STATUS_HEIGHT);
522
523 if (cstatus_vp[i] < 0)
524 return;
525
526 vp_switch(cstatus_vp[i]);
527 set_rgb_color(COLOR_FOREGROUND, COLOR_BACKGROUND);
528 }
529
530 /* Initialize icons */
531 ic_pixmaps[CONS_SELECTED] =
532 make_pixmap(_binary_gfx_cons_selected_ppm_start,
533 (size_t) &_binary_gfx_cons_selected_ppm_size);
534 ic_pixmaps[CONS_IDLE] =
535 make_pixmap(_binary_gfx_cons_idle_ppm_start,
536 (size_t) &_binary_gfx_cons_idle_ppm_size);
537 ic_pixmaps[CONS_HAS_DATA] =
538 make_pixmap(_binary_gfx_cons_has_data_ppm_start,
539 (size_t) &_binary_gfx_cons_has_data_ppm_size);
540 ic_pixmaps[CONS_DISCONNECTED] =
541 make_pixmap(_binary_gfx_cons_idle_ppm_start,
542 (size_t) &_binary_gfx_cons_idle_ppm_size);
543 ic_pixmaps[CONS_KERNEL] =
544 make_pixmap(_binary_gfx_cons_kernel_ppm_start,
545 (size_t) &_binary_gfx_cons_kernel_ppm_size);
546 ic_pixmaps[CONS_DISCONNECTED_SEL] = ic_pixmaps[CONS_SELECTED];
547
548 make_anim();
549
550 use_gcons = true;
551 console_state[0] = CONS_DISCONNECTED_SEL;
552 console_state[KERNEL_CONSOLE] = CONS_KERNEL;
553
554 vp_switch(console_vp);
555}
556
557/** @}
558 */
Note: See TracBrowser for help on using the repository browser.