~vojtech-horky/helenos/numa

« back to all changes in this revision

Viewing changes to uspace/srv/fb/fb.c

  • Committer: Martin Decky
  • Date: 2009-08-04 11:19:19 UTC
  • Revision ID: martin@uranus.dsrg.hide.ms.mff.cuni.cz-20090804111919-evyclddlr3v5lhmp
Initial import

Show diffs side-by-side

added added

removed removed

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