Changes in uspace/srv/hid/fb/fb.c [7c014d1:9934f7d] in mainline


Ignore:
File:
1 edited

Legend:

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

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