Ignore:
File:
1 edited

Legend:

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

    r854eddd6 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 <devmap_obsolete.h>
    57 #include <fcntl.h>
    58 #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>
    5952#include <fibril_synch.h>
    60 #include <io/style.h>
    61 #include <io/screenbuffer.h>
    62 
     53#include "images.h"
    6354#include "console.h"
    64 #include "gcons.h"
    65 #include "keybuffer.h"
    6655
    6756#define NAME       "console"
    6857#define NAMESPACE  "term"
    6958
    70 /** Phone to the input server. */
    71 static int input_phone;
    72 
    73 /** Information about framebuffer */
    74 struct {
    75         int phone;           /**< Framebuffer phone */
    76         sysarg_t cols;       /**< Framebuffer columns */
    77         sysarg_t rows;       /**< Framebuffer rows */
    78         sysarg_t color_cap;  /**< Color capabilities (FB_CCAP_xxx) */
    79 } fb_info;
     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;
    8077
    8178typedef struct {
    82         size_t index;             /**< Console index */
    83         size_t refcount;          /**< Connection reference count */
    84         devmap_handle_t devmap_handle;  /**< Device handle */
    85         keybuffer_t keybuffer;    /**< Buffer for incoming keys. */
    86         screenbuffer_t scr;       /**< Screenbuffer for saving screen
    87                                        contents and related settings. */
     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 */
    8895} 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 */
     110static async_sess_t *input_sess;
     111
     112/** Session to the framebuffer server */
     113static async_sess_t *fb_sess;
     114
     115/** Framebuffer resolution */
     116static sysarg_t xres;
     117static sysarg_t yres;
    89118
    90119/** Array of data for virtual consoles */
    91120static console_t consoles[CONSOLE_COUNT];
    92121
     122/** Mutex for console switching */
     123static FIBRIL_MUTEX_INITIALIZE(switch_mtx);
     124
     125static console_t *prev_console = &consoles[0];
    93126static console_t *active_console = &consoles[0];
    94 static console_t *prev_console = &consoles[0];
    95127static console_t *kernel_console = &consoles[KERNEL_CONSOLE];
    96128
    97 /** Pointer to memory shared with framebufer used for
    98     faster virtual console switching */
    99 static keyfield_t *interbuffer = NULL;
    100 
    101 /** 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
    102160struct {
    103         sysarg_t col;  /**< Leftmost column of the span. */
    104         sysarg_t row;  /**< Row where the span lies. */
    105         sysarg_t cnt;  /**< Width of the span. */
    106 } fb_pending;
    107 
    108 static FIBRIL_MUTEX_INITIALIZE(input_mutex);
    109 static FIBRIL_CONDVAR_INITIALIZE(input_cv);
    110 
    111 static void curs_visibility(bool visible)
    112 {
    113         async_obsolete_msg_1(fb_info.phone, FB_CURSOR_VISIBILITY, visible);
    114 }
    115 
    116 static void curs_hide_sync(void)
    117 {
    118         async_obsolete_req_1_0(fb_info.phone, FB_CURSOR_VISIBILITY, false);
    119 }
    120 
    121 static void curs_goto(sysarg_t x, sysarg_t y)
    122 {
    123         async_obsolete_msg_2(fb_info.phone, FB_CURSOR_GOTO, x, y);
    124 }
    125 
    126 static void screen_clear(void)
    127 {
    128         async_obsolete_msg_0(fb_info.phone, FB_CLEAR);
    129 }
    130 
    131 static void screen_yield(void)
    132 {
    133         async_obsolete_req_0_0(fb_info.phone, FB_SCREEN_YIELD);
    134 }
    135 
    136 static void screen_reclaim(void)
    137 {
    138         async_obsolete_req_0_0(fb_info.phone, FB_SCREEN_RECLAIM);
    139 }
    140 
    141 static void input_yield(void)
    142 {
    143         async_obsolete_req_0_0(input_phone, INPUT_YIELD);
    144 }
    145 
    146 static void input_reclaim(void)
    147 {
    148         async_obsolete_req_0_0(input_phone, INPUT_RECLAIM);
    149 }
    150 
    151 static void set_style(uint8_t style)
    152 {
    153         async_obsolete_msg_1(fb_info.phone, FB_SET_STYLE, style);
    154 }
    155 
    156 static void set_color(uint8_t fgcolor, uint8_t bgcolor, uint8_t flags)
    157 {
    158         async_obsolete_msg_3(fb_info.phone, FB_SET_COLOR, fgcolor, bgcolor, flags);
    159 }
    160 
    161 static void set_rgb_color(uint32_t fgcolor, uint32_t bgcolor)
    162 {
    163         async_obsolete_msg_2(fb_info.phone, FB_SET_RGB_COLOR, fgcolor, bgcolor);
    164 }
    165 
    166 static void set_attrs(attrs_t *attrs)
    167 {
    168         switch (attrs->t) {
    169         case at_style:
    170                 set_style(attrs->a.s.style);
    171                 break;
    172         case at_idx:
    173                 set_color(attrs->a.i.fg_color, attrs->a.i.bg_color,
    174                     attrs->a.i.flags);
    175                 break;
    176         case at_rgb:
    177                 set_rgb_color(attrs->a.r.fg_color, attrs->a.r.bg_color);
    178                 break;
    179         }
    180 }
    181 
    182 static int ccap_fb_to_con(sysarg_t ccap_fb, sysarg_t *ccap_con)
    183 {
    184         switch (ccap_fb) {
    185         case FB_CCAP_NONE:
    186                 *ccap_con = CONSOLE_CCAP_NONE;
    187                 break;
    188         case FB_CCAP_STYLE:
    189                 *ccap_con = CONSOLE_CCAP_STYLE;
    190                 break;
    191         case FB_CCAP_INDEXED:
    192                 *ccap_con = CONSOLE_CCAP_INDEXED;
    193                 break;
    194         case FB_CCAP_RGB:
    195                 *ccap_con = CONSOLE_CCAP_RGB;
    196                 break;
    197         default:
    198                 return EINVAL;
    199         }
    200        
    201         return EOK;
    202 }
    203 
    204 /** Send an area of screenbuffer to the FB driver. */
    205 static void fb_update_area(console_t *cons, sysarg_t x0, sysarg_t y0, sysarg_t width, sysarg_t height)
    206 {
    207         if (interbuffer) {
    208                 sysarg_t x;
    209                 sysarg_t y;
    210                
    211                 for (y = 0; y < height; y++) {
    212                         for (x = 0; x < width; x++) {
    213                                 interbuffer[y * width + x] =
    214                                     *get_field_at(&cons->scr, x0 + x, y0 + y);
    215                         }
    216                 }
    217                
    218                 async_obsolete_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA,
    219                     x0, y0, width, height);
    220         }
    221 }
    222 
    223 /** Flush pending cells to FB. */
    224 static void fb_pending_flush(void)
    225 {
    226         if (fb_pending.cnt > 0) {
    227                 fb_update_area(active_console, fb_pending.col,
    228                     fb_pending.row, fb_pending.cnt, 1);
    229                 fb_pending.cnt = 0;
    230         }
    231 }
    232 
    233 /** Mark a character cell as changed.
     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);
     312                return;
     313        }
     314       
     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
    234394 *
    235  * This adds the cell to the pending rowspan if possible. Otherwise
    236  * the old span is flushed first.
     395 * @param state Button state (true - pressed, false - depressed)
    237396 *
    238397 */
    239 static void cell_mark_changed(sysarg_t col, sysarg_t row)
    240 {
    241         if (fb_pending.cnt != 0) {
    242                 if ((col != fb_pending.col + fb_pending.cnt)
    243                     || (row != fb_pending.row)) {
    244                         fb_pending_flush();
    245                 }
    246         }
    247        
    248         if (fb_pending.cnt == 0) {
    249                 fb_pending.col = col;
    250                 fb_pending.row = row;
    251         }
    252        
    253         fb_pending.cnt++;
    254 }
    255 
    256 /** Print a character to the active VC with buffering. */
    257 static void fb_putchar(wchar_t c, sysarg_t col, sysarg_t row)
    258 {
    259         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        }
    260491}
    261492
    262493/** Process a character from the client (TTY emulation). */
    263 static void write_char(console_t *cons, wchar_t ch)
    264 {
    265         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);
    266499       
    267500        switch (ch) {
    268501        case '\n':
    269                 fb_pending_flush();
    270                 flush_cursor = true;
    271                 cons->scr.position_y++;
    272                 cons->scr.position_x = 0;
     502                updated = screenbuffer_newline(cons->frontbuf);
    273503                break;
    274504        case '\r':
    275505                break;
    276506        case '\t':
    277                 cons->scr.position_x += 8;
    278                 cons->scr.position_x -= cons->scr.position_x % 8;
     507                updated = screenbuffer_tabstop(cons->frontbuf, 8);
    279508                break;
    280509        case '\b':
    281                 if (cons->scr.position_x == 0)
    282                         break;
    283                 cons->scr.position_x--;
    284                 if (cons == active_console)
    285                         cell_mark_changed(cons->scr.position_x, cons->scr.position_y);
    286                 screenbuffer_putchar(&cons->scr, ' ');
     510                updated = screenbuffer_backspace(cons->frontbuf);
    287511                break;
    288512        default:
    289                 if (cons == active_console)
    290                         cell_mark_changed(cons->scr.position_x, cons->scr.position_y);
    291                
    292                 screenbuffer_putchar(&cons->scr, ch);
    293                 cons->scr.position_x++;
    294         }
    295        
    296         if (cons->scr.position_x >= cons->scr.size_x) {
    297                 flush_cursor = true;
    298                 cons->scr.position_y++;
    299         }
    300        
    301         if (cons->scr.position_y >= cons->scr.size_y) {
    302                 fb_pending_flush();
    303                 cons->scr.position_y = cons->scr.size_y - 1;
    304                 screenbuffer_clear_line(&cons->scr, cons->scr.top_line);
    305                 cons->scr.top_line = (cons->scr.top_line + 1) % cons->scr.size_y;
    306                
    307                 if (cons == active_console)
    308                         async_obsolete_msg_1(fb_info.phone, FB_SCROLL, 1);
    309         }
    310        
    311         if (cons == active_console && flush_cursor)
    312                 curs_goto(cons->scr.position_x, cons->scr.position_y);
    313         cons->scr.position_x = cons->scr.position_x % cons->scr.size_x;
    314 }
    315 
    316 /** Switch to new console */
    317 static void change_console(console_t *cons)
    318 {
    319         if (cons == active_console)
    320                 return;
    321        
    322         fb_pending_flush();
    323        
    324         if (cons == kernel_console) {
    325                 async_obsolete_serialize_start();
    326                 curs_hide_sync();
    327                 gcons_in_kernel();
    328                 screen_yield();
    329                 input_yield();
    330                 async_obsolete_serialize_end();
    331                
    332                 if (__SYSCALL0(SYS_DEBUG_ENABLE_CONSOLE)) {
    333                         prev_console = active_console;
    334                         active_console = kernel_console;
    335                 } else
    336                         cons = active_console;
    337         }
    338        
    339         if (cons != kernel_console) {
    340                 async_obsolete_serialize_start();
    341                
    342                 if (active_console == kernel_console) {
    343                         screen_reclaim();
    344                         input_reclaim();
    345                         gcons_redraw_console();
    346                 }
    347                
    348                 active_console = cons;
    349                 gcons_change_console(cons->index);
    350                
    351                 set_attrs(&cons->scr.attrs);
    352                 curs_visibility(false);
    353                
    354                 sysarg_t x;
    355                 sysarg_t y;
    356                 int rc = 0;
    357                
    358                 if (interbuffer) {
    359                         for (y = 0; y < cons->scr.size_y; y++) {
    360                                 for (x = 0; x < cons->scr.size_x; x++) {
    361                                         interbuffer[y * cons->scr.size_x + x] =
    362                                             *get_field_at(&cons->scr, x, y);
    363                                 }
    364                         }
    365                        
    366                         /* This call can preempt, but we are already at the end */
    367                         rc = async_obsolete_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA,
    368                             0, 0, cons->scr.size_x,
    369                             cons->scr.size_y);
    370                 }
    371                
    372                 if ((!interbuffer) || (rc != 0)) {
    373                         set_attrs(&cons->scr.attrs);
    374                         screen_clear();
    375                        
    376                         for (y = 0; y < cons->scr.size_y; y++)
    377                                 for (x = 0; x < cons->scr.size_x; x++) {
    378                                         keyfield_t *field = get_field_at(&cons->scr, x, y);
    379                                        
    380                                         if (!attrs_same(cons->scr.attrs, field->attrs))
    381                                                 set_attrs(&field->attrs);
    382                                        
    383                                         cons->scr.attrs = field->attrs;
    384                                         if ((field->character == ' ') &&
    385                                             (attrs_same(field->attrs, cons->scr.attrs)))
    386                                                 continue;
    387                                        
    388                                         fb_putchar(field->character, x, y);
    389                                 }
    390                 }
    391                
    392                 curs_goto(cons->scr.position_x, cons->scr.position_y);
    393                 curs_visibility(cons->scr.is_cursor_visible);
    394                
    395                 async_obsolete_serialize_end();
    396         }
    397 }
    398 
    399 /** Handler for input events */
    400 static void input_events(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    401 {
    402         /* Ignore parameters, the connection is already opened */
    403         while (true) {
    404                 ipc_call_t call;
    405                 ipc_callid_t callid = async_get_call(&call);
    406                
    407                 int retval;
    408                 kbd_event_t ev;
    409                
    410                 if (!IPC_GET_IMETHOD(call)) {
    411                         /* TODO: Handle hangup */
    412                         async_obsolete_hangup(input_phone);
    413                         return;
    414                 }
    415                
    416                 switch (IPC_GET_IMETHOD(call)) {
    417                 case INPUT_EVENT_KEY:
    418                         /* Got key press/release event */
    419                         retval = 0;
    420                         ev.type = IPC_GET_ARG1(call);
    421                         ev.key = IPC_GET_ARG2(call);
    422                         ev.mods = IPC_GET_ARG3(call);
    423                         ev.c = IPC_GET_ARG4(call);
    424                        
    425                         if ((ev.key >= KC_F1) && (ev.key < KC_F1 +
    426                             CONSOLE_COUNT) && ((ev.mods & KM_CTRL) == 0)) {
    427                                 if (ev.key == KC_F1 + KERNEL_CONSOLE)
    428                                         change_console(kernel_console);
    429                                 else
    430                                         change_console(&consoles[ev.key - KC_F1]);
    431                                 break;
    432                         }
    433                        
    434                         fibril_mutex_lock(&input_mutex);
    435                         keybuffer_push(&active_console->keybuffer, &ev);
    436                         fibril_condvar_broadcast(&input_cv);
    437                         fibril_mutex_unlock(&input_mutex);
    438                         break;
    439                 case INPUT_EVENT_MOVE:
    440                         /* Got pointer move event */
    441                         gcons_mouse_move((int) IPC_GET_ARG1(call),
    442                             (int) IPC_GET_ARG2(call));
    443                         retval = 0;
    444                         break;
    445                 case INPUT_EVENT_BUTTON:
    446                         /* Got pointer button press/release event */
    447                         if (IPC_GET_ARG1(call) == 1) {
    448                                 int newcon = gcons_mouse_btn((bool) IPC_GET_ARG2(call));
    449                                 if (newcon != -1)
    450                                         change_console(&consoles[newcon]);
    451                         }
    452                         retval = 0;
    453                         break;
    454                 default:
    455                         retval = ENOENT;
    456                 }
    457                 async_answer_0(callid, retval);
    458         }
    459 }
    460 
    461 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)
    462553{
    463554        void *buf;
     
    466557       
    467558        if (rc != EOK) {
    468                 async_answer_0(rid, rc);
     559                async_answer_0(iid, rc);
    469560                return;
    470561        }
    471562       
    472         async_obsolete_serialize_start();
    473        
    474563        size_t off = 0;
    475         while (off < size) {
    476                 wchar_t ch = str_decode(buf, &off, size);
    477                 write_char(cons, ch);
    478         }
    479        
    480         async_obsolete_serialize_end();
    481        
    482         gcons_notify_char(cons->index);
    483         async_answer_1(rid, EOK, size);
    484        
     564        while (off < size)
     565                cons_write_char(cons, str_decode(buf, &off, size));
     566       
     567        async_answer_1(iid, EOK, size);
    485568        free(buf);
    486 }
    487 
    488 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)
    489574{
    490575        ipc_callid_t callid;
     
    492577        if (!async_data_read_receive(&callid, &size)) {
    493578                async_answer_0(callid, EINVAL);
    494                 async_answer_0(rid, EINVAL);
     579                async_answer_0(iid, EINVAL);
    495580                return;
    496581        }
     
    499584        if (buf == NULL) {
    500585                async_answer_0(callid, ENOMEM);
    501                 async_answer_0(rid, ENOMEM);
     586                async_answer_0(iid, ENOMEM);
    502587                return;
    503588        }
    504589       
    505590        size_t pos = 0;
    506         kbd_event_t ev;
    507         fibril_mutex_lock(&input_mutex);
    508        
    509 recheck:
    510         while ((keybuffer_pop(&cons->keybuffer, &ev)) && (pos < size)) {
    511                 if (ev.type == KEY_PRESS) {
    512                         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;
    513597                        pos++;
    514598                }
    515         }
    516        
    517         if (pos == size) {
    518                 (void) async_data_read_finalize(callid, buf, size);
    519                 async_answer_1(rid, EOK, size);
    520                 free(buf);
    521         } else {
    522                 fibril_condvar_wait(&input_cv, &input_mutex);
    523                 goto recheck;
    524         }
    525        
    526         fibril_mutex_unlock(&input_mutex);
    527 }
    528 
    529 static void cons_get_event(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
    530 {
    531         kbd_event_t ev;
    532        
    533         fibril_mutex_lock(&input_mutex);
    534        
    535 recheck:
    536         if (keybuffer_pop(&cons->keybuffer, &ev)) {
    537                 async_answer_4(rid, EOK, ev.type, ev.key, ev.mods, ev.c);
    538         } else {
    539                 fibril_condvar_wait(&input_cv, &input_mutex);
    540                 goto recheck;
    541         }
    542        
    543         fibril_mutex_unlock(&input_mutex);
    544 }
    545 
    546 /** 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
    547640static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    548641{
    549642        console_t *cons = NULL;
    550643       
    551         size_t i;
    552         for (i = 0; i < CONSOLE_COUNT; i++) {
     644        for (size_t i = 0; i < CONSOLE_COUNT; i++) {
    553645                if (i == KERNEL_CONSOLE)
    554646                        continue;
    555647               
    556                 if (consoles[i].devmap_handle == (devmap_handle_t) IPC_GET_ARG1(*icall)) {
     648                if (consoles[i].dsid == (service_id_t) IPC_GET_ARG1(*icall)) {
    557649                        cons = &consoles[i];
    558650                        break;
     
    565657        }
    566658       
    567         ipc_callid_t callid;
    568         ipc_call_t call;
    569         sysarg_t arg1;
    570         sysarg_t arg2;
    571         sysarg_t arg3;
    572        
    573         int rc;
    574        
    575         async_obsolete_serialize_start();
    576         if (cons->refcount == 0)
    577                 gcons_notify_connect(cons->index);
    578        
    579         cons->refcount++;
     659        if (atomic_postinc(&cons->refcnt) == 0) {
     660                cons_set_cursor_visibility(cons, true);
     661                cons_notify_connect(cons);
     662        }
    580663       
    581664        /* Accept the connection */
     
    583666       
    584667        while (true) {
    585                 async_obsolete_serialize_end();
    586                 callid = async_get_call(&call);
    587                 async_obsolete_serialize_start();
    588                
    589                 arg1 = 0;
    590                 arg2 = 0;
    591                 arg3 = 0;
     668                ipc_call_t call;
     669                ipc_callid_t callid = async_get_call(&call);
    592670               
    593671                if (!IPC_GET_IMETHOD(call)) {
    594                         cons->refcount--;
    595                         if (cons->refcount == 0)
    596                                 gcons_notify_disconnect(cons->index);
     672                        if (atomic_postdec(&cons->refcnt) == 1)
     673                                cons_notify_disconnect(cons);
     674                       
    597675                        return;
    598676                }
     
    600678                switch (IPC_GET_IMETHOD(call)) {
    601679                case VFS_OUT_READ:
    602                         async_obsolete_serialize_end();
    603680                        cons_read(cons, callid, &call);
    604                         async_obsolete_serialize_start();
     681                        break;
     682                case VFS_OUT_WRITE:
     683                        cons_write(cons, callid, &call);
     684                        break;
     685                case VFS_OUT_SYNC:
     686                        cons_update(cons);
     687                        async_answer_0(callid, EOK);
     688                        break;
     689                case CONSOLE_CLEAR:
     690                        cons_clear(cons);
     691                        async_answer_0(callid, EOK);
     692                        break;
     693                case CONSOLE_GOTO:
     694                        cons_set_cursor(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
     695                        async_answer_0(callid, EOK);
     696                        break;
     697                case CONSOLE_GET_POS:
     698                        cons_get_cursor(cons, callid, &call);
     699                        break;
     700                case CONSOLE_GET_SIZE:
     701                        async_answer_2(callid, EOK, cons->cols, cons->rows);
     702                        break;
     703                case CONSOLE_GET_COLOR_CAP:
     704                        async_answer_1(callid, EOK, cons->ccaps);
     705                        break;
     706                case CONSOLE_SET_STYLE:
     707                        cons_set_style(cons, IPC_GET_ARG1(call));
     708                        async_answer_0(callid, EOK);
     709                        break;
     710                case CONSOLE_SET_COLOR:
     711                        cons_set_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call),
     712                            IPC_GET_ARG3(call));
     713                        async_answer_0(callid, EOK);
     714                        break;
     715                case CONSOLE_SET_RGB_COLOR:
     716                        cons_set_rgb_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
     717                        async_answer_0(callid, EOK);
     718                        break;
     719                case CONSOLE_CURSOR_VISIBILITY:
     720                        cons_set_cursor_visibility(cons, IPC_GET_ARG1(call));
     721                        async_answer_0(callid, EOK);
     722                        break;
     723                case CONSOLE_GET_EVENT:
     724                        cons_get_event(cons, callid, &call);
     725                        break;
     726                default:
     727                        async_answer_0(callid, EINVAL);
     728                }
     729        }
     730}
     731
     732static async_sess_t *input_connect(const char *svc)
     733{
     734        async_sess_t *sess;
     735        service_id_t dsid;
     736       
     737        int rc = loc_service_get_id(svc, &dsid, 0);
     738        if (rc == EOK) {
     739                sess = loc_service_connect(EXCHANGE_ATOMIC, dsid, 0);
     740                if (sess == NULL) {
     741                        printf("%s: Unable to connect to input service %s\n", NAME,
     742                            svc);
     743                        return NULL;
     744                }
     745        } else
     746                return NULL;
     747       
     748        async_exch_t *exch = async_exchange_begin(sess);
     749        rc = async_connect_to_me(exch, 0, 0, 0, input_events, NULL);
     750        async_exchange_end(exch);
     751       
     752        if (rc != EOK) {
     753                async_hangup(sess);
     754                printf("%s: Unable to create callback connection to service %s (%s)\n",
     755                    NAME, svc, str_error(rc));
     756                return NULL;
     757        }
     758       
     759        return sess;
     760}
     761
     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);
     794        if (input_sess == NULL)
     795                return false;
     796       
     797        /* Connect to framebuffer service */
     798        fb_sess = fb_connect(fb_svc);
     799        if (fb_sess == NULL)
     800                return false;
     801       
     802        /* Register server */
     803        int rc = loc_server_register(NAME, client_connection);
     804        if (rc < 0) {
     805                printf("%s: Unable to register server (%s)\n", NAME,
     806                    str_error(rc));
     807                return false;
     808        }
     809       
     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;
     900       
     901        /* Inititalize consoles */
     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]);
    605919                        continue;
    606                 case VFS_OUT_WRITE:
    607                         async_obsolete_serialize_end();
    608                         cons_write(cons, callid, &call);
    609                         async_obsolete_serialize_start();
    610                         continue;
    611                 case VFS_OUT_SYNC:
    612                         fb_pending_flush();
    613                         if (cons == active_console) {
    614                                 async_obsolete_req_0_0(fb_info.phone, FB_FLUSH);
    615                                 curs_goto(cons->scr.position_x, cons->scr.position_y);
    616                         }
    617                         break;
    618                 case CONSOLE_CLEAR:
    619                         /* Send message to fb */
    620                         if (cons == active_console)
    621                                 async_obsolete_msg_0(fb_info.phone, FB_CLEAR);
    622                        
    623                         screenbuffer_clear(&cons->scr);
    624                        
    625                         break;
    626                 case CONSOLE_GOTO:
    627                         screenbuffer_goto(&cons->scr,
    628                             IPC_GET_ARG1(call), IPC_GET_ARG2(call));
    629                         if (cons == active_console)
    630                                 curs_goto(IPC_GET_ARG1(call),
    631                                     IPC_GET_ARG2(call));
    632                         break;
    633                 case CONSOLE_GET_POS:
    634                         arg1 = cons->scr.position_x;
    635                         arg2 = cons->scr.position_y;
    636                         break;
    637                 case CONSOLE_GET_SIZE:
    638                         arg1 = fb_info.cols;
    639                         arg2 = fb_info.rows;
    640                         break;
    641                 case CONSOLE_GET_COLOR_CAP:
    642                         rc = ccap_fb_to_con(fb_info.color_cap, &arg1);
    643                         if (rc != EOK) {
    644                                 async_answer_0(callid, rc);
    645                                 continue;
    646                         }
    647                         break;
    648                 case CONSOLE_SET_STYLE:
    649                         fb_pending_flush();
    650                         arg1 = IPC_GET_ARG1(call);
    651                         screenbuffer_set_style(&cons->scr, arg1);
    652                         if (cons == active_console)
    653                                 set_style(arg1);
    654                         break;
    655                 case CONSOLE_SET_COLOR:
    656                         fb_pending_flush();
    657                         arg1 = IPC_GET_ARG1(call);
    658                         arg2 = IPC_GET_ARG2(call);
    659                         arg3 = IPC_GET_ARG3(call);
    660                         screenbuffer_set_color(&cons->scr, arg1, arg2, arg3);
    661                         if (cons == active_console)
    662                                 set_color(arg1, arg2, arg3);
    663                         break;
    664                 case CONSOLE_SET_RGB_COLOR:
    665                         fb_pending_flush();
    666                         arg1 = IPC_GET_ARG1(call);
    667                         arg2 = IPC_GET_ARG2(call);
    668                         screenbuffer_set_rgb_color(&cons->scr, arg1, arg2);
    669                         if (cons == active_console)
    670                                 set_rgb_color(arg1, arg2);
    671                         break;
    672                 case CONSOLE_CURSOR_VISIBILITY:
    673                         fb_pending_flush();
    674                         arg1 = IPC_GET_ARG1(call);
    675                         cons->scr.is_cursor_visible = arg1;
    676                         if (cons == active_console)
    677                                 curs_visibility(arg1);
    678                         break;
    679                 case CONSOLE_GET_EVENT:
    680                         async_obsolete_serialize_end();
    681                         cons_get_event(cons, callid, &call);
    682                         async_obsolete_serialize_start();
    683                         continue;
    684                 case CONSOLE_KCON_ENABLE:
    685                         change_console(kernel_console);
    686                         break;
    687                 }
    688                 async_answer_3(callid, EOK, arg1, arg2, arg3);
    689         }
    690 }
    691 
    692 static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
    693 {
    694         change_console(prev_console);
    695 }
    696 
    697 static int connect_input(const char *dev_path)
    698 {
    699         int phone;
    700         devmap_handle_t handle;
    701        
    702         int rc = devmap_device_get_handle(dev_path, &handle, 0);
    703         if (rc == EOK) {
    704                 phone = devmap_obsolete_device_connect(handle, 0);
    705                 if (phone < 0) {
    706                         printf("%s: Failed to connect to input device\n", NAME);
    707                         return phone;
    708                 }
    709         } else {
    710                 return rc;
    711         }
    712        
    713         /* NB: The callback connection is slotted for removal */
    714         rc = async_obsolete_connect_to_me(phone, SERVICE_CONSOLE, 0, 0,
    715             input_events, NULL);
    716 
    717         if (rc != EOK) {
    718                 async_obsolete_hangup(phone);
    719                 printf("%s: Failed to create callback from input device (%s).\n",
    720                     NAME, str_error(rc));
    721                 return rc;
    722         }
    723        
    724         return phone;
    725 }
    726 
    727 static bool console_srv_init(char *input_dev)
    728 {
    729         /* Connect to input server */
    730         input_phone = connect_input(input_dev);
    731         if (input_phone < 0)
    732                 return false;
    733        
    734         /* Connect to framebuffer driver */
    735         fb_info.phone = service_obsolete_connect_blocking(SERVICE_VIDEO, 0, 0);
    736         if (fb_info.phone < 0) {
    737                 printf("%s: Failed to connect to video service\n", NAME);
    738                 return false;
    739         }
    740        
    741         /* Register driver */
    742         int rc = devmap_driver_register(NAME, client_connection);
    743         if (rc < 0) {
    744                 printf("%s: Unable to register driver (%d)\n", NAME, rc);
    745                 return false;
    746         }
    747        
    748         /* Initialize gcons */
    749         gcons_init(fb_info.phone);
    750        
    751         /* Synchronize, the gcons could put something in queue */
    752         async_obsolete_req_0_0(fb_info.phone, FB_FLUSH);
    753         async_obsolete_req_0_2(fb_info.phone, FB_GET_CSIZE, &fb_info.cols, &fb_info.rows);
    754         async_obsolete_req_0_1(fb_info.phone, FB_GET_COLOR_CAP, &fb_info.color_cap);
    755        
    756         /* Set up shared memory buffer. */
    757         size_t ib_size = sizeof(keyfield_t) * fb_info.cols * fb_info.rows;
    758         interbuffer = as_get_mappable_page(ib_size);
    759        
    760         if (as_area_create(interbuffer, ib_size, AS_AREA_READ |
    761             AS_AREA_WRITE | AS_AREA_CACHEABLE) != interbuffer)
    762                 interbuffer = NULL;
    763        
    764         if (interbuffer) {
    765                 if (async_obsolete_share_out_start(fb_info.phone, interbuffer,
    766                     AS_AREA_READ) != EOK) {
    767                         as_area_destroy(interbuffer);
    768                         interbuffer = NULL;
    769                 }
    770         }
    771        
    772         fb_pending.cnt = 0;
    773        
    774         /* Inititalize consoles */
    775         size_t i;
    776         for (i = 0; i < CONSOLE_COUNT; i++) {
    777                 if (i != KERNEL_CONSOLE) {
    778                         if (screenbuffer_init(&consoles[i].scr,
    779                             fb_info.cols, fb_info.rows) == NULL) {
    780                                 printf("%s: Unable to allocate screen buffer %zu\n", NAME, i);
    781                                 return false;
    782                         }
    783                         screenbuffer_clear(&consoles[i].scr);
    784                         keybuffer_init(&consoles[i].keybuffer);
    785                         consoles[i].index = i;
    786                         consoles[i].refcount = 0;
    787                        
    788                         char vc[DEVMAP_NAME_MAXLEN + 1];
    789                         snprintf(vc, DEVMAP_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i);
    790                        
    791                         if (devmap_device_register(vc, &consoles[i].devmap_handle) != EOK) {
    792                                 printf("%s: Unable to register device %s\n", NAME, vc);
    793                                 return false;
    794                         }
    795                 }
    796         }
    797        
    798         /* Disable kernel output to the console */
    799         __SYSCALL0(SYS_DEBUG_DISABLE_CONSOLE);
    800        
    801         /* Initialize the screen */
    802         async_obsolete_serialize_start();
    803         gcons_redraw_console();
    804         set_style(STYLE_NORMAL);
    805         screen_clear();
    806         curs_goto(0, 0);
    807         curs_visibility(active_console->scr.is_cursor_visible);
    808         async_obsolete_serialize_end();
     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        }
    809955       
    810956        /* Receive kernel notifications */
    811957        async_set_interrupt_received(interrupt_received);
    812         if (event_subscribe(EVENT_KCONSOLE, 0) != EOK)
    813                 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));
    814962       
    815963        return true;
     
    818966static void usage(void)
    819967{
    820         printf("Usage: console <input_dev>\n");
     968        printf("Usage: console <input_dev> <framebuffer_dev>\n");
    821969}
    822970
    823971int main(int argc, char *argv[])
    824972{
    825         if (argc < 2) {
     973        if (argc < 3) {
    826974                usage();
    827975                return -1;
    828976        }
    829977       
    830         printf(NAME ": HelenOS Console service\n");
    831        
    832         if (!console_srv_init(argv[1]))
     978        printf("%s: HelenOS Console service\n", NAME);
     979       
     980        if (!console_srv_init(argv[1], argv[2]))
    833981                return -1;
    834982       
    835         printf(NAME ": Accepting connections\n");
     983        printf("%s: Accepting connections\n", NAME);
     984        task_retval(0);
    836985        async_manager();
    837986       
Note: See TracChangeset for help on using the changeset viewer.