Changeset 7c014d1 in mainline for uspace/srv/hid/fb/fb.c


Ignore:
Timestamp:
2011-09-09T15:46:21Z (13 years ago)
Author:
Martin Decky <martin@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
c69646f8
Parents:
14a60e3
Message:

console and framebuffer server rewrite

File:
1 edited

Legend:

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

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