Ignore:
File:
1 edited

Legend:

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

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