source: mainline/uspace/srv/hid/fb/fb.c@ 302a4b6

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

do not intermix low-level IPC methods with async framework methods

  • Property mode set to 100644
File size: 42.4 KB
RevLine 
[afa6e74]1/*
[76fca31]2 * Copyright (c) 2008 Martin Decky
[df4ed85]3 * Copyright (c) 2006 Jakub Vana
4 * Copyright (c) 2006 Ondrej Palkovsky
[afa6e74]5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * - The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
[231a60a]31/**
32 * @defgroup fb Graphical framebuffer
[ab1861a]33 * @brief HelenOS graphical framebuffer.
[ce5bcb4]34 * @ingroup fbs
35 * @{
[76fca31]36 */
[06e1e95]37
[ce5bcb4]38/** @file
39 */
40
[afa6e74]41#include <stdlib.h>
[7f5b37a]42#include <unistd.h>
[19f857a]43#include <str.h>
[afa6e74]44#include <ddi.h>
45#include <sysinfo.h>
46#include <align.h>
47#include <as.h>
48#include <ipc/fb.h>
49#include <ipc/ns.h>
[7f5b37a]50#include <ipc/services.h>
[afa6e74]51#include <kernel/errno.h>
[2bc137c2]52#include <kernel/genarch/fb/visuals.h>
[8dc12ac]53#include <io/color.h>
54#include <io/style.h>
[80649a91]55#include <async.h>
[26360f7]56#include <fibril.h>
[2bc137c2]57#include <bool.h>
[7ece1fbe]58#include <stdio.h>
[30885b9]59#include <byteorder.h>
[369a5f8]60#include <io/screenbuffer.h>
[83b1d61]61
[a2cd194]62#include "font-8x16.h"
[afa6e74]63#include "fb.h"
[83b1d61]64#include "main.h"
[90f5d64]65#include "ppm.h"
[afa6e74]66
[2ce520c]67#include "pointer.xbm"
68#include "pointer_mask.xbm"
69
[76fca31]70#define DEFAULT_BGCOLOR 0xf0f0f0
71#define DEFAULT_FGCOLOR 0x000000
[afa6e74]72
[9f1362d4]73#define GLYPH_UNAVAIL '?'
[171f9a1]74
[9f1362d4]75#define MAX_ANIM_LEN 8
76#define MAX_ANIMATIONS 4
77#define MAX_PIXMAPS 256 /**< Maximum number of saved pixmaps */
78#define MAX_VIEWPORTS 128 /**< Viewport is a rectangular area on the screen */
[afa6e74]79
[68a4442]80/** Function to render a pixel from a RGB value. */
[76fca31]81typedef void (*rgb_conv_t)(void *, uint32_t);
[afa6e74]82
[ab1861a]83/** Function to render a bit mask. */
84typedef void (*mask_conv_t)(void *, bool);
85
[68a4442]86/** Function to draw a glyph. */
87typedef void (*dg_t)(unsigned int x, unsigned int y, bool cursor,
[171f9a1]88 uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color);
[68a4442]89
[a2ae4f4]90struct {
[76fca31]91 uint8_t *fb_addr;
92
[253f35a1]93 unsigned int xres;
94 unsigned int yres;
[76fca31]95
[253f35a1]96 unsigned int scanline;
[76fca31]97 unsigned int glyphscanline;
98
[253f35a1]99 unsigned int pixelbytes;
[76fca31]100 unsigned int glyphbytes;
[ab1861a]101
[4527fb5]102 /** Pre-rendered mask for rendering glyphs. Specific for the visual. */
103 uint8_t *glyphs;
[76fca31]104
105 rgb_conv_t rgb_conv;
[ab1861a]106 mask_conv_t mask_conv;
[a2ae4f4]107} screen;
[afa6e74]108
[9805cde]109/** Backbuffer character cell. */
110typedef struct {
[7ce3cb2]111 uint32_t glyph;
[9805cde]112 uint32_t fg_color;
113 uint32_t bg_color;
114} bb_cell_t;
115
[a2ae4f4]116typedef struct {
[76fca31]117 bool initialized;
118 unsigned int x;
119 unsigned int y;
120 unsigned int width;
121 unsigned int height;
122
[a2ae4f4]123 /* Text support in window */
[76fca31]124 unsigned int cols;
125 unsigned int rows;
126
[68a4442]127 /*
128 * Style and glyphs for text printing
129 */
[ab1861a]130
[9805cde]131 /** Current attributes. */
132 attr_rgb_t attr;
[ab1861a]133
[76fca31]134 uint8_t *bgpixel;
[ab1861a]135
[4527fb5]136 /**
137 * Glyph drawing function for this viewport. Different viewports
138 * might use different drawing functions depending on whether their
139 * scanlines are aligned on a word boundary.
140 */
[68a4442]141 dg_t dglyph;
[76fca31]142
[a2ae4f4]143 /* Auto-cursor position */
[76fca31]144 bool cursor_active;
145 unsigned int cur_col;
146 unsigned int cur_row;
147 bool cursor_shown;
148
149 /* Back buffer */
[9805cde]150 bb_cell_t *backbuf;
[76fca31]151 unsigned int bbsize;
[a2ae4f4]152} viewport_t;
153
[1fd7700]154typedef struct {
[76fca31]155 bool initialized;
156 bool enabled;
[1fd7700]157 unsigned int vp;
[76fca31]158
[1fd7700]159 unsigned int pos;
160 unsigned int animlen;
161 unsigned int pixmaps[MAX_ANIM_LEN];
162} animation_t;
[76fca31]163
[1fd7700]164static animation_t animations[MAX_ANIMATIONS];
[76fca31]165static bool anims_enabled;
[1fd7700]166
[429acb9]167typedef struct {
168 unsigned int width;
169 unsigned int height;
[afbe96a]170 uint8_t *data;
[429acb9]171} pixmap_t;
172
[76fca31]173static pixmap_t pixmaps[MAX_PIXMAPS];
[a2ae4f4]174static viewport_t viewports[128];
175
[76fca31]176static bool client_connected = false; /**< Allow only 1 connection */
[afa6e74]177
[9805cde]178static uint32_t color_table[16] = {
[ab1861a]179 [COLOR_BLACK] = 0x000000,
180 [COLOR_BLUE] = 0x0000f0,
181 [COLOR_GREEN] = 0x00f000,
182 [COLOR_CYAN] = 0x00f0f0,
183 [COLOR_RED] = 0xf00000,
184 [COLOR_MAGENTA] = 0xf000f0,
185 [COLOR_YELLOW] = 0xf0f000,
186 [COLOR_WHITE] = 0xf0f0f0,
187
188 [8 + COLOR_BLACK] = 0x000000,
189 [8 + COLOR_BLUE] = 0x0000ff,
190 [8 + COLOR_GREEN] = 0x00ff00,
191 [8 + COLOR_CYAN] = 0x00ffff,
192 [8 + COLOR_RED] = 0xff0000,
193 [8 + COLOR_MAGENTA] = 0xff00ff,
194 [8 + COLOR_YELLOW] = 0xffff00,
195 [8 + COLOR_WHITE] = 0xffffff,
[9805cde]196};
197
[4a62ec9]198static int rgb_from_attr(attr_rgb_t *rgb, const attrs_t *a);
[9805cde]199static int rgb_from_style(attr_rgb_t *rgb, int style);
[96b02eb9]200static int rgb_from_idx(attr_rgb_t *rgb, sysarg_t fg_color,
201 sysarg_t bg_color, sysarg_t flags);
[9805cde]202
[96b02eb9]203static int fb_set_color(viewport_t *vport, sysarg_t fg_color,
204 sysarg_t bg_color, sysarg_t attr);
[9805cde]205
[68a4442]206static void draw_glyph_aligned(unsigned int x, unsigned int y, bool cursor,
[7ce3cb2]207 uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color);
[68a4442]208static void draw_glyph_fallback(unsigned int x, unsigned int y, bool cursor,
[7ce3cb2]209 uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color);
[68a4442]210
[67c6c651]211static void draw_vp_glyph(viewport_t *vport, bool cursor, unsigned int col,
[2d32081]212 unsigned int row);
213
214
[30885b9]215#define RED(x, bits) (((x) >> (8 + 8 + 8 - (bits))) & ((1 << (bits)) - 1))
216#define GREEN(x, bits) (((x) >> (8 + 8 - (bits))) & ((1 << (bits)) - 1))
217#define BLUE(x, bits) (((x) >> (8 - (bits))) & ((1 << (bits)) - 1))
[afa6e74]218
[76fca31]219#define COL2X(col) ((col) * FONT_WIDTH)
220#define ROW2Y(row) ((row) * FONT_SCANLINES)
[afa6e74]221
[76fca31]222#define X2COL(x) ((x) / FONT_WIDTH)
223#define Y2ROW(y) ((y) / FONT_SCANLINES)
[afa6e74]224
[76fca31]225#define FB_POS(x, y) ((y) * screen.scanline + (x) * screen.pixelbytes)
226#define BB_POS(vport, col, row) ((row) * vport->cols + (col))
227#define GLYPH_POS(glyph, y, cursor) (((glyph) + (cursor) * FONT_GLYPHS) * screen.glyphbytes + (y) * screen.glyphscanline)
[253f35a1]228
[30885b9]229/*
230 * RGB conversion and mask functions.
[76fca31]231 *
[30885b9]232 * These functions write an RGB value to some memory in some predefined format.
233 * The naming convention corresponds to the format created by these functions.
234 * The functions use the so called network order (i.e. big endian) with respect
235 * to their names.
[76fca31]236 */
[30885b9]237
[76fca31]238static void rgb_0888(void *dst, uint32_t rgb)
[afa6e74]239{
[30885b9]240 *((uint32_t *) dst) = host2uint32_t_be((0 << 24) |
241 (RED(rgb, 8) << 16) | (GREEN(rgb, 8) << 8) | (BLUE(rgb, 8)));
[ab1861a]242}
243
[30885b9]244static void bgr_0888(void *dst, uint32_t rgb)
[ab1861a]245{
[30885b9]246 *((uint32_t *) dst) = host2uint32_t_be((0 << 24) |
247 (BLUE(rgb, 8) << 16) | (GREEN(rgb, 8) << 8) | (RED(rgb, 8)));
[afa6e74]248}
249
[30885b9]250static void mask_0888(void *dst, bool mask)
[ccb0cbc]251{
[30885b9]252 bgr_0888(dst, mask ? 0xffffff : 0);
[ccb0cbc]253}
254
[6ac14a70]255static void rgb_8880(void *dst, uint32_t rgb)
256{
[30885b9]257 *((uint32_t *) dst) = host2uint32_t_be((RED(rgb, 8) << 24) |
258 (GREEN(rgb, 8) << 16) | (BLUE(rgb, 8) << 8) | 0);
[6ac14a70]259}
260
[30885b9]261static void bgr_8880(void *dst, uint32_t rgb)
[6ac14a70]262{
[30885b9]263 *((uint32_t *) dst) = host2uint32_t_be((BLUE(rgb, 8) << 24) |
264 (GREEN(rgb, 8) << 16) | (RED(rgb, 8) << 8) | 0);
[6ac14a70]265}
[76fca31]266
[30885b9]267static void mask_8880(void *dst, bool mask)
[afa6e74]268{
[30885b9]269 bgr_8880(dst, mask ? 0xffffff : 0);
[fcd7053]270}
271
[30885b9]272static void rgb_888(void *dst, uint32_t rgb)
[ab1861a]273{
[30885b9]274 ((uint8_t *) dst)[0] = RED(rgb, 8);
275 ((uint8_t *) dst)[1] = GREEN(rgb, 8);
276 ((uint8_t *) dst)[2] = BLUE(rgb, 8);
[ab1861a]277}
278
[fcd7053]279static void bgr_888(void *dst, uint32_t rgb)
280{
[30885b9]281 ((uint8_t *) dst)[0] = BLUE(rgb, 8);
[fcd7053]282 ((uint8_t *) dst)[1] = GREEN(rgb, 8);
[30885b9]283 ((uint8_t *) dst)[2] = RED(rgb, 8);
[afa6e74]284}
285
[30885b9]286static void mask_888(void *dst, bool mask)
287{
288 bgr_888(dst, mask ? 0xffffff : 0);
289}
[afa6e74]290
[19490ce]291static void rgb_555_be(void *dst, uint32_t rgb)
[2bc137c2]292{
[19490ce]293 *((uint16_t *) dst) = host2uint16_t_be(RED(rgb, 5) << 10 |
294 GREEN(rgb, 5) << 5 | BLUE(rgb, 5));
[2bc137c2]295}
296
[19490ce]297static void rgb_555_le(void *dst, uint32_t rgb)
298{
299 *((uint16_t *) dst) = host2uint16_t_le(RED(rgb, 5) << 10 |
300 GREEN(rgb, 5) << 5 | BLUE(rgb, 5));
301}
302
303static void rgb_565_be(void *dst, uint32_t rgb)
304{
305 *((uint16_t *) dst) = host2uint16_t_be(RED(rgb, 5) << 11 |
306 GREEN(rgb, 6) << 5 | BLUE(rgb, 5));
307}
308
309static void rgb_565_le(void *dst, uint32_t rgb)
[ab1861a]310{
[19490ce]311 *((uint16_t *) dst) = host2uint16_t_le(RED(rgb, 5) << 11 |
312 GREEN(rgb, 6) << 5 | BLUE(rgb, 5));
[ab1861a]313}
314
[19490ce]315static void mask_555(void *dst, bool mask)
[afa6e74]316{
[19490ce]317 rgb_555_be(dst, mask ? 0xffffff : 0);
[afa6e74]318}
319
[ab1861a]320static void mask_565(void *dst, bool mask)
321{
[19490ce]322 rgb_565_be(dst, mask ? 0xffffff : 0);
[ab1861a]323}
324
[30885b9]325static void bgr_323(void *dst, uint32_t rgb)
[afa6e74]326{
[76fca31]327 *((uint8_t *) dst)
328 = ~((RED(rgb, 3) << 5) | (GREEN(rgb, 2) << 3) | BLUE(rgb, 3));
[afa6e74]329}
330
[ab1861a]331static void mask_323(void *dst, bool mask)
332{
[30885b9]333 bgr_323(dst, mask ? 0x0 : ~0x0);
[ab1861a]334}
335
[d410328]336/** Draw a filled rectangle.
337 *
338 * @note Need real implementation that does not access VRAM twice.
[ab1861a]339 *
[d410328]340 */
[2d32081]341static void draw_filled_rect(unsigned int x0, unsigned int y0, unsigned int x1,
342 unsigned int y1, uint32_t color)
343{
[ab1861a]344 unsigned int x;
345 unsigned int y;
[d410328]346 unsigned int copy_bytes;
[ab1861a]347
348 uint8_t *sp;
349 uint8_t *dp;
[2d32081]350 uint8_t cbuf[4];
[ab1861a]351
352 if ((y0 >= y1) || (x0 >= x1))
353 return;
354
[2d32081]355 screen.rgb_conv(cbuf, color);
[ab1861a]356
[d410328]357 sp = &screen.fb_addr[FB_POS(x0, y0)];
358 dp = sp;
[ab1861a]359
[d410328]360 /* Draw the first line. */
361 for (x = x0; x < x1; x++) {
362 memcpy(dp, cbuf, screen.pixelbytes);
363 dp += screen.pixelbytes;
364 }
[ab1861a]365
[d410328]366 dp = sp + screen.scanline;
367 copy_bytes = (x1 - x0) * screen.pixelbytes;
[ab1861a]368
[d410328]369 /* Draw the remaining lines by copying. */
370 for (y = y0 + 1; y < y1; y++) {
371 memcpy(dp, sp, copy_bytes);
372 dp += screen.scanline;
[2d32081]373 }
374}
[afa6e74]375
[2d32081]376/** Redraw viewport.
[76fca31]377 *
378 * @param vport Viewport to redraw
[1180a88e]379 *
380 */
[76fca31]381static void vport_redraw(viewport_t *vport)
[a2ae4f4]382{
[ab1861a]383 unsigned int col;
[8dc12ac]384 unsigned int row;
[ab1861a]385
[76fca31]386 for (row = 0; row < vport->rows; row++) {
[2d32081]387 for (col = 0; col < vport->cols; col++) {
[67c6c651]388 draw_vp_glyph(vport, false, col, row);
[76fca31]389 }
[e92aabf]390 }
[ab1861a]391
[76fca31]392 if (COL2X(vport->cols) < vport->width) {
[2d32081]393 draw_filled_rect(
394 vport->x + COL2X(vport->cols), vport->y,
395 vport->x + vport->width, vport->y + vport->height,
[9805cde]396 vport->attr.bg_color);
[e92aabf]397 }
[ab1861a]398
[76fca31]399 if (ROW2Y(vport->rows) < vport->height) {
[2d32081]400 draw_filled_rect(
401 vport->x, vport->y + ROW2Y(vport->rows),
402 vport->x + vport->width, vport->y + vport->height,
[9805cde]403 vport->attr.bg_color);
[e92aabf]404 }
[67ec84b]405}
406
[9805cde]407static void backbuf_clear(bb_cell_t *backbuf, size_t len, uint32_t fg_color,
408 uint32_t bg_color)
409{
[ab1861a]410 size_t i;
411
[9805cde]412 for (i = 0; i < len; i++) {
413 backbuf[i].glyph = 0;
414 backbuf[i].fg_color = fg_color;
415 backbuf[i].bg_color = bg_color;
416 }
417}
[afa6e74]418
[a728ed3]419/** Clear viewport.
[76fca31]420 *
421 * @param vport Viewport to clear
[a2ae4f4]422 *
423 */
[76fca31]424static void vport_clear(viewport_t *vport)
[afa6e74]425{
[9805cde]426 backbuf_clear(vport->backbuf, vport->cols * vport->rows,
427 vport->attr.fg_color, vport->attr.bg_color);
[76fca31]428 vport_redraw(vport);
[e92aabf]429}
430
[a728ed3]431/** Scroll viewport by the specified number of lines.
[76fca31]432 *
433 * @param vport Viewport to scroll
434 * @param lines Number of lines to scroll
435 *
436 */
437static void vport_scroll(viewport_t *vport, int lines)
[e92aabf]438{
[ab1861a]439 unsigned int col;
[8dc12ac]440 unsigned int row;
[ab1861a]441 unsigned int x;
442 unsigned int y;
[67ebf21]443 uint32_t glyph;
[9805cde]444 uint32_t fg_color;
445 uint32_t bg_color;
[ab1861a]446 bb_cell_t *bbp;
447 bb_cell_t *xbp;
448
[67c6c651]449 /*
450 * Redraw.
451 */
[ab1861a]452
[67c6c651]453 y = vport->y;
454 for (row = 0; row < vport->rows; row++) {
455 x = vport->x;
456 for (col = 0; col < vport->cols; col++) {
[0471786]457 if (((int) row + lines >= 0) &&
458 ((int) row + lines < (int) vport->rows)) {
[9805cde]459 xbp = &vport->backbuf[BB_POS(vport, col, row + lines)];
460 bbp = &vport->backbuf[BB_POS(vport, col, row)];
[ab1861a]461
[9805cde]462 glyph = xbp->glyph;
463 fg_color = xbp->fg_color;
464 bg_color = xbp->bg_color;
[ab1861a]465
466 if ((bbp->glyph == glyph)
467 && (bbp->fg_color == xbp->fg_color)
468 && (bbp->bg_color == xbp->bg_color)) {
[67c6c651]469 x += FONT_WIDTH;
470 continue;
471 }
472 } else {
473 glyph = 0;
[9805cde]474 fg_color = vport->attr.fg_color;
475 bg_color = vport->attr.bg_color;
[67c6c651]476 }
[ab1861a]477
[4527fb5]478 (*vport->dglyph)(x, y, false, screen.glyphs, glyph,
[9805cde]479 fg_color, bg_color);
[67c6c651]480 x += FONT_WIDTH;
481 }
482 y += FONT_SCANLINES;
483 }
[ab1861a]484
[a728ed3]485 /*
486 * Scroll backbuffer.
487 */
[ab1861a]488
[76fca31]489 if (lines > 0) {
[67c6c651]490 memmove(vport->backbuf, vport->backbuf + vport->cols * lines,
[9805cde]491 vport->cols * (vport->rows - lines) * sizeof(bb_cell_t));
492 backbuf_clear(&vport->backbuf[BB_POS(vport, 0, vport->rows - lines)],
493 vport->cols * lines, vport->attr.fg_color, vport->attr.bg_color);
[76fca31]494 } else {
[67c6c651]495 memmove(vport->backbuf - vport->cols * lines, vport->backbuf,
[9805cde]496 vport->cols * (vport->rows + lines) * sizeof(bb_cell_t));
497 backbuf_clear(vport->backbuf, - vport->cols * lines,
498 vport->attr.fg_color, vport->attr.bg_color);
[76fca31]499 }
[2d32081]500}
[afa6e74]501
[76fca31]502/** Render glyphs
503 *
504 * Convert glyphs from device independent font
505 * description to current visual representation.
[ab1861a]506 *
[d530237a]507 */
[4527fb5]508static void render_glyphs(void)
[afa6e74]509{
[76fca31]510 unsigned int glyph;
[ab1861a]511
[76fca31]512 for (glyph = 0; glyph < FONT_GLYPHS; glyph++) {
513 unsigned int y;
[ab1861a]514
[76fca31]515 for (y = 0; y < FONT_SCANLINES; y++) {
516 unsigned int x;
[ab1861a]517
[76fca31]518 for (x = 0; x < FONT_WIDTH; x++) {
[ab1861a]519 screen.mask_conv(&screen.glyphs[GLYPH_POS(glyph, y, false) + x * screen.pixelbytes],
[3c101bd4]520 (fb_font[glyph][y] & (1 << (7 - x))) ? true : false);
[ab1861a]521
522 screen.mask_conv(&screen.glyphs[GLYPH_POS(glyph, y, true) + x * screen.pixelbytes],
[3c101bd4]523 (fb_font[glyph][y] & (1 << (7 - x))) ? false : true);
[76fca31]524 }
[6b5111a]525 }
526 }
[afa6e74]527}
528
[a2ae4f4]529/** Create new viewport
[afa6e74]530 *
[76fca31]531 * @param x Origin of the viewport (x).
532 * @param y Origin of the viewport (y).
533 * @param width Width of the viewport.
534 * @param height Height of the viewport.
535 *
536 * @return New viewport number.
537 *
[afa6e74]538 */
[76fca31]539static int vport_create(unsigned int x, unsigned int y,
540 unsigned int width, unsigned int height)
[afa6e74]541{
[76fca31]542 unsigned int i;
543
[d7baee6]544 for (i = 0; i < MAX_VIEWPORTS; i++) {
[a2ae4f4]545 if (!viewports[i].initialized)
[afa6e74]546 break;
547 }
[ab1861a]548
[a2ae4f4]549 if (i == MAX_VIEWPORTS)
550 return ELIMIT;
[76fca31]551
552 unsigned int cols = width / FONT_WIDTH;
553 unsigned int rows = height / FONT_SCANLINES;
[9805cde]554 unsigned int bbsize = cols * rows * sizeof(bb_cell_t);
[68a4442]555 unsigned int word_size = sizeof(unsigned long);
[76fca31]556
[9805cde]557 bb_cell_t *backbuf = (bb_cell_t *) malloc(bbsize);
[76fca31]558 if (!backbuf)
559 return ENOMEM;
560
561 uint8_t *bgpixel = (uint8_t *) malloc(screen.pixelbytes);
562 if (!bgpixel) {
563 free(backbuf);
564 return ENOMEM;
565 }
[ab1861a]566
[9805cde]567 backbuf_clear(backbuf, cols * rows, DEFAULT_FGCOLOR, DEFAULT_BGCOLOR);
[76fca31]568 memset(bgpixel, 0, screen.pixelbytes);
569
[a2ae4f4]570 viewports[i].x = x;
571 viewports[i].y = y;
572 viewports[i].width = width;
573 viewports[i].height = height;
[afa6e74]574
[76fca31]575 viewports[i].cols = cols;
576 viewports[i].rows = rows;
577
[9805cde]578 viewports[i].attr.bg_color = DEFAULT_BGCOLOR;
579 viewports[i].attr.fg_color = DEFAULT_FGCOLOR;
[afa6e74]580
[76fca31]581 viewports[i].bgpixel = bgpixel;
[ab1861a]582
[68a4442]583 /*
[ab1861a]584 * Conditions necessary to select aligned version:
585 * - word size is divisible by pixelbytes
586 * - cell scanline size is divisible by word size
587 * - cell scanlines are word-aligned
[68a4442]588 *
589 */
[ab1861a]590 if (((word_size % screen.pixelbytes) == 0)
591 && ((FONT_WIDTH * screen.pixelbytes) % word_size == 0)
592 && ((x * screen.pixelbytes) % word_size == 0)
593 && (screen.scanline % word_size == 0)) {
[68a4442]594 viewports[i].dglyph = draw_glyph_aligned;
595 } else {
596 viewports[i].dglyph = draw_glyph_fallback;
597 }
[ab1861a]598
[c1d2c9d]599 viewports[i].cur_col = 0;
600 viewports[i].cur_row = 0;
[76fca31]601 viewports[i].cursor_active = false;
602 viewports[i].cursor_shown = false;
603
604 viewports[i].bbsize = bbsize;
605 viewports[i].backbuf = backbuf;
606
607 viewports[i].initialized = true;
608
[4527fb5]609 screen.rgb_conv(viewports[i].bgpixel, viewports[i].attr.bg_color);
[76fca31]610
[a2ae4f4]611 return i;
[afa6e74]612}
613
[76fca31]614
[afa6e74]615/** Initialize framebuffer as a chardev output device
616 *
[76fca31]617 * @param addr Address of the framebuffer
618 * @param xres Screen width in pixels
619 * @param yres Screen height in pixels
620 * @param visual Bits per pixel (8, 16, 24, 32)
621 * @param scan Bytes per one scanline
[afa6e74]622 *
623 */
[76fca31]624static bool screen_init(void *addr, unsigned int xres, unsigned int yres,
625 unsigned int scan, unsigned int visual)
[afa6e74]626{
[2bc137c2]627 switch (visual) {
628 case VISUAL_INDIRECT_8:
[30885b9]629 screen.rgb_conv = bgr_323;
[ab1861a]630 screen.mask_conv = mask_323;
[775df25]631 screen.pixelbytes = 1;
632 break;
[19490ce]633 case VISUAL_RGB_5_5_5_LE:
634 screen.rgb_conv = rgb_555_le;
635 screen.mask_conv = mask_555;
636 screen.pixelbytes = 2;
637 break;
638 case VISUAL_RGB_5_5_5_BE:
639 screen.rgb_conv = rgb_555_be;
[ab1861a]640 screen.mask_conv = mask_555;
[775df25]641 screen.pixelbytes = 2;
642 break;
[19490ce]643 case VISUAL_RGB_5_6_5_LE:
644 screen.rgb_conv = rgb_565_le;
645 screen.mask_conv = mask_565;
646 screen.pixelbytes = 2;
647 break;
648 case VISUAL_RGB_5_6_5_BE:
649 screen.rgb_conv = rgb_565_be;
[ab1861a]650 screen.mask_conv = mask_565;
[2bc137c2]651 screen.pixelbytes = 2;
[775df25]652 break;
[2bc137c2]653 case VISUAL_RGB_8_8_8:
[76fca31]654 screen.rgb_conv = rgb_888;
[ab1861a]655 screen.mask_conv = mask_888;
[2bc137c2]656 screen.pixelbytes = 3;
657 break;
[fcd7053]658 case VISUAL_BGR_8_8_8:
659 screen.rgb_conv = bgr_888;
[ab1861a]660 screen.mask_conv = mask_888;
[fcd7053]661 screen.pixelbytes = 3;
662 break;
[2bc137c2]663 case VISUAL_RGB_8_8_8_0:
[6ac14a70]664 screen.rgb_conv = rgb_8880;
665 screen.mask_conv = mask_8880;
[2bc137c2]666 screen.pixelbytes = 4;
667 break;
668 case VISUAL_RGB_0_8_8_8:
[76fca31]669 screen.rgb_conv = rgb_0888;
[ab1861a]670 screen.mask_conv = mask_0888;
[775df25]671 screen.pixelbytes = 4;
672 break;
[ccb0cbc]673 case VISUAL_BGR_0_8_8_8:
[76fca31]674 screen.rgb_conv = bgr_0888;
[ab1861a]675 screen.mask_conv = mask_0888;
[ccb0cbc]676 screen.pixelbytes = 4;
677 break;
[30885b9]678 case VISUAL_BGR_8_8_8_0:
679 screen.rgb_conv = bgr_8880;
680 screen.mask_conv = mask_8880;
681 screen.pixelbytes = 4;
682 break;
[2bc137c2]683 default:
684 return false;
[afa6e74]685 }
[ab1861a]686
[76fca31]687 screen.fb_addr = (unsigned char *) addr;
[a2ae4f4]688 screen.xres = xres;
689 screen.yres = yres;
690 screen.scanline = scan;
[76fca31]691
692 screen.glyphscanline = FONT_WIDTH * screen.pixelbytes;
693 screen.glyphbytes = screen.glyphscanline * FONT_SCANLINES;
[ab1861a]694
695 size_t glyphsize = 2 * FONT_GLYPHS * screen.glyphbytes;
696 uint8_t *glyphs = (uint8_t *) malloc(glyphsize);
[4527fb5]697 if (!glyphs)
698 return false;
699
700 memset(glyphs, 0, glyphsize);
701 screen.glyphs = glyphs;
[ab1861a]702
[4527fb5]703 render_glyphs();
[afa6e74]704
[a2ae4f4]705 /* Create first viewport */
[76fca31]706 vport_create(0, 0, xres, yres);
[2bc137c2]707
708 return true;
[afa6e74]709}
710
[76fca31]711
[68a4442]712/** Draw a glyph, takes advantage of alignment.
[67c6c651]713 *
[68a4442]714 * This version can only be used if the following conditions are met:
715 *
716 * - word size is divisible by pixelbytes
717 * - cell scanline size is divisible by word size
718 * - cell scanlines are word-aligned
[67c6c651]719 *
[68a4442]720 * It makes use of the pre-rendered mask to process (possibly) several
721 * pixels at once (word size / pixelbytes pixels at a time are processed)
722 * making it very fast. Most notably this version is not applicable at 24 bits
723 * per pixel.
724 *
[ab1861a]725 * @param x x coordinate of top-left corner on screen.
726 * @param y y coordinate of top-left corner on screen.
727 * @param cursor Draw glyph with cursor
728 * @param glyphs Pointer to font bitmap.
729 * @param glyph Code of the glyph to draw.
730 * @param fg_color Foreground color.
731 * @param bg_color Backgroudn color.
732 *
[67c6c651]733 */
[68a4442]734static void draw_glyph_aligned(unsigned int x, unsigned int y, bool cursor,
[7ce3cb2]735 uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color)
[67c6c651]736{
[ab1861a]737 unsigned int i;
738 unsigned int yd;
739 unsigned long fg_buf;
740 unsigned long bg_buf;
[68a4442]741 unsigned long mask;
[ab1861a]742
[68a4442]743 /*
744 * Prepare a pair of words, one filled with foreground-color
745 * pattern and the other filled with background-color pattern.
746 */
747 for (i = 0; i < sizeof(unsigned long) / screen.pixelbytes; i++) {
[ab1861a]748 screen.rgb_conv(&((uint8_t *) &fg_buf)[i * screen.pixelbytes],
[68a4442]749 fg_color);
[ab1861a]750 screen.rgb_conv(&((uint8_t *) &bg_buf)[i * screen.pixelbytes],
[68a4442]751 bg_color);
752 }
[ab1861a]753
[68a4442]754 /* Pointer to the current position in the mask. */
[ab1861a]755 unsigned long *maskp = (unsigned long *) &glyphs[GLYPH_POS(glyph, 0, cursor)];
756
[68a4442]757 /* Pointer to the current position on the screen. */
[ab1861a]758 unsigned long *dp = (unsigned long *) &screen.fb_addr[FB_POS(x, y)];
759
[68a4442]760 /* Width of the character cell in words. */
[ab1861a]761 unsigned int ww = FONT_WIDTH * screen.pixelbytes / sizeof(unsigned long);
762
[68a4442]763 /* Offset to add when moving to another screen scanline. */
[ab1861a]764 unsigned int d_add = screen.scanline - FONT_WIDTH * screen.pixelbytes;
765
[68a4442]766 for (yd = 0; yd < FONT_SCANLINES; yd++) {
767 /*
768 * Now process the cell scanline, combining foreground
769 * and background color patters using the pre-rendered mask.
770 */
771 for (i = 0; i < ww; i++) {
772 mask = *maskp++;
773 *dp++ = (fg_buf & mask) | (bg_buf & ~mask);
774 }
[ab1861a]775
[68a4442]776 /* Move to the beginning of the next scanline of the cell. */
777 dp = (unsigned long *) ((uint8_t *) dp + d_add);
778 }
779}
780
781/** Draw a glyph, fallback version.
782 *
783 * This version does not make use of the pre-rendered mask, it uses
784 * the font bitmap directly. It works always, but it is slower.
785 *
[ab1861a]786 * @param x x coordinate of top-left corner on screen.
787 * @param y y coordinate of top-left corner on screen.
788 * @param cursor Draw glyph with cursor
789 * @param glyphs Pointer to font bitmap.
790 * @param glyph Code of the glyph to draw.
791 * @param fg_color Foreground color.
792 * @param bg_color Backgroudn color.
793 *
[68a4442]794 */
795void draw_glyph_fallback(unsigned int x, unsigned int y, bool cursor,
[7ce3cb2]796 uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color)
[68a4442]797{
[ab1861a]798 unsigned int i;
799 unsigned int j;
800 unsigned int yd;
801 uint8_t fg_buf[4];
802 uint8_t bg_buf[4];
803 uint8_t *sp;
[68a4442]804 uint8_t b;
[ab1861a]805
[68a4442]806 /* Pre-render 1x the foreground and background color pixels. */
807 if (cursor) {
808 screen.rgb_conv(fg_buf, bg_color);
809 screen.rgb_conv(bg_buf, fg_color);
810 } else {
811 screen.rgb_conv(fg_buf, fg_color);
812 screen.rgb_conv(bg_buf, bg_color);
813 }
[ab1861a]814
[68a4442]815 /* Pointer to the current position on the screen. */
[ab1861a]816 uint8_t *dp = (uint8_t *) &screen.fb_addr[FB_POS(x, y)];
817
[68a4442]818 /* Offset to add when moving to another screen scanline. */
[ab1861a]819 unsigned int d_add = screen.scanline - FONT_WIDTH * screen.pixelbytes;
820
[68a4442]821 for (yd = 0; yd < FONT_SCANLINES; yd++) {
822 /* Byte containing bits of the glyph scanline. */
[67ebf21]823 b = fb_font[glyph][yd];
[ab1861a]824
[68a4442]825 for (i = 0; i < FONT_WIDTH; i++) {
826 /* Choose color based on the current bit. */
827 sp = (b & 0x80) ? fg_buf : bg_buf;
[ab1861a]828
[68a4442]829 /* Copy the pixel. */
830 for (j = 0; j < screen.pixelbytes; j++) {
831 *dp++ = *sp++;
832 }
[ab1861a]833
[68a4442]834 /* Move to the next bit. */
835 b = b << 1;
836 }
837
838 /* Move to the beginning of the next scanline of the cell. */
839 dp += d_add;
840 }
[67c6c651]841}
842
[ab1861a]843/** Draw glyph at specified position in viewport.
[76fca31]844 *
845 * @param vport Viewport identification
846 * @param cursor Draw glyph with cursor
847 * @param col Screen position relative to viewport
848 * @param row Screen position relative to viewport
849 *
850 */
[67c6c651]851static void draw_vp_glyph(viewport_t *vport, bool cursor, unsigned int col,
852 unsigned int row)
[76fca31]853{
854 unsigned int x = vport->x + COL2X(col);
855 unsigned int y = vport->y + ROW2Y(row);
856
[ab1861a]857 uint32_t glyph = vport->backbuf[BB_POS(vport, col, row)].glyph;
858 uint32_t fg_color = vport->backbuf[BB_POS(vport, col, row)].fg_color;
859 uint32_t bg_color = vport->backbuf[BB_POS(vport, col, row)].bg_color;
860
[4527fb5]861 (*vport->dglyph)(x, y, cursor, screen.glyphs, glyph,
[9805cde]862 fg_color, bg_color);
[68a4442]863}
[76fca31]864
865/** Hide cursor if it is shown
866 *
867 */
868static void cursor_hide(viewport_t *vport)
[49d072e]869{
[76fca31]870 if ((vport->cursor_active) && (vport->cursor_shown)) {
[67c6c651]871 draw_vp_glyph(vport, false, vport->cur_col, vport->cur_row);
[76fca31]872 vport->cursor_shown = false;
[49d072e]873 }
874}
875
[76fca31]876
877/** Show cursor if cursor showing is enabled
878 *
879 */
880static void cursor_show(viewport_t *vport)
[49d072e]881{
882 /* Do not check for cursor_shown */
883 if (vport->cursor_active) {
[67c6c651]884 draw_vp_glyph(vport, true, vport->cur_col, vport->cur_row);
[76fca31]885 vport->cursor_shown = true;
[49d072e]886 }
887}
888
[76fca31]889
890/** Invert cursor, if it is enabled
891 *
892 */
893static void cursor_blink(viewport_t *vport)
[49d072e]894{
895 if (vport->cursor_shown)
[bd02038]896 cursor_hide(vport);
[49d072e]897 else
[76fca31]898 cursor_show(vport);
[49d072e]899}
900
[76fca31]901
902/** Draw character at given position relative to viewport
903 *
904 * @param vport Viewport identification
905 * @param c Character to draw
906 * @param col Screen position relative to viewport
907 * @param row Screen position relative to viewport
908 *
[1180a88e]909 */
[7ce3cb2]910static void draw_char(viewport_t *vport, wchar_t c, unsigned int col, unsigned int row)
[88c3151]911{
[9805cde]912 bb_cell_t *bbp;
[ab1861a]913
[76fca31]914 /* Do not hide cursor if we are going to overwrite it */
915 if ((vport->cursor_active) && (vport->cursor_shown) &&
916 ((vport->cur_col != col) || (vport->cur_row != row)))
917 cursor_hide(vport);
[ab1861a]918
[9805cde]919 bbp = &vport->backbuf[BB_POS(vport, col, row)];
[67ebf21]920 bbp->glyph = fb_font_glyph(c);
[9805cde]921 bbp->fg_color = vport->attr.fg_color;
922 bbp->bg_color = vport->attr.bg_color;
[ab1861a]923
[67c6c651]924 draw_vp_glyph(vport, false, col, row);
[88c3151]925
[c1d2c9d]926 vport->cur_col = col;
927 vport->cur_row = row;
[76fca31]928
[c1d2c9d]929 vport->cur_col++;
[00bb6965]930 if (vport->cur_col >= vport->cols) {
[c1d2c9d]931 vport->cur_col = 0;
932 vport->cur_row++;
933 if (vport->cur_row >= vport->rows)
934 vport->cur_row--;
[88c3151]935 }
[76fca31]936
937 cursor_show(vport);
[88c3151]938}
939
[dc033a1]940/** Draw text data to viewport.
[429acb9]941 *
[096ba7a]942 * @param vport Viewport id
[dc033a1]943 * @param data Text data.
[ab1861a]944 * @param x Leftmost column of the area.
945 * @param y Topmost row of the area.
946 * @param w Number of rows.
947 * @param h Number of columns.
948 *
[429acb9]949 */
[dc033a1]950static void draw_text_data(viewport_t *vport, keyfield_t *data, unsigned int x,
951 unsigned int y, unsigned int w, unsigned int h)
[83b1d61]952{
[ab1861a]953 unsigned int i;
954 unsigned int j;
[9805cde]955 bb_cell_t *bbp;
956 attrs_t *a;
[ab1861a]957
[dc033a1]958 for (j = 0; j < h; j++) {
959 for (i = 0; i < w; i++) {
960 unsigned int col = x + i;
961 unsigned int row = y + j;
[ab1861a]962
[dc033a1]963 bbp = &vport->backbuf[BB_POS(vport, col, row)];
[ab1861a]964
[dc033a1]965 a = &data[j * w + i].attrs;
[9f1362d4]966
967 attr_rgb_t rgb;
968 rgb.fg_color = 0;
969 rgb.bg_color = 0;
[dc033a1]970 rgb_from_attr(&rgb, a);
[ab1861a]971
[67ebf21]972 bbp->glyph = fb_font_glyph(data[j * w + i].character);
[dc033a1]973 bbp->fg_color = rgb.fg_color;
974 bbp->bg_color = rgb.bg_color;
[ab1861a]975
[dc033a1]976 draw_vp_glyph(vport, false, col, row);
977 }
[83b1d61]978 }
[76fca31]979 cursor_show(vport);
[83b1d61]980}
981
[76fca31]982
983static void putpixel_pixmap(void *data, unsigned int x, unsigned int y, uint32_t color)
[a7d2d78]984{
[76fca31]985 int pm = *((int *) data);
986 pixmap_t *pmap = &pixmaps[pm];
987 unsigned int pos = (y * pmap->width + x) * screen.pixelbytes;
[a7d2d78]988
[76fca31]989 screen.rgb_conv(&pmap->data[pos], color);
[a7d2d78]990}
991
[76fca31]992
993static void putpixel(void *data, unsigned int x, unsigned int y, uint32_t color)
[a7d2d78]994{
[76fca31]995 viewport_t *vport = (viewport_t *) data;
996 unsigned int dx = vport->x + x;
997 unsigned int dy = vport->y + y;
998
999 screen.rgb_conv(&screen.fb_addr[FB_POS(dx, dy)], color);
1000}
1001
[a7d2d78]1002
[76fca31]1003/** Return first free pixmap
1004 *
1005 */
1006static int find_free_pixmap(void)
1007{
1008 unsigned int i;
1009
1010 for (i = 0; i < MAX_PIXMAPS; i++)
1011 if (!pixmaps[i].data)
1012 return i;
1013
1014 return -1;
[a7d2d78]1015}
1016
[76fca31]1017
1018/** Create a new pixmap and return appropriate ID
1019 *
1020 */
1021static int shm2pixmap(unsigned char *shm, size_t size)
[a7d2d78]1022{
1023 int pm;
1024 pixmap_t *pmap;
[76fca31]1025
[a7d2d78]1026 pm = find_free_pixmap();
1027 if (pm == -1)
1028 return ELIMIT;
[76fca31]1029
[a7d2d78]1030 pmap = &pixmaps[pm];
1031
1032 if (ppm_get_data(shm, size, &pmap->width, &pmap->height))
1033 return EINVAL;
1034
1035 pmap->data = malloc(pmap->width * pmap->height * screen.pixelbytes);
1036 if (!pmap->data)
1037 return ENOMEM;
[76fca31]1038
1039 ppm_draw(shm, size, 0, 0, pmap->width, pmap->height, putpixel_pixmap, (void *) &pm);
1040
[a7d2d78]1041 return pm;
1042}
1043
[76fca31]1044
[429acb9]1045/** Handle shared memory communication calls
1046 *
1047 * Protocol for drawing pixmaps:
1048 * - FB_PREPARE_SHM(client shm identification)
[00bb6965]1049 * - IPC_M_AS_AREA_SEND
[76fca31]1050 * - FB_DRAW_PPM(startx, starty)
[429acb9]1051 * - FB_DROP_SHM
1052 *
1053 * Protocol for text drawing
[00bb6965]1054 * - IPC_M_AS_AREA_SEND
[429acb9]1055 * - FB_DRAW_TEXT_DATA
1056 *
1057 * @param callid Callid of the current call
[76fca31]1058 * @param call Current call data
1059 * @param vp Active viewport
[429acb9]1060 *
[76fca31]1061 * @return false if the call was not handled byt this function, true otherwise
1062 *
[26360f7]1063 * Note: this function is not thread-safe, you would have
1064 * to redefine static variables with fibril_local.
[76fca31]1065 *
[429acb9]1066 */
[76fca31]1067static bool shm_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
[90f5d64]1068{
1069 static keyfield_t *interbuffer = NULL;
1070 static size_t intersize = 0;
[76fca31]1071
[153a209]1072 static unsigned char *shm = NULL;
[96b02eb9]1073 static sysarg_t shm_id = 0;
[a7d2d78]1074 static size_t shm_size;
[76fca31]1075
1076 bool handled = true;
1077 int retval = EOK;
[90f5d64]1078 viewport_t *vport = &viewports[vp];
[76fca31]1079 unsigned int x;
1080 unsigned int y;
[dc033a1]1081 unsigned int w;
1082 unsigned int h;
[76fca31]1083
[228e490]1084 switch (IPC_GET_IMETHOD(*call)) {
[27d293a]1085 case IPC_M_SHARE_OUT:
[90f5d64]1086 /* We accept one area for data interchange */
[a7d2d78]1087 if (IPC_GET_ARG1(*call) == shm_id) {
[2057572]1088 void *dest = as_get_mappable_page(IPC_GET_ARG2(*call));
[a7d2d78]1089 shm_size = IPC_GET_ARG2(*call);
[ffa2c8ef]1090 if (async_answer_1(callid, EOK, (sysarg_t) dest)) {
[a7d2d78]1091 shm_id = 0;
[7ece1fbe]1092 return false;
1093 }
1094 shm = dest;
[76fca31]1095
[a7d2d78]1096 if (shm[0] != 'P')
[76fca31]1097 return false;
1098
1099 return true;
[90f5d64]1100 } else {
1101 intersize = IPC_GET_ARG2(*call);
[f8ddd17]1102 receive_comm_area(callid, call, (void *) &interbuffer);
[90f5d64]1103 }
[76fca31]1104 return true;
[90f5d64]1105 case FB_PREPARE_SHM:
[a7d2d78]1106 if (shm_id)
[90f5d64]1107 retval = EBUSY;
1108 else
[a7d2d78]1109 shm_id = IPC_GET_ARG1(*call);
[90f5d64]1110 break;
1111
1112 case FB_DROP_SHM:
[a7d2d78]1113 if (shm) {
1114 as_area_destroy(shm);
1115 shm = NULL;
[90f5d64]1116 }
[a7d2d78]1117 shm_id = 0;
1118 break;
[76fca31]1119
[a7d2d78]1120 case FB_SHM2PIXMAP:
1121 if (!shm) {
1122 retval = EINVAL;
1123 break;
1124 }
1125 retval = shm2pixmap(shm, shm_size);
[90f5d64]1126 break;
1127 case FB_DRAW_PPM:
[a7d2d78]1128 if (!shm) {
[90f5d64]1129 retval = EINVAL;
1130 break;
1131 }
1132 x = IPC_GET_ARG1(*call);
1133 y = IPC_GET_ARG2(*call);
[76fca31]1134
1135 if ((x > vport->width) || (y > vport->height)) {
[90f5d64]1136 retval = EINVAL;
1137 break;
1138 }
1139
[00bb6965]1140 ppm_draw(shm, shm_size, IPC_GET_ARG1(*call),
[76fca31]1141 IPC_GET_ARG2(*call), vport->width - x, vport->height - y, putpixel, (void *) vport);
[90f5d64]1142 break;
1143 case FB_DRAW_TEXT_DATA:
[dc033a1]1144 x = IPC_GET_ARG1(*call);
1145 y = IPC_GET_ARG2(*call);
1146 w = IPC_GET_ARG3(*call);
1147 h = IPC_GET_ARG4(*call);
[90f5d64]1148 if (!interbuffer) {
1149 retval = EINVAL;
1150 break;
1151 }
[dc033a1]1152 if (x + w > vport->cols || y + h > vport->rows) {
1153 retval = EINVAL;
1154 break;
1155 }
1156 if (intersize < w * h * sizeof(*interbuffer)) {
[90f5d64]1157 retval = EINVAL;
1158 break;
1159 }
[dc033a1]1160 draw_text_data(vport, interbuffer, x, y, w, h);
[90f5d64]1161 break;
1162 default:
[76fca31]1163 handled = false;
[90f5d64]1164 }
1165
1166 if (handled)
[ffa2c8ef]1167 async_answer_0(callid, retval);
[90f5d64]1168 return handled;
1169}
[83b1d61]1170
[2ce520c]1171
[76fca31]1172static void copy_vp_to_pixmap(viewport_t *vport, pixmap_t *pmap)
1173{
1174 unsigned int width = vport->width;
1175 unsigned int height = vport->height;
1176
[2ce520c]1177 if (width + vport->x > screen.xres)
1178 width = screen.xres - vport->x;
[07bd231e]1179 if (height + vport->y > screen.yres)
[2ce520c]1180 height = screen.yres - vport->y;
[07bd231e]1181
[76fca31]1182 unsigned int realwidth = pmap->width <= width ? pmap->width : width;
1183 unsigned int realheight = pmap->height <= height ? pmap->height : height;
[07bd231e]1184
[76fca31]1185 unsigned int srcrowsize = vport->width * screen.pixelbytes;
1186 unsigned int realrowsize = realwidth * screen.pixelbytes;
1187
1188 unsigned int y;
[07bd231e]1189 for (y = 0; y < realheight; y++) {
[76fca31]1190 unsigned int tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;
1191 memcpy(pmap->data + srcrowsize * y, screen.fb_addr + tmp, realrowsize);
[2ce520c]1192 }
1193}
1194
[76fca31]1195
1196/** Save viewport to pixmap
1197 *
1198 */
1199static int save_vp_to_pixmap(viewport_t *vport)
[2ce520c]1200{
1201 int pm;
1202 pixmap_t *pmap;
[76fca31]1203
[429acb9]1204 pm = find_free_pixmap();
1205 if (pm == -1)
1206 return ELIMIT;
1207
1208 pmap = &pixmaps[pm];
1209 pmap->data = malloc(screen.pixelbytes * vport->width * vport->height);
1210 if (!pmap->data)
1211 return ENOMEM;
[76fca31]1212
[429acb9]1213 pmap->width = vport->width;
1214 pmap->height = vport->height;
[76fca31]1215
[2ce520c]1216 copy_vp_to_pixmap(vport, pmap);
[429acb9]1217
1218 return pm;
1219}
1220
[76fca31]1221
[429acb9]1222/** Draw pixmap on screen
1223 *
1224 * @param vp Viewport to draw on
1225 * @param pm Pixmap identifier
[76fca31]1226 *
[429acb9]1227 */
1228static int draw_pixmap(int vp, int pm)
1229{
1230 pixmap_t *pmap = &pixmaps[pm];
1231 viewport_t *vport = &viewports[vp];
[76fca31]1232
1233 unsigned int width = vport->width;
1234 unsigned int height = vport->height;
1235
[2ce520c]1236 if (width + vport->x > screen.xres)
1237 width = screen.xres - vport->x;
1238 if (height + vport->y > screen.yres)
1239 height = screen.yres - vport->y;
[76fca31]1240
[429acb9]1241 if (!pmap->data)
1242 return EINVAL;
[76fca31]1243
1244 unsigned int realwidth = pmap->width <= width ? pmap->width : width;
1245 unsigned int realheight = pmap->height <= height ? pmap->height : height;
1246
1247 unsigned int srcrowsize = vport->width * screen.pixelbytes;
1248 unsigned int realrowsize = realwidth * screen.pixelbytes;
1249
1250 unsigned int y;
[d7baee6]1251 for (y = 0; y < realheight; y++) {
[76fca31]1252 unsigned int tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;
1253 memcpy(screen.fb_addr + tmp, pmap->data + y * srcrowsize, realrowsize);
[429acb9]1254 }
[76fca31]1255
1256 return EOK;
[429acb9]1257}
1258
[76fca31]1259
1260/** Tick animation one step forward
1261 *
1262 */
1263static void anims_tick(void)
[1fd7700]1264{
[76fca31]1265 unsigned int i;
[1fd7700]1266 static int counts = 0;
1267
1268 /* Limit redrawing */
[00bb6965]1269 counts = (counts + 1) % 8;
[1fd7700]1270 if (counts)
1271 return;
[ab1861a]1272
[d7baee6]1273 for (i = 0; i < MAX_ANIMATIONS; i++) {
[76fca31]1274 if ((!animations[i].animlen) || (!animations[i].initialized) ||
1275 (!animations[i].enabled))
[1fd7700]1276 continue;
[76fca31]1277
1278 draw_pixmap(animations[i].vp, animations[i].pixmaps[animations[i].pos]);
1279 animations[i].pos = (animations[i].pos + 1) % animations[i].animlen;
[1fd7700]1280 }
1281}
1282
[2ce520c]1283
[76fca31]1284static unsigned int pointer_x;
1285static unsigned int pointer_y;
1286static bool pointer_shown, pointer_enabled;
[2ce520c]1287static int pointer_vport = -1;
1288static int pointer_pixmap = -1;
1289
[76fca31]1290
1291static void mouse_show(void)
[2ce520c]1292{
[d7baee6]1293 int i, j;
[2ce520c]1294 int visibility;
1295 int color;
1296 int bytepos;
[76fca31]1297
1298 if ((pointer_shown) || (!pointer_enabled))
[a3d2939]1299 return;
[76fca31]1300
[2d32081]1301 /* Save image under the pointer. */
[2ce520c]1302 if (pointer_vport == -1) {
[76fca31]1303 pointer_vport = vport_create(pointer_x, pointer_y, pointer_width, pointer_height);
[2ce520c]1304 if (pointer_vport < 0)
1305 return;
1306 } else {
1307 viewports[pointer_vport].x = pointer_x;
1308 viewports[pointer_vport].y = pointer_y;
1309 }
[76fca31]1310
[2ce520c]1311 if (pointer_pixmap == -1)
1312 pointer_pixmap = save_vp_to_pixmap(&viewports[pointer_vport]);
1313 else
[76fca31]1314 copy_vp_to_pixmap(&viewports[pointer_vport], &pixmaps[pointer_pixmap]);
1315
[2d32081]1316 /* Draw mouse pointer. */
[00bb6965]1317 for (i = 0; i < pointer_height; i++)
1318 for (j = 0; j < pointer_width; j++) {
1319 bytepos = i * ((pointer_width - 1) / 8 + 1) + j / 8;
[d7baee6]1320 visibility = pointer_mask_bits[bytepos] &
[b74959bd]1321 (1 << (j % 8));
[2ce520c]1322 if (visibility) {
[b74959bd]1323 color = pointer_bits[bytepos] &
1324 (1 << (j % 8)) ? 0 : 0xffffff;
[00bb6965]1325 if (pointer_x + j < screen.xres && pointer_y +
[b74959bd]1326 i < screen.yres)
[00bb6965]1327 putpixel(&viewports[0], pointer_x + j,
[b74959bd]1328 pointer_y + i, color);
[2ce520c]1329 }
1330 }
1331 pointer_shown = 1;
1332}
1333
[76fca31]1334
1335static void mouse_hide(void)
[2ce520c]1336{
[2d32081]1337 /* Restore image under the pointer. */
[2ce520c]1338 if (pointer_shown) {
1339 draw_pixmap(pointer_vport, pointer_pixmap);
1340 pointer_shown = 0;
1341 }
1342}
1343
[76fca31]1344
1345static void mouse_move(unsigned int x, unsigned int y)
[2ce520c]1346{
1347 mouse_hide();
[5b8b66c]1348 pointer_x = x % screen.xres;
1349 pointer_y = y % screen.yres;
[2ce520c]1350 mouse_show();
1351}
1352
[76fca31]1353
1354static int anim_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
[1fd7700]1355{
[76fca31]1356 bool handled = true;
1357 int retval = EOK;
1358 int i, nvp;
[1fd7700]1359 int newval;
[76fca31]1360
[228e490]1361 switch (IPC_GET_IMETHOD(*call)) {
[1fd7700]1362 case FB_ANIM_CREATE:
1363 nvp = IPC_GET_ARG1(*call);
1364 if (nvp == -1)
1365 nvp = vp;
[00bb6965]1366 if (nvp >= MAX_VIEWPORTS || nvp < 0 ||
1367 !viewports[nvp].initialized) {
[1fd7700]1368 retval = EINVAL;
1369 break;
1370 }
[00bb6965]1371 for (i = 0; i < MAX_ANIMATIONS; i++) {
1372 if (!animations[i].initialized)
[1fd7700]1373 break;
1374 }
1375 if (i == MAX_ANIMATIONS) {
1376 retval = ELIMIT;
1377 break;
1378 }
1379 animations[i].initialized = 1;
1380 animations[i].animlen = 0;
1381 animations[i].pos = 0;
1382 animations[i].enabled = 0;
1383 animations[i].vp = nvp;
1384 retval = i;
1385 break;
1386 case FB_ANIM_DROP:
1387 i = IPC_GET_ARG1(*call);
[153a209]1388 if (i >= MAX_ANIMATIONS || i < 0) {
[1fd7700]1389 retval = EINVAL;
1390 break;
1391 }
1392 animations[i].initialized = 0;
1393 break;
1394 case FB_ANIM_ADDPIXMAP:
1395 i = IPC_GET_ARG1(*call);
[00bb6965]1396 if (i >= MAX_ANIMATIONS || i < 0 ||
1397 !animations[i].initialized) {
[1fd7700]1398 retval = EINVAL;
1399 break;
1400 }
1401 if (animations[i].animlen == MAX_ANIM_LEN) {
1402 retval = ELIMIT;
1403 break;
1404 }
1405 newval = IPC_GET_ARG2(*call);
[00bb6965]1406 if (newval < 0 || newval > MAX_PIXMAPS ||
1407 !pixmaps[newval].data) {
[1fd7700]1408 retval = EINVAL;
1409 break;
1410 }
1411 animations[i].pixmaps[animations[i].animlen++] = newval;
1412 break;
1413 case FB_ANIM_CHGVP:
1414 i = IPC_GET_ARG1(*call);
1415 if (i >= MAX_ANIMATIONS || i < 0) {
1416 retval = EINVAL;
1417 break;
1418 }
1419 nvp = IPC_GET_ARG2(*call);
1420 if (nvp == -1)
1421 nvp = vp;
[00bb6965]1422 if (nvp >= MAX_VIEWPORTS || nvp < 0 ||
1423 !viewports[nvp].initialized) {
[1fd7700]1424 retval = EINVAL;
1425 break;
1426 }
1427 animations[i].vp = nvp;
1428 break;
1429 case FB_ANIM_START:
1430 case FB_ANIM_STOP:
1431 i = IPC_GET_ARG1(*call);
1432 if (i >= MAX_ANIMATIONS || i < 0) {
1433 retval = EINVAL;
1434 break;
1435 }
[228e490]1436 newval = (IPC_GET_IMETHOD(*call) == FB_ANIM_START);
[1fd7700]1437 if (newval ^ animations[i].enabled) {
1438 animations[i].enabled = newval;
1439 anims_enabled += newval ? 1 : -1;
1440 }
1441 break;
1442 default:
1443 handled = 0;
1444 }
1445 if (handled)
[ffa2c8ef]1446 async_answer_0(callid, retval);
[1fd7700]1447 return handled;
1448}
1449
[429acb9]1450
[76fca31]1451/** Handler for messages concerning pixmap handling
1452 *
1453 */
1454static int pixmap_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
1455{
1456 bool handled = true;
1457 int retval = EOK;
1458 int i, nvp;
1459
[228e490]1460 switch (IPC_GET_IMETHOD(*call)) {
[429acb9]1461 case FB_VP_DRAW_PIXMAP:
1462 nvp = IPC_GET_ARG1(*call);
1463 if (nvp == -1)
1464 nvp = vp;
[00bb6965]1465 if (nvp < 0 || nvp >= MAX_VIEWPORTS ||
1466 !viewports[nvp].initialized) {
[429acb9]1467 retval = EINVAL;
1468 break;
1469 }
1470 i = IPC_GET_ARG2(*call);
1471 retval = draw_pixmap(nvp, i);
1472 break;
1473 case FB_VP2PIXMAP:
1474 nvp = IPC_GET_ARG1(*call);
1475 if (nvp == -1)
1476 nvp = vp;
[00bb6965]1477 if (nvp < 0 || nvp >= MAX_VIEWPORTS ||
1478 !viewports[nvp].initialized)
[429acb9]1479 retval = EINVAL;
1480 else
[2ce520c]1481 retval = save_vp_to_pixmap(&viewports[nvp]);
[429acb9]1482 break;
1483 case FB_DROP_PIXMAP:
1484 i = IPC_GET_ARG1(*call);
1485 if (i >= MAX_PIXMAPS) {
1486 retval = EINVAL;
1487 break;
1488 }
1489 if (pixmaps[i].data) {
1490 free(pixmaps[i].data);
1491 pixmaps[i].data = NULL;
1492 }
1493 break;
1494 default:
1495 handled = 0;
1496 }
[76fca31]1497
[429acb9]1498 if (handled)
[ffa2c8ef]1499 async_answer_0(callid, retval);
[429acb9]1500 return handled;
1501
1502}
1503
[9805cde]1504static int rgb_from_style(attr_rgb_t *rgb, int style)
1505{
1506 switch (style) {
1507 case STYLE_NORMAL:
1508 rgb->fg_color = color_table[COLOR_BLACK];
1509 rgb->bg_color = color_table[COLOR_WHITE];
1510 break;
1511 case STYLE_EMPHASIS:
1512 rgb->fg_color = color_table[COLOR_RED];
1513 rgb->bg_color = color_table[COLOR_WHITE];
1514 break;
[9f1362d4]1515 case STYLE_INVERTED:
1516 rgb->fg_color = color_table[COLOR_WHITE];
1517 rgb->bg_color = color_table[COLOR_BLACK];
1518 break;
1519 case STYLE_SELECTED:
1520 rgb->fg_color = color_table[COLOR_WHITE];
1521 rgb->bg_color = color_table[COLOR_RED];
1522 break;
[9805cde]1523 default:
1524 return EINVAL;
1525 }
[9f1362d4]1526
[9805cde]1527 return EOK;
1528}
1529
[96b02eb9]1530static int rgb_from_idx(attr_rgb_t *rgb, sysarg_t fg_color,
1531 sysarg_t bg_color, sysarg_t flags)
[9805cde]1532{
1533 fg_color = (fg_color & 7) | ((flags & CATTR_BRIGHT) ? 8 : 0);
1534 bg_color = (bg_color & 7) | ((flags & CATTR_BRIGHT) ? 8 : 0);
1535
1536 rgb->fg_color = color_table[fg_color];
1537 rgb->bg_color = color_table[bg_color];
1538
1539 return EOK;
1540}
1541
[4a62ec9]1542static int rgb_from_attr(attr_rgb_t *rgb, const attrs_t *a)
1543{
1544 int rc;
1545
1546 switch (a->t) {
1547 case at_style:
1548 rc = rgb_from_style(rgb, a->a.s.style);
1549 break;
1550 case at_idx:
1551 rc = rgb_from_idx(rgb, a->a.i.fg_color,
1552 a->a.i.bg_color, a->a.i.flags);
1553 break;
1554 case at_rgb:
1555 *rgb = a->a.r;
1556 rc = EOK;
1557 break;
1558 }
1559
1560 return rc;
1561}
1562
[96b02eb9]1563static int fb_set_style(viewport_t *vport, sysarg_t style)
[9805cde]1564{
1565 return rgb_from_style(&vport->attr, (int) style);
1566}
1567
[96b02eb9]1568static int fb_set_color(viewport_t *vport, sysarg_t fg_color,
1569 sysarg_t bg_color, sysarg_t flags)
[9805cde]1570{
1571 return rgb_from_idx(&vport->attr, fg_color, bg_color, flags);
1572}
1573
[1180a88e]1574/** Function for handling connections to FB
1575 *
1576 */
[76fca31]1577static void fb_client_connection(ipc_callid_t iid, ipc_call_t *icall)
[a2ae4f4]1578{
[76fca31]1579 unsigned int vp = 0;
1580 viewport_t *vport = &viewports[vp];
1581
[a2ae4f4]1582 if (client_connected) {
[ffa2c8ef]1583 async_answer_0(iid, ELIMIT);
[a2ae4f4]1584 return;
1585 }
[76fca31]1586
1587 /* Accept connection */
1588 client_connected = true;
[ffa2c8ef]1589 async_answer_0(iid, EOK);
[76fca31]1590
1591 while (true) {
1592 ipc_callid_t callid;
1593 ipc_call_t call;
1594 int retval;
1595 unsigned int i;
1596 int scroll;
[67ebf21]1597 wchar_t ch;
[8dc12ac]1598 unsigned int col, row;
[76fca31]1599
1600 if ((vport->cursor_active) || (anims_enabled))
[d7baee6]1601 callid = async_get_call_timeout(&call, 250000);
[d3f2cad]1602 else
1603 callid = async_get_call(&call);
[76fca31]1604
[d552ab9]1605 mouse_hide();
[49d072e]1606 if (!callid) {
[bd02038]1607 cursor_blink(vport);
[1fd7700]1608 anims_tick();
[a3d2939]1609 mouse_show();
[49d072e]1610 continue;
1611 }
[76fca31]1612
[90f5d64]1613 if (shm_handle(callid, &call, vp))
1614 continue;
[76fca31]1615
[429acb9]1616 if (pixmap_handle(callid, &call, vp))
1617 continue;
[76fca31]1618
[1fd7700]1619 if (anim_handle(callid, &call, vp))
1620 continue;
[76fca31]1621
[228e490]1622 switch (IPC_GET_IMETHOD(call)) {
[a2ae4f4]1623 case IPC_M_PHONE_HUNGUP:
[76fca31]1624 client_connected = false;
1625
1626 /* Cleanup other viewports */
[00bb6965]1627 for (i = 1; i < MAX_VIEWPORTS; i++)
[76fca31]1628 vport->initialized = false;
1629
1630 /* Exit thread */
1631 return;
1632
[a2ae4f4]1633 case FB_PUTCHAR:
[67ebf21]1634 ch = IPC_GET_ARG1(call);
[8dc12ac]1635 col = IPC_GET_ARG2(call);
1636 row = IPC_GET_ARG3(call);
[76fca31]1637
1638 if ((col >= vport->cols) || (row >= vport->rows)) {
[a2ae4f4]1639 retval = EINVAL;
1640 break;
1641 }
[ffa2c8ef]1642 async_answer_0(callid, EOK);
[76fca31]1643
[67ebf21]1644 draw_char(vport, ch, col, row);
[76fca31]1645
1646 /* Message already answered */
1647 continue;
[a2ae4f4]1648 case FB_CLEAR:
[76fca31]1649 vport_clear(vport);
1650 cursor_show(vport);
1651 retval = EOK;
[a2ae4f4]1652 break;
[76fca31]1653 case FB_CURSOR_GOTO:
[8dc12ac]1654 col = IPC_GET_ARG1(call);
1655 row = IPC_GET_ARG2(call);
[76fca31]1656
1657 if ((col >= vport->cols) || (row >= vport->rows)) {
[88c3151]1658 retval = EINVAL;
1659 break;
1660 }
[76fca31]1661 retval = EOK;
1662
[bd02038]1663 cursor_hide(vport);
[88c3151]1664 vport->cur_col = col;
1665 vport->cur_row = row;
[76fca31]1666 cursor_show(vport);
1667 break;
[88c3151]1668 case FB_CURSOR_VISIBILITY:
[bd02038]1669 cursor_hide(vport);
[49d072e]1670 vport->cursor_active = IPC_GET_ARG1(call);
[76fca31]1671 cursor_show(vport);
1672 retval = EOK;
[88c3151]1673 break;
[a2ae4f4]1674 case FB_GET_CSIZE:
[ffa2c8ef]1675 async_answer_2(callid, EOK, vport->cols, vport->rows);
[88c3151]1676 continue;
[50cfa6c]1677 case FB_GET_COLOR_CAP:
[ffa2c8ef]1678 async_answer_1(callid, EOK, FB_CCAP_RGB);
[50cfa6c]1679 continue;
[88c3151]1680 case FB_SCROLL:
[76fca31]1681 scroll = IPC_GET_ARG1(call);
1682 if ((scroll > (int) vport->rows) || (scroll < (-(int) vport->rows))) {
[88c3151]1683 retval = EINVAL;
1684 break;
1685 }
[bd02038]1686 cursor_hide(vport);
[76fca31]1687 vport_scroll(vport, scroll);
1688 cursor_show(vport);
1689 retval = EOK;
[e92aabf]1690 break;
[88c3151]1691 case FB_VIEWPORT_SWITCH:
1692 i = IPC_GET_ARG1(call);
[76fca31]1693 if (i >= MAX_VIEWPORTS) {
[88c3151]1694 retval = EINVAL;
1695 break;
1696 }
[76fca31]1697 if (!viewports[i].initialized) {
[88c3151]1698 retval = EADDRNOTAVAIL;
1699 break;
1700 }
[bd02038]1701 cursor_hide(vport);
[88c3151]1702 vp = i;
1703 vport = &viewports[vp];
[76fca31]1704 cursor_show(vport);
1705 retval = EOK;
[88c3151]1706 break;
1707 case FB_VIEWPORT_CREATE:
[76fca31]1708 retval = vport_create(IPC_GET_ARG1(call) >> 16,
[b74959bd]1709 IPC_GET_ARG1(call) & 0xffff,
1710 IPC_GET_ARG2(call) >> 16,
1711 IPC_GET_ARG2(call) & 0xffff);
[88c3151]1712 break;
1713 case FB_VIEWPORT_DELETE:
1714 i = IPC_GET_ARG1(call);
[76fca31]1715 if (i >= MAX_VIEWPORTS) {
[88c3151]1716 retval = EINVAL;
1717 break;
1718 }
[76fca31]1719 if (!viewports[i].initialized) {
[88c3151]1720 retval = EADDRNOTAVAIL;
1721 break;
1722 }
[76fca31]1723 viewports[i].initialized = false;
1724 if (viewports[i].bgpixel)
1725 free(viewports[i].bgpixel);
1726 if (viewports[i].backbuf)
1727 free(viewports[i].backbuf);
1728 retval = EOK;
[88c3151]1729 break;
1730 case FB_SET_STYLE:
[9805cde]1731 retval = fb_set_style(vport, IPC_GET_ARG1(call));
1732 break;
1733 case FB_SET_COLOR:
1734 retval = fb_set_color(vport, IPC_GET_ARG1(call),
1735 IPC_GET_ARG2(call), IPC_GET_ARG3(call));
1736 break;
1737 case FB_SET_RGB_COLOR:
1738 vport->attr.fg_color = IPC_GET_ARG1(call);
1739 vport->attr.bg_color = IPC_GET_ARG2(call);
[76fca31]1740 retval = EOK;
[88c3151]1741 break;
1742 case FB_GET_RESOLUTION:
[ffa2c8ef]1743 async_answer_2(callid, EOK, screen.xres, screen.yres);
[a2ae4f4]1744 continue;
[830ac99]1745 case FB_POINTER_MOVE:
[76fca31]1746 pointer_enabled = true;
[2ce520c]1747 mouse_move(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
[76fca31]1748 retval = EOK;
[830ac99]1749 break;
[ebfabf6]1750 case FB_SCREEN_YIELD:
1751 case FB_SCREEN_RECLAIM:
[10270a8]1752 retval = EOK;
1753 break;
[a2ae4f4]1754 default:
1755 retval = ENOENT;
1756 }
[ffa2c8ef]1757 async_answer_0(callid, retval);
[a2ae4f4]1758 }
[afa6e74]1759}
1760
[76fca31]1761/** Initialization of framebuffer
1762 *
1763 */
1764int fb_init(void)
[a2ae4f4]1765{
[da0c91e7]1766 async_set_client_connection(fb_client_connection);
[a2ae4f4]1767
[d9fae235]1768 sysarg_t fb_ph_addr;
1769 if (sysinfo_get_value("fb.address.physical", &fb_ph_addr) != EOK)
1770 return -1;
1771
1772 sysarg_t fb_offset;
1773 if (sysinfo_get_value("fb.offset", &fb_offset) != EOK)
1774 fb_offset = 0;
1775
1776 sysarg_t fb_width;
1777 if (sysinfo_get_value("fb.width", &fb_width) != EOK)
1778 return -1;
1779
1780 sysarg_t fb_height;
1781 if (sysinfo_get_value("fb.height", &fb_height) != EOK)
1782 return -1;
1783
1784 sysarg_t fb_scanline;
1785 if (sysinfo_get_value("fb.scanline", &fb_scanline) != EOK)
1786 return -1;
1787
1788 sysarg_t fb_visual;
1789 if (sysinfo_get_value("fb.visual", &fb_visual) != EOK)
1790 return -1;
1791
1792 sysarg_t fbsize = fb_scanline * fb_height;
[76fca31]1793 void *fb_addr = as_get_mappable_page(fbsize);
[d9fae235]1794
1795 if (physmem_map((void *) fb_ph_addr + fb_offset, fb_addr,
[ae318d3]1796 ALIGN_UP(fbsize, PAGE_SIZE) >> PAGE_WIDTH, AS_AREA_READ | AS_AREA_WRITE) != 0)
1797 return -1;
[d9fae235]1798
[76fca31]1799 if (screen_init(fb_addr, fb_width, fb_height, fb_scanline, fb_visual))
[2bc137c2]1800 return 0;
[d9fae235]1801
[2bc137c2]1802 return -1;
[a2ae4f4]1803}
[da0c91e7]1804
[76fca31]1805/**
[ce5bcb4]1806 * @}
1807 */
Note: See TracBrowser for help on using the repository browser.