source: mainline/uspace/srv/console/gcons.c@ bbb01b98

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

keep the kernel console intact as long as it is possible (to be able to see any out-of-order errors)

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