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


Ignore:
File:
1 edited

Legend:

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

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