Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/hid/fb/fb.c

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