Changeset 7c014d1 in mainline


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

Location:
uspace
Files:
12 added
13 deleted
23 edited
15 moved

Legend:

Unmodified
Added
Removed
  • uspace/Makefile

    r14a60e3 r7c014d1  
    186186        lib/drv \
    187187        lib/packet \
    188         lib/imgmap \
     188        lib/fb \
    189189        lib/net \
    190190        lib/ext2 \
  • uspace/Makefile.common

    r14a60e3 r7c014d1  
    110110LIBBLOCK_PREFIX = $(LIB_PREFIX)/block
    111111LIBFS_PREFIX = $(LIB_PREFIX)/fs
    112 LIBIMGMAP_PREFIX = $(LIB_PREFIX)/imgmap
     112LIBFB_PREFIX = $(LIB_PREFIX)/fb
    113113LIBCLUI_PREFIX = $(LIB_PREFIX)/clui
    114114LIBFMTUTIL_PREFIX = $(LIB_PREFIX)/fmtutil
     
    126126LIBNET_PREFIX = $(LIB_PREFIX)/net
    127127LIBMINIX_PREFIX = $(LIB_PREFIX)/minix
     128
    128129LIBSCSI_PREFIX = $(LIB_PREFIX)/scsi
    129130
  • uspace/app/bdsh/cmds/modules/cat/cat.c

    r14a60e3 r7c014d1  
    103103{
    104104        console_set_pos(console, 0, console_rows-1);
    105         console_set_color(console, COLOR_BLUE, COLOR_WHITE, 0);
     105        console_set_color(console, COLOR_WHITE, COLOR_BLUE, 0);
    106106       
    107107        printf("ENTER/SPACE/PAGE DOWN - next page, "
  • uspace/app/init/init.c

    r14a60e3 r7c014d1  
    196196}
    197197
    198 static void console(const char *svc)
    199 {
    200         printf("%s: Spawning %s %s\n", NAME, SRV_CONSOLE, svc);
     198static void console(const char *isvc, const char *fbsvc)
     199{
     200        printf("%s: Spawning %s %s %s\n", NAME, SRV_CONSOLE, isvc, fbsvc);
    201201       
    202202        /* Wait for the input service to be ready */
    203203        service_id_t service_id;
    204         int rc = loc_service_get_id(svc, &service_id, IPC_FLAG_BLOCKING);
    205         if (rc != EOK) {
    206                 printf("%s: Error waiting on %s (%s)\n", NAME, svc,
    207                     str_error(rc));
    208                 return;
    209         }
    210        
    211         rc = task_spawnl(NULL, SRV_CONSOLE, SRV_CONSOLE, svc, NULL);
    212         if (rc != EOK) {
    213                 printf("%s: Error spawning %s %s (%s)\n", NAME, SRV_CONSOLE,
    214                     svc, str_error(rc));
     204        int rc = loc_service_get_id(isvc, &service_id, IPC_FLAG_BLOCKING);
     205        if (rc != EOK) {
     206                printf("%s: Error waiting on %s (%s)\n", NAME, isvc,
     207                    str_error(rc));
     208                return;
     209        }
     210       
     211        /* Wait for the framebuffer service to be ready */
     212        rc = loc_service_get_id(fbsvc, &service_id, IPC_FLAG_BLOCKING);
     213        if (rc != EOK) {
     214                printf("%s: Error waiting on %s (%s)\n", NAME, fbsvc,
     215                    str_error(rc));
     216                return;
     217        }
     218       
     219        rc = task_spawnl(NULL, SRV_CONSOLE, SRV_CONSOLE, isvc, fbsvc, NULL);
     220        if (rc != EOK) {
     221                printf("%s: Error spawning %s %s %s (%s)\n", NAME, SRV_CONSOLE,
     222                    isvc, fbsvc, str_error(rc));
    215223        }
    216224}
     
    300308        spawn("/srv/fb");
    301309        spawn("/srv/input");
    302         console("hid/input");
     310        console("hid/input", "hid/fb0");
    303311       
    304312        spawn("/srv/clip");
  • uspace/app/tester/console/console1.c

    r14a60e3 r7c014d1  
    7676                        for (i = COLOR_BLACK; i <= COLOR_WHITE; i++) {
    7777                                console_flush(console);
    78                                 console_set_color(console, i, COLOR_WHITE,
     78                                console_set_color(console, COLOR_WHITE, i,
    7979                                    j ? CATTR_BRIGHT : 0);
    8080                                printf(" %s ", color_name[i]);
     
    8989                        for (i = COLOR_BLACK; i <= COLOR_WHITE; i++) {
    9090                                console_flush(console);
    91                                 console_set_color(console, COLOR_WHITE, i,
     91                                console_set_color(console, i, COLOR_WHITE,
    9292                                    j ? CATTR_BRIGHT : 0);
    9393                                printf(" %s ", color_name[i]);
     
    102102                for (i = 0; i < 255; i += 16) {
    103103                        console_flush(console);
    104                         console_set_rgb_color(console, (255 - i) << 16, i << 16);
     104                        console_set_rgb_color(console, i << 16, (255 - i) << 16);
    105105                        putchar('X');
    106106                }
    107107                console_flush(console);
    108                 console_set_color(console, COLOR_BLACK, COLOR_WHITE, 0);
     108                console_set_color(console, COLOR_WHITE, COLOR_BLACK, 0);
    109109                putchar('\n');
    110110               
    111111                for (i = 0; i < 255; i += 16) {
    112112                        console_flush(console);
    113                         console_set_rgb_color(console, (255 - i) << 8, i << 8);
     113                        console_set_rgb_color(console, i << 8, (255 - i) << 8);
    114114                        putchar('X');
    115115                }
    116116                console_flush(console);
    117                 console_set_color(console, COLOR_BLACK, COLOR_WHITE, 0);
     117                console_set_color(console, COLOR_WHITE, COLOR_BLACK, 0);
    118118                putchar('\n');
    119119               
    120120                for (i = 0; i < 255; i += 16) {
    121121                        console_flush(console);
    122                         console_set_rgb_color(console, 255 - i, i);
     122                        console_set_rgb_color(console, i, 255 - i);
    123123                        putchar('X');
    124124                }
  • uspace/app/tetris/screen.c

    r14a60e3 r7c014d1  
    9595{
    9696        console_flush(console);
    97         console_set_rgb_color(console, 0xffffff,
    98             use_color ? color : 0x000000);
     97        console_set_rgb_color(console, use_color ? color : 0x000000,
     98            0xffffff);
    9999}
    100100
     
    153153                return false;
    154154       
    155         return (ccap >= CONSOLE_CCAP_RGB);
     155        return ((ccap & CONSOLE_CAP_RGB) == CONSOLE_CAP_RGB);
    156156}
    157157
  • uspace/app/trace/trace.c

    r14a60e3 r7c014d1  
    8686void thread_trace_start(uintptr_t thread_hash);
    8787
    88 static proto_t *proto_console;
    8988static task_id_t task_id;
    9089static loader_t *task_ldr;
     
    659658        ipcp_init();
    660659
    661         /*
    662          * User apps now typically have console on phone 3.
    663          * (Phones 1 and 2 are used by the loader).
    664          */
    665         ipcp_connection_set(3, 0, proto_console);
    666 
    667660        rc = get_thread_list();
    668661        if (rc < 0) {
     
    714707                        fibril_mutex_unlock(&state_lock);
    715708                        printf("Resume...\n");
     709                        break;
     710                default:
    716711                        break;
    717712                }
     
    790785
    791786        proto_register(SERVICE_VFS, p);
    792 
    793 #if 0
    794         p = proto_new("console");
    795 
    796         o = oper_new("write", 1, arg_def, V_ERRNO, 1, resp_def);
    797         proto_add_oper(p, VFS_IN_WRITE, o);
    798 
    799         resp_def[0] = V_INTEGER; resp_def[1] = V_INTEGER;
    800         resp_def[2] = V_INTEGER; resp_def[3] = V_CHAR;
    801         o = oper_new("getkey", 0, arg_def, V_ERRNO, 4, resp_def);
    802 
    803         arg_def[0] = V_CHAR;
    804         o = oper_new("clear", 0, arg_def, V_VOID, 0, resp_def);
    805         proto_add_oper(p, CONSOLE_CLEAR, o);
    806 
    807         arg_def[0] = V_INTEGER; arg_def[1] = V_INTEGER;
    808         o = oper_new("goto", 2, arg_def, V_VOID, 0, resp_def);
    809         proto_add_oper(p, CONSOLE_GOTO, o);
    810 
    811         resp_def[0] = V_INTEGER; resp_def[1] = V_INTEGER;
    812         o = oper_new("getsize", 0, arg_def, V_INTEGER, 2, resp_def);
    813         proto_add_oper(p, CONSOLE_GET_SIZE, o);
    814 
    815         arg_def[0] = V_INTEGER;
    816         o = oper_new("set_style", 1, arg_def, V_VOID, 0, resp_def);
    817         proto_add_oper(p, CONSOLE_SET_STYLE, o);
    818         arg_def[0] = V_INTEGER; arg_def[1] = V_INTEGER; arg_def[2] = V_INTEGER;
    819         o = oper_new("set_color", 3, arg_def, V_VOID, 0, resp_def);
    820         proto_add_oper(p, CONSOLE_SET_COLOR, o);
    821         arg_def[0] = V_INTEGER; arg_def[1] = V_INTEGER;
    822         o = oper_new("set_rgb_color", 2, arg_def, V_VOID, 0, resp_def);
    823         proto_add_oper(p, CONSOLE_SET_RGB_COLOR, o);
    824         o = oper_new("cursor_visibility", 1, arg_def, V_VOID, 0, resp_def);
    825         proto_add_oper(p, CONSOLE_CURSOR_VISIBILITY, o);
    826 
    827         proto_console = p;
    828         proto_register(SERVICE_CONSOLE, p);
    829 #endif
    830787}
    831788
  • uspace/lib/c/Makefile

    r14a60e3 r7c014d1  
    9393        generic/io/printf_core.c \
    9494        generic/io/console.c \
    95         generic/io/screenbuffer.c \
    9695        generic/malloc.c \
    9796        generic/sysinfo.c \
  • uspace/lib/c/generic/io/console.c

    r14a60e3 r7c014d1  
    8787{
    8888        async_exch_t *exch = async_exchange_begin(ctrl->output_sess);
    89         async_msg_0(exch, CONSOLE_CLEAR);
     89        async_req_0_0(exch, CONSOLE_CLEAR);
    9090        async_exchange_end(exch);
    9191}
     
    103103{
    104104        async_exch_t *exch = async_exchange_begin(ctrl->output_sess);
    105         async_msg_1(exch, CONSOLE_SET_STYLE, style);
    106         async_exchange_end(exch);
    107 }
    108 
    109 void console_set_color(console_ctrl_t *ctrl, uint8_t fg_color, uint8_t bg_color,
     105        async_req_1_0(exch, CONSOLE_SET_STYLE, style);
     106        async_exchange_end(exch);
     107}
     108
     109void console_set_color(console_ctrl_t *ctrl, uint8_t bgcolor, uint8_t fgcolor,
    110110    uint8_t flags)
    111111{
    112112        async_exch_t *exch = async_exchange_begin(ctrl->output_sess);
    113         async_msg_3(exch, CONSOLE_SET_COLOR, fg_color, bg_color, flags);
    114         async_exchange_end(exch);
    115 }
    116 
    117 void console_set_rgb_color(console_ctrl_t *ctrl, uint32_t fg_color,
    118     uint32_t bg_color)
    119 {
    120         async_exch_t *exch = async_exchange_begin(ctrl->output_sess);
    121         async_msg_2(exch, CONSOLE_SET_RGB_COLOR, fg_color, bg_color);
     113        async_req_3_0(exch, CONSOLE_SET_COLOR, bgcolor, fgcolor, flags);
     114        async_exchange_end(exch);
     115}
     116
     117void console_set_rgb_color(console_ctrl_t *ctrl, uint32_t bgcolor,
     118    uint32_t fgcolor)
     119{
     120        async_exch_t *exch = async_exchange_begin(ctrl->output_sess);
     121        async_req_2_0(exch, CONSOLE_SET_RGB_COLOR, bgcolor, fgcolor);
    122122        async_exchange_end(exch);
    123123}
     
    126126{
    127127        async_exch_t *exch = async_exchange_begin(ctrl->output_sess);
    128         async_msg_1(exch, CONSOLE_CURSOR_VISIBILITY, (show != false));
     128        async_req_1_0(exch, CONSOLE_CURSOR_VISIBILITY, (show != false));
    129129        async_exchange_end(exch);
    130130}
     
    151151{
    152152        async_exch_t *exch = async_exchange_begin(ctrl->output_sess);
    153         async_msg_2(exch, CONSOLE_GOTO, col, row);
     153        async_req_2_0(exch, CONSOLE_GOTO, col, row);
    154154        async_exchange_end(exch);
    155155}
  • uspace/lib/c/include/io/color.h

    r14a60e3 r7c014d1  
    4444        COLOR_MAGENTA = 5,
    4545        COLOR_YELLOW  = 6,
    46         COLOR_WHITE   = 7,
    47        
    48         CATTR_BRIGHT  = 8,
    49         CATTR_BLINK   = 8
     46        COLOR_WHITE   = 7
    5047} console_color_t;
     48
     49typedef enum {
     50        CATTR_NORMAL = 0,
     51        CATTR_BRIGHT = 8,
     52        CATTR_BLINK  = 16
     53} console_color_attr_t;
    5154
    5255#endif
  • uspace/lib/c/include/io/console.h

    r14a60e3 r7c014d1  
    3737
    3838#include <sys/time.h>
     39#include <io/keycode.h>
    3940#include <async.h>
    4041#include <bool.h>
     
    4243
    4344typedef enum {
    44         CONSOLE_CCAP_NONE = 0,
    45         CONSOLE_CCAP_STYLE,
    46         CONSOLE_CCAP_INDEXED,
    47         CONSOLE_CCAP_RGB
     45        CONSOLE_CAP_NONE = 0,
     46        CONSOLE_CAP_STYLE = 1,
     47        CONSOLE_CAP_INDEXED = 2,
     48        CONSOLE_CAP_RGB = 4
    4849} console_caps_t;
    4950
     
    7677/** Console event structure. */
    7778typedef struct {
     79        /** List handle */
     80        link_t link;
     81       
    7882        /** Press or release event. */
    7983        kbd_event_type_t type;
    8084       
    8185        /** Keycode of the key that was pressed or released. */
    82         unsigned int key;
     86        keycode_t key;
    8387       
    8488        /** Bitmask of modifiers held. */
    85         unsigned int mods;
     89        keymod_t mods;
    8690       
    8791        /** The character that was generated or '\0' for none. */
  • uspace/lib/c/include/ipc/services.h

    r14a60e3 r7c014d1  
    4343        SERVICE_NONE       = 0,
    4444        SERVICE_LOAD       = FOURCC('l', 'o', 'a', 'd'),
    45         SERVICE_VIDEO      = FOURCC('v', 'i', 'd', ' '),
    4645        SERVICE_VFS        = FOURCC('v', 'f', 's', ' '),
    4746        SERVICE_LOC        = FOURCC('l', 'o', 'c', ' '),
  • uspace/lib/fb/Makefile

    r14a60e3 r7c014d1  
    2828
    2929USPACE_PREFIX = ../..
    30 LIBRARY = libimgmap
     30LIBRARY = libfb
    3131
    3232SOURCES = \
    33         imgmap.c
     33        fb.c \
     34        imgmap.c \
     35        screenbuffer.c
    3436
    3537include $(USPACE_PREFIX)/Makefile.common
  • uspace/srv/hid/console/Makefile

    r14a60e3 r7c014d1  
    2929
    3030USPACE_PREFIX = ../../..
    31 LIBS = $(LIBIMGMAP_PREFIX)/libimgmap.a
    32 EXTRA_CFLAGS += -I$(LIBIMGMAP_PREFIX)
     31LIBS = $(LIBFB_PREFIX)/libfb.a
     32EXTRA_CFLAGS += -I$(LIBFB_PREFIX)
    3333BINARY = console
    3434
    3535SOURCES = \
    3636        console.c \
    37         keybuffer.c \
    38         images.c \
    39         gcons.c
     37        images.c
    4038
    4139IMAGES = \
    4240        gfx/helenos.tga \
    4341        gfx/nameic.tga \
    44         gfx/cons_selected.tga \
     42        gfx/cons_data.tga \
     43        gfx/cons_dis.tga \
     44        gfx/cons_dis_sel.tga \
    4545        gfx/cons_idle.tga \
    46         gfx/cons_has_data.tga \
     46        gfx/cons_sel.tga \
    4747        gfx/cons_kernel.tga \
    4848        gfx/anim_1.tga \
  • uspace/srv/hid/console/console.c

    r14a60e3 r7c014d1  
    11/*
    2  * Copyright (c) 2006 Josef Cejka
    3  * Copyright (c) 2011 Jiri Svoboda
     2 * Copyright (c) 2011 Martin Decky
    43 * All rights reserved.
    54 *
     
    3433 */
    3534
    36 #include <libc.h>
     35#include <async.h>
     36#include <stdio.h>
     37#include <adt/prodcons.h>
    3738#include <ipc/input.h>
    38 #include <io/keycode.h>
    39 #include <ipc/fb.h>
    40 #include <ipc/services.h>
    41 #include <ns.h>
    42 #include <ns_obsolete.h>
     39#include <ipc/console.h>
     40#include <ipc/vfs.h>
    4341#include <errno.h>
    4442#include <str_error.h>
    45 #include <ipc/console.h>
    46 #include <unistd.h>
    47 #include <async.h>
    48 #include <async_obsolete.h>
    49 #include <adt/fifo.h>
    50 #include <sys/mman.h>
    51 #include <stdio.h>
    52 #include <str.h>
    53 #include <sysinfo.h>
     43#include <loc.h>
    5444#include <event.h>
    55 #include <loc.h>
    56 #include <fcntl.h>
    57 #include <vfs/vfs.h>
     45#include <io/keycode.h>
     46#include <screenbuffer.h>
     47#include <fb.h>
     48#include <imgmap.h>
     49#include <align.h>
     50#include <malloc.h>
     51#include <as.h>
    5852#include <fibril_synch.h>
    59 #include <io/style.h>
    60 #include <io/screenbuffer.h>
    61 
     53#include "images.h"
    6254#include "console.h"
    63 #include "gcons.h"
    64 #include "keybuffer.h"
    6555
    6656#define NAME       "console"
    6757#define NAMESPACE  "term"
    6858
    69 /** Session with the input server. */
     59#define CONSOLE_TOP     66
     60#define CONSOLE_MARGIN  12
     61
     62#define STATE_START   110
     63#define STATE_TOP     8
     64#define STATE_SPACE   4
     65#define STATE_WIDTH   48
     66#define STATE_HEIGHT  48
     67
     68typedef enum {
     69        CONS_DISCONNECTED = 0,
     70        CONS_DISCONNECTED_SELECTED,
     71        CONS_SELECTED,
     72        CONS_IDLE,
     73        CONS_DATA,
     74        CONS_KERNEL,
     75        CONS_LAST
     76} console_state_t;
     77
     78typedef struct {
     79        atomic_t refcnt;           /**< Connection reference count */
     80        prodcons_t input_pc;       /**< Incoming keyboard events */
     81       
     82        fibril_mutex_t mtx;        /**< Lock protecting mutable fields */
     83       
     84        size_t index;              /**< Console index */
     85        console_state_t state;     /**< Console state */
     86        service_id_t dsid;         /**< Service handle */
     87       
     88        vp_handle_t state_vp;      /**< State icon viewport */
     89        sysarg_t cols;             /**< Number of columns */
     90        sysarg_t rows;             /**< Number of rows */
     91        console_caps_t ccaps;      /**< Console capabilities */
     92       
     93        screenbuffer_t *frontbuf;  /**< Front buffer */
     94        frontbuf_handle_t fbid;    /**< Front buffer handle */
     95} console_t;
     96
     97typedef enum {
     98        GRAPHICS_NONE = 0,
     99        GRAPHICS_BASIC = 1,
     100        GRAPHICS_FULL = 2
     101} graphics_state_t;
     102
     103/** Current console state */
     104static graphics_state_t graphics_state = GRAPHICS_NONE;
     105
     106/** State icons */
     107static imagemap_handle_t state_icons[CONS_LAST];
     108
     109/** Session to the input server */
    70110static async_sess_t *input_sess;
    71111
    72 /** Information about framebuffer */
    73 struct {
    74         int phone;           /**< Framebuffer phone */
    75         sysarg_t cols;       /**< Framebuffer columns */
    76         sysarg_t rows;       /**< Framebuffer rows */
    77         sysarg_t color_cap;  /**< Color capabilities (FB_CCAP_xxx) */
    78 } fb_info;
    79 
    80 typedef struct {
    81         size_t index;             /**< Console index */
    82         size_t refcount;          /**< Connection reference count */
    83         service_id_t service_id;  /**< Service ID */
    84         keybuffer_t keybuffer;    /**< Buffer for incoming keys. */
    85         screenbuffer_t scr;       /**< Screenbuffer for saving screen
    86                                        contents and related settings. */
    87 } console_t;
     112/** Session to the framebuffer server */
     113static async_sess_t *fb_sess;
     114
     115/** Framebuffer resolution */
     116static sysarg_t xres;
     117static sysarg_t yres;
    88118
    89119/** Array of data for virtual consoles */
    90120static console_t consoles[CONSOLE_COUNT];
    91121
     122/** Mutex for console switching */
     123static FIBRIL_MUTEX_INITIALIZE(switch_mtx);
     124
     125static console_t *prev_console = &consoles[0];
    92126static console_t *active_console = &consoles[0];
    93 static console_t *prev_console = &consoles[0];
    94127static console_t *kernel_console = &consoles[KERNEL_CONSOLE];
    95128
    96 /** Pointer to memory shared with framebufer used for
    97     faster virtual console switching */
    98 static keyfield_t *interbuffer = NULL;
    99 
    100 /** Information on row-span yet unsent to FB driver. */
     129static imgmap_t *logo_img;
     130static imgmap_t *nameic_img;
     131
     132static imgmap_t *anim_1_img;
     133static imgmap_t *anim_2_img;
     134static imgmap_t *anim_3_img;
     135static imgmap_t *anim_4_img;
     136
     137static imagemap_handle_t anim_1;
     138static imagemap_handle_t anim_2;
     139static imagemap_handle_t anim_3;
     140static imagemap_handle_t anim_4;
     141
     142static sequence_handle_t anim_seq;
     143
     144static imgmap_t *cons_data_img;
     145static imgmap_t *cons_dis_img;
     146static imgmap_t *cons_dis_sel_img;
     147static imgmap_t *cons_idle_img;
     148static imgmap_t *cons_kernel_img;
     149static imgmap_t *cons_sel_img;
     150
     151static vp_handle_t logo_vp;
     152static imagemap_handle_t logo_handle;
     153
     154static vp_handle_t nameic_vp;
     155static imagemap_handle_t nameic_handle;
     156
     157static vp_handle_t screen_vp;
     158static vp_handle_t console_vp;
     159
    101160struct {
    102         sysarg_t col;  /**< Leftmost column of the span. */
    103         sysarg_t row;  /**< Row where the span lies. */
    104         sysarg_t cnt;  /**< Width of the span. */
    105 } fb_pending;
    106 
    107 static FIBRIL_MUTEX_INITIALIZE(input_mutex);
    108 static FIBRIL_CONDVAR_INITIALIZE(input_cv);
    109 
    110 static FIBRIL_MUTEX_INITIALIZE(big_console_lock);
    111 
    112 static void console_serialize_start(void)
    113 {
    114         fibril_mutex_lock(&big_console_lock);
    115 }
    116 
    117 static void console_serialize_end(void)
    118 {
    119         fibril_mutex_unlock(&big_console_lock);
    120 }
    121 
    122 static void curs_visibility(bool visible)
    123 {
    124         async_obsolete_msg_1(fb_info.phone, FB_CURSOR_VISIBILITY, visible);
    125 }
    126 
    127 static void curs_hide_sync(void)
    128 {
    129         async_obsolete_req_1_0(fb_info.phone, FB_CURSOR_VISIBILITY, false);
    130 }
    131 
    132 static void curs_goto(sysarg_t x, sysarg_t y)
    133 {
    134         async_obsolete_msg_2(fb_info.phone, FB_CURSOR_GOTO, x, y);
    135 }
    136 
    137 static void screen_clear(void)
    138 {
    139         async_obsolete_msg_0(fb_info.phone, FB_CLEAR);
    140 }
    141 
    142 static void screen_yield(void)
    143 {
    144         async_obsolete_req_0_0(fb_info.phone, FB_SCREEN_YIELD);
    145 }
    146 
    147 static void screen_reclaim(void)
    148 {
    149         async_obsolete_req_0_0(fb_info.phone, FB_SCREEN_RECLAIM);
    150 }
    151 
    152 static void input_yield(void)
    153 {
    154         async_exch_t *exch = async_exchange_begin(input_sess);
    155         if (exch == NULL) {
    156                 printf("%s: Failed starting exchange with input device.\n",
    157                     NAME);
     161        sysarg_t x;
     162        sysarg_t y;
     163       
     164        sysarg_t btn_x;
     165        sysarg_t btn_y;
     166       
     167        bool pressed;
     168} mouse;
     169
     170static void cons_redraw_state(console_t *cons)
     171{
     172        if (graphics_state == GRAPHICS_FULL) {
     173                fibril_mutex_lock(&cons->mtx);
     174               
     175                fb_vp_imagemap_damage(fb_sess, cons->state_vp,
     176                    state_icons[cons->state], 0, 0, STATE_WIDTH, STATE_HEIGHT);
     177               
     178                if ((cons->state != CONS_DISCONNECTED) &&
     179                    (cons->state != CONS_KERNEL) &&
     180                    (cons->state != CONS_DISCONNECTED_SELECTED)) {
     181                        char data[5];
     182                        snprintf(data, 5, "%zu", cons->index + 1);
     183                       
     184                        for (size_t i = 0; data[i] != 0; i++)
     185                                fb_vp_putchar(fb_sess, cons->state_vp, i + 2, 1, data[i]);
     186                }
     187               
     188                fibril_mutex_unlock(&cons->mtx);
     189        }
     190}
     191
     192static void cons_kernel_sequence_start(console_t *cons)
     193{
     194        if (graphics_state == GRAPHICS_FULL) {
     195                fibril_mutex_lock(&cons->mtx);
     196               
     197                fb_vp_sequence_start(fb_sess, cons->state_vp, anim_seq);
     198                fb_vp_imagemap_damage(fb_sess, cons->state_vp,
     199                    state_icons[cons->state], 0, 0, STATE_WIDTH, STATE_HEIGHT);
     200               
     201                fibril_mutex_unlock(&cons->mtx);
     202        }
     203}
     204
     205static void cons_update_state(console_t *cons, console_state_t state)
     206{
     207        bool update = false;
     208       
     209        fibril_mutex_lock(&cons->mtx);
     210       
     211        if (cons->state != state) {
     212                cons->state = state;
     213                update = true;
     214        }
     215       
     216        fibril_mutex_unlock(&cons->mtx);
     217       
     218        if (update)
     219                cons_redraw_state(cons);
     220}
     221
     222static void cons_notify_data(console_t *cons)
     223{
     224        fibril_mutex_lock(&switch_mtx);
     225       
     226        if (cons != active_console)
     227                cons_update_state(cons, CONS_DATA);
     228       
     229        fibril_mutex_unlock(&switch_mtx);
     230}
     231
     232static void cons_notify_connect(console_t *cons)
     233{
     234        fibril_mutex_lock(&switch_mtx);
     235       
     236        if (cons == active_console)
     237                cons_update_state(cons, CONS_SELECTED);
     238        else
     239                cons_update_state(cons, CONS_IDLE);
     240       
     241        fibril_mutex_unlock(&switch_mtx);
     242}
     243
     244static void cons_notify_disconnect(console_t *cons)
     245{
     246        fibril_mutex_lock(&switch_mtx);
     247       
     248        if (cons == active_console)
     249                cons_update_state(cons, CONS_DISCONNECTED_SELECTED);
     250        else
     251                cons_update_state(cons, CONS_DISCONNECTED);
     252       
     253        fibril_mutex_unlock(&switch_mtx);
     254}
     255
     256static void cons_update(console_t *cons)
     257{
     258        fibril_mutex_lock(&switch_mtx);
     259        fibril_mutex_lock(&cons->mtx);
     260       
     261        if ((cons == active_console) && (active_console != kernel_console)) {
     262                fb_vp_update(fb_sess, console_vp, cons->fbid);
     263                fb_vp_cursor_update(fb_sess, console_vp, cons->fbid);
     264        }
     265       
     266        fibril_mutex_unlock(&cons->mtx);
     267        fibril_mutex_unlock(&switch_mtx);
     268}
     269
     270static void cons_update_cursor(console_t *cons)
     271{
     272        fibril_mutex_lock(&switch_mtx);
     273        fibril_mutex_lock(&cons->mtx);
     274       
     275        if ((cons == active_console) && (active_console != kernel_console))
     276                fb_vp_cursor_update(fb_sess, console_vp, cons->fbid);
     277       
     278        fibril_mutex_unlock(&cons->mtx);
     279        fibril_mutex_unlock(&switch_mtx);
     280}
     281
     282static void cons_clear(console_t *cons)
     283{
     284        fibril_mutex_lock(&cons->mtx);
     285        screenbuffer_clear(cons->frontbuf);
     286        fibril_mutex_unlock(&cons->mtx);
     287       
     288        cons_update(cons);
     289}
     290
     291static void cons_damage_all(console_t *cons)
     292{
     293        fibril_mutex_lock(&switch_mtx);
     294        fibril_mutex_lock(&cons->mtx);
     295       
     296        if ((cons == active_console) && (active_console != kernel_console)) {
     297                fb_vp_damage(fb_sess, console_vp, cons->fbid, 0, 0, cons->cols,
     298                    cons->rows);
     299                fb_vp_cursor_update(fb_sess, console_vp, cons->fbid);
     300        }
     301       
     302        fibril_mutex_unlock(&cons->mtx);
     303        fibril_mutex_unlock(&switch_mtx);
     304}
     305
     306static void cons_switch(console_t *cons)
     307{
     308        fibril_mutex_lock(&switch_mtx);
     309       
     310        if (cons == active_console) {
     311                fibril_mutex_unlock(&switch_mtx);
    158312                return;
    159313        }
    160314       
    161         async_req_0_0(exch, INPUT_YIELD);
    162         async_exchange_end(exch);
    163 }
    164 
    165 static void input_reclaim(void)
    166 {
    167         async_exch_t *exch = async_exchange_begin(input_sess);
    168         if (exch == NULL) {
    169                 printf("%s: Failed starting exchange with input device.\n",
    170                     NAME);
    171                 return;
    172         }
    173        
    174         async_req_0_0(exch, INPUT_RECLAIM);
    175         async_exchange_end(exch);
    176 }
    177 
    178 static void set_style(uint8_t style)
    179 {
    180         async_obsolete_msg_1(fb_info.phone, FB_SET_STYLE, style);
    181 }
    182 
    183 static void set_color(uint8_t fgcolor, uint8_t bgcolor, uint8_t flags)
    184 {
    185         async_obsolete_msg_3(fb_info.phone, FB_SET_COLOR, fgcolor, bgcolor, flags);
    186 }
    187 
    188 static void set_rgb_color(uint32_t fgcolor, uint32_t bgcolor)
    189 {
    190         async_obsolete_msg_2(fb_info.phone, FB_SET_RGB_COLOR, fgcolor, bgcolor);
    191 }
    192 
    193 static void set_attrs(attrs_t *attrs)
    194 {
    195         switch (attrs->t) {
    196         case at_style:
    197                 set_style(attrs->a.s.style);
    198                 break;
    199         case at_idx:
    200                 set_color(attrs->a.i.fg_color, attrs->a.i.bg_color,
    201                     attrs->a.i.flags);
    202                 break;
    203         case at_rgb:
    204                 set_rgb_color(attrs->a.r.fg_color, attrs->a.r.bg_color);
    205                 break;
    206         }
    207 }
    208 
    209 static int ccap_fb_to_con(sysarg_t ccap_fb, sysarg_t *ccap_con)
    210 {
    211         switch (ccap_fb) {
    212         case FB_CCAP_NONE:
    213                 *ccap_con = CONSOLE_CCAP_NONE;
    214                 break;
    215         case FB_CCAP_STYLE:
    216                 *ccap_con = CONSOLE_CCAP_STYLE;
    217                 break;
    218         case FB_CCAP_INDEXED:
    219                 *ccap_con = CONSOLE_CCAP_INDEXED;
    220                 break;
    221         case FB_CCAP_RGB:
    222                 *ccap_con = CONSOLE_CCAP_RGB;
    223                 break;
    224         default:
    225                 return EINVAL;
    226         }
    227        
    228         return EOK;
    229 }
    230 
    231 /** Send an area of screenbuffer to the FB driver. */
    232 static void fb_update_area(console_t *cons, sysarg_t x0, sysarg_t y0, sysarg_t width, sysarg_t height)
    233 {
    234         if (interbuffer) {
    235                 sysarg_t x;
    236                 sysarg_t y;
    237                
    238                 for (y = 0; y < height; y++) {
    239                         for (x = 0; x < width; x++) {
    240                                 interbuffer[y * width + x] =
    241                                     *get_field_at(&cons->scr, x0 + x, y0 + y);
    242                         }
    243                 }
    244                
    245                 async_obsolete_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA,
    246                     x0, y0, width, height);
    247         }
    248 }
    249 
    250 /** Flush pending cells to FB. */
    251 static void fb_pending_flush(void)
    252 {
    253         if (fb_pending.cnt > 0) {
    254                 fb_update_area(active_console, fb_pending.col,
    255                     fb_pending.row, fb_pending.cnt, 1);
    256                 fb_pending.cnt = 0;
    257         }
    258 }
    259 
    260 /** Mark a character cell as changed.
     315        if (cons == kernel_console) {
     316                fb_yield(fb_sess);
     317                if (!console_kcon()) {
     318                        fb_claim(fb_sess);
     319                        fibril_mutex_unlock(&switch_mtx);
     320                        return;
     321                }
     322        }
     323       
     324        if (active_console == kernel_console)
     325                fb_claim(fb_sess);
     326       
     327        prev_console = active_console;
     328        active_console = cons;
     329       
     330        if (prev_console->state == CONS_DISCONNECTED_SELECTED)
     331                cons_update_state(prev_console, CONS_DISCONNECTED);
     332        else
     333                cons_update_state(prev_console, CONS_IDLE);
     334       
     335        if ((cons->state == CONS_DISCONNECTED) ||
     336            (cons->state == CONS_DISCONNECTED_SELECTED))
     337                cons_update_state(cons, CONS_DISCONNECTED_SELECTED);
     338        else
     339                cons_update_state(cons, CONS_SELECTED);
     340       
     341        fibril_mutex_unlock(&switch_mtx);
     342       
     343        cons_damage_all(cons);
     344}
     345
     346static ssize_t limit(ssize_t val, ssize_t lo, ssize_t hi)
     347{
     348        if (val > hi)
     349                return hi;
     350       
     351        if (val < lo)
     352                return lo;
     353       
     354        return val;
     355}
     356
     357static void cons_mouse_move(sysarg_t dx, sysarg_t dy)
     358{
     359        ssize_t sx = (ssize_t) dx;
     360        ssize_t sy = (ssize_t) dy;
     361       
     362        mouse.x = limit(mouse.x + sx, 0, xres);
     363        mouse.y = limit(mouse.y + sy, 0, yres);
     364       
     365        fb_pointer_update(fb_sess, mouse.x, mouse.y, true);
     366}
     367
     368static console_t *cons_find_icon(sysarg_t x, sysarg_t y)
     369{
     370        sysarg_t status_start = STATE_START + (xres - 800) / 2;
     371       
     372        if ((y < STATE_TOP) || (y >= STATE_TOP + STATE_HEIGHT))
     373                return NULL;
     374       
     375        if (x < status_start)
     376                return NULL;
     377       
     378        if (x >= status_start + (STATE_WIDTH + STATE_SPACE) * CONSOLE_COUNT)
     379                return NULL;
     380       
     381        if (((x - status_start) % (STATE_WIDTH + STATE_SPACE)) < STATE_SPACE)
     382                return NULL;
     383       
     384        sysarg_t btn = (x - status_start) / (STATE_WIDTH + STATE_SPACE);
     385       
     386        if (btn < CONSOLE_COUNT)
     387                return consoles + btn;
     388       
     389        return NULL;
     390}
     391
     392/** Handle mouse click
    261393 *
    262  * This adds the cell to the pending rowspan if possible. Otherwise
    263  * the old span is flushed first.
     394 * @param state Button state (true - pressed, false - depressed)
    264395 *
    265396 */
    266 static void cell_mark_changed(sysarg_t col, sysarg_t row)
    267 {
    268         if (fb_pending.cnt != 0) {
    269                 if ((col != fb_pending.col + fb_pending.cnt)
    270                     || (row != fb_pending.row)) {
    271                         fb_pending_flush();
    272                 }
    273         }
    274        
    275         if (fb_pending.cnt == 0) {
    276                 fb_pending.col = col;
    277                 fb_pending.row = row;
    278         }
    279        
    280         fb_pending.cnt++;
    281 }
    282 
    283 /** Print a character to the active VC with buffering. */
    284 static void fb_putchar(wchar_t c, sysarg_t col, sysarg_t row)
    285 {
    286         async_obsolete_msg_3(fb_info.phone, FB_PUTCHAR, c, col, row);
     397static console_t *cons_mouse_button(bool state)
     398{
     399        if (graphics_state != GRAPHICS_FULL)
     400                return NULL;
     401       
     402        if (state) {
     403                console_t *cons = cons_find_icon(mouse.x, mouse.y);
     404                if (cons != NULL) {
     405                        mouse.btn_x = mouse.x;
     406                        mouse.btn_y = mouse.y;
     407                        mouse.pressed = true;
     408                }
     409               
     410                return NULL;
     411        }
     412       
     413        if ((!state) && (!mouse.pressed))
     414                return NULL;
     415       
     416        console_t *cons = cons_find_icon(mouse.x, mouse.y);
     417        if (cons == cons_find_icon(mouse.btn_x, mouse.btn_y))
     418                return cons;
     419       
     420        mouse.pressed = false;
     421        return NULL;
     422}
     423
     424static void input_events(ipc_callid_t iid, ipc_call_t *icall, void *arg)
     425{
     426        /* Ignore parameters, the connection is already opened */
     427        while (true) {
     428                ipc_call_t call;
     429                ipc_callid_t callid = async_get_call(&call);
     430               
     431                if (!IPC_GET_IMETHOD(call)) {
     432                        /* TODO: Handle hangup */
     433                        async_hangup(input_sess);
     434                        return;
     435                }
     436               
     437                kbd_event_type_t type;
     438                keycode_t key;
     439                keymod_t mods;
     440                wchar_t c;
     441               
     442                switch (IPC_GET_IMETHOD(call)) {
     443                case INPUT_EVENT_KEY:
     444                        type = IPC_GET_ARG1(call);
     445                        key = IPC_GET_ARG2(call);
     446                        mods = IPC_GET_ARG3(call);
     447                        c = IPC_GET_ARG4(call);
     448                       
     449                        if ((key >= KC_F1) && (key < KC_F1 + CONSOLE_COUNT) &&
     450                            ((mods & KM_CTRL) == 0))
     451                                cons_switch(&consoles[key - KC_F1]);
     452                        else {
     453                                /* Got key press/release event */
     454                                kbd_event_t *event =
     455                                    (kbd_event_t *) malloc(sizeof(kbd_event_t));
     456                                if (event == NULL) {
     457                                        async_answer_0(callid, ENOMEM);
     458                                        break;
     459                                }
     460                               
     461                                link_initialize(&event->link);
     462                                event->type = type;
     463                                event->key = key;
     464                                event->mods = mods;
     465                                event->c = c;
     466                               
     467                                prodcons_produce(&active_console->input_pc, &event->link);
     468                        }
     469                       
     470                        async_answer_0(callid, EOK);
     471                        break;
     472                case INPUT_EVENT_MOVE:
     473                        cons_mouse_move(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
     474                        async_answer_0(callid, EOK);
     475                        break;
     476                case INPUT_EVENT_BUTTON:
     477                        /* Got pointer button press/release event */
     478                        if (IPC_GET_ARG1(call) == 1) {
     479                                console_t *cons =
     480                                    cons_mouse_button((bool) IPC_GET_ARG2(call));
     481                                if (cons != NULL)
     482                                        cons_switch(cons);
     483                        }
     484                        async_answer_0(callid, EOK);
     485                        break;
     486                default:
     487                        async_answer_0(callid, EINVAL);
     488                }
     489        }
    287490}
    288491
    289492/** Process a character from the client (TTY emulation). */
    290 static void write_char(console_t *cons, wchar_t ch)
    291 {
    292         bool flush_cursor = false;
     493static void cons_write_char(console_t *cons, wchar_t ch)
     494{
     495        sysarg_t updated = 0;
     496       
     497        fibril_mutex_lock(&cons->mtx);
    293498       
    294499        switch (ch) {
    295500        case '\n':
    296                 fb_pending_flush();
    297                 flush_cursor = true;
    298                 cons->scr.position_y++;
    299                 cons->scr.position_x = 0;
     501                updated = screenbuffer_newline(cons->frontbuf);
    300502                break;
    301503        case '\r':
    302504                break;
    303505        case '\t':
    304                 cons->scr.position_x += 8;
    305                 cons->scr.position_x -= cons->scr.position_x % 8;
     506                updated = screenbuffer_tabstop(cons->frontbuf, 8);
    306507                break;
    307508        case '\b':
    308                 if (cons->scr.position_x == 0)
    309                         break;
    310                 cons->scr.position_x--;
    311                 if (cons == active_console)
    312                         cell_mark_changed(cons->scr.position_x, cons->scr.position_y);
    313                 screenbuffer_putchar(&cons->scr, ' ');
     509                updated = screenbuffer_backspace(cons->frontbuf);
    314510                break;
    315511        default:
    316                 if (cons == active_console)
    317                         cell_mark_changed(cons->scr.position_x, cons->scr.position_y);
    318                
    319                 screenbuffer_putchar(&cons->scr, ch);
    320                 cons->scr.position_x++;
    321         }
    322        
    323         if (cons->scr.position_x >= cons->scr.size_x) {
    324                 flush_cursor = true;
    325                 cons->scr.position_y++;
    326         }
    327        
    328         if (cons->scr.position_y >= cons->scr.size_y) {
    329                 fb_pending_flush();
    330                 cons->scr.position_y = cons->scr.size_y - 1;
    331                 screenbuffer_clear_line(&cons->scr, cons->scr.top_line);
    332                 cons->scr.top_line = (cons->scr.top_line + 1) % cons->scr.size_y;
    333                
    334                 if (cons == active_console)
    335                         async_obsolete_msg_1(fb_info.phone, FB_SCROLL, 1);
    336         }
    337        
    338         if (cons == active_console && flush_cursor)
    339                 curs_goto(cons->scr.position_x, cons->scr.position_y);
    340         cons->scr.position_x = cons->scr.position_x % cons->scr.size_x;
    341 }
    342 
    343 /** Switch to new console */
    344 static void change_console(console_t *cons)
    345 {
    346         if (cons == active_console)
    347                 return;
    348        
    349         fb_pending_flush();
    350        
    351         if (cons == kernel_console) {
    352                 console_serialize_start();
    353                 curs_hide_sync();
    354                 gcons_in_kernel();
    355                 screen_yield();
    356                 input_yield();
    357                 console_serialize_end();
    358                
    359                 if (console_kcon()) {
    360                         prev_console = active_console;
    361                         active_console = kernel_console;
    362                 } else
    363                         cons = active_console;
    364         }
    365        
    366         if (cons != kernel_console) {
    367                 console_serialize_start();
    368                
    369                 if (active_console == kernel_console) {
    370                         screen_reclaim();
    371                         input_reclaim();
    372                         gcons_redraw_console();
    373                 }
    374                
    375                 active_console = cons;
    376                 gcons_change_console(cons->index);
    377                
    378                 set_attrs(&cons->scr.attrs);
    379                 curs_visibility(false);
    380                
    381                 sysarg_t x;
    382                 sysarg_t y;
    383                 int rc = 0;
    384                
    385                 if (interbuffer) {
    386                         for (y = 0; y < cons->scr.size_y; y++) {
    387                                 for (x = 0; x < cons->scr.size_x; x++) {
    388                                         interbuffer[y * cons->scr.size_x + x] =
    389                                             *get_field_at(&cons->scr, x, y);
    390                                 }
    391                         }
    392                        
    393                         /* This call can preempt, but we are already at the end */
    394                         rc = async_obsolete_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA,
    395                             0, 0, cons->scr.size_x,
    396                             cons->scr.size_y);
    397                 }
    398                
    399                 if ((!interbuffer) || (rc != 0)) {
    400                         set_attrs(&cons->scr.attrs);
    401                         screen_clear();
    402                        
    403                         for (y = 0; y < cons->scr.size_y; y++)
    404                                 for (x = 0; x < cons->scr.size_x; x++) {
    405                                         keyfield_t *field = get_field_at(&cons->scr, x, y);
    406                                        
    407                                         if (!attrs_same(cons->scr.attrs, field->attrs))
    408                                                 set_attrs(&field->attrs);
    409                                        
    410                                         cons->scr.attrs = field->attrs;
    411                                         if ((field->character == ' ') &&
    412                                             (attrs_same(field->attrs, cons->scr.attrs)))
    413                                                 continue;
    414                                        
    415                                         fb_putchar(field->character, x, y);
    416                                 }
    417                 }
    418                
    419                 curs_goto(cons->scr.position_x, cons->scr.position_y);
    420                 curs_visibility(cons->scr.is_cursor_visible);
    421                
    422                 console_serialize_end();
    423         }
    424 }
    425 
    426 /** Handler for input events */
    427 static void input_events(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    428 {
    429         /* Ignore parameters, the connection is already opened */
    430         while (true) {
    431                 ipc_call_t call;
    432                 ipc_callid_t callid = async_get_call(&call);
    433                
    434                 int retval;
    435                 kbd_event_t ev;
    436                
    437                 if (!IPC_GET_IMETHOD(call)) {
    438                         /* TODO: Handle hangup */
    439                         async_hangup(input_sess);
    440                         return;
    441                 }
    442                
    443                 switch (IPC_GET_IMETHOD(call)) {
    444                 case INPUT_EVENT_KEY:
    445                         /* Got key press/release event */
    446                         retval = 0;
    447                         ev.type = IPC_GET_ARG1(call);
    448                         ev.key = IPC_GET_ARG2(call);
    449                         ev.mods = IPC_GET_ARG3(call);
    450                         ev.c = IPC_GET_ARG4(call);
    451                        
    452                         if ((ev.key >= KC_F1) && (ev.key < KC_F1 +
    453                             CONSOLE_COUNT) && ((ev.mods & KM_CTRL) == 0)) {
    454                                 if (ev.key == KC_F1 + KERNEL_CONSOLE)
    455                                         change_console(kernel_console);
    456                                 else
    457                                         change_console(&consoles[ev.key - KC_F1]);
    458                                 break;
    459                         }
    460                        
    461                         fibril_mutex_lock(&input_mutex);
    462                         keybuffer_push(&active_console->keybuffer, &ev);
    463                         fibril_condvar_broadcast(&input_cv);
    464                         fibril_mutex_unlock(&input_mutex);
    465                         break;
    466                 case INPUT_EVENT_MOVE:
    467                         /* Got pointer move event */
    468                         gcons_mouse_move((int) IPC_GET_ARG1(call),
    469                             (int) IPC_GET_ARG2(call));
    470                         retval = 0;
    471                         break;
    472                 case INPUT_EVENT_BUTTON:
    473                         /* Got pointer button press/release event */
    474                         if (IPC_GET_ARG1(call) == 1) {
    475                                 int newcon = gcons_mouse_btn((bool) IPC_GET_ARG2(call));
    476                                 if (newcon != -1)
    477                                         change_console(&consoles[newcon]);
    478                         }
    479                         retval = 0;
    480                         break;
    481                 default:
    482                         retval = ENOENT;
    483                 }
    484 
    485                 async_answer_0(callid, retval);
    486         }
    487 }
    488 
    489 static void cons_write(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
     512                updated = screenbuffer_putchar(cons->frontbuf, ch, true);
     513        }
     514       
     515        fibril_mutex_unlock(&cons->mtx);
     516       
     517        if (updated > 1)
     518                cons_update(cons);
     519}
     520
     521static void cons_set_cursor(console_t *cons, sysarg_t col, sysarg_t row)
     522{
     523        fibril_mutex_lock(&cons->mtx);
     524        screenbuffer_set_cursor(cons->frontbuf, col, row);
     525        fibril_mutex_unlock(&cons->mtx);
     526       
     527        cons_update_cursor(cons);
     528}
     529
     530static void cons_set_cursor_visibility(console_t *cons, bool visible)
     531{
     532        fibril_mutex_lock(&cons->mtx);
     533        screenbuffer_set_cursor_visibility(cons->frontbuf, visible);
     534        fibril_mutex_unlock(&cons->mtx);
     535       
     536        cons_update_cursor(cons);
     537}
     538
     539static void cons_get_cursor(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
     540{
     541        sysarg_t col;
     542        sysarg_t row;
     543       
     544        fibril_mutex_lock(&cons->mtx);
     545        screenbuffer_get_cursor(cons->frontbuf, &col, &row);
     546        fibril_mutex_unlock(&cons->mtx);
     547       
     548        async_answer_2(iid, EOK, col, row);
     549}
     550
     551static void cons_write(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
    490552{
    491553        void *buf;
     
    494556       
    495557        if (rc != EOK) {
    496                 async_answer_0(rid, rc);
     558                async_answer_0(iid, rc);
    497559                return;
    498560        }
    499561       
    500         console_serialize_start();
    501        
    502562        size_t off = 0;
    503         while (off < size) {
    504                 wchar_t ch = str_decode(buf, &off, size);
    505                 write_char(cons, ch);
    506         }
    507        
    508         console_serialize_end();
    509        
    510         gcons_notify_char(cons->index);
    511         async_answer_1(rid, EOK, size);
    512        
     563        while (off < size)
     564                cons_write_char(cons, str_decode(buf, &off, size));
     565       
     566        async_answer_1(iid, EOK, size);
    513567        free(buf);
    514 }
    515 
    516 static void cons_read(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
     568       
     569        cons_notify_data(cons);
     570}
     571
     572static void cons_read(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
    517573{
    518574        ipc_callid_t callid;
     
    520576        if (!async_data_read_receive(&callid, &size)) {
    521577                async_answer_0(callid, EINVAL);
    522                 async_answer_0(rid, EINVAL);
     578                async_answer_0(iid, EINVAL);
    523579                return;
    524580        }
     
    527583        if (buf == NULL) {
    528584                async_answer_0(callid, ENOMEM);
    529                 async_answer_0(rid, ENOMEM);
     585                async_answer_0(iid, ENOMEM);
    530586                return;
    531587        }
    532588       
    533589        size_t pos = 0;
    534         kbd_event_t ev;
    535         fibril_mutex_lock(&input_mutex);
    536        
    537 recheck:
    538         while ((keybuffer_pop(&cons->keybuffer, &ev)) && (pos < size)) {
    539                 if (ev.type == KEY_PRESS) {
    540                         buf[pos] = ev.c;
     590        while (pos < size) {
     591                link_t *link = prodcons_consume(&cons->input_pc);
     592                kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
     593               
     594                if (event->type == KEY_PRESS) {
     595                        buf[pos] = event->c;
    541596                        pos++;
    542597                }
    543         }
    544        
    545         if (pos == size) {
    546                 (void) async_data_read_finalize(callid, buf, size);
    547                 async_answer_1(rid, EOK, size);
    548                 free(buf);
    549         } else {
    550                 fibril_condvar_wait(&input_cv, &input_mutex);
    551                 goto recheck;
    552         }
    553        
    554         fibril_mutex_unlock(&input_mutex);
    555 }
    556 
    557 static void cons_get_event(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
    558 {
    559         kbd_event_t ev;
    560        
    561         fibril_mutex_lock(&input_mutex);
    562        
    563 recheck:
    564         if (keybuffer_pop(&cons->keybuffer, &ev)) {
    565                 async_answer_4(rid, EOK, ev.type, ev.key, ev.mods, ev.c);
    566         } else {
    567                 fibril_condvar_wait(&input_cv, &input_mutex);
    568                 goto recheck;
    569         }
    570        
    571         fibril_mutex_unlock(&input_mutex);
    572 }
    573 
    574 /** Default thread for new connections */
     598               
     599                free(event);
     600        }
     601       
     602        (void) async_data_read_finalize(callid, buf, size);
     603        async_answer_1(iid, EOK, size);
     604        free(buf);
     605}
     606
     607static void cons_set_style(console_t *cons, console_style_t style)
     608{
     609        fibril_mutex_lock(&cons->mtx);
     610        screenbuffer_set_style(cons->frontbuf, style);
     611        fibril_mutex_unlock(&cons->mtx);
     612}
     613
     614static void cons_set_color(console_t *cons, console_color_t bgcolor,
     615    console_color_t fgcolor, console_color_attr_t attr)
     616{
     617        fibril_mutex_lock(&cons->mtx);
     618        screenbuffer_set_color(cons->frontbuf, bgcolor, fgcolor, attr);
     619        fibril_mutex_unlock(&cons->mtx);
     620}
     621
     622static void cons_set_rgb_color(console_t *cons, pixel_t bgcolor,
     623    pixel_t fgcolor)
     624{
     625        fibril_mutex_lock(&cons->mtx);
     626        screenbuffer_set_rgb_color(cons->frontbuf, bgcolor, fgcolor);
     627        fibril_mutex_unlock(&cons->mtx);
     628}
     629
     630static void cons_get_event(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
     631{
     632        link_t *link = prodcons_consume(&cons->input_pc);
     633        kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
     634       
     635        async_answer_4(iid, EOK, event->type, event->key, event->mods, event->c);
     636        free(event);
     637}
     638
    575639static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    576640{
    577641        console_t *cons = NULL;
    578642       
    579         size_t i;
    580         for (i = 0; i < CONSOLE_COUNT; i++) {
     643        for (size_t i = 0; i < CONSOLE_COUNT; i++) {
    581644                if (i == KERNEL_CONSOLE)
    582645                        continue;
    583646               
    584                 if (consoles[i].service_id == (service_id_t) IPC_GET_ARG1(*icall)) {
     647                if (consoles[i].dsid == (service_id_t) IPC_GET_ARG1(*icall)) {
    585648                        cons = &consoles[i];
    586649                        break;
     
    593656        }
    594657       
    595         ipc_callid_t callid;
    596         ipc_call_t call;
    597         sysarg_t arg1;
    598         sysarg_t arg2;
    599         sysarg_t arg3;
    600        
    601         int rc;
    602        
    603         console_serialize_start();
    604         if (cons->refcount == 0)
    605                 gcons_notify_connect(cons->index);
    606        
    607         cons->refcount++;
     658        if (atomic_postinc(&cons->refcnt) == 0) {
     659                cons_set_cursor_visibility(cons, true);
     660                cons_notify_connect(cons);
     661        }
    608662       
    609663        /* Accept the connection */
     
    611665       
    612666        while (true) {
    613                 console_serialize_end();
    614                 callid = async_get_call(&call);
    615                 console_serialize_start();
    616                
    617                 arg1 = 0;
    618                 arg2 = 0;
    619                 arg3 = 0;
     667                ipc_call_t call;
     668                ipc_callid_t callid = async_get_call(&call);
    620669               
    621670                if (!IPC_GET_IMETHOD(call)) {
    622                         cons->refcount--;
    623                         if (cons->refcount == 0)
    624                                 gcons_notify_disconnect(cons->index);
    625                         console_serialize_end();
     671                        if (atomic_postdec(&cons->refcnt) == 1)
     672                                cons_notify_disconnect(cons);
     673                       
    626674                        return;
    627675                }
     
    629677                switch (IPC_GET_IMETHOD(call)) {
    630678                case VFS_OUT_READ:
    631                         console_serialize_end();
    632679                        cons_read(cons, callid, &call);
    633                         console_serialize_start();
    634                         continue;
     680                        break;
    635681                case VFS_OUT_WRITE:
    636                         console_serialize_end();
    637682                        cons_write(cons, callid, &call);
    638                         console_serialize_start();
    639                         continue;
     683                        break;
    640684                case VFS_OUT_SYNC:
    641                         fb_pending_flush();
    642                         if (cons == active_console) {
    643                                 async_obsolete_req_0_0(fb_info.phone, FB_FLUSH);
    644                                 curs_goto(cons->scr.position_x, cons->scr.position_y);
    645                         }
     685                        cons_update(cons);
     686                        async_answer_0(callid, EOK);
    646687                        break;
    647688                case CONSOLE_CLEAR:
    648                         /* Send message to fb */
    649                         if (cons == active_console)
    650                                 async_obsolete_msg_0(fb_info.phone, FB_CLEAR);
    651                        
    652                         screenbuffer_clear(&cons->scr);
    653                        
     689                        cons_clear(cons);
     690                        async_answer_0(callid, EOK);
    654691                        break;
    655692                case CONSOLE_GOTO:
    656                         screenbuffer_goto(&cons->scr,
    657                             IPC_GET_ARG1(call), IPC_GET_ARG2(call));
    658                         if (cons == active_console)
    659                                 curs_goto(IPC_GET_ARG1(call),
    660                                     IPC_GET_ARG2(call));
     693                        cons_set_cursor(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
     694                        async_answer_0(callid, EOK);
    661695                        break;
    662696                case CONSOLE_GET_POS:
    663                         arg1 = cons->scr.position_x;
    664                         arg2 = cons->scr.position_y;
     697                        cons_get_cursor(cons, callid, &call);
    665698                        break;
    666699                case CONSOLE_GET_SIZE:
    667                         arg1 = fb_info.cols;
    668                         arg2 = fb_info.rows;
     700                        async_answer_2(callid, EOK, cons->cols, cons->rows);
    669701                        break;
    670702                case CONSOLE_GET_COLOR_CAP:
    671                         rc = ccap_fb_to_con(fb_info.color_cap, &arg1);
    672                         if (rc != EOK) {
    673                                 async_answer_0(callid, rc);
    674                                 continue;
    675                         }
     703                        async_answer_1(callid, EOK, cons->ccaps);
    676704                        break;
    677705                case CONSOLE_SET_STYLE:
    678                         fb_pending_flush();
    679                         arg1 = IPC_GET_ARG1(call);
    680                         screenbuffer_set_style(&cons->scr, arg1);
    681                         if (cons == active_console)
    682                                 set_style(arg1);
     706                        cons_set_style(cons, IPC_GET_ARG1(call));
     707                        async_answer_0(callid, EOK);
    683708                        break;
    684709                case CONSOLE_SET_COLOR:
    685                         fb_pending_flush();
    686                         arg1 = IPC_GET_ARG1(call);
    687                         arg2 = IPC_GET_ARG2(call);
    688                         arg3 = IPC_GET_ARG3(call);
    689                         screenbuffer_set_color(&cons->scr, arg1, arg2, arg3);
    690                         if (cons == active_console)
    691                                 set_color(arg1, arg2, arg3);
     710                        cons_set_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call),
     711                            IPC_GET_ARG3(call));
     712                        async_answer_0(callid, EOK);
    692713                        break;
    693714                case CONSOLE_SET_RGB_COLOR:
    694                         fb_pending_flush();
    695                         arg1 = IPC_GET_ARG1(call);
    696                         arg2 = IPC_GET_ARG2(call);
    697                         screenbuffer_set_rgb_color(&cons->scr, arg1, arg2);
    698                         if (cons == active_console)
    699                                 set_rgb_color(arg1, arg2);
     715                        cons_set_rgb_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
     716                        async_answer_0(callid, EOK);
    700717                        break;
    701718                case CONSOLE_CURSOR_VISIBILITY:
    702                         fb_pending_flush();
    703                         arg1 = IPC_GET_ARG1(call);
    704                         cons->scr.is_cursor_visible = arg1;
    705                         if (cons == active_console)
    706                                 curs_visibility(arg1);
     719                        cons_set_cursor_visibility(cons, IPC_GET_ARG1(call));
     720                        async_answer_0(callid, EOK);
    707721                        break;
    708722                case CONSOLE_GET_EVENT:
    709                         console_serialize_end();
    710723                        cons_get_event(cons, callid, &call);
    711                         console_serialize_start();
    712                         continue;
    713                 }
    714                 async_answer_3(callid, EOK, arg1, arg2, arg3);
    715         }
    716 }
    717 
    718 static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
    719 {
    720         change_console(prev_console);
    721 }
    722 
    723 static async_sess_t *connect_input(const char *svc_path)
     724                        break;
     725                default:
     726                        async_answer_0(callid, EINVAL);
     727                }
     728        }
     729}
     730
     731static async_sess_t *input_connect(const char *svc)
    724732{
    725733        async_sess_t *sess;
    726         async_exch_t *exch;
    727         service_id_t service_id;
    728        
    729         int rc = loc_service_get_id(svc_path, &service_id, 0);
     734        service_id_t dsid;
     735       
     736        int rc = loc_service_get_id(svc, &dsid, 0);
    730737        if (rc == EOK) {
    731                 sess = loc_service_connect(EXCHANGE_ATOMIC, service_id, 0);
     738                sess = loc_service_connect(EXCHANGE_ATOMIC, dsid, 0);
    732739                if (sess == NULL) {
    733                         printf("%s: Failed to connect to input server\n", NAME);
     740                        printf("%s: Unable to connect to input service %s\n", NAME,
     741                            svc);
    734742                        return NULL;
    735743                }
    736         } else {
     744        } else
    737745                return NULL;
    738         }
    739        
    740         exch = async_exchange_begin(sess);
    741         if (exch == NULL) {
    742                 printf("%s: Failed to create callback from input server.\n", NAME);
    743                 return NULL;
    744         }
    745        
    746         /* NB: The callback connection is slotted for removal */
     746       
     747        async_exch_t *exch = async_exchange_begin(sess);
    747748        rc = async_connect_to_me(exch, 0, 0, 0, input_events, NULL);
    748 
    749749        async_exchange_end(exch);
    750 
     750       
    751751        if (rc != EOK) {
    752752                async_hangup(sess);
    753                 printf("%s: Failed to create callback from input server (%s).\n",
    754                     NAME, str_error(rc));
     753                printf("%s: Unable to create callback connection to service %s (%s)\n",
     754                    NAME, svc, str_error(rc));
    755755                return NULL;
    756756        }
     
    759759}
    760760
    761 static bool console_srv_init(char *input_dev)
    762 {
    763         /* Connect to input server */
    764         input_sess = connect_input(input_dev);
     761static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
     762{
     763        cons_switch(prev_console);
     764}
     765
     766static async_sess_t *fb_connect(const char *svc)
     767{
     768        async_sess_t *sess;
     769        service_id_t dsid;
     770       
     771        int rc = loc_service_get_id(svc, &dsid, 0);
     772        if (rc == EOK) {
     773                sess = loc_service_connect(EXCHANGE_SERIALIZE, dsid, 0);
     774                if (sess == NULL) {
     775                        printf("%s: Unable to connect to framebuffer service %s\n",
     776                            NAME, svc);
     777                        return NULL;
     778                }
     779        } else
     780                return NULL;
     781       
     782        return sess;
     783}
     784
     785static bool console_srv_init(char *input_svc, char *fb_svc)
     786{
     787        /* Avoid double initialization */
     788        if (graphics_state != GRAPHICS_NONE)
     789                return false;
     790       
     791        /* Connect to input service */
     792        input_sess = input_connect(input_svc);
    765793        if (input_sess == NULL)
    766794                return false;
    767795       
    768         /* Connect to framebuffer driver */
    769         fb_info.phone = service_obsolete_connect_blocking(SERVICE_VIDEO, 0, 0);
    770         if (fb_info.phone < 0) {
    771                 printf("%s: Failed to connect to video service\n", NAME);
     796        /* Connect to framebuffer service */
     797        fb_sess = fb_connect(fb_svc);
     798        if (fb_sess == NULL)
    772799                return false;
    773         }
    774800       
    775801        /* Register server */
    776802        int rc = loc_server_register(NAME, client_connection);
    777803        if (rc < 0) {
    778                 printf("%s: Unable to register server (%d)\n", NAME, rc);
     804                printf("%s: Unable to register server (%s)\n", NAME,
     805                    str_error(rc));
    779806                return false;
    780807        }
    781808       
    782         /* Initialize gcons */
    783         gcons_init(fb_info.phone);
    784        
    785         /* Synchronize, the gcons could put something in queue */
    786         async_obsolete_req_0_0(fb_info.phone, FB_FLUSH);
    787         async_obsolete_req_0_2(fb_info.phone, FB_GET_CSIZE, &fb_info.cols, &fb_info.rows);
    788         async_obsolete_req_0_1(fb_info.phone, FB_GET_COLOR_CAP, &fb_info.color_cap);
    789        
    790         /* Set up shared memory buffer. */
    791         size_t ib_size = sizeof(keyfield_t) * fb_info.cols * fb_info.rows;
    792         interbuffer = as_get_mappable_page(ib_size);
    793        
    794         if (as_area_create(interbuffer, ib_size, AS_AREA_READ |
    795             AS_AREA_WRITE | AS_AREA_CACHEABLE) != interbuffer)
    796                 interbuffer = NULL;
    797        
    798         if (interbuffer) {
    799                 if (async_obsolete_share_out_start(fb_info.phone, interbuffer,
    800                     AS_AREA_READ) != EOK) {
    801                         as_area_destroy(interbuffer);
    802                         interbuffer = NULL;
    803                 }
    804         }
    805        
    806         fb_pending.cnt = 0;
     809        fb_get_resolution(fb_sess, &xres, &yres);
     810       
     811        /* Initialize the screen */
     812        screen_vp = fb_vp_create(fb_sess, 0, 0, xres, yres);
     813       
     814        if ((xres >= 800) && (yres >= 600)) {
     815                logo_vp = fb_vp_create(fb_sess, xres - 66, 2, 64, 60);
     816                logo_img = imgmap_decode_tga((void *) helenos_tga,
     817                    helenos_tga_size, IMGMAP_FLAG_SHARED);
     818                logo_handle = fb_imagemap_create(fb_sess, logo_img);
     819               
     820                nameic_vp = fb_vp_create(fb_sess, 5, 17, 100, 26);
     821                nameic_img = imgmap_decode_tga((void *) nameic_tga,
     822                    nameic_tga_size, IMGMAP_FLAG_SHARED);
     823                nameic_handle = fb_imagemap_create(fb_sess, nameic_img);
     824               
     825                cons_data_img = imgmap_decode_tga((void *) cons_data_tga,
     826                    cons_data_tga_size, IMGMAP_FLAG_SHARED);
     827                cons_dis_img = imgmap_decode_tga((void *) cons_dis_tga,
     828                    cons_dis_tga_size, IMGMAP_FLAG_SHARED);
     829                cons_dis_sel_img = imgmap_decode_tga((void *) cons_dis_sel_tga,
     830                    cons_dis_sel_tga_size, IMGMAP_FLAG_SHARED);
     831                cons_idle_img = imgmap_decode_tga((void *) cons_idle_tga,
     832                    cons_idle_tga_size, IMGMAP_FLAG_SHARED);
     833                cons_kernel_img = imgmap_decode_tga((void *) cons_kernel_tga,
     834                    cons_kernel_tga_size, IMGMAP_FLAG_SHARED);
     835                cons_sel_img = imgmap_decode_tga((void *) cons_sel_tga,
     836                    cons_sel_tga_size, IMGMAP_FLAG_SHARED);
     837               
     838                state_icons[CONS_DISCONNECTED] =
     839                    fb_imagemap_create(fb_sess, cons_dis_img);
     840                state_icons[CONS_DISCONNECTED_SELECTED] =
     841                    fb_imagemap_create(fb_sess, cons_dis_sel_img);
     842                state_icons[CONS_SELECTED] =
     843                    fb_imagemap_create(fb_sess, cons_sel_img);
     844                state_icons[CONS_IDLE] =
     845                    fb_imagemap_create(fb_sess, cons_idle_img);
     846                state_icons[CONS_DATA] =
     847                    fb_imagemap_create(fb_sess, cons_data_img);
     848                state_icons[CONS_KERNEL] =
     849                    fb_imagemap_create(fb_sess, cons_kernel_img);
     850               
     851                anim_1_img = imgmap_decode_tga((void *) anim_1_tga,
     852                    anim_1_tga_size, IMGMAP_FLAG_SHARED);
     853                anim_2_img = imgmap_decode_tga((void *) anim_2_tga,
     854                    anim_2_tga_size, IMGMAP_FLAG_SHARED);
     855                anim_3_img = imgmap_decode_tga((void *) anim_3_tga,
     856                    anim_3_tga_size, IMGMAP_FLAG_SHARED);
     857                anim_4_img = imgmap_decode_tga((void *) anim_4_tga,
     858                    anim_4_tga_size, IMGMAP_FLAG_SHARED);
     859               
     860                anim_1 = fb_imagemap_create(fb_sess, anim_1_img);
     861                anim_2 = fb_imagemap_create(fb_sess, anim_2_img);
     862                anim_3 = fb_imagemap_create(fb_sess, anim_3_img);
     863                anim_4 = fb_imagemap_create(fb_sess, anim_4_img);
     864               
     865                anim_seq = fb_sequence_create(fb_sess);
     866                fb_sequence_add_imagemap(fb_sess, anim_seq, anim_1);
     867                fb_sequence_add_imagemap(fb_sess, anim_seq, anim_2);
     868                fb_sequence_add_imagemap(fb_sess, anim_seq, anim_3);
     869                fb_sequence_add_imagemap(fb_sess, anim_seq, anim_4);
     870               
     871                console_vp = fb_vp_create(fb_sess, CONSOLE_MARGIN, CONSOLE_TOP,
     872                    xres - 2 * CONSOLE_MARGIN, yres - (CONSOLE_TOP + CONSOLE_MARGIN));
     873               
     874                fb_vp_clear(fb_sess, screen_vp);
     875                fb_vp_imagemap_damage(fb_sess, logo_vp, logo_handle,
     876                    0, 0, 64, 60);
     877                fb_vp_imagemap_damage(fb_sess, nameic_vp, nameic_handle,
     878                    0, 0, 100, 26);
     879               
     880                graphics_state = GRAPHICS_FULL;
     881        } else {
     882                console_vp = screen_vp;
     883                graphics_state = GRAPHICS_BASIC;
     884        }
     885       
     886        fb_vp_set_style(fb_sess, console_vp, STYLE_NORMAL);
     887        fb_vp_clear(fb_sess, console_vp);
     888       
     889        sysarg_t cols;
     890        sysarg_t rows;
     891        fb_vp_get_dimensions(fb_sess, console_vp, &cols, &rows);
     892       
     893        console_caps_t ccaps;
     894        fb_vp_get_caps(fb_sess, console_vp, &ccaps);
     895       
     896        mouse.pressed = false;
    807897       
    808898        /* Inititalize consoles */
    809         size_t i;
    810         for (i = 0; i < CONSOLE_COUNT; i++) {
    811                 if (i != KERNEL_CONSOLE) {
    812                         if (screenbuffer_init(&consoles[i].scr,
    813                             fb_info.cols, fb_info.rows) == NULL) {
    814                                 printf("%s: Unable to allocate screen buffer %zu\n", NAME, i);
    815                                 return false;
    816                         }
    817                         screenbuffer_clear(&consoles[i].scr);
    818                         keybuffer_init(&consoles[i].keybuffer);
    819                         consoles[i].index = i;
    820                         consoles[i].refcount = 0;
    821                        
    822                         char vc[LOC_NAME_MAXLEN + 1];
    823                         snprintf(vc, LOC_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i);
    824                        
    825                         if (loc_service_register(vc, &consoles[i].service_id) != EOK) {
    826                                 printf("%s: Unable to register service %s\n", NAME, vc);
    827                                 return false;
    828                         }
    829                 }
    830         }
    831        
    832         /* Initialize the screen */
    833         console_serialize_start();
    834         gcons_redraw_console();
    835         set_style(STYLE_NORMAL);
    836         screen_clear();
    837         curs_goto(0, 0);
    838         curs_visibility(active_console->scr.is_cursor_visible);
    839         console_serialize_end();
     899        for (size_t i = 0; i < CONSOLE_COUNT; i++) {
     900                consoles[i].index = i;
     901                atomic_set(&consoles[i].refcnt, 0);
     902                fibril_mutex_initialize(&consoles[i].mtx);
     903               
     904                if (graphics_state == GRAPHICS_FULL) {
     905                        /* Create state buttons */
     906                        consoles[i].state_vp =
     907                            fb_vp_create(fb_sess, STATE_START + (xres - 800) / 2 +
     908                            CONSOLE_MARGIN + i * (STATE_WIDTH + STATE_SPACE),
     909                            STATE_TOP, STATE_WIDTH, STATE_HEIGHT);
     910                }
     911               
     912                if (i == KERNEL_CONSOLE) {
     913                        consoles[i].state = CONS_KERNEL;
     914                        cons_redraw_state(&consoles[i]);
     915                        cons_kernel_sequence_start(&consoles[i]);
     916                        continue;
     917                }
     918               
     919                if (i == 0)
     920                        consoles[i].state = CONS_DISCONNECTED_SELECTED;
     921                else
     922                        consoles[i].state = CONS_DISCONNECTED;
     923               
     924                consoles[i].cols = cols;
     925                consoles[i].rows = rows;
     926                consoles[i].ccaps = ccaps;
     927                consoles[i].frontbuf =
     928                    screenbuffer_create(cols, rows, SCREENBUFFER_FLAG_SHARED);
     929               
     930                if (consoles[i].frontbuf == NULL) {
     931                        printf("%s: Unable to allocate frontbuffer %zu\n", NAME, i);
     932                        return false;
     933                }
     934               
     935                consoles[i].fbid = fb_frontbuf_create(fb_sess, consoles[i].frontbuf);
     936                if (consoles[i].fbid == 0) {
     937                        printf("%s: Unable to create frontbuffer %zu\n", NAME, i);
     938                        return false;
     939                }
     940               
     941                prodcons_initialize(&consoles[i].input_pc);
     942                cons_redraw_state(&consoles[i]);
     943               
     944                char vc[LOC_NAME_MAXLEN + 1];
     945                snprintf(vc, LOC_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i);
     946               
     947                if (loc_service_register(vc, &consoles[i].dsid) != EOK) {
     948                        printf("%s: Unable to register device %s\n", NAME, vc);
     949                        return false;
     950                }
     951        }
    840952       
    841953        /* Receive kernel notifications */
    842954        async_set_interrupt_received(interrupt_received);
    843         if (event_subscribe(EVENT_KCONSOLE, 0) != EOK)
    844                 printf("%s: Error registering kconsole notifications\n", NAME);
     955        rc = event_subscribe(EVENT_KCONSOLE, 0);
     956        if (rc != EOK)
     957                printf("%s: Failed to register kconsole notifications (%s)\n",
     958                    NAME, str_error(rc));
    845959       
    846960        return true;
     
    849963static void usage(void)
    850964{
    851         printf("Usage: console <input_dev>\n");
     965        printf("Usage: console <input_dev> <framebuffer_dev>\n");
    852966}
    853967
    854968int main(int argc, char *argv[])
    855969{
    856         if (argc < 2) {
     970        if (argc < 3) {
    857971                usage();
    858972                return -1;
    859973        }
    860974       
    861         printf(NAME ": HelenOS Console service\n");
    862        
    863         if (!console_srv_init(argv[1]))
     975        printf("%s: HelenOS Console service\n", NAME);
     976       
     977        if (!console_srv_init(argv[1], argv[2]))
    864978                return -1;
    865979       
    866         printf(NAME ": Accepting connections\n");
     980        printf("%s: Accepting connections\n", NAME);
     981        task_retval(0);
    867982        async_manager();
    868983       
  • uspace/srv/hid/console/console.h

    r14a60e3 r7c014d1  
    3333 */
    3434
    35 #ifndef __CONSOLE_H__
    36 #define __CONSOLE_H__
     35#ifndef CONSOLE_CONSOLE_H__
     36#define CONSOLE_CONSOLE_H__
    3737
    3838#define CONSOLE_COUNT   12
  • uspace/srv/hid/fb/Makefile

    r14a60e3 r7c014d1  
    2929
    3030USPACE_PREFIX = ../../..
    31 ROOT_PATH = $(USPACE_PREFIX)/..
    32 
    33 COMMON_MAKEFILE = $(ROOT_PATH)/Makefile.common
    34 CONFIG_MAKEFILE = $(ROOT_PATH)/Makefile.config
    35 
     31LIBS = $(LIBFB_PREFIX)/libfb.a
     32EXTRA_CFLAGS += -I$(LIBFB_PREFIX)
    3633BINARY = fb
    3734
    38 -include $(COMMON_MAKEFILE)
    39 -include $(CONFIG_MAKEFILE)
    40 
    4135SOURCES = \
    42         main.c
    43 
    44 ifneq ($(UARCH),ia64)
    45         SOURCES += \
    46                 fb.c \
    47                 font-8x16.c
    48         EXTRA_CFLAGS += -DFB_ENABLED
    49 endif
    50 
    51 ifeq ($(UARCH),ia32)
    52         SOURCES += \
    53                 ega.c
    54         EXTRA_CFLAGS += -DEGA_ENABLED
    55 endif
    56 
    57 ifeq ($(UARCH),ia64)
    58         SOURCES += \
    59                 ega.c \
    60                 ski.c \
    61                 serial_console.c
    62         EXTRA_CFLAGS += -DSKI_ENABLED -DEGA_ENABLED
    63 endif
    64 
    65 ifeq ($(UARCH),amd64)
    66         SOURCES += \
    67                 ega.c
    68         EXTRA_CFLAGS += -DEGA_ENABLED
    69 endif
    70 
    71 ifeq ($(UARCH),mips32)
    72         SOURCES += \
    73                 msim.c \
    74                 serial_console.c
    75         EXTRA_CFLAGS += -DMSIM_ENABLED
    76 endif
    77 
    78 ifeq ($(UARCH),sparc64)
    79         ifeq ($(PROCESSOR),sun4v)
    80                 SOURCES += \
    81                         niagara.c \
    82                         serial_console.c
    83                 EXTRA_CFLAGS += -DNIAGARA_ENABLED
    84         endif
    85 endif
    86 
    87 LIBS = $(LIBIMGMAP_PREFIX)/libimgmap.a
    88 EXTRA_CFLAGS += -I$(LIBIMGMAP_PREFIX) -D$(UARCH)
     36        gfx/font-8x16.c \
     37        ctl/serial.c \
     38        port/ega.c \
     39        port/kfb.c \
     40        port/kchar.c \
     41        port/niagara.c \
     42        port/ski.c \
     43        proto/vt100.c \
     44        fb.c
    8945
    9046include $(USPACE_PREFIX)/Makefile.common
  • uspace/srv/hid/fb/ctl/serial.h

    r14a60e3 r7c014d1  
    2828 */
    2929
    30 /** @addtogroup msimfb
    31  * @brief       HelenOS MSIM text console.
    32  * @ingroup fbs
    33  * @{
    34  */
    3530/** @file
    3631 */
    3732
    38 #ifndef FB_MSIM_H_
    39 #define FB_MSIM_H_
     33#ifndef FB_CTL_SERIAL_H_
     34#define FB_CTL_SERIAL_H_
    4035
    41 extern int msim_init(void);
     36#include "../proto/vt100.h"
     37
     38extern int serial_init(vt100_putchar_t, vt100_control_puts_t);
    4239
    4340#endif
     
    4542/** @}
    4643 */
    47 
  • 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}
  • uspace/srv/hid/fb/fb.h

    r14a60e3 r7c014d1  
    11/*
    2  * Copyright (c) 2006 Ondrej Palkovsky
     2 * Copyright (c) 2011 Martin Decky
    33 * All rights reserved.
    44 *
     
    2727 */
    2828
    29 /** @addtogroup fb
    30  * @ingroup fbs
    31  * @{
    32  */
    33 /** @file
    34  */
    35 
    3629#ifndef FB_FB_H_
    3730#define FB_FB_H_
    3831
    39 #include <stdint.h>
     32#include <sys/types.h>
     33#include <bool.h>
     34#include <loc.h>
     35#include <io/console.h>
     36#include <io/style.h>
     37#include <io/color.h>
     38#include <fb.h>
     39#include <screenbuffer.h>
     40#include <imgmap.h>
    4041
    41 extern int fb_init(void);
     42struct fbdev;
     43struct fbvp;
     44
     45typedef struct {
     46        int (* yield)(struct fbdev *dev);
     47        int (* claim)(struct fbdev *dev);
     48        void (* pointer_update)(struct fbdev *dev, sysarg_t x, sysarg_t y,
     49            bool visible);
     50       
     51        int (* get_resolution)(struct fbdev *dev, sysarg_t *width,
     52            sysarg_t *height);
     53        void (* font_metrics)(struct fbdev *dev, sysarg_t width,
     54            sysarg_t height, sysarg_t *cols, sysarg_t *rows);
     55       
     56        int (* vp_create)(struct fbdev *dev, struct fbvp *vp);
     57        void (* vp_destroy)(struct fbdev *dev, struct fbvp *vp);
     58       
     59        void (* vp_clear)(struct fbdev *dev, struct fbvp *vp);
     60        console_caps_t (* vp_get_caps)(struct fbdev *dev, struct fbvp *vp);
     61       
     62        void (* vp_cursor_update)(struct fbdev *dev, struct fbvp *vp,
     63            sysarg_t prev_col, sysarg_t prev_row, sysarg_t col, sysarg_t row,
     64            bool visible);
     65        void (* vp_cursor_flash)(struct fbdev *dev, struct fbvp *vp,
     66            sysarg_t col, sysarg_t row);
     67       
     68        void (* vp_char_update)(struct fbdev *dev, struct fbvp *vp, sysarg_t col,
     69            sysarg_t row);
     70       
     71        void (* vp_imgmap_damage)(struct fbdev *dev, struct fbvp *vp,
     72            imgmap_t *imgmap, sysarg_t col, sysarg_t row, sysarg_t cols,
     73            sysarg_t rows);
     74} fbdev_ops_t;
     75
     76typedef struct fbdev {
     77        link_t link;
     78       
     79        atomic_t refcnt;
     80        bool claimed;
     81       
     82        sysarg_t index;
     83        service_id_t dsid;
     84        struct fbvp *active_vp;
     85       
     86        list_t vps;
     87        list_t frontbufs;
     88        list_t imagemaps;
     89        list_t sequences;
     90       
     91        fbdev_ops_t ops;
     92        void *data;
     93} fbdev_t;
     94
     95typedef struct fbvp {
     96        link_t link;
     97       
     98        sysarg_t x;
     99        sysarg_t y;
     100       
     101        sysarg_t width;
     102        sysarg_t height;
     103       
     104        sysarg_t cols;
     105        sysarg_t rows;
     106       
     107        char_attrs_t attrs;
     108        list_t sequences;
     109       
     110        screenbuffer_t *backbuf;
     111        sysarg_t top_row;
     112       
     113        bool cursor_active;
     114        bool cursor_flash;
     115       
     116        void *data;
     117} fbvp_t;
     118
     119typedef struct {
     120        link_t link;
     121       
     122        size_t size;
     123        unsigned int flags;
     124        void *data;
     125} frontbuf_t;
     126
     127typedef struct {
     128        link_t link;
     129        link_t seq_link;
     130       
     131        size_t size;
     132        unsigned int flags;
     133        void *data;
     134} imagemap_t;
     135
     136typedef struct {
     137        link_t link;
     138       
     139        list_t imagemaps;
     140        size_t count;
     141} sequence_t;
     142
     143typedef struct {
     144        link_t link;
     145       
     146        sequence_t *seq;
     147        size_t current;
     148} sequence_vp_t;
     149
     150extern fbdev_t *fbdev_register(fbdev_ops_t *, void *);
    42151
    43152#endif
    44 
    45 /** @}
    46  */
  • uspace/srv/hid/fb/gfx/font-8x16.c

    r14a60e3 r7c014d1  
    4343 * glyph in the font or returns an index to the question
    4444 * mark glyph if no specific glyph exists.
     45 *
    4546 */
    4647uint16_t fb_font_glyph(const wchar_t ch)
  • uspace/srv/hid/fb/gfx/font-8x16.h

    r14a60e3 r7c014d1  
    3636#define FONT_8X16_H_
    3737
     38#include <sys/types.h>
     39
    3840#define FONT_GLYPHS     2899
    3941#define FONT_WIDTH      8
    4042#define FONT_SCANLINES  16
    4143
    42 #include <sys/types.h>
    43 
    44 extern uint16_t fb_font_glyph(const wchar_t ch);
     44extern uint16_t fb_font_glyph(const wchar_t);
    4545extern uint8_t fb_font[FONT_GLYPHS][FONT_SCANLINES];
    4646
  • uspace/srv/hid/fb/port/ega.h

    r14a60e3 r7c014d1  
    2727 */
    2828
    29 /** @addtogroup egafb
    30  * @brief HelenOS EGA framebuffer.
    31  * @ingroup fbs
    32  * @{
    33  */
    3429/** @file
    3530 */
    3631
    37 #ifndef FB_EGA_H_
    38 #define FB_EGA_H_
     32#ifndef FB_PORT_EGA_H_
     33#define FB_PORT_EGA_H_
    3934
    4035extern int ega_init(void);
  • uspace/srv/hid/fb/port/kchar.c

    r14a60e3 r7c014d1  
    2828 */
    2929
    30 /** @defgroup msimfb MSIM text console
    31  * @brief HelenOS MSIM text console.
    32  * @ingroup fbs
    33  * @{
    34  */
    3530/** @file
    3631 */
    3732
    38 #include <async.h>
    39 #include <libc.h>
     33#include <sys/types.h>
     34#include <errno.h>
    4035#include <sysinfo.h>
     36#include <ddi.h>
    4137#include <as.h>
    42 #include <ddi.h>
    43 #include <errno.h>
     38#include <align.h>
     39#include "../ctl/serial.h"
     40#include "kchar.h"
    4441
    45 #include "serial_console.h"
    46 #include "msim.h"
     42typedef struct {
     43        uint8_t *addr;
     44} kchar_t;
    4745
    48 #define WIDTH 80
    49 #define HEIGHT 24
     46static kchar_t kchar;
    5047
    51 static char *virt_addr;
    52 
    53 static void msim_putc(const char c)
     48static void kchar_putchar(wchar_t ch)
    5449{
    55         *virt_addr = c;
     50        if ((ch >= 0) && (ch < 128))
     51                *kchar.addr = ch;
     52        else
     53                *kchar.addr = '?';
    5654}
    5755
    58 int msim_init(void)
     56static void kchar_control_puts(const char *str)
    5957{
    60         sysarg_t phys_addr;
    61         if (sysinfo_get_value("fb.address.physical", &phys_addr) != EOK)
    62                 return -1;
     58        while (*str)
     59                *kchar.addr = *(str++);
     60}
     61
     62int kchar_init(void)
     63{
     64        sysarg_t present;
     65        int rc = sysinfo_get_value("fb", &present);
     66        if (rc != EOK)
     67                present = false;
    6368       
    64         virt_addr = (char *) as_get_mappable_page(1);
     69        if (!present)
     70                return ENOENT;
    6571       
    66         if (physmem_map((void *) phys_addr, virt_addr, 1,
    67             AS_AREA_READ | AS_AREA_WRITE) != 0)
    68                 return -1;
     72        sysarg_t kind;
     73        rc = sysinfo_get_value("fb.kind", &kind);
     74        if (rc != EOK)
     75                kind = (sysarg_t) -1;
    6976       
    70         serial_console_init(msim_putc, WIDTH, HEIGHT);
     77        if (kind != 3)
     78                return EINVAL;
    7179       
    72         async_set_client_connection(serial_client_connection);
    73         return 0;
     80        sysarg_t paddr;
     81        rc = sysinfo_get_value("fb.address.physical", &paddr);
     82        if (rc != EOK)
     83                return rc;
     84       
     85        kchar.addr = as_get_mappable_page(1);
     86        if (kchar.addr == NULL)
     87                return ENOMEM;
     88       
     89        rc = physmem_map((void *) paddr, kchar.addr,
     90            ALIGN_UP(1, PAGE_SIZE) >> PAGE_WIDTH, AS_AREA_READ | AS_AREA_WRITE);
     91        if (rc != EOK)
     92                return rc;
     93       
     94        return serial_init(kchar_putchar, kchar_control_puts);
    7495}
    7596
  • uspace/srv/hid/fb/port/kchar.h

    r14a60e3 r7c014d1  
    11/*
    22 * Copyright (c) 2006 Ondrej Palkovsky
     3 * Copyright (c) 2008 Martin Decky
    34 * All rights reserved.
    45 *
     
    2728 */
    2829
    29 #ifndef FB_MAIN_H_
    30 #define FB_MAIN_H_
     30/** @file
     31 */
    3132
    32 extern void receive_comm_area(ipc_callid_t, ipc_call_t *, void **);
     33#ifndef FB_PORT_KCHAR_H_
     34#define FB_PORT_KCHAR_H_
     35
     36extern int kchar_init(void);
    3337
    3438#endif
     39
     40/** @}
     41 */
  • uspace/srv/hid/fb/port/kfb.h

    r14a60e3 r7c014d1  
    11/*
    2  * Copyright (c) 2011 Martin Decky
     2 * Copyright (c) 2006 Ondrej Palkovsky
    33 * All rights reserved.
    44 *
     
    2727 */
    2828
    29 /** @addtogroup imgmap
     29/** @addtogroup fb
     30 * @ingroup fbs
    3031 * @{
    3132 */
    32 /**
    33  * @file
     33/** @file
    3434 */
    3535
    36 #ifndef IMGMAP_IMGMAP_H_
    37 #define IMGMAP_IMGMAP_H_
     36#ifndef FB_PORT_KFB_H_
     37#define FB_PORT_KFB_H_
    3838
    39 #include <sys/types.h>
    40 #include <abi/fb/visuals.h>
    41 
    42 typedef struct {
    43         size_t size;
    44         sysarg_t width;
    45         sysarg_t height;
    46         visual_t visual;
    47         uint8_t data[];
    48 } imgmap_t;
    49 
    50 extern imgmap_t *imgmap_decode_tga(void *, size_t);
     39extern int kfb_init(void);
    5140
    5241#endif
  • uspace/srv/hid/fb/port/niagara.c

    r14a60e3 r7c014d1  
    2929 */
    3030
    31 /** @defgroup niagarafb
    32  * @brief       userland driver of the Niagara console output
    33  * @{
    34  */
    3531/** @file
    3632 */
    3733
    38 #include <async.h>
     34#include <sys/types.h>
     35#include <errno.h>
    3936#include <sysinfo.h>
     37#include <ddi.h>
    4038#include <as.h>
    41 #include <errno.h>
    42 #include <stdio.h>
    43 #include <ddi.h>
    44 
    45 #include "serial_console.h"
     39#include <align.h>
     40#include "../ctl/serial.h"
    4641#include "niagara.h"
    4742
    48 #define WIDTH 80
    49 #define HEIGHT 24
     43#define OUTPUT_FIFO_SIZE  ((PAGE_SIZE) - 2 * sizeof(uint64_t))
    5044
    51 /**
    52  * Virtual address mapped to the buffer shared with the kernel counterpart.
    53  */
    54 static uintptr_t output_buffer_addr;
    55 
    56 /*
    57  * Kernel counterpart of the driver reads characters to be printed from here.
    58  * Keep in sync with the definition from
    59  * kernel/arch/sparc64/src/drivers/niagara.c.
    60  */
    61 #define OUTPUT_BUFFER_SIZE      ((PAGE_SIZE) - 2 * 8)
    6245typedef volatile struct {
    6346        uint64_t read_ptr;
    6447        uint64_t write_ptr;
    65         char data[OUTPUT_BUFFER_SIZE];
    66 }
    67         __attribute__ ((packed))
    68         __attribute__ ((aligned(PAGE_SIZE)))
    69         *output_buffer_t;
     48        char data[OUTPUT_FIFO_SIZE];
     49} __attribute__((packed)) output_fifo_t;
    7050
    71 output_buffer_t output_buffer;
     51typedef struct {
     52        output_fifo_t *fifo;
     53} niagara_t;
    7254
    73 /**
    74  * Pushes the character to the Niagara serial.
    75  * @param c     character to be pushed
    76  */
    77 static void niagara_putc(char c)
     55static niagara_t niagara;
     56
     57static void niagara_putc(const char c)
    7858{
    79         while (output_buffer->write_ptr ==
    80                (output_buffer->read_ptr + OUTPUT_BUFFER_SIZE - 1)
    81                % OUTPUT_BUFFER_SIZE)
    82                 ;
    83         output_buffer->data[output_buffer->write_ptr] = (uint64_t) c;
    84         output_buffer->write_ptr =
    85                 ((output_buffer->write_ptr) + 1) % OUTPUT_BUFFER_SIZE;
     59        while (niagara.fifo->write_ptr ==
     60            (niagara.fifo->read_ptr + OUTPUT_FIFO_SIZE - 1)
     61            % OUTPUT_FIFO_SIZE);
     62       
     63        niagara.fifo->data[niagara.fifo->write_ptr] = c;
     64        niagara.fifo->write_ptr =
     65            ((niagara.fifo->write_ptr) + 1) % OUTPUT_FIFO_SIZE;
    8666}
    8767
    88 /**
    89  * Initializes the Niagara serial driver.
    90  */
     68static void niagara_putchar(wchar_t ch)
     69{
     70        if ((ch >= 0) && (ch < 128))
     71                niagara_putc(ch);
     72        else
     73                niagara_putc('?');
     74}
     75
     76static void niagara_control_puts(const char *str)
     77{
     78        while (*str)
     79                niagara_putc(*(str++));
     80}
     81
    9182int niagara_init(void)
    9283{
     84        sysarg_t present;
     85        int rc = sysinfo_get_value("fb", &present);
     86        if (rc != EOK)
     87                present = false;
     88       
     89        if (!present)
     90                return ENOENT;
     91       
     92        sysarg_t kind;
     93        rc = sysinfo_get_value("fb.kind", &kind);
     94        if (rc != EOK)
     95                kind = (sysarg_t) -1;
     96       
     97        if (kind != 5)
     98                return EINVAL;
     99       
    93100        sysarg_t paddr;
    94         if (sysinfo_get_value("niagara.outbuf.address", &paddr) != EOK)
    95                 return -1;
     101        rc = sysinfo_get_value("niagara.outbuf.address", &paddr);
     102        if (rc != EOK)
     103                return rc;
    96104       
    97         output_buffer_addr = (uintptr_t) as_get_mappable_page(PAGE_SIZE);
    98         int result = physmem_map((void *) paddr,
    99             (void *) output_buffer_addr, 1,
     105        niagara.fifo =
     106            (output_fifo_t *) as_get_mappable_page(sizeof(output_fifo_t));
     107        if (niagara.fifo == NULL)
     108                return ENOMEM;
     109       
     110        rc = physmem_map((void *) paddr, (void *) niagara.fifo, 1,
    100111            AS_AREA_READ | AS_AREA_WRITE);
    101 
    102         if (result != 0) {
    103                 printf("Niagara: uspace driver couldn't map physical memory: %d\n",
    104                         result);
    105         }
    106 
    107         output_buffer = (output_buffer_t) output_buffer_addr;
    108 
    109         serial_console_init(niagara_putc, WIDTH, HEIGHT);
    110         async_set_client_connection(serial_client_connection);
    111         return 0;
     112        if (rc != EOK)
     113                return rc;
     114       
     115        return serial_init(niagara_putchar, niagara_control_puts);
    112116}
    113117
    114 /**
    115  * @}
     118/** @}
    116119 */
    117  
  • uspace/srv/hid/fb/port/niagara.h

    r14a60e3 r7c014d1  
    2727 */
    2828
    29 /** @defgroup niagarafb
    30  * @brief       userland driver of the Niagara console output
    31  * @{
    32  */
    33  
    3429/** @file
    3530 */
    3631
    37 #ifndef FB_NIAGARA_H_
    38 #define FB_NIAGARA_H_
     32#ifndef FB_PORT_NIAGARA_H_
     33#define FB_PORT_NIAGARA_H_
    3934
    40 int niagara_init(void);
     35extern int niagara_init(void);
    4136
    4237#endif
    4338
    44 /** 
     39/**
    4540 * @}
    4641 */
  • uspace/srv/hid/fb/port/ski.c

    r14a60e3 r7c014d1  
    11/*
    2  * Copyright (c) 2005 Jakub Jermar
    3  * Copyright (c) 2008 Jiri Svoboda
     2 * Copyright (c) 2006 Ondrej Palkovsky
     3 * Copyright (c) 2008 Martin Decky
    44 * All rights reserved.
    55 *
     
    2828 */
    2929
    30 /** @defgroup msimfb MSIM text console
    31  * @brief       HelenOS MSIM text console.
    32  * @ingroup fbs
    33  * @{
    34  */
    3530/** @file
    3631 */
    3732
    38 #include <async.h>
    39 #include <libc.h>
     33#include <sys/types.h>
     34#include <errno.h>
    4035#include <sysinfo.h>
    41 #include <as.h>
    42 #include <ddi.h>
    43 
    44 #include "serial_console.h"
     36#include "../ctl/serial.h"
    4537#include "ski.h"
    4638
    47 #define SKI_PUTCHAR             31
     39#ifdef UARCH_ia64
    4840
    49 #define WIDTH 80
    50 #define HEIGHT 24
     41#define SKI_PUTCHAR  31
    5142
    5243/** Display character on ski debug console
     
    5546 * display character on debug console.
    5647 *
    57  * @param ch Character to be printed.
     48 * @param c Character to be printed.
     49 *
    5850 */
    59 static void ski_putc(const char ch)
     51static void ski_putc(const char c)
    6052{
    6153        asm volatile (
    6254                "mov r15 = %0\n"
    63                 "mov r32 = %1\n"        /* r32 is in0 */
    64                 "break 0x80000\n"       /* modifies r8 */
     55                "mov r32 = %1\n"   /* r32 is in0 */
     56                "break 0x80000\n"  /* modifies r8 */
    6557                :
    66                 : "i" (SKI_PUTCHAR), "r" (ch)
     58                : "i" (SKI_PUTCHAR), "r" (c)
    6759                : "r15", "in0", "r8"
    6860        );
    6961       
    70         if (ch == '\n')
     62        if (c == '\n')
    7163                ski_putc('\r');
     64}
     65
     66static void ski_putchar(wchar_t ch)
     67{
     68        if ((ch >= 0) && (ch < 128))
     69                ski_putc(ch);
     70        else
     71                ski_putc('?');
     72}
     73
     74static void ski_control_puts(const char *str)
     75{
     76        while (*str)
     77                ski_putc(*(str++));
    7278}
    7379
    7480int ski_init(void)
    7581{
    76         serial_console_init(ski_putc, WIDTH, HEIGHT);
     82        sysarg_t present;
     83        int rc = sysinfo_get_value("fb", &present);
     84        if (rc != EOK)
     85                present = false;
    7786       
    78         async_set_client_connection(serial_client_connection);
    79         return 0;
     87        if (!present)
     88                return ENOENT;
     89       
     90        sysarg_t kind;
     91        rc = sysinfo_get_value("fb.kind", &kind);
     92        if (rc != EOK)
     93                kind = (sysarg_t) -1;
     94       
     95        if (kind != 6)
     96                return EINVAL;
     97       
     98        return serial_init(ski_putchar, ski_control_puts);
    8099}
    81100
    82 /**
    83  * @}
     101#else /* UARCH_ia64 */
     102
     103int ski_init(void)
     104{
     105        return ENOENT;
     106}
     107
     108#endif
     109
     110/** @}
    84111 */
  • uspace/srv/hid/fb/port/ski.h

    r14a60e3 r7c014d1  
    2727 */
    2828
    29 /** @addtogroup skifb
    30  * @brief       HelenOS ski text console.
    31  * @ingroup fbs
    32  * @{
    33  */
    3429/** @file
    3530 */
    3631
    37 #ifndef FB_SKI_H_
    38 #define FB_SKI_H_
     32#ifndef FB_PORT_SKI_H_
     33#define FB_PORT_SKI_H_
    3934
    4035extern int ski_init(void);
     
    4439/** @}
    4540 */
    46 
  • uspace/srv/hid/fb/proto/vt100.h

    r14a60e3 r7c014d1  
    11/*
    2  * Copyright (c) 2006 Ondrej Palkovsky
     2 * Copyright (c) 2011 Martin Decky
    33 * All rights reserved.
    44 *
     
    2727 */
    2828
    29 /** @addtogroup console
    30  * @{
    31  */
    3229/** @file
    3330 */
    3431
    35 #ifndef GCONS_H_
    36 #define GCONS_H_
     32#ifndef FB_PROTO_VT100_H_
     33#define FB_PROTO_VT100_H_
    3734
    3835#include <sys/types.h>
     36#include <screenbuffer.h>
    3937
    40 void gcons_init(int);
     38typedef void (* vt100_putchar_t)(wchar_t ch);
     39typedef void (* vt100_control_puts_t)(const char *str);
    4140
    42 void gcons_redraw_console(void);
    43 void gcons_change_console(size_t);
    44 void gcons_notify_char(size_t);
    45 void gcons_in_kernel(void);
     41/** Forward declaration */
     42struct vt100_state;
     43typedef struct vt100_state vt100_state_t;
    4644
    47 void gcons_notify_connect(size_t);
    48 void gcons_notify_disconnect(size_t);
     45extern vt100_state_t *vt100_state_create(sysarg_t, sysarg_t, vt100_putchar_t,
     46    vt100_control_puts_t);
     47extern void vt100_get_resolution(vt100_state_t *, sysarg_t *, sysarg_t *);
     48extern int vt100_yield(vt100_state_t *);
     49extern int vt100_claim(vt100_state_t *);
    4950
    50 void gcons_mouse_move(ssize_t, ssize_t);
    51 int gcons_mouse_btn(bool state);
     51extern void vt100_putchar(vt100_state_t *, wchar_t);
     52
     53extern void vt100_set_attr(vt100_state_t *, char_attrs_t);
     54extern void vt100_goto(vt100_state_t *, sysarg_t, sysarg_t);
     55extern void vt100_cursor_visibility(vt100_state_t *, bool);
    5256
    5357#endif
Note: See TracChangeset for help on using the changeset viewer.