Changeset 925a21e in mainline for uspace/srv/hid


Ignore:
Timestamp:
2011-09-24T14:20:29Z (14 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
5bf76c1
Parents:
867e2555 (diff), 1ab4aca (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge mainline changes.

Location:
uspace/srv/hid
Files:
18 added
19 deleted
19 edited
10 moved

Legend:

Unmodified
Added
Removed
  • uspace/srv/hid/console/Makefile

    r867e2555 r925a21e  
    2929
    3030USPACE_PREFIX = ../../..
     31LIBS = $(LIBFB_PREFIX)/libfb.a
     32EXTRA_CFLAGS += -I$(LIBFB_PREFIX)
    3133BINARY = console
    3234
    33 GENERIC_SOURCES = \
     35SOURCES = \
    3436        console.c \
    35         keybuffer.c \
    36         gcons.c
     37        images.c
    3738
    3839IMAGES = \
    39         gfx/helenos.ppm \
    40         gfx/nameic.ppm \
    41         gfx/cons_selected.ppm \
    42         gfx/cons_idle.ppm \
    43         gfx/cons_has_data.ppm \
    44         gfx/cons_kernel.ppm \
    45         gfx/anim_1.ppm \
    46         gfx/anim_2.ppm \
    47         gfx/anim_3.ppm \
    48         gfx/anim_4.ppm
     40        gfx/helenos.tga \
     41        gfx/nameic.tga \
     42        gfx/cons_data.tga \
     43        gfx/cons_dis.tga \
     44        gfx/cons_dis_sel.tga \
     45        gfx/cons_idle.tga \
     46        gfx/cons_sel.tga \
     47        gfx/cons_kernel.tga \
     48        gfx/anim_1.tga \
     49        gfx/anim_2.tga \
     50        gfx/anim_3.tga \
     51        gfx/anim_4.tga
    4952
    50 SOURCES = \
    51         $(GENERIC_SOURCES) \
    52         $(IMAGES)
     53PRE_DEPEND = images.c images.h
     54EXTRA_CLEAN = images.c images.h
    5355
    5456include $(USPACE_PREFIX)/Makefile.common
    5557
    56 %.o: %.ppm
    57         $(OBJCOPY) -I binary -O $(BFD_NAME) -B $(BFD_ARCH) $< $@
     58images.c images.h: $(IMAGES)
     59        $(ROOT_PATH)/tools/mkarray.py images CONSOLE_IMAGES $^
  • uspace/srv/hid/console/console.c

    r867e2555 r925a21e  
    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 <devmap.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   100
     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         devmap_handle_t devmap_handle;  /**< Device handle */
    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 =
     371            STATE_START + (xres - 800) / 2 + CONSOLE_MARGIN;
     372       
     373        if ((y < STATE_TOP) || (y >= STATE_TOP + STATE_HEIGHT))
     374                return NULL;
     375       
     376        if (x < status_start)
     377                return NULL;
     378       
     379        if (x >= status_start + (STATE_WIDTH + STATE_SPACE) * CONSOLE_COUNT)
     380                return NULL;
     381       
     382        if (((x - status_start) % (STATE_WIDTH + STATE_SPACE)) >= STATE_WIDTH)
     383                return NULL;
     384       
     385        sysarg_t btn = (x - status_start) / (STATE_WIDTH + STATE_SPACE);
     386       
     387        if (btn < CONSOLE_COUNT)
     388                return consoles + btn;
     389       
     390        return NULL;
     391}
     392
     393/** Handle mouse click
    261394 *
    262  * This adds the cell to the pending rowspan if possible. Otherwise
    263  * the old span is flushed first.
     395 * @param state Button state (true - pressed, false - depressed)
    264396 *
    265397 */
    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);
     398static console_t *cons_mouse_button(bool state)
     399{
     400        if (graphics_state != GRAPHICS_FULL)
     401                return NULL;
     402       
     403        if (state) {
     404                console_t *cons = cons_find_icon(mouse.x, mouse.y);
     405                if (cons != NULL) {
     406                        mouse.btn_x = mouse.x;
     407                        mouse.btn_y = mouse.y;
     408                        mouse.pressed = true;
     409                }
     410               
     411                return NULL;
     412        }
     413       
     414        if ((!state) && (!mouse.pressed))
     415                return NULL;
     416       
     417        console_t *cons = cons_find_icon(mouse.x, mouse.y);
     418        if (cons == cons_find_icon(mouse.btn_x, mouse.btn_y))
     419                return cons;
     420       
     421        mouse.pressed = false;
     422        return NULL;
     423}
     424
     425static void input_events(ipc_callid_t iid, ipc_call_t *icall, void *arg)
     426{
     427        /* Ignore parameters, the connection is already opened */
     428        while (true) {
     429                ipc_call_t call;
     430                ipc_callid_t callid = async_get_call(&call);
     431               
     432                if (!IPC_GET_IMETHOD(call)) {
     433                        /* TODO: Handle hangup */
     434                        async_hangup(input_sess);
     435                        return;
     436                }
     437               
     438                kbd_event_type_t type;
     439                keycode_t key;
     440                keymod_t mods;
     441                wchar_t c;
     442               
     443                switch (IPC_GET_IMETHOD(call)) {
     444                case INPUT_EVENT_KEY:
     445                        type = IPC_GET_ARG1(call);
     446                        key = IPC_GET_ARG2(call);
     447                        mods = IPC_GET_ARG3(call);
     448                        c = IPC_GET_ARG4(call);
     449                       
     450                        if ((key >= KC_F1) && (key < KC_F1 + CONSOLE_COUNT) &&
     451                            ((mods & KM_CTRL) == 0))
     452                                cons_switch(&consoles[key - KC_F1]);
     453                        else {
     454                                /* Got key press/release event */
     455                                kbd_event_t *event =
     456                                    (kbd_event_t *) malloc(sizeof(kbd_event_t));
     457                                if (event == NULL) {
     458                                        async_answer_0(callid, ENOMEM);
     459                                        break;
     460                                }
     461                               
     462                                link_initialize(&event->link);
     463                                event->type = type;
     464                                event->key = key;
     465                                event->mods = mods;
     466                                event->c = c;
     467                               
     468                                prodcons_produce(&active_console->input_pc, &event->link);
     469                        }
     470                       
     471                        async_answer_0(callid, EOK);
     472                        break;
     473                case INPUT_EVENT_MOVE:
     474                        cons_mouse_move(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
     475                        async_answer_0(callid, EOK);
     476                        break;
     477                case INPUT_EVENT_BUTTON:
     478                        /* Got pointer button press/release event */
     479                        if (IPC_GET_ARG1(call) == 1) {
     480                                console_t *cons =
     481                                    cons_mouse_button((bool) IPC_GET_ARG2(call));
     482                                if (cons != NULL)
     483                                        cons_switch(cons);
     484                        }
     485                        async_answer_0(callid, EOK);
     486                        break;
     487                default:
     488                        async_answer_0(callid, EINVAL);
     489                }
     490        }
    287491}
    288492
    289493/** 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;
     494static void cons_write_char(console_t *cons, wchar_t ch)
     495{
     496        sysarg_t updated = 0;
     497       
     498        fibril_mutex_lock(&cons->mtx);
    293499       
    294500        switch (ch) {
    295501        case '\n':
    296                 fb_pending_flush();
    297                 flush_cursor = true;
    298                 cons->scr.position_y++;
    299                 cons->scr.position_x = 0;
     502                updated = screenbuffer_newline(cons->frontbuf);
    300503                break;
    301504        case '\r':
    302505                break;
    303506        case '\t':
    304                 cons->scr.position_x += 8;
    305                 cons->scr.position_x -= cons->scr.position_x % 8;
     507                updated = screenbuffer_tabstop(cons->frontbuf, 8);
    306508                break;
    307509        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, ' ');
     510                updated = screenbuffer_backspace(cons->frontbuf);
    314511                break;
    315512        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)
     513                updated = screenbuffer_putchar(cons->frontbuf, ch, true);
     514        }
     515       
     516        fibril_mutex_unlock(&cons->mtx);
     517       
     518        if (updated > 1)
     519                cons_update(cons);
     520}
     521
     522static void cons_set_cursor(console_t *cons, sysarg_t col, sysarg_t row)
     523{
     524        fibril_mutex_lock(&cons->mtx);
     525        screenbuffer_set_cursor(cons->frontbuf, col, row);
     526        fibril_mutex_unlock(&cons->mtx);
     527       
     528        cons_update_cursor(cons);
     529}
     530
     531static void cons_set_cursor_visibility(console_t *cons, bool visible)
     532{
     533        fibril_mutex_lock(&cons->mtx);
     534        screenbuffer_set_cursor_visibility(cons->frontbuf, visible);
     535        fibril_mutex_unlock(&cons->mtx);
     536       
     537        cons_update_cursor(cons);
     538}
     539
     540static void cons_get_cursor(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
     541{
     542        sysarg_t col;
     543        sysarg_t row;
     544       
     545        fibril_mutex_lock(&cons->mtx);
     546        screenbuffer_get_cursor(cons->frontbuf, &col, &row);
     547        fibril_mutex_unlock(&cons->mtx);
     548       
     549        async_answer_2(iid, EOK, col, row);
     550}
     551
     552static void cons_write(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
    490553{
    491554        void *buf;
     
    494557       
    495558        if (rc != EOK) {
    496                 async_answer_0(rid, rc);
     559                async_answer_0(iid, rc);
    497560                return;
    498561        }
    499562       
    500         console_serialize_start();
    501        
    502563        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        
     564        while (off < size)
     565                cons_write_char(cons, str_decode(buf, &off, size));
     566       
     567        async_answer_1(iid, EOK, size);
    513568        free(buf);
    514 }
    515 
    516 static void cons_read(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
     569       
     570        cons_notify_data(cons);
     571}
     572
     573static void cons_read(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
    517574{
    518575        ipc_callid_t callid;
     
    520577        if (!async_data_read_receive(&callid, &size)) {
    521578                async_answer_0(callid, EINVAL);
    522                 async_answer_0(rid, EINVAL);
     579                async_answer_0(iid, EINVAL);
    523580                return;
    524581        }
     
    527584        if (buf == NULL) {
    528585                async_answer_0(callid, ENOMEM);
    529                 async_answer_0(rid, ENOMEM);
     586                async_answer_0(iid, ENOMEM);
    530587                return;
    531588        }
    532589       
    533590        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;
     591        while (pos < size) {
     592                link_t *link = prodcons_consume(&cons->input_pc);
     593                kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
     594               
     595                if (event->type == KEY_PRESS) {
     596                        buf[pos] = event->c;
    541597                        pos++;
    542598                }
    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 */
     599               
     600                free(event);
     601        }
     602       
     603        (void) async_data_read_finalize(callid, buf, size);
     604        async_answer_1(iid, EOK, size);
     605        free(buf);
     606}
     607
     608static void cons_set_style(console_t *cons, console_style_t style)
     609{
     610        fibril_mutex_lock(&cons->mtx);
     611        screenbuffer_set_style(cons->frontbuf, style);
     612        fibril_mutex_unlock(&cons->mtx);
     613}
     614
     615static void cons_set_color(console_t *cons, console_color_t bgcolor,
     616    console_color_t fgcolor, console_color_attr_t attr)
     617{
     618        fibril_mutex_lock(&cons->mtx);
     619        screenbuffer_set_color(cons->frontbuf, bgcolor, fgcolor, attr);
     620        fibril_mutex_unlock(&cons->mtx);
     621}
     622
     623static void cons_set_rgb_color(console_t *cons, pixel_t bgcolor,
     624    pixel_t fgcolor)
     625{
     626        fibril_mutex_lock(&cons->mtx);
     627        screenbuffer_set_rgb_color(cons->frontbuf, bgcolor, fgcolor);
     628        fibril_mutex_unlock(&cons->mtx);
     629}
     630
     631static void cons_get_event(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
     632{
     633        link_t *link = prodcons_consume(&cons->input_pc);
     634        kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
     635       
     636        async_answer_4(iid, EOK, event->type, event->key, event->mods, event->c);
     637        free(event);
     638}
     639
    575640static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    576641{
    577642        console_t *cons = NULL;
    578643       
    579         size_t i;
    580         for (i = 0; i < CONSOLE_COUNT; i++) {
     644        for (size_t i = 0; i < CONSOLE_COUNT; i++) {
    581645                if (i == KERNEL_CONSOLE)
    582646                        continue;
    583647               
    584                 if (consoles[i].devmap_handle == (devmap_handle_t) IPC_GET_ARG1(*icall)) {
     648                if (consoles[i].dsid == (service_id_t) IPC_GET_ARG1(*icall)) {
    585649                        cons = &consoles[i];
    586650                        break;
     
    593657        }
    594658       
    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++;
     659        if (atomic_postinc(&cons->refcnt) == 0) {
     660                cons_set_cursor_visibility(cons, true);
     661                cons_notify_connect(cons);
     662        }
    608663       
    609664        /* Accept the connection */
     
    611666       
    612667        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;
     668                ipc_call_t call;
     669                ipc_callid_t callid = async_get_call(&call);
    620670               
    621671                if (!IPC_GET_IMETHOD(call)) {
    622                         cons->refcount--;
    623                         if (cons->refcount == 0)
    624                                 gcons_notify_disconnect(cons->index);
    625                         console_serialize_end();
     672                        if (atomic_postdec(&cons->refcnt) == 1)
     673                                cons_notify_disconnect(cons);
     674                       
    626675                        return;
    627676                }
     
    629678                switch (IPC_GET_IMETHOD(call)) {
    630679                case VFS_OUT_READ:
    631                         console_serialize_end();
    632680                        cons_read(cons, callid, &call);
    633                         console_serialize_start();
    634                         continue;
     681                        break;
    635682                case VFS_OUT_WRITE:
    636                         console_serialize_end();
    637683                        cons_write(cons, callid, &call);
    638                         console_serialize_start();
    639                         continue;
     684                        break;
    640685                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                         }
     686                        cons_update(cons);
     687                        async_answer_0(callid, EOK);
    646688                        break;
    647689                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                        
     690                        cons_clear(cons);
     691                        async_answer_0(callid, EOK);
    654692                        break;
    655693                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));
     694                        cons_set_cursor(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
     695                        async_answer_0(callid, EOK);
    661696                        break;
    662697                case CONSOLE_GET_POS:
    663                         arg1 = cons->scr.position_x;
    664                         arg2 = cons->scr.position_y;
     698                        cons_get_cursor(cons, callid, &call);
    665699                        break;
    666700                case CONSOLE_GET_SIZE:
    667                         arg1 = fb_info.cols;
    668                         arg2 = fb_info.rows;
     701                        async_answer_2(callid, EOK, cons->cols, cons->rows);
    669702                        break;
    670703                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                         }
     704                        async_answer_1(callid, EOK, cons->ccaps);
    676705                        break;
    677706                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);
     707                        cons_set_style(cons, IPC_GET_ARG1(call));
     708                        async_answer_0(callid, EOK);
    683709                        break;
    684710                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);
     711                        cons_set_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call),
     712                            IPC_GET_ARG3(call));
     713                        async_answer_0(callid, EOK);
    692714                        break;
    693715                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);
     716                        cons_set_rgb_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
     717                        async_answer_0(callid, EOK);
    700718                        break;
    701719                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);
     720                        cons_set_cursor_visibility(cons, IPC_GET_ARG1(call));
     721                        async_answer_0(callid, EOK);
    707722                        break;
    708723                case CONSOLE_GET_EVENT:
    709                         console_serialize_end();
    710724                        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 *dev_path)
     725                        break;
     726                default:
     727                        async_answer_0(callid, EINVAL);
     728                }
     729        }
     730}
     731
     732static async_sess_t *input_connect(const char *svc)
    724733{
    725734        async_sess_t *sess;
    726         async_exch_t *exch;
    727         devmap_handle_t handle;
    728        
    729         int rc = devmap_device_get_handle(dev_path, &handle, 0);
     735        service_id_t dsid;
     736       
     737        int rc = loc_service_get_id(svc, &dsid, 0);
    730738        if (rc == EOK) {
    731                 sess = devmap_device_connect(EXCHANGE_ATOMIC, handle, 0);
     739                sess = loc_service_connect(EXCHANGE_ATOMIC, dsid, 0);
    732740                if (sess == NULL) {
    733                         printf("%s: Failed to connect to input server\n", NAME);
     741                        printf("%s: Unable to connect to input service %s\n", NAME,
     742                            svc);
    734743                        return NULL;
    735744                }
    736         } else {
     745        } else
    737746                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 */
     747       
     748        async_exch_t *exch = async_exchange_begin(sess);
    747749        rc = async_connect_to_me(exch, 0, 0, 0, input_events, NULL);
    748 
    749750        async_exchange_end(exch);
    750 
     751       
    751752        if (rc != EOK) {
    752753                async_hangup(sess);
    753                 printf("%s: Failed to create callback from input server (%s).\n",
    754                     NAME, str_error(rc));
     754                printf("%s: Unable to create callback connection to service %s (%s)\n",
     755                    NAME, svc, str_error(rc));
    755756                return NULL;
    756757        }
     
    759760}
    760761
    761 static bool console_srv_init(char *input_dev)
    762 {
    763         /* Connect to input server */
    764         input_sess = connect_input(input_dev);
     762static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
     763{
     764        cons_switch(prev_console);
     765}
     766
     767static async_sess_t *fb_connect(const char *svc)
     768{
     769        async_sess_t *sess;
     770        service_id_t dsid;
     771       
     772        int rc = loc_service_get_id(svc, &dsid, 0);
     773        if (rc == EOK) {
     774                sess = loc_service_connect(EXCHANGE_SERIALIZE, dsid, 0);
     775                if (sess == NULL) {
     776                        printf("%s: Unable to connect to framebuffer service %s\n",
     777                            NAME, svc);
     778                        return NULL;
     779                }
     780        } else
     781                return NULL;
     782       
     783        return sess;
     784}
     785
     786static bool console_srv_init(char *input_svc, char *fb_svc)
     787{
     788        /* Avoid double initialization */
     789        if (graphics_state != GRAPHICS_NONE)
     790                return false;
     791       
     792        /* Connect to input service */
     793        input_sess = input_connect(input_svc);
    765794        if (input_sess == NULL)
    766795                return false;
    767796       
    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);
     797        /* Connect to framebuffer service */
     798        fb_sess = fb_connect(fb_svc);
     799        if (fb_sess == NULL)
    772800                return false;
    773         }
    774        
    775         /* Register driver */
    776         int rc = devmap_driver_register(NAME, client_connection);
     801       
     802        /* Register server */
     803        int rc = loc_server_register(NAME, client_connection);
    777804        if (rc < 0) {
    778                 printf("%s: Unable to register driver (%d)\n", NAME, rc);
     805                printf("%s: Unable to register server (%s)\n", NAME,
     806                    str_error(rc));
    779807                return false;
    780808        }
    781809       
    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;
     810        fb_get_resolution(fb_sess, &xres, &yres);
     811       
     812        /* Initialize the screen */
     813        screen_vp = fb_vp_create(fb_sess, 0, 0, xres, yres);
     814       
     815        if ((xres >= 800) && (yres >= 600)) {
     816                logo_vp = fb_vp_create(fb_sess, xres - 66, 2, 64, 60);
     817                logo_img = imgmap_decode_tga((void *) helenos_tga,
     818                    helenos_tga_size, IMGMAP_FLAG_SHARED);
     819                logo_handle = fb_imagemap_create(fb_sess, logo_img);
     820               
     821                nameic_vp = fb_vp_create(fb_sess, 5, 17, 100, 26);
     822                nameic_img = imgmap_decode_tga((void *) nameic_tga,
     823                    nameic_tga_size, IMGMAP_FLAG_SHARED);
     824                nameic_handle = fb_imagemap_create(fb_sess, nameic_img);
     825               
     826                cons_data_img = imgmap_decode_tga((void *) cons_data_tga,
     827                    cons_data_tga_size, IMGMAP_FLAG_SHARED);
     828                cons_dis_img = imgmap_decode_tga((void *) cons_dis_tga,
     829                    cons_dis_tga_size, IMGMAP_FLAG_SHARED);
     830                cons_dis_sel_img = imgmap_decode_tga((void *) cons_dis_sel_tga,
     831                    cons_dis_sel_tga_size, IMGMAP_FLAG_SHARED);
     832                cons_idle_img = imgmap_decode_tga((void *) cons_idle_tga,
     833                    cons_idle_tga_size, IMGMAP_FLAG_SHARED);
     834                cons_kernel_img = imgmap_decode_tga((void *) cons_kernel_tga,
     835                    cons_kernel_tga_size, IMGMAP_FLAG_SHARED);
     836                cons_sel_img = imgmap_decode_tga((void *) cons_sel_tga,
     837                    cons_sel_tga_size, IMGMAP_FLAG_SHARED);
     838               
     839                state_icons[CONS_DISCONNECTED] =
     840                    fb_imagemap_create(fb_sess, cons_dis_img);
     841                state_icons[CONS_DISCONNECTED_SELECTED] =
     842                    fb_imagemap_create(fb_sess, cons_dis_sel_img);
     843                state_icons[CONS_SELECTED] =
     844                    fb_imagemap_create(fb_sess, cons_sel_img);
     845                state_icons[CONS_IDLE] =
     846                    fb_imagemap_create(fb_sess, cons_idle_img);
     847                state_icons[CONS_DATA] =
     848                    fb_imagemap_create(fb_sess, cons_data_img);
     849                state_icons[CONS_KERNEL] =
     850                    fb_imagemap_create(fb_sess, cons_kernel_img);
     851               
     852                anim_1_img = imgmap_decode_tga((void *) anim_1_tga,
     853                    anim_1_tga_size, IMGMAP_FLAG_SHARED);
     854                anim_2_img = imgmap_decode_tga((void *) anim_2_tga,
     855                    anim_2_tga_size, IMGMAP_FLAG_SHARED);
     856                anim_3_img = imgmap_decode_tga((void *) anim_3_tga,
     857                    anim_3_tga_size, IMGMAP_FLAG_SHARED);
     858                anim_4_img = imgmap_decode_tga((void *) anim_4_tga,
     859                    anim_4_tga_size, IMGMAP_FLAG_SHARED);
     860               
     861                anim_1 = fb_imagemap_create(fb_sess, anim_1_img);
     862                anim_2 = fb_imagemap_create(fb_sess, anim_2_img);
     863                anim_3 = fb_imagemap_create(fb_sess, anim_3_img);
     864                anim_4 = fb_imagemap_create(fb_sess, anim_4_img);
     865               
     866                anim_seq = fb_sequence_create(fb_sess);
     867                fb_sequence_add_imagemap(fb_sess, anim_seq, anim_1);
     868                fb_sequence_add_imagemap(fb_sess, anim_seq, anim_2);
     869                fb_sequence_add_imagemap(fb_sess, anim_seq, anim_3);
     870                fb_sequence_add_imagemap(fb_sess, anim_seq, anim_4);
     871               
     872                console_vp = fb_vp_create(fb_sess, CONSOLE_MARGIN, CONSOLE_TOP,
     873                    xres - 2 * CONSOLE_MARGIN, yres - (CONSOLE_TOP + CONSOLE_MARGIN));
     874               
     875                fb_vp_clear(fb_sess, screen_vp);
     876                fb_vp_imagemap_damage(fb_sess, logo_vp, logo_handle,
     877                    0, 0, 64, 60);
     878                fb_vp_imagemap_damage(fb_sess, nameic_vp, nameic_handle,
     879                    0, 0, 100, 26);
     880               
     881                graphics_state = GRAPHICS_FULL;
     882        } else {
     883                console_vp = screen_vp;
     884                graphics_state = GRAPHICS_BASIC;
     885        }
     886       
     887        fb_vp_set_style(fb_sess, console_vp, STYLE_NORMAL);
     888        fb_vp_clear(fb_sess, console_vp);
     889       
     890        sysarg_t cols;
     891        sysarg_t rows;
     892        fb_vp_get_dimensions(fb_sess, console_vp, &cols, &rows);
     893       
     894        console_caps_t ccaps;
     895        fb_vp_get_caps(fb_sess, console_vp, &ccaps);
     896       
     897        mouse.x = xres / 2;
     898        mouse.y = yres / 2;
     899        mouse.pressed = false;
    807900       
    808901        /* 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[DEVMAP_NAME_MAXLEN + 1];
    823                         snprintf(vc, DEVMAP_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i);
    824                        
    825                         if (devmap_device_register(vc, &consoles[i].devmap_handle) != EOK) {
    826                                 printf("%s: Unable to register device %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();
     902        for (size_t i = 0; i < CONSOLE_COUNT; i++) {
     903                consoles[i].index = i;
     904                atomic_set(&consoles[i].refcnt, 0);
     905                fibril_mutex_initialize(&consoles[i].mtx);
     906               
     907                if (graphics_state == GRAPHICS_FULL) {
     908                        /* Create state buttons */
     909                        consoles[i].state_vp =
     910                            fb_vp_create(fb_sess, STATE_START + (xres - 800) / 2 +
     911                            CONSOLE_MARGIN + i * (STATE_WIDTH + STATE_SPACE),
     912                            STATE_TOP, STATE_WIDTH, STATE_HEIGHT);
     913                }
     914               
     915                if (i == KERNEL_CONSOLE) {
     916                        consoles[i].state = CONS_KERNEL;
     917                        cons_redraw_state(&consoles[i]);
     918                        cons_kernel_sequence_start(&consoles[i]);
     919                        continue;
     920                }
     921               
     922                if (i == 0)
     923                        consoles[i].state = CONS_DISCONNECTED_SELECTED;
     924                else
     925                        consoles[i].state = CONS_DISCONNECTED;
     926               
     927                consoles[i].cols = cols;
     928                consoles[i].rows = rows;
     929                consoles[i].ccaps = ccaps;
     930                consoles[i].frontbuf =
     931                    screenbuffer_create(cols, rows, SCREENBUFFER_FLAG_SHARED);
     932               
     933                if (consoles[i].frontbuf == NULL) {
     934                        printf("%s: Unable to allocate frontbuffer %zu\n", NAME, i);
     935                        return false;
     936                }
     937               
     938                consoles[i].fbid = fb_frontbuf_create(fb_sess, consoles[i].frontbuf);
     939                if (consoles[i].fbid == 0) {
     940                        printf("%s: Unable to create frontbuffer %zu\n", NAME, i);
     941                        return false;
     942                }
     943               
     944                prodcons_initialize(&consoles[i].input_pc);
     945                cons_redraw_state(&consoles[i]);
     946               
     947                char vc[LOC_NAME_MAXLEN + 1];
     948                snprintf(vc, LOC_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i);
     949               
     950                if (loc_service_register(vc, &consoles[i].dsid) != EOK) {
     951                        printf("%s: Unable to register device %s\n", NAME, vc);
     952                        return false;
     953                }
     954        }
    840955       
    841956        /* Receive kernel notifications */
    842957        async_set_interrupt_received(interrupt_received);
    843         if (event_subscribe(EVENT_KCONSOLE, 0) != EOK)
    844                 printf("%s: Error registering kconsole notifications\n", NAME);
     958        rc = event_subscribe(EVENT_KCONSOLE, 0);
     959        if (rc != EOK)
     960                printf("%s: Failed to register kconsole notifications (%s)\n",
     961                    NAME, str_error(rc));
    845962       
    846963        return true;
     
    849966static void usage(void)
    850967{
    851         printf("Usage: console <input_dev>\n");
     968        printf("Usage: console <input_dev> <framebuffer_dev>\n");
    852969}
    853970
    854971int main(int argc, char *argv[])
    855972{
    856         if (argc < 2) {
     973        if (argc < 3) {
    857974                usage();
    858975                return -1;
    859976        }
    860977       
    861         printf(NAME ": HelenOS Console service\n");
    862        
    863         if (!console_srv_init(argv[1]))
     978        printf("%s: HelenOS Console service\n", NAME);
     979       
     980        if (!console_srv_init(argv[1], argv[2]))
    864981                return -1;
    865982       
    866         printf(NAME ": Accepting connections\n");
     983        printf("%s: Accepting connections\n", NAME);
     984        task_retval(0);
    867985        async_manager();
    868986       
  • uspace/srv/hid/console/console.h

    r867e2555 r925a21e  
    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

    r867e2555 r925a21e  
    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         ppm.c
    44 
    45 ifneq ($(UARCH),ia64)
    46         SOURCES += \
    47                 fb.c \
    48                 font-8x16.c
    49         EXTRA_CFLAGS += -DFB_ENABLED
    50 endif
    51 
    52 ifeq ($(UARCH),ia32)
    53         SOURCES += \
    54                 ega.c
    55         EXTRA_CFLAGS += -DEGA_ENABLED
    56 endif
    57 
    58 ifeq ($(UARCH),ia64)
    59         SOURCES += \
    60                 ega.c \
    61                 ski.c \
    62                 serial_console.c
    63         EXTRA_CFLAGS += -DSKI_ENABLED -DEGA_ENABLED
    64 endif
    65 
    66 ifeq ($(UARCH),amd64)
    67         SOURCES += \
    68                 ega.c
    69         EXTRA_CFLAGS += -DEGA_ENABLED
    70 endif
    71 
    72 ifeq ($(UARCH),mips32)
    73         SOURCES += \
    74                 msim.c \
    75                 serial_console.c
    76         EXTRA_CFLAGS += -DMSIM_ENABLED
    77 endif
    78 
    79 ifeq ($(UARCH),sparc64)
    80         ifeq ($(PROCESSOR),sun4v)
    81                 SOURCES += \
    82                         niagara.c \
    83                         serial_console.c
    84                 EXTRA_CFLAGS += -DNIAGARA_ENABLED
    85         endif
    86 endif
    87 
    88 EXTRA_CFLAGS += -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

    r867e2555 r925a21e  
    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

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

    r867e2555 r925a21e  
    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 typedef void (* putpixel_cb_t)(void *, unsigned int, unsigned int, uint32_t);
     42struct fbdev;
     43struct fbvp;
    4244
    43 extern int fb_init(void);
     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 *);
    44151
    45152#endif
    46 
    47 /** @}
    48  */
  • uspace/srv/hid/fb/gfx/font-8x16.c

    r867e2555 r925a21e  
    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

    r867e2555 r925a21e  
    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

    r867e2555 r925a21e  
    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

    r867e2555 r925a21e  
    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

    r867e2555 r925a21e  
    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/niagara.c

    r867e2555 r925a21e  
    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

    r867e2555 r925a21e  
    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

    r867e2555 r925a21e  
    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

    r867e2555 r925a21e  
    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/input/ctl/kbdev.c

    r867e2555 r925a21e  
    4848#include <kbd_ctl.h>
    4949#include <kbd_port.h>
     50#include <loc.h>
    5051#include <stdlib.h>
    5152#include <vfs/vfs_sess.h>
    52 
     53#include <sys/typefmt.h>
    5354
    5455static int kbdev_ctl_init(kbd_dev_t *);
     
    7071        /** Session with kbdev device */
    7172        async_sess_t *sess;
    72 
    73         /** File descriptor of open kbdev device */
    74         int fd;
    7573} kbdev_t;
    7674
     
    8482
    8583        kbdev->kbd_dev = kdev;
    86         kbdev->fd = -1;
    8784
    8885        return kbdev;
     
    9390        if (kbdev->sess != NULL)
    9491                async_hangup(kbdev->sess);
    95         if (kbdev->fd >= 0)
    96                 close(kbdev->fd);
    9792        free(kbdev);
    9893}
     
    10095static int kbdev_ctl_init(kbd_dev_t *kdev)
    10196{
    102         const char *pathname;
    10397        async_sess_t *sess;
    10498        async_exch_t *exch;
    10599        kbdev_t *kbdev;
    106         int fd;
    107100        int rc;
    108101
    109         pathname = kdev->dev_path;
    110 
    111         fd = open(pathname, O_RDWR);
    112         if (fd < 0) {
    113                 return -1;
    114         }
    115 
    116         sess = fd_session(EXCHANGE_SERIALIZE, fd);
     102        sess = loc_service_connect(EXCHANGE_SERIALIZE, kdev->svc_id, 0);
    117103        if (sess == NULL) {
    118                 printf("%s: Failed starting session with '%s'\n", NAME, pathname);
    119                 close(fd);
     104                printf("%s: Failed starting session with '%s.'\n", NAME,
     105                    kdev->svc_name);
    120106                return -1;
    121107        }
     
    124110        if (kbdev == NULL) {
    125111                printf("%s: Failed allocating device structure for '%s'.\n",
    126                     NAME, pathname);
     112                    NAME, kdev->svc_name);
    127113                return -1;
    128114        }
    129115
    130         kbdev->fd = fd;
    131116        kbdev->sess = sess;
    132117
    133118        exch = async_exchange_begin(sess);
    134119        if (exch == NULL) {
    135                 printf("%s: Failed starting exchange with '%s'.\n", NAME, pathname);
     120                printf("%s: Failed starting exchange with '%s'.\n", NAME,
     121                    kdev->svc_name);
    136122                kbdev_destroy(kbdev);
    137123                return -1;
     
    141127        if (rc != EOK) {
    142128                printf("%s: Failed creating callback connection from '%s'.\n",
    143                     NAME, pathname);
     129                    NAME, kdev->svc_name);
    144130                async_exchange_end(exch);
    145131                kbdev_destroy(kbdev);
  • uspace/srv/hid/input/generic/input.c

    r867e2555 r925a21e  
    3838
    3939#include <adt/list.h>
     40#include <bool.h>
    4041#include <ipc/services.h>
    4142#include <ipc/input.h>
     
    4647#include <stdio.h>
    4748#include <ns.h>
    48 #include <ns_obsolete.h>
    4949#include <async.h>
    50 #include <async_obsolete.h>
    5150#include <errno.h>
    5251#include <adt/fifo.h>
    5352#include <io/console.h>
    5453#include <io/keycode.h>
    55 #include <devmap.h>
     54#include <loc.h>
    5655#include <input.h>
    5756#include <kbd.h>
     
    6261#include <mouse.h>
    6362
    64 // FIXME: remove this header
    65 #include <kernel/ipc/ipc_methods.h>
    66 
    67 /* In microseconds */
    68 #define DISCOVERY_POLL_INTERVAL  (10 * 1000 * 1000)
    69 
    7063#define NUM_LAYOUTS  3
    7164
     
    7972static void kbd_devs_reclaim(void);
    8073
    81 int client_phone = -1;
     74async_sess_t *client_sess = NULL;
    8275
    8376/** List of keyboard devices */
     
    8881
    8982bool irc_service = false;
    90 int irc_phone = -1;
     83async_sess_t *irc_sess = NULL;
    9184
    9285void kbd_push_data(kbd_dev_t *kdev, sysarg_t data)
     
    172165       
    173166        ev.c = layout_parse_ev(kdev->active_layout, &ev);
    174         async_obsolete_msg_4(client_phone, INPUT_EVENT_KEY, ev.type, ev.key,
    175             ev.mods, ev.c);
     167       
     168        async_exch_t *exch = async_exchange_begin(client_sess);
     169        async_msg_4(exch, INPUT_EVENT_KEY, ev.type, ev.key, ev.mods, ev.c);
     170        async_exchange_end(exch);
    176171}
    177172
     
    179174void mouse_push_event_move(mouse_dev_t *mdev, int dx, int dy)
    180175{
    181         async_obsolete_msg_2(client_phone, INPUT_EVENT_MOVE, dx, dy);
     176        async_exch_t *exch = async_exchange_begin(client_sess);
     177        async_msg_2(exch, INPUT_EVENT_MOVE, dx, dy);
     178        async_exchange_end(exch);
    182179}
    183180
     
    185182void mouse_push_event_button(mouse_dev_t *mdev, int bnum, int press)
    186183{
    187         async_obsolete_msg_2(client_phone, INPUT_EVENT_BUTTON, bnum, press);
     184        async_exch_t *exch = async_exchange_begin(client_sess);
     185        async_msg_2(exch, INPUT_EVENT_BUTTON, bnum, press);
     186        async_exchange_end(exch);
    188187}
    189188
    190189static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    191190{
    192         ipc_callid_t callid;
    193         ipc_call_t call;
    194         int retval;
    195        
    196191        async_answer_0(iid, EOK);
    197192       
    198193        while (true) {
    199                 callid = async_get_call(&call);
     194                ipc_call_t call;
     195                ipc_callid_t callid = async_get_call(&call);
    200196               
    201197                if (!IPC_GET_IMETHOD(call)) {
    202                         if (client_phone != -1) {
    203                                 async_obsolete_hangup(client_phone);
    204                                 client_phone = -1;
     198                        if (client_sess != NULL) {
     199                                async_hangup(client_sess);
     200                                client_sess = NULL;
    205201                        }
    206202                       
     
    209205                }
    210206               
    211                 switch (IPC_GET_IMETHOD(call)) {
    212                 case IPC_M_CONNECT_TO_ME:
    213                         if (client_phone != -1) {
    214                                 retval = ELIMIT;
     207                async_sess_t *sess =
     208                    async_callback_receive_start(EXCHANGE_SERIALIZE, &call);
     209                if (sess != NULL) {
     210                        if (client_sess == NULL) {
     211                                client_sess = sess;
     212                                async_answer_0(callid, EOK);
     213                        } else
     214                                async_answer_0(callid, ELIMIT);
     215                } else {
     216                        switch (IPC_GET_IMETHOD(call)) {
     217                        case INPUT_YIELD:
     218                                kbd_devs_yield();
     219                                async_answer_0(callid, EOK);
    215220                                break;
     221                        case INPUT_RECLAIM:
     222                                kbd_devs_reclaim();
     223                                async_answer_0(callid, EOK);
     224                                break;
     225                        default:
     226                                async_answer_0(callid, EINVAL);
    216227                        }
    217                         client_phone = IPC_GET_ARG5(call);
    218                         retval = 0;
    219                         break;
    220                 case INPUT_YIELD:
    221                         kbd_devs_yield();
    222                         retval = 0;
    223                         break;
    224                 case INPUT_RECLAIM:
    225                         kbd_devs_reclaim();
    226                         retval = 0;
    227                         break;
    228                 default:
    229                         retval = EINVAL;
    230228                }
    231                
    232                 async_answer_0(callid, retval);
    233229        }
    234230}
     
    275271        kdev->port_ops = port;
    276272        kdev->ctl_ops = ctl;
    277         kdev->dev_path = NULL;
     273        kdev->svc_id = 0;
    278274       
    279275        /* Initialize port driver. */
     
    303299        mdev->port_ops = port;
    304300        mdev->proto_ops = proto;
    305         mdev->dev_path = NULL;
     301        mdev->svc_id = 0;
    306302       
    307303        /* Initialize port driver. */
     
    324320/** Add new kbdev device.
    325321 *
    326  * @param dev_path Filesystem path to the device (/dev/class/...)
     322 * @param service_id    Service ID of the keyboard device
    327323 *
    328324 */
    329 static int kbd_add_kbdev(const char *dev_path)
     325static int kbd_add_kbdev(service_id_t service_id, kbd_dev_t **kdevp)
    330326{
    331327        kbd_dev_t *kdev = kbd_dev_new();
     
    333329                return -1;
    334330       
    335         kdev->dev_path = dev_path;
     331        kdev->svc_id = service_id;
    336332        kdev->port_ops = NULL;
    337333        kdev->ctl_ops = &kbdev_ctl;
    338334       
     335        int rc = loc_service_get_name(service_id, &kdev->svc_name);
     336        if (rc != EOK) {
     337                kdev->svc_name = NULL;
     338                goto fail;
     339        }
     340       
    339341        /* Initialize controller driver. */
    340342        if ((*kdev->ctl_ops->init)(kdev) != 0) {
     
    343345       
    344346        list_append(&kdev->kbd_devs, &kbd_devs);
     347        *kdevp = kdev;
    345348        return EOK;
    346349       
    347350fail:
     351        if (kdev->svc_name != NULL)
     352                free(kdev->svc_name);
    348353        free(kdev);
    349354        return -1;
     
    352357/** Add new mousedev device.
    353358 *
    354  * @param dev_path Filesystem path to the device (/dev/class/...)
     359 * @param service_id    Service ID of the mouse device
    355360 *
    356361 */
    357 static int mouse_add_mousedev(const char *dev_path)
     362static int mouse_add_mousedev(service_id_t service_id, mouse_dev_t **mdevp)
    358363{
    359364        mouse_dev_t *mdev = mouse_dev_new();
     
    361366                return -1;
    362367       
    363         mdev->dev_path = dev_path;
     368        mdev->svc_id = service_id;
    364369        mdev->port_ops = NULL;
    365370        mdev->proto_ops = &mousedev_proto;
    366371       
     372        int rc = loc_service_get_name(service_id, &mdev->svc_name);
     373        if (rc != EOK) {
     374                mdev->svc_name = NULL;
     375                goto fail;
     376        }
     377       
    367378        /* Initialize controller driver. */
    368379        if ((*mdev->proto_ops->init)(mdev) != 0) {
     
    371382       
    372383        list_append(&mdev->mouse_devs, &mouse_devs);
     384        *mdevp = mdev;
    373385        return EOK;
    374386       
     
    480492}
    481493
    482 /** Periodically check for new input devices.
    483  *
    484  * Looks under /dev/class/keyboard and /dev/class/mouse.
    485  *
    486  * @param arg Ignored
    487  *
    488  */
    489 static int dev_discovery_fibril(void *arg)
    490 {
    491         char *dev_path;
    492         size_t kbd_id = 1;
    493         size_t mouse_id = 1;
     494static int dev_check_new_kbdevs(void)
     495{
     496        category_id_t keyboard_cat;
     497        service_id_t *svcs;
     498        size_t count, i;
     499        bool already_known;
    494500        int rc;
    495501       
    496         while (true) {
    497                 async_usleep(DISCOVERY_POLL_INTERVAL);
    498                
    499                 /*
    500                  * Check for new keyboard device
    501                  */
    502                 rc = asprintf(&dev_path, "/dev/class/keyboard\\%zu", kbd_id);
    503                 if (rc < 0)
    504                         continue;
    505                
    506                 if (kbd_add_kbdev(dev_path) == EOK) {
    507                         printf("%s: Connected keyboard device '%s'\n",
    508                             NAME, dev_path);
    509                        
    510                         /* XXX Handle device removal */
    511                         ++kbd_id;
     502        rc = loc_category_get_id("keyboard", &keyboard_cat, IPC_FLAG_BLOCKING);
     503        if (rc != EOK) {
     504                printf("%s: Failed resolving category 'keyboard'.\n", NAME);
     505                return ENOENT;
     506        }
     507       
     508        /*
     509         * Check for new keyboard devices
     510         */
     511        rc = loc_category_get_svcs(keyboard_cat, &svcs, &count);
     512        if (rc != EOK) {
     513                printf("%s: Failed getting list of keyboard devices.\n",
     514                    NAME);
     515                return EIO;
     516        }
     517
     518        for (i = 0; i < count; i++) {
     519                already_known = false;
     520               
     521                /* Determine whether we already know this device. */
     522                list_foreach(kbd_devs, kdev_link) {
     523                        kbd_dev_t *kdev = list_get_instance(kdev_link,
     524                            kbd_dev_t, kbd_devs);
     525                        if (kdev->svc_id == svcs[i]) {
     526                                already_known = true;
     527                                break;
     528                        }
    512529                }
    513530               
    514                 free(dev_path);
    515                
    516                 /*
    517                  * Check for new mouse device
    518                  */
    519                 rc = asprintf(&dev_path, "/dev/class/mouse\\%zu", mouse_id);
    520                 if (rc < 0)
    521                         continue;
    522                
    523                 if (mouse_add_mousedev(dev_path) == EOK) {
    524                         printf("%s: Connected mouse device '%s'\n",
    525                             NAME, dev_path);
    526                        
    527                         /* XXX Handle device removal */
    528                         ++mouse_id;
     531                if (!already_known) {
     532                        kbd_dev_t *kdev;
     533                        if (kbd_add_kbdev(svcs[i], &kdev) == EOK) {
     534                                printf("%s: Connected keyboard device '%s'\n",
     535                                    NAME, kdev->svc_name);
     536                        }
    529537                }
    530                
    531                 free(dev_path);
    532         }
     538        }
     539       
     540        free(svcs);
     541       
     542        /* XXX Handle device removal */
    533543       
    534544        return EOK;
    535545}
    536546
    537 /** Start a fibril for discovering new devices. */
    538 static void input_start_dev_discovery(void)
    539 {
    540         fid_t fid = fibril_create(dev_discovery_fibril, NULL);
    541         if (!fid) {
    542                 printf("%s: Failed to create device discovery fibril.\n",
     547static int dev_check_new_mousedevs(void)
     548{
     549        category_id_t mouse_cat;
     550        service_id_t *svcs;
     551        size_t count, i;
     552        bool already_known;
     553        int rc;
     554       
     555        rc = loc_category_get_id("mouse", &mouse_cat, IPC_FLAG_BLOCKING);
     556        if (rc != EOK) {
     557                printf("%s: Failed resolving category 'mouse'.\n", NAME);
     558                return ENOENT;
     559        }
     560       
     561        /*
     562         * Check for new mouse devices
     563         */
     564        rc = loc_category_get_svcs(mouse_cat, &svcs, &count);
     565        if (rc != EOK) {
     566                printf("%s: Failed getting list of mouse devices.\n",
    543567                    NAME);
    544                 return;
    545         }
    546        
    547         fibril_add_ready(fid);
     568                return EIO;
     569        }
     570       
     571        for (i = 0; i < count; i++) {
     572                already_known = false;
     573               
     574                /* Determine whether we already know this device. */
     575                list_foreach(mouse_devs, mdev_link) {
     576                        mouse_dev_t *mdev = list_get_instance(mdev_link,
     577                            mouse_dev_t, mouse_devs);
     578                        if (mdev->svc_id == svcs[i]) {
     579                                already_known = true;
     580                                break;
     581                        }
     582                }
     583               
     584                if (!already_known) {
     585                        mouse_dev_t *mdev;
     586                        if (mouse_add_mousedev(svcs[i], &mdev) == EOK) {
     587                                printf("%s: Connected mouse device '%s'\n",
     588                                    NAME, mdev->svc_name);
     589                        }
     590                }
     591        }
     592       
     593        free(svcs);
     594       
     595        /* XXX Handle device removal */
     596       
     597        return EOK;
     598}
     599
     600static int dev_check_new(void)
     601{
     602        int rc;
     603       
     604        rc = dev_check_new_kbdevs();
     605        if (rc != EOK)
     606                return rc;
     607       
     608        rc = dev_check_new_mousedevs();
     609        if (rc != EOK)
     610                return rc;
     611
     612        return EOK;
     613}
     614
     615static void cat_change_cb(void)
     616{
     617        dev_check_new();
     618}
     619
     620/** Start listening for new devices. */
     621static int input_start_dev_discovery(void)
     622{
     623        int rc;
     624
     625        rc = loc_register_cat_change_cb(cat_change_cb);
     626        if (rc != EOK) {
     627                printf("%s: Failed registering callback for device discovery. "
     628                    "(%d)\n", NAME, rc);
     629                return rc;
     630        }
     631
     632        return dev_check_new();
    548633}
    549634
     
    561646       
    562647        if (irc_service) {
    563                 while (irc_phone < 0)
    564                         irc_phone = service_obsolete_connect_blocking(SERVICE_IRC, 0, 0);
     648                while (irc_sess == NULL)
     649                        irc_sess = service_connect_blocking(EXCHANGE_SERIALIZE,
     650                            SERVICE_IRC, 0, 0);
    565651        }
    566652       
     
    572658       
    573659        /* Register driver */
    574         int rc = devmap_driver_register(NAME, client_connection);
     660        int rc = loc_server_register(NAME, client_connection);
    575661        if (rc < 0) {
    576                 printf("%s: Unable to register driver (%d)\n", NAME, rc);
     662                printf("%s: Unable to register server (%d)\n", NAME, rc);
    577663                return -1;
    578664        }
    579665       
    580         char kbd[DEVMAP_NAME_MAXLEN + 1];
    581         snprintf(kbd, DEVMAP_NAME_MAXLEN, "%s/%s", NAMESPACE, NAME);
    582        
    583         devmap_handle_t devmap_handle;
    584         if (devmap_device_register(kbd, &devmap_handle) != EOK) {
    585                 printf("%s: Unable to register device %s\n", NAME, kbd);
     666        char kbd[LOC_NAME_MAXLEN + 1];
     667        snprintf(kbd, LOC_NAME_MAXLEN, "%s/%s", NAMESPACE, NAME);
     668       
     669        service_id_t service_id;
     670        if (loc_service_register(kbd, &service_id) != EOK) {
     671                printf("%s: Unable to register service %s\n", NAME, kbd);
    586672                return -1;
    587673        }
  • uspace/srv/hid/input/include/input.h

    r867e2555 r925a21e  
    4040
    4141#include <bool.h>
     42#include <async.h>
    4243
    4344#define NAME       "input"
     
    4546
    4647extern bool irc_service;
    47 extern int irc_phone;
     48extern async_sess_t *irc_sess;
    4849
    4950#endif
  • uspace/srv/hid/input/include/kbd.h

    r867e2555 r925a21e  
    4040
    4141#include <adt/list.h>
     42#include <ipc/loc.h>
    4243
    4344struct kbd_port_ops;
     
    4950        link_t kbd_devs;
    5051
    51         /** Path to the device (only for kbdev devices) */
    52         const char *dev_path;
     52        /** Service ID (only for kbdev devices) */
     53        service_id_t svc_id;
     54
     55        /** Device service name (only for kbdev devices) */
     56        char *svc_name;
    5357
    5458        /** Port ops */
  • uspace/srv/hid/input/include/mouse.h

    r867e2555 r925a21e  
    3939
    4040#include <adt/list.h>
     41#include <ipc/loc.h>
    4142
    4243struct mouse_port_ops;
     
    4748        link_t mouse_devs;
    4849       
    49         /** Path to the device (only for mouseev devices) */
    50         const char *dev_path;
     50        /** Service ID (only for mousedev devices) */
     51        service_id_t svc_id;
     52       
     53        /** Device service name (only for mousedev devices) */
     54        char *svc_name;
    5155       
    5256        /** Port ops */
  • uspace/srv/hid/input/port/adb.c

    r867e2555 r925a21e  
    4343#include <fcntl.h>
    4444#include <errno.h>
    45 #include <devmap.h>
     45#include <loc.h>
    4646
    4747static void kbd_port_events(ipc_callid_t iid, ipc_call_t *icall, void *arg);
     
    6666{
    6767        const char *dev = "adb/kbd";
    68         devmap_handle_t handle;
     68        service_id_t service_id;
    6969        async_exch_t *exch;
    7070        int rc;
     
    7272        kbd_dev = kdev;
    7373       
    74         rc = devmap_device_get_handle(dev, &handle, 0);
     74        rc = loc_service_get_id(dev, &service_id, 0);
    7575        if (rc != EOK)
    7676                return rc;
    7777       
    78         dev_sess = devmap_device_connect(EXCHANGE_ATOMIC, handle, 0);
     78        dev_sess = loc_service_connect(EXCHANGE_ATOMIC, service_id, 0);
    7979        if (dev_sess == NULL) {
    8080                printf("%s: Failed to connect to device\n", NAME);
  • uspace/srv/hid/input/port/adb_mouse.c

    r867e2555 r925a21e  
    4141#include <mouse.h>
    4242#include <errno.h>
    43 #include <devmap.h>
     43#include <loc.h>
     44#include <stdio.h>
    4445
    4546static mouse_dev_t *mouse_dev;
     
    7879        mouse_dev = mdev;
    7980       
    80         devmap_handle_t handle;
    81         int rc = devmap_device_get_handle(dev, &handle, 0);
     81        service_id_t service_id;
     82        int rc = loc_service_get_id(dev, &service_id, 0);
    8283        if (rc != EOK)
    8384                return rc;
    8485       
    85         dev_sess = devmap_device_connect(EXCHANGE_ATOMIC, handle, 0);
     86        dev_sess = loc_service_connect(EXCHANGE_ATOMIC, service_id, 0);
    8687        if (dev_sess == NULL) {
    8788                printf("%s: Failed to connect to device\n", NAME);
  • uspace/srv/hid/input/port/chardev.c

    r867e2555 r925a21e  
    4040#include <kbd_port.h>
    4141#include <kbd.h>
    42 #include <devmap.h>
     42#include <loc.h>
    4343#include <errno.h>
    4444#include <stdio.h>
     
    7171static int chardev_port_init(kbd_dev_t *kdev)
    7272{
    73         devmap_handle_t handle;
     73        service_id_t service_id;
    7474        async_exch_t *exch;
    7575        unsigned int i;
     
    7979       
    8080        for (i = 0; i < num_devs; i++) {
    81                 rc = devmap_device_get_handle(in_devs[i], &handle, 0);
     81                rc = loc_service_get_id(in_devs[i], &service_id, 0);
    8282                if (rc == EOK)
    8383                        break;
     
    8989        }
    9090       
    91         dev_sess = devmap_device_connect(EXCHANGE_ATOMIC, handle,
     91        dev_sess = loc_service_connect(EXCHANGE_ATOMIC, service_id,
    9292            IPC_FLAG_BLOCKING);
    9393        if (dev_sess == NULL) {
  • uspace/srv/hid/input/port/chardev_mouse.c

    r867e2555 r925a21e  
    3939#include <async.h>
    4040#include <errno.h>
    41 #include <devmap.h>
     41#include <loc.h>
    4242#include <input.h>
    4343#include <mouse_port.h>
     
    8282static int chardev_port_init(mouse_dev_t *mdev)
    8383{
    84         devmap_handle_t handle;
     84        service_id_t service_id;
    8585        unsigned int i;
    8686        int rc;
     
    8989       
    9090        for (i = 0; i < num_devs; i++) {
    91                 rc = devmap_device_get_handle(in_devs[i], &handle, 0);
     91                rc = loc_service_get_id(in_devs[i], &service_id, 0);
    9292                if (rc == EOK)
    9393                        break;
     
    9999        }
    100100       
    101         dev_sess = devmap_device_connect(EXCHANGE_ATOMIC, handle,
     101        dev_sess = loc_service_connect(EXCHANGE_ATOMIC, service_id,
    102102            IPC_FLAG_BLOCKING);
    103103        if (dev_sess == NULL) {
  • uspace/srv/hid/input/port/ns16550.c

    r867e2555 r925a21e  
    3838#include <ipc/irc.h>
    3939#include <async.h>
    40 #include <async_obsolete.h>
    4140#include <sysinfo.h>
    4241#include <input.h>
     
    158157        kbd_push_data(kbd_dev, IPC_GET_ARG2(*call));
    159158       
    160         if (irc_service)
    161                 async_obsolete_msg_1(irc_phone, IRC_CLEAR_INTERRUPT,
    162                     IPC_GET_IMETHOD(*call));
     159        if (irc_service) {
     160                async_exch_t *exch = async_exchange_begin(irc_sess);
     161                async_msg_1(exch, IRC_CLEAR_INTERRUPT, IPC_GET_IMETHOD(*call));
     162                async_exchange_end(exch);
     163        }
    163164}
    164165
  • uspace/srv/hid/input/proto/mousedev.c

    r867e2555 r925a21e  
    4444#include <ipc/mouseev.h>
    4545#include <input.h>
     46#include <loc.h>
    4647#include <mouse.h>
    4748#include <mouse_port.h>
    4849#include <mouse_proto.h>
     50#include <sys/typefmt.h>
    4951
    5052/** Mousedev softstate */
     
    5557        /** Session to mouse device */
    5658        async_sess_t *sess;
    57        
    58         /** File descriptor of open mousedev device */
    59         int fd;
    6059} mousedev_t;
    6160
     
    6766       
    6867        mousedev->mouse_dev = mdev;
    69         mousedev->fd = -1;
    7068       
    7169        return mousedev;
     
    7674        if (mousedev->sess != NULL)
    7775                async_hangup(mousedev->sess);
    78        
    79         if (mousedev->fd >= 0)
    80                 close(mousedev->fd);
    8176       
    8277        free(mousedev);
     
    122117static int mousedev_proto_init(mouse_dev_t *mdev)
    123118{
    124         const char *pathname = mdev->dev_path;
    125        
    126         int fd = open(pathname, O_RDWR);
    127         if (fd < 0)
    128                 return -1;
    129        
    130         async_sess_t *sess = fd_session(EXCHANGE_SERIALIZE, fd);
     119        async_sess_t *sess = loc_service_connect(EXCHANGE_SERIALIZE,
     120            mdev->svc_id, 0);
    131121        if (sess == NULL) {
    132                 printf("%s: Failed starting session with '%s'\n", NAME, pathname);
    133                 close(fd);
     122                printf("%s: Failed starting session with '%s'\n", NAME,
     123                    mdev->svc_name);
    134124                return -1;
    135125        }
     
    138128        if (mousedev == NULL) {
    139129                printf("%s: Failed allocating device structure for '%s'.\n",
    140                     NAME, pathname);
     130                    NAME, mdev->svc_name);
    141131                return -1;
    142132        }
    143133       
    144         mousedev->fd = fd;
    145134        mousedev->sess = sess;
    146135       
    147136        async_exch_t *exch = async_exchange_begin(sess);
    148137        if (exch == NULL) {
    149                 printf("%s: Failed starting exchange with '%s'.\n", NAME, pathname);
     138                printf("%s: Failed starting exchange with '%s'.\n", NAME,
     139                    mdev->svc_name);
    150140                mousedev_destroy(mousedev);
    151141                return -1;
     
    157147        if (rc != EOK) {
    158148                printf("%s: Failed creating callback connection from '%s'.\n",
    159                     NAME, pathname);
     149                    NAME, mdev->svc_name);
    160150                mousedev_destroy(mousedev);
    161151                return -1;
  • uspace/srv/hid/s3c24xx_ts/s3c24xx_ts.c

    r867e2555 r925a21e  
    3939#include <ddi.h>
    4040#include <libarch/ddi.h>
    41 #include <devmap.h>
     41#include <loc.h>
    4242#include <io/console.h>
    4343#include <vfs/vfs.h>
    4444#include <ipc/mouseev.h>
    4545#include <async.h>
    46 #include <async_obsolete.h>
    4746#include <unistd.h>
    4847#include <stdio.h>
     
    5352#include "s3c24xx_ts.h"
    5453
    55 // FIXME: remove this header
    56 #include <kernel/ipc/ipc_methods.h>
    57 
    58 #define NAME "s3c24ser"
    59 #define NAMESPACE "hid"
     54#define NAME       "s3c24ser"
     55#define NAMESPACE  "hid"
    6056
    6157static irq_cmd_t ts_irq_cmds[] = {
     
    9086        printf(NAME ": S3C24xx touchscreen driver\n");
    9187
    92         rc = devmap_driver_register(NAME, s3c24xx_ts_connection);
     88        rc = loc_server_register(NAME, s3c24xx_ts_connection);
    9389        if (rc < 0) {
    9490                printf(NAME ": Unable to register driver.\n");
     
    10399                return -1;
    104100
    105         rc = devmap_device_register(NAMESPACE "/mouse", &ts->devmap_handle);
     101        rc = loc_service_register(NAMESPACE "/mouse", &ts->service_id);
    106102        if (rc != EOK) {
    107103                printf(NAME ": Unable to register device %s.\n",
     
    134130
    135131        ts->io = vaddr;
    136         ts->client_phone = -1;
     132        ts->client_sess = NULL;
    137133        ts->state = ts_wait_pendown;
    138134        ts->last_x = 0;
     
    284280        button = 1;
    285281        press = 0;
    286         async_obsolete_msg_2(ts->client_phone, MOUSEEV_BUTTON_EVENT, button, press);
     282       
     283        async_exch_t *exch = async_exchange_begin(ts->client_sess);
     284        async_msg_2(exch, MOUSEEV_BUTTON_EVENT, button, press);
     285        async_exchange_end(exch);
    287286
    288287        s3c24xx_ts_wait_for_int_mode(ts, updn_down);
     
    325324
    326325        /* Send notifications to client. */
    327         async_obsolete_msg_2(ts->client_phone, MOUSEEV_MOVE_EVENT, dx, dy);
    328         async_obsolete_msg_2(ts->client_phone, MOUSEEV_BUTTON_EVENT, button, press);
     326        async_exch_t *exch = async_exchange_begin(ts->client_sess);
     327        async_msg_2(exch, MOUSEEV_MOVE_EVENT, dx, dy);
     328        async_msg_2(exch, MOUSEEV_BUTTON_EVENT, button, press);
     329        async_exchange_end(exch);
    329330
    330331        ts->last_x = x_pos;
     
    377378    void *arg)
    378379{
    379         ipc_callid_t callid;
    380         ipc_call_t call;
    381         int retval;
    382 
    383380        async_answer_0(iid, EOK);
    384 
    385         while (1) {
    386                 callid = async_get_call(&call);
     381       
     382        while (true) {
     383                ipc_call_t call;
     384                ipc_callid_t callid = async_get_call(&call);
    387385               
    388386                if (!IPC_GET_IMETHOD(call)) {
    389                         if (ts->client_phone != -1) {
    390                                 async_obsolete_hangup(ts->client_phone);
    391                                 ts->client_phone = -1;
     387                        if (ts->client_sess != NULL) {
     388                                async_hangup(ts->client_sess);
     389                                ts->client_sess = NULL;
    392390                        }
    393 
     391                       
    394392                        async_answer_0(callid, EOK);
    395393                        return;
    396394                }
    397395               
    398                 switch (IPC_GET_IMETHOD(call)) {
    399                 case IPC_M_CONNECT_TO_ME:
    400                         if (ts->client_phone != -1) {
    401                                 retval = ELIMIT;
    402                                 break;
    403                         }
    404                         ts->client_phone = IPC_GET_ARG5(call);
    405                         retval = 0;
    406                         break;
    407                 default:
    408                         retval = EINVAL;
    409                 }
    410                 async_answer_0(callid, retval);
     396                async_sess_t *sess =
     397                    async_callback_receive_start(EXCHANGE_SERIALIZE, &call);
     398                if (sess != NULL) {
     399                        if (ts->client_sess == NULL) {
     400                                ts->client_sess = sess;
     401                                async_answer_0(callid, EOK);
     402                        } else
     403                                async_answer_0(callid, ELIMIT);
     404                } else
     405                        async_answer_0(callid, EINVAL);
    411406        }
    412407}
  • uspace/srv/hid/s3c24xx_ts/s3c24xx_ts.h

    r867e2555 r925a21e  
    3939
    4040#include <sys/types.h>
     41#include <async.h>
    4142
    4243/** S3C24xx ADC and touch-screen I/O */
     
    121122        s3c24xx_adc_io_t *io;
    122123
    123         /** Callback phone to the client */
    124         int client_phone;
     124        /** Callback session to the client */
     125        async_sess_t *client_sess;
    125126
    126         /** Device handle */
    127         devmap_handle_t devmap_handle;
     127        /** Service ID */
     128        service_id_t service_id;
    128129
    129130        /** Device/driver state */
Note: See TracChangeset for help on using the changeset viewer.