Ignore:
File:
1 edited

Legend:

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

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