Ignore:
File:
1 edited

Legend:

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

    rb366a6f4 rcccc091  
    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       
Note: See TracChangeset for help on using the changeset viewer.