Ignore:
File:
1 edited

Legend:

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

    rffa2c8ef r024fcc5  
    11/*
    2  * Copyright (c) 2006 Josef Cejka
     2 * Copyright (c) 2011 Martin Decky
    33 * All rights reserved.
    44 *
     
    3333 */
    3434
    35 #include <libc.h>
    36 #include <ipc/kbd.h>
     35#include <async.h>
     36#include <stdio.h>
     37#include <adt/prodcons.h>
     38#include <ipc/input.h>
     39#include <ipc/console.h>
     40#include <ipc/vfs.h>
     41#include <errno.h>
     42#include <str_error.h>
     43#include <loc.h>
     44#include <event.h>
    3745#include <io/keycode.h>
    38 #include <ipc/mouse.h>
    39 #include <ipc/fb.h>
    40 #include <ipc/services.h>
    41 #include <ipc/ns.h>
    42 #include <errno.h>
    43 #include <ipc/console.h>
    44 #include <unistd.h>
    45 #include <async.h>
    46 #include <adt/fifo.h>
    47 #include <sys/mman.h>
    48 #include <stdio.h>
    49 #include <str.h>
    50 #include <sysinfo.h>
    51 #include <event.h>
    52 #include <devmap.h>
    53 #include <fcntl.h>
    54 #include <vfs/vfs.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>
    5552#include <fibril_synch.h>
    56 #include <io/style.h>
    57 #include <io/screenbuffer.h>
    58 
     53#include "images.h"
    5954#include "console.h"
    60 #include "gcons.h"
    61 #include "keybuffer.h"
    62 
    6355
    6456#define NAME       "console"
    6557#define NAMESPACE  "term"
    6658
    67 /** Phone to the keyboard driver. */
    68 static int kbd_phone;
    69 
    70 /** Phone to the mouse driver. */
    71 static int mouse_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_msg_1(fb_info.phone, FB_CURSOR_VISIBILITY, visible);
    114 }
    115 
    116 static void curs_hide_sync(void)
    117 {
    118         async_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_msg_2(fb_info.phone, FB_CURSOR_GOTO, x, y);
    124 }
    125 
    126 static void screen_clear(void)
    127 {
    128         async_msg_0(fb_info.phone, FB_CLEAR);
    129 }
    130 
    131 static void screen_yield(void)
    132 {
    133         async_req_0_0(fb_info.phone, FB_SCREEN_YIELD);
    134 }
    135 
    136 static void screen_reclaim(void)
    137 {
    138         async_req_0_0(fb_info.phone, FB_SCREEN_RECLAIM);
    139 }
    140 
    141 static void kbd_yield(void)
    142 {
    143         async_req_0_0(kbd_phone, KBD_YIELD);
    144 }
    145 
    146 static void kbd_reclaim(void)
    147 {
    148         async_req_0_0(kbd_phone, KBD_RECLAIM);
    149 }
    150 
    151 static void set_style(uint8_t style)
    152 {
    153         async_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_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_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_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 console_t *cons_get_active_uspace(void)
     347{
     348        fibril_mutex_lock(&switch_mtx);
     349
     350        console_t *active_uspace = active_console;
     351        if (active_uspace == kernel_console) {
     352                active_uspace = prev_console;
     353        }
     354        assert(active_uspace != kernel_console);
     355
     356        fibril_mutex_unlock(&switch_mtx);
     357
     358        return active_uspace;
     359}
     360
     361static ssize_t limit(ssize_t val, ssize_t lo, ssize_t hi)
     362{
     363        if (val > hi)
     364                return hi;
     365       
     366        if (val < lo)
     367                return lo;
     368       
     369        return val;
     370}
     371
     372static void cons_mouse_move(sysarg_t dx, sysarg_t dy)
     373{
     374        ssize_t sx = (ssize_t) dx;
     375        ssize_t sy = (ssize_t) dy;
     376       
     377        mouse.x = limit(mouse.x + sx, 0, xres);
     378        mouse.y = limit(mouse.y + sy, 0, yres);
     379       
     380        fb_pointer_update(fb_sess, mouse.x, mouse.y, true);
     381}
     382
     383static console_t *cons_find_icon(sysarg_t x, sysarg_t y)
     384{
     385        sysarg_t status_start =
     386            STATE_START + (xres - 800) / 2 + CONSOLE_MARGIN;
     387       
     388        if ((y < STATE_TOP) || (y >= STATE_TOP + STATE_HEIGHT))
     389                return NULL;
     390       
     391        if (x < status_start)
     392                return NULL;
     393       
     394        if (x >= status_start + (STATE_WIDTH + STATE_SPACE) * CONSOLE_COUNT)
     395                return NULL;
     396       
     397        if (((x - status_start) % (STATE_WIDTH + STATE_SPACE)) >= STATE_WIDTH)
     398                return NULL;
     399       
     400        sysarg_t btn = (x - status_start) / (STATE_WIDTH + STATE_SPACE);
     401       
     402        if (btn < CONSOLE_COUNT)
     403                return consoles + btn;
     404       
     405        return NULL;
     406}
     407
     408/** Handle mouse click
    234409 *
    235  * This adds the cell to the pending rowspan if possible. Otherwise
    236  * the old span is flushed first.
     410 * @param state Button state (true - pressed, false - depressed)
    237411 *
    238412 */
    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_msg_3(fb_info.phone, FB_PUTCHAR, c, col, row);
     413static console_t *cons_mouse_button(bool state)
     414{
     415        if (graphics_state != GRAPHICS_FULL)
     416                return NULL;
     417       
     418        if (state) {
     419                console_t *cons = cons_find_icon(mouse.x, mouse.y);
     420                if (cons != NULL) {
     421                        mouse.btn_x = mouse.x;
     422                        mouse.btn_y = mouse.y;
     423                        mouse.pressed = true;
     424                }
     425               
     426                return NULL;
     427        }
     428       
     429        if ((!state) && (!mouse.pressed))
     430                return NULL;
     431       
     432        console_t *cons = cons_find_icon(mouse.x, mouse.y);
     433        if (cons == cons_find_icon(mouse.btn_x, mouse.btn_y))
     434                return cons;
     435       
     436        mouse.pressed = false;
     437        return NULL;
     438}
     439
     440static void input_events(ipc_callid_t iid, ipc_call_t *icall, void *arg)
     441{
     442        /* Ignore parameters, the connection is already opened */
     443        while (true) {
     444                ipc_call_t call;
     445                ipc_callid_t callid = async_get_call(&call);
     446               
     447                if (!IPC_GET_IMETHOD(call)) {
     448                        /* TODO: Handle hangup */
     449                        async_hangup(input_sess);
     450                        return;
     451                }
     452               
     453                kbd_event_type_t type;
     454                keycode_t key;
     455                keymod_t mods;
     456                wchar_t c;
     457               
     458                switch (IPC_GET_IMETHOD(call)) {
     459                case INPUT_EVENT_KEY:
     460                        type = IPC_GET_ARG1(call);
     461                        key = IPC_GET_ARG2(call);
     462                        mods = IPC_GET_ARG3(call);
     463                        c = IPC_GET_ARG4(call);
     464                       
     465                        if ((key >= KC_F1) && (key < KC_F1 + CONSOLE_COUNT) &&
     466                            ((mods & KM_CTRL) == 0))
     467                                cons_switch(&consoles[key - KC_F1]);
     468                        else {
     469                                /* Got key press/release event */
     470                                kbd_event_t *event =
     471                                    (kbd_event_t *) malloc(sizeof(kbd_event_t));
     472                                if (event == NULL) {
     473                                        async_answer_0(callid, ENOMEM);
     474                                        break;
     475                                }
     476                               
     477                                link_initialize(&event->link);
     478                                event->type = type;
     479                                event->key = key;
     480                                event->mods = mods;
     481                                event->c = c;
     482                               
     483                                /* Kernel console does not read events
     484                                 * from us, so we will redirect them
     485                                 * to the (last) active userspace console
     486                                 * if necessary.
     487                                 */
     488                                console_t *target_console = cons_get_active_uspace();
     489
     490                                prodcons_produce(&target_console->input_pc,
     491                                    &event->link);
     492                        }
     493                       
     494                        async_answer_0(callid, EOK);
     495                        break;
     496                case INPUT_EVENT_MOVE:
     497                        cons_mouse_move(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
     498                        async_answer_0(callid, EOK);
     499                        break;
     500                case INPUT_EVENT_BUTTON:
     501                        /* Got pointer button press/release event */
     502                        if (IPC_GET_ARG1(call) == 1) {
     503                                console_t *cons =
     504                                    cons_mouse_button((bool) IPC_GET_ARG2(call));
     505                                if (cons != NULL)
     506                                        cons_switch(cons);
     507                        }
     508                        async_answer_0(callid, EOK);
     509                        break;
     510                default:
     511                        async_answer_0(callid, EINVAL);
     512                }
     513        }
    260514}
    261515
    262516/** 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;
     517static void cons_write_char(console_t *cons, wchar_t ch)
     518{
     519        sysarg_t updated = 0;
     520       
     521        fibril_mutex_lock(&cons->mtx);
    266522       
    267523        switch (ch) {
    268524        case '\n':
    269                 fb_pending_flush();
    270                 flush_cursor = true;
    271                 cons->scr.position_y++;
    272                 cons->scr.position_x = 0;
     525                updated = screenbuffer_newline(cons->frontbuf);
    273526                break;
    274527        case '\r':
    275528                break;
    276529        case '\t':
    277                 cons->scr.position_x += 8;
    278                 cons->scr.position_x -= cons->scr.position_x % 8;
     530                updated = screenbuffer_tabstop(cons->frontbuf, 8);
    279531                break;
    280532        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, ' ');
     533                updated = screenbuffer_backspace(cons->frontbuf);
    287534                break;
    288535        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_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_serialize_start();
    326                 curs_hide_sync();
    327                 gcons_in_kernel();
    328                 screen_yield();
    329                 kbd_yield();
    330                 async_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_serialize_start();
    341                
    342                 if (active_console == kernel_console) {
    343                         screen_reclaim();
    344                         kbd_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_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_serialize_end();
    396         }
    397 }
    398 
    399 /** Handler for keyboard */
    400 static void keyboard_events(ipc_callid_t iid, ipc_call_t *icall)
    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                 console_event_t ev;
    409                
    410                 switch (IPC_GET_IMETHOD(call)) {
    411                 case IPC_M_PHONE_HUNGUP:
    412                         /* TODO: Handle hangup */
    413                         return;
    414                 case KBD_EVENT:
    415                         /* Got event from keyboard driver. */
    416                         retval = 0;
    417                         ev.type = IPC_GET_ARG1(call);
    418                         ev.key = IPC_GET_ARG2(call);
    419                         ev.mods = IPC_GET_ARG3(call);
    420                         ev.c = IPC_GET_ARG4(call);
    421                        
    422                         if ((ev.key >= KC_F1) && (ev.key < KC_F1 +
    423                             CONSOLE_COUNT) && ((ev.mods & KM_CTRL) == 0)) {
    424                                 if (ev.key == KC_F1 + KERNEL_CONSOLE)
    425                                         change_console(kernel_console);
    426                                 else
    427                                         change_console(&consoles[ev.key - KC_F1]);
    428                                 break;
    429                         }
    430                        
    431                         fibril_mutex_lock(&input_mutex);
    432                         keybuffer_push(&active_console->keybuffer, &ev);
    433                         fibril_condvar_broadcast(&input_cv);
    434                         fibril_mutex_unlock(&input_mutex);
    435                         break;
    436                 default:
    437                         retval = ENOENT;
    438                 }
    439                 async_answer_0(callid, retval);
    440         }
    441 }
    442 
    443 /** Handler for mouse events */
    444 static void mouse_events(ipc_callid_t iid, ipc_call_t *icall)
    445 {
    446         /* Ignore parameters, the connection is already opened */
    447         while (true) {
    448                 ipc_call_t call;
    449                 ipc_callid_t callid = async_get_call(&call);
    450                
    451                 int retval;
    452                
    453                 switch (IPC_GET_IMETHOD(call)) {
    454                 case IPC_M_PHONE_HUNGUP:
    455                         /* TODO: Handle hangup */
    456                         return;
    457                 case MEVENT_BUTTON:
    458                         if (IPC_GET_ARG1(call) == 1) {
    459                                 int newcon = gcons_mouse_btn((bool) IPC_GET_ARG2(call));
    460                                 if (newcon != -1)
    461                                         change_console(&consoles[newcon]);
    462                         }
    463                         retval = 0;
    464                         break;
    465                 case MEVENT_MOVE:
    466                         gcons_mouse_move((int) IPC_GET_ARG1(call),
    467                             (int) IPC_GET_ARG2(call));
    468                         retval = 0;
    469                         break;
    470                 default:
    471                         retval = ENOENT;
    472                 }
    473 
    474                 async_answer_0(callid, retval);
    475         }
    476 }
    477 
    478 static void cons_write(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
     536                updated = screenbuffer_putchar(cons->frontbuf, ch, true);
     537        }
     538       
     539        fibril_mutex_unlock(&cons->mtx);
     540       
     541        if (updated > 1)
     542                cons_update(cons);
     543}
     544
     545static void cons_set_cursor(console_t *cons, sysarg_t col, sysarg_t row)
     546{
     547        fibril_mutex_lock(&cons->mtx);
     548        screenbuffer_set_cursor(cons->frontbuf, col, row);
     549        fibril_mutex_unlock(&cons->mtx);
     550       
     551        cons_update_cursor(cons);
     552}
     553
     554static void cons_set_cursor_visibility(console_t *cons, bool visible)
     555{
     556        fibril_mutex_lock(&cons->mtx);
     557        screenbuffer_set_cursor_visibility(cons->frontbuf, visible);
     558        fibril_mutex_unlock(&cons->mtx);
     559       
     560        cons_update_cursor(cons);
     561}
     562
     563static void cons_get_cursor(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
     564{
     565        sysarg_t col;
     566        sysarg_t row;
     567       
     568        fibril_mutex_lock(&cons->mtx);
     569        screenbuffer_get_cursor(cons->frontbuf, &col, &row);
     570        fibril_mutex_unlock(&cons->mtx);
     571       
     572        async_answer_2(iid, EOK, col, row);
     573}
     574
     575static void cons_write(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
    479576{
    480577        void *buf;
     
    483580       
    484581        if (rc != EOK) {
    485                 async_answer_0(rid, rc);
     582                async_answer_0(iid, rc);
    486583                return;
    487584        }
    488585       
    489         async_serialize_start();
    490        
    491586        size_t off = 0;
    492         while (off < size) {
    493                 wchar_t ch = str_decode(buf, &off, size);
    494                 write_char(cons, ch);
    495         }
    496        
    497         async_serialize_end();
    498        
    499         gcons_notify_char(cons->index);
    500         async_answer_1(rid, EOK, size);
    501        
     587        while (off < size)
     588                cons_write_char(cons, str_decode(buf, &off, size));
     589       
     590        async_answer_1(iid, EOK, size);
    502591        free(buf);
    503 }
    504 
    505 static void cons_read(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
     592       
     593        cons_notify_data(cons);
     594}
     595
     596static void cons_read(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
    506597{
    507598        ipc_callid_t callid;
     
    509600        if (!async_data_read_receive(&callid, &size)) {
    510601                async_answer_0(callid, EINVAL);
    511                 async_answer_0(rid, EINVAL);
     602                async_answer_0(iid, EINVAL);
    512603                return;
    513604        }
     
    516607        if (buf == NULL) {
    517608                async_answer_0(callid, ENOMEM);
    518                 async_answer_0(rid, ENOMEM);
     609                async_answer_0(iid, ENOMEM);
    519610                return;
    520611        }
    521612       
    522613        size_t pos = 0;
    523         console_event_t ev;
    524         fibril_mutex_lock(&input_mutex);
    525        
    526 recheck:
    527         while ((keybuffer_pop(&cons->keybuffer, &ev)) && (pos < size)) {
    528                 if (ev.type == KEY_PRESS) {
    529                         buf[pos] = ev.c;
     614        while (pos < size) {
     615                link_t *link = prodcons_consume(&cons->input_pc);
     616                kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
     617               
     618                if (event->type == KEY_PRESS) {
     619                        buf[pos] = event->c;
    530620                        pos++;
    531621                }
    532         }
    533        
    534         if (pos == size) {
    535                 (void) async_data_read_finalize(callid, buf, size);
    536                 async_answer_1(rid, EOK, size);
    537                 free(buf);
    538         } else {
    539                 fibril_condvar_wait(&input_cv, &input_mutex);
    540                 goto recheck;
    541         }
    542        
    543         fibril_mutex_unlock(&input_mutex);
    544 }
    545 
    546 static void cons_get_event(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
    547 {
    548         console_event_t ev;
    549        
    550         fibril_mutex_lock(&input_mutex);
    551        
    552 recheck:
    553         if (keybuffer_pop(&cons->keybuffer, &ev)) {
    554                 async_answer_4(rid, EOK, ev.type, ev.key, ev.mods, ev.c);
    555         } else {
    556                 fibril_condvar_wait(&input_cv, &input_mutex);
    557                 goto recheck;
    558         }
    559        
    560         fibril_mutex_unlock(&input_mutex);
    561 }
    562 
    563 /** Default thread for new connections */
    564 static void client_connection(ipc_callid_t iid, ipc_call_t *icall)
     622               
     623                free(event);
     624        }
     625       
     626        (void) async_data_read_finalize(callid, buf, size);
     627        async_answer_1(iid, EOK, size);
     628        free(buf);
     629}
     630
     631static void cons_set_style(console_t *cons, console_style_t style)
     632{
     633        fibril_mutex_lock(&cons->mtx);
     634        screenbuffer_set_style(cons->frontbuf, style);
     635        fibril_mutex_unlock(&cons->mtx);
     636}
     637
     638static void cons_set_color(console_t *cons, console_color_t bgcolor,
     639    console_color_t fgcolor, console_color_attr_t attr)
     640{
     641        fibril_mutex_lock(&cons->mtx);
     642        screenbuffer_set_color(cons->frontbuf, bgcolor, fgcolor, attr);
     643        fibril_mutex_unlock(&cons->mtx);
     644}
     645
     646static void cons_set_rgb_color(console_t *cons, pixel_t bgcolor,
     647    pixel_t fgcolor)
     648{
     649        fibril_mutex_lock(&cons->mtx);
     650        screenbuffer_set_rgb_color(cons->frontbuf, bgcolor, fgcolor);
     651        fibril_mutex_unlock(&cons->mtx);
     652}
     653
     654static void cons_get_event(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
     655{
     656        link_t *link = prodcons_consume(&cons->input_pc);
     657        kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
     658       
     659        async_answer_4(iid, EOK, event->type, event->key, event->mods, event->c);
     660        free(event);
     661}
     662
     663static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    565664{
    566665        console_t *cons = NULL;
    567666       
    568         size_t i;
    569         for (i = 0; i < CONSOLE_COUNT; i++) {
     667        for (size_t i = 0; i < CONSOLE_COUNT; i++) {
    570668                if (i == KERNEL_CONSOLE)
    571669                        continue;
    572670               
    573                 if (consoles[i].devmap_handle == (devmap_handle_t) IPC_GET_ARG1(*icall)) {
     671                if (consoles[i].dsid == (service_id_t) IPC_GET_ARG1(*icall)) {
    574672                        cons = &consoles[i];
    575673                        break;
     
    582680        }
    583681       
    584         ipc_callid_t callid;
    585         ipc_call_t call;
    586         sysarg_t arg1;
    587         sysarg_t arg2;
    588         sysarg_t arg3;
    589        
    590         int rc;
    591        
    592         async_serialize_start();
    593         if (cons->refcount == 0)
    594                 gcons_notify_connect(cons->index);
    595        
    596         cons->refcount++;
     682        if (atomic_postinc(&cons->refcnt) == 0) {
     683                cons_set_cursor_visibility(cons, true);
     684                cons_notify_connect(cons);
     685        }
    597686       
    598687        /* Accept the connection */
     
    600689       
    601690        while (true) {
    602                 async_serialize_end();
    603                 callid = async_get_call(&call);
    604                 async_serialize_start();
    605                
    606                 arg1 = 0;
    607                 arg2 = 0;
    608                 arg3 = 0;
     691                ipc_call_t call;
     692                ipc_callid_t callid = async_get_call(&call);
     693               
     694                if (!IPC_GET_IMETHOD(call)) {
     695                        if (atomic_postdec(&cons->refcnt) == 1)
     696                                cons_notify_disconnect(cons);
     697                       
     698                        return;
     699                }
    609700               
    610701                switch (IPC_GET_IMETHOD(call)) {
    611                 case IPC_M_PHONE_HUNGUP:
    612                         cons->refcount--;
    613                         if (cons->refcount == 0)
    614                                 gcons_notify_disconnect(cons->index);
    615                         return;
    616702                case VFS_OUT_READ:
    617                         async_serialize_end();
    618703                        cons_read(cons, callid, &call);
    619                         async_serialize_start();
     704                        break;
     705                case VFS_OUT_WRITE:
     706                        cons_write(cons, callid, &call);
     707                        break;
     708                case VFS_OUT_SYNC:
     709                        cons_update(cons);
     710                        async_answer_0(callid, EOK);
     711                        break;
     712                case CONSOLE_CLEAR:
     713                        cons_clear(cons);
     714                        async_answer_0(callid, EOK);
     715                        break;
     716                case CONSOLE_GOTO:
     717                        cons_set_cursor(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
     718                        async_answer_0(callid, EOK);
     719                        break;
     720                case CONSOLE_GET_POS:
     721                        cons_get_cursor(cons, callid, &call);
     722                        break;
     723                case CONSOLE_GET_SIZE:
     724                        async_answer_2(callid, EOK, cons->cols, cons->rows);
     725                        break;
     726                case CONSOLE_GET_COLOR_CAP:
     727                        async_answer_1(callid, EOK, cons->ccaps);
     728                        break;
     729                case CONSOLE_SET_STYLE:
     730                        cons_set_style(cons, IPC_GET_ARG1(call));
     731                        async_answer_0(callid, EOK);
     732                        break;
     733                case CONSOLE_SET_COLOR:
     734                        cons_set_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call),
     735                            IPC_GET_ARG3(call));
     736                        async_answer_0(callid, EOK);
     737                        break;
     738                case CONSOLE_SET_RGB_COLOR:
     739                        cons_set_rgb_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
     740                        async_answer_0(callid, EOK);
     741                        break;
     742                case CONSOLE_CURSOR_VISIBILITY:
     743                        cons_set_cursor_visibility(cons, IPC_GET_ARG1(call));
     744                        async_answer_0(callid, EOK);
     745                        break;
     746                case CONSOLE_GET_EVENT:
     747                        cons_get_event(cons, callid, &call);
     748                        break;
     749                default:
     750                        async_answer_0(callid, EINVAL);
     751                }
     752        }
     753}
     754
     755static async_sess_t *input_connect(const char *svc)
     756{
     757        async_sess_t *sess;
     758        service_id_t dsid;
     759       
     760        int rc = loc_service_get_id(svc, &dsid, 0);
     761        if (rc == EOK) {
     762                sess = loc_service_connect(EXCHANGE_ATOMIC, dsid, 0);
     763                if (sess == NULL) {
     764                        printf("%s: Unable to connect to input service %s\n", NAME,
     765                            svc);
     766                        return NULL;
     767                }
     768        } else
     769                return NULL;
     770       
     771        async_exch_t *exch = async_exchange_begin(sess);
     772        rc = async_connect_to_me(exch, 0, 0, 0, input_events, NULL);
     773        async_exchange_end(exch);
     774       
     775        if (rc != EOK) {
     776                async_hangup(sess);
     777                printf("%s: Unable to create callback connection to service %s (%s)\n",
     778                    NAME, svc, str_error(rc));
     779                return NULL;
     780        }
     781       
     782        return sess;
     783}
     784
     785static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
     786{
     787        cons_switch(prev_console);
     788}
     789
     790static async_sess_t *fb_connect(const char *svc)
     791{
     792        async_sess_t *sess;
     793        service_id_t dsid;
     794       
     795        int rc = loc_service_get_id(svc, &dsid, 0);
     796        if (rc == EOK) {
     797                sess = loc_service_connect(EXCHANGE_SERIALIZE, dsid, 0);
     798                if (sess == NULL) {
     799                        printf("%s: Unable to connect to framebuffer service %s\n",
     800                            NAME, svc);
     801                        return NULL;
     802                }
     803        } else
     804                return NULL;
     805       
     806        return sess;
     807}
     808
     809static bool console_srv_init(char *input_svc, char *fb_svc)
     810{
     811        /* Avoid double initialization */
     812        if (graphics_state != GRAPHICS_NONE)
     813                return false;
     814       
     815        /* Connect to input service */
     816        input_sess = input_connect(input_svc);
     817        if (input_sess == NULL)
     818                return false;
     819       
     820        /* Connect to framebuffer service */
     821        fb_sess = fb_connect(fb_svc);
     822        if (fb_sess == NULL)
     823                return false;
     824       
     825        /* Register server */
     826        int rc = loc_server_register(NAME, client_connection);
     827        if (rc < 0) {
     828                printf("%s: Unable to register server (%s)\n", NAME,
     829                    str_error(rc));
     830                return false;
     831        }
     832       
     833        fb_get_resolution(fb_sess, &xres, &yres);
     834       
     835        /* Initialize the screen */
     836        screen_vp = fb_vp_create(fb_sess, 0, 0, xres, yres);
     837       
     838        if ((xres >= 800) && (yres >= 600)) {
     839                logo_vp = fb_vp_create(fb_sess, xres - 66, 2, 64, 60);
     840                logo_img = imgmap_decode_tga((void *) helenos_tga,
     841                    helenos_tga_size, IMGMAP_FLAG_SHARED);
     842                logo_handle = fb_imagemap_create(fb_sess, logo_img);
     843               
     844                nameic_vp = fb_vp_create(fb_sess, 5, 17, 100, 26);
     845                nameic_img = imgmap_decode_tga((void *) nameic_tga,
     846                    nameic_tga_size, IMGMAP_FLAG_SHARED);
     847                nameic_handle = fb_imagemap_create(fb_sess, nameic_img);
     848               
     849                cons_data_img = imgmap_decode_tga((void *) cons_data_tga,
     850                    cons_data_tga_size, IMGMAP_FLAG_SHARED);
     851                cons_dis_img = imgmap_decode_tga((void *) cons_dis_tga,
     852                    cons_dis_tga_size, IMGMAP_FLAG_SHARED);
     853                cons_dis_sel_img = imgmap_decode_tga((void *) cons_dis_sel_tga,
     854                    cons_dis_sel_tga_size, IMGMAP_FLAG_SHARED);
     855                cons_idle_img = imgmap_decode_tga((void *) cons_idle_tga,
     856                    cons_idle_tga_size, IMGMAP_FLAG_SHARED);
     857                cons_kernel_img = imgmap_decode_tga((void *) cons_kernel_tga,
     858                    cons_kernel_tga_size, IMGMAP_FLAG_SHARED);
     859                cons_sel_img = imgmap_decode_tga((void *) cons_sel_tga,
     860                    cons_sel_tga_size, IMGMAP_FLAG_SHARED);
     861               
     862                state_icons[CONS_DISCONNECTED] =
     863                    fb_imagemap_create(fb_sess, cons_dis_img);
     864                state_icons[CONS_DISCONNECTED_SELECTED] =
     865                    fb_imagemap_create(fb_sess, cons_dis_sel_img);
     866                state_icons[CONS_SELECTED] =
     867                    fb_imagemap_create(fb_sess, cons_sel_img);
     868                state_icons[CONS_IDLE] =
     869                    fb_imagemap_create(fb_sess, cons_idle_img);
     870                state_icons[CONS_DATA] =
     871                    fb_imagemap_create(fb_sess, cons_data_img);
     872                state_icons[CONS_KERNEL] =
     873                    fb_imagemap_create(fb_sess, cons_kernel_img);
     874               
     875                anim_1_img = imgmap_decode_tga((void *) anim_1_tga,
     876                    anim_1_tga_size, IMGMAP_FLAG_SHARED);
     877                anim_2_img = imgmap_decode_tga((void *) anim_2_tga,
     878                    anim_2_tga_size, IMGMAP_FLAG_SHARED);
     879                anim_3_img = imgmap_decode_tga((void *) anim_3_tga,
     880                    anim_3_tga_size, IMGMAP_FLAG_SHARED);
     881                anim_4_img = imgmap_decode_tga((void *) anim_4_tga,
     882                    anim_4_tga_size, IMGMAP_FLAG_SHARED);
     883               
     884                anim_1 = fb_imagemap_create(fb_sess, anim_1_img);
     885                anim_2 = fb_imagemap_create(fb_sess, anim_2_img);
     886                anim_3 = fb_imagemap_create(fb_sess, anim_3_img);
     887                anim_4 = fb_imagemap_create(fb_sess, anim_4_img);
     888               
     889                anim_seq = fb_sequence_create(fb_sess);
     890                fb_sequence_add_imagemap(fb_sess, anim_seq, anim_1);
     891                fb_sequence_add_imagemap(fb_sess, anim_seq, anim_2);
     892                fb_sequence_add_imagemap(fb_sess, anim_seq, anim_3);
     893                fb_sequence_add_imagemap(fb_sess, anim_seq, anim_4);
     894               
     895                console_vp = fb_vp_create(fb_sess, CONSOLE_MARGIN, CONSOLE_TOP,
     896                    xres - 2 * CONSOLE_MARGIN, yres - (CONSOLE_TOP + CONSOLE_MARGIN));
     897               
     898                fb_vp_clear(fb_sess, screen_vp);
     899                fb_vp_imagemap_damage(fb_sess, logo_vp, logo_handle,
     900                    0, 0, 64, 60);
     901                fb_vp_imagemap_damage(fb_sess, nameic_vp, nameic_handle,
     902                    0, 0, 100, 26);
     903               
     904                graphics_state = GRAPHICS_FULL;
     905        } else {
     906                console_vp = screen_vp;
     907                graphics_state = GRAPHICS_BASIC;
     908        }
     909       
     910        fb_vp_set_style(fb_sess, console_vp, STYLE_NORMAL);
     911        fb_vp_clear(fb_sess, console_vp);
     912       
     913        sysarg_t cols;
     914        sysarg_t rows;
     915        fb_vp_get_dimensions(fb_sess, console_vp, &cols, &rows);
     916       
     917        console_caps_t ccaps;
     918        fb_vp_get_caps(fb_sess, console_vp, &ccaps);
     919       
     920        mouse.x = xres / 2;
     921        mouse.y = yres / 2;
     922        mouse.pressed = false;
     923       
     924        /* Inititalize consoles */
     925        for (size_t i = 0; i < CONSOLE_COUNT; i++) {
     926                consoles[i].index = i;
     927                atomic_set(&consoles[i].refcnt, 0);
     928                fibril_mutex_initialize(&consoles[i].mtx);
     929                prodcons_initialize(&consoles[i].input_pc);
     930               
     931                if (graphics_state == GRAPHICS_FULL) {
     932                        /* Create state buttons */
     933                        consoles[i].state_vp =
     934                            fb_vp_create(fb_sess, STATE_START + (xres - 800) / 2 +
     935                            CONSOLE_MARGIN + i * (STATE_WIDTH + STATE_SPACE),
     936                            STATE_TOP, STATE_WIDTH, STATE_HEIGHT);
     937                }
     938               
     939                if (i == KERNEL_CONSOLE) {
     940                        consoles[i].state = CONS_KERNEL;
     941                        cons_redraw_state(&consoles[i]);
     942                        cons_kernel_sequence_start(&consoles[i]);
    620943                        continue;
    621                 case VFS_OUT_WRITE:
    622                         async_serialize_end();
    623                         cons_write(cons, callid, &call);
    624                         async_serialize_start();
    625                         continue;
    626                 case VFS_OUT_SYNC:
    627                         fb_pending_flush();
    628                         if (cons == active_console) {
    629                                 async_req_0_0(fb_info.phone, FB_FLUSH);
    630                                 curs_goto(cons->scr.position_x, cons->scr.position_y);
    631                         }
    632                         break;
    633                 case CONSOLE_CLEAR:
    634                         /* Send message to fb */
    635                         if (cons == active_console)
    636                                 async_msg_0(fb_info.phone, FB_CLEAR);
    637                        
    638                         screenbuffer_clear(&cons->scr);
    639                        
    640                         break;
    641                 case CONSOLE_GOTO:
    642                         screenbuffer_goto(&cons->scr,
    643                             IPC_GET_ARG1(call), IPC_GET_ARG2(call));
    644                         if (cons == active_console)
    645                                 curs_goto(IPC_GET_ARG1(call),
    646                                     IPC_GET_ARG2(call));
    647                         break;
    648                 case CONSOLE_GET_POS:
    649                         arg1 = cons->scr.position_x;
    650                         arg2 = cons->scr.position_y;
    651                         break;
    652                 case CONSOLE_GET_SIZE:
    653                         arg1 = fb_info.cols;
    654                         arg2 = fb_info.rows;
    655                         break;
    656                 case CONSOLE_GET_COLOR_CAP:
    657                         rc = ccap_fb_to_con(fb_info.color_cap, &arg1);
    658                         if (rc != EOK) {
    659                                 async_answer_0(callid, rc);
    660                                 continue;
    661                         }
    662                         break;
    663                 case CONSOLE_SET_STYLE:
    664                         fb_pending_flush();
    665                         arg1 = IPC_GET_ARG1(call);
    666                         screenbuffer_set_style(&cons->scr, arg1);
    667                         if (cons == active_console)
    668                                 set_style(arg1);
    669                         break;
    670                 case CONSOLE_SET_COLOR:
    671                         fb_pending_flush();
    672                         arg1 = IPC_GET_ARG1(call);
    673                         arg2 = IPC_GET_ARG2(call);
    674                         arg3 = IPC_GET_ARG3(call);
    675                         screenbuffer_set_color(&cons->scr, arg1, arg2, arg3);
    676                         if (cons == active_console)
    677                                 set_color(arg1, arg2, arg3);
    678                         break;
    679                 case CONSOLE_SET_RGB_COLOR:
    680                         fb_pending_flush();
    681                         arg1 = IPC_GET_ARG1(call);
    682                         arg2 = IPC_GET_ARG2(call);
    683                         screenbuffer_set_rgb_color(&cons->scr, arg1, arg2);
    684                         if (cons == active_console)
    685                                 set_rgb_color(arg1, arg2);
    686                         break;
    687                 case CONSOLE_CURSOR_VISIBILITY:
    688                         fb_pending_flush();
    689                         arg1 = IPC_GET_ARG1(call);
    690                         cons->scr.is_cursor_visible = arg1;
    691                         if (cons == active_console)
    692                                 curs_visibility(arg1);
    693                         break;
    694                 case CONSOLE_GET_EVENT:
    695                         async_serialize_end();
    696                         cons_get_event(cons, callid, &call);
    697                         async_serialize_start();
    698                         continue;
    699                 case CONSOLE_KCON_ENABLE:
    700                         change_console(kernel_console);
    701                         break;
    702                 }
    703                 async_answer_3(callid, EOK, arg1, arg2, arg3);
    704         }
    705 }
    706 
    707 static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
    708 {
    709         change_console(prev_console);
    710 }
    711 
    712 static bool console_init(char *input)
    713 {
    714         /* Connect to input device */
    715         int input_fd = open(input, O_RDONLY);
    716         if (input_fd < 0) {
    717                 printf(NAME ": Failed opening %s\n", input);
    718                 return false;
    719         }
    720        
    721         kbd_phone = fd_phone(input_fd);
    722         if (kbd_phone < 0) {
    723                 printf(NAME ": Failed to connect to input device\n");
    724                 return false;
    725         }
    726        
    727         /* NB: The callback connection is slotted for removal */
    728         if (async_connect_to_me(kbd_phone, SERVICE_CONSOLE, 0, 0, keyboard_events)
    729             != 0) {
    730                 printf(NAME ": Failed to create callback from input device\n");
    731                 return false;
    732         }
    733        
    734         /* Connect to mouse device */
    735         mouse_phone = -1;
    736         int mouse_fd = open("/dev/hid_in/mouse", O_RDONLY);
    737        
    738         if (mouse_fd < 0) {
    739                 printf(NAME ": Notice - failed opening %s\n", "/dev/hid_in/mouse");
    740                 goto skip_mouse;
    741         }
    742        
    743         mouse_phone = fd_phone(mouse_fd);
    744         if (mouse_phone < 0) {
    745                 printf(NAME ": Failed to connect to mouse device\n");
    746                 goto skip_mouse;
    747         }
    748        
    749         if (async_connect_to_me(mouse_phone, SERVICE_CONSOLE, 0, 0, mouse_events)
    750             != 0) {
    751                 printf(NAME ": Failed to create callback from mouse device\n");
    752                 mouse_phone = -1;
    753                 goto skip_mouse;
    754         }
    755        
    756 skip_mouse:
    757        
    758         /* Connect to framebuffer driver */
    759         fb_info.phone = service_connect_blocking(SERVICE_VIDEO, 0, 0);
    760         if (fb_info.phone < 0) {
    761                 printf(NAME ": Failed to connect to video service\n");
    762                 return -1;
    763         }
    764        
    765         /* Register driver */
    766         int rc = devmap_driver_register(NAME, client_connection);
    767         if (rc < 0) {
    768                 printf(NAME ": Unable to register driver (%d)\n", rc);
    769                 return false;
    770         }
    771        
    772         /* Initialize gcons */
    773         gcons_init(fb_info.phone);
    774        
    775         /* Synchronize, the gcons could put something in queue */
    776         async_req_0_0(fb_info.phone, FB_FLUSH);
    777         async_req_0_2(fb_info.phone, FB_GET_CSIZE, &fb_info.cols, &fb_info.rows);
    778         async_req_0_1(fb_info.phone, FB_GET_COLOR_CAP, &fb_info.color_cap);
    779        
    780         /* Set up shared memory buffer. */
    781         size_t ib_size = sizeof(keyfield_t) * fb_info.cols * fb_info.rows;
    782         interbuffer = as_get_mappable_page(ib_size);
    783        
    784         if (as_area_create(interbuffer, ib_size, AS_AREA_READ |
    785             AS_AREA_WRITE | AS_AREA_CACHEABLE) != interbuffer)
    786                 interbuffer = NULL;
    787        
    788         if (interbuffer) {
    789                 if (async_share_out_start(fb_info.phone, interbuffer,
    790                     AS_AREA_READ) != EOK) {
    791                         as_area_destroy(interbuffer);
    792                         interbuffer = NULL;
    793                 }
    794         }
    795        
    796         fb_pending.cnt = 0;
    797        
    798         /* Inititalize consoles */
    799         size_t i;
    800         for (i = 0; i < CONSOLE_COUNT; i++) {
    801                 if (i != KERNEL_CONSOLE) {
    802                         if (screenbuffer_init(&consoles[i].scr,
    803                             fb_info.cols, fb_info.rows) == NULL) {
    804                                 printf(NAME ": Unable to allocate screen buffer %zu\n", i);
    805                                 return false;
    806                         }
    807                         screenbuffer_clear(&consoles[i].scr);
    808                         keybuffer_init(&consoles[i].keybuffer);
    809                         consoles[i].index = i;
    810                         consoles[i].refcount = 0;
    811                        
    812                         char vc[DEVMAP_NAME_MAXLEN + 1];
    813                         snprintf(vc, DEVMAP_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i);
    814                        
    815                         if (devmap_device_register(vc, &consoles[i].devmap_handle) != EOK) {
    816                                 printf(NAME ": Unable to register device %s\n", vc);
    817                                 return false;
    818                         }
    819                 }
    820         }
    821        
    822         /* Disable kernel output to the console */
    823         __SYSCALL0(SYS_DEBUG_DISABLE_CONSOLE);
    824        
    825         /* Initialize the screen */
    826         async_serialize_start();
    827         gcons_redraw_console();
    828         set_style(STYLE_NORMAL);
    829         screen_clear();
    830         curs_goto(0, 0);
    831         curs_visibility(active_console->scr.is_cursor_visible);
    832         async_serialize_end();
     944                }
     945               
     946                if (i == 0)
     947                        consoles[i].state = CONS_DISCONNECTED_SELECTED;
     948                else
     949                        consoles[i].state = CONS_DISCONNECTED;
     950               
     951                consoles[i].cols = cols;
     952                consoles[i].rows = rows;
     953                consoles[i].ccaps = ccaps;
     954                consoles[i].frontbuf =
     955                    screenbuffer_create(cols, rows, SCREENBUFFER_FLAG_SHARED);
     956               
     957                if (consoles[i].frontbuf == NULL) {
     958                        printf("%s: Unable to allocate frontbuffer %zu\n", NAME, i);
     959                        return false;
     960                }
     961               
     962                consoles[i].fbid = fb_frontbuf_create(fb_sess, consoles[i].frontbuf);
     963                if (consoles[i].fbid == 0) {
     964                        printf("%s: Unable to create frontbuffer %zu\n", NAME, i);
     965                        return false;
     966                }
     967               
     968                cons_redraw_state(&consoles[i]);
     969               
     970                char vc[LOC_NAME_MAXLEN + 1];
     971                snprintf(vc, LOC_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i);
     972               
     973                if (loc_service_register(vc, &consoles[i].dsid) != EOK) {
     974                        printf("%s: Unable to register device %s\n", NAME, vc);
     975                        return false;
     976                }
     977        }
    833978       
    834979        /* Receive kernel notifications */
    835980        async_set_interrupt_received(interrupt_received);
    836         if (event_subscribe(EVENT_KCONSOLE, 0) != EOK)
    837                 printf(NAME ": Error registering kconsole notifications\n");
     981        rc = event_subscribe(EVENT_KCONSOLE, 0);
     982        if (rc != EOK)
     983                printf("%s: Failed to register kconsole notifications (%s)\n",
     984                    NAME, str_error(rc));
    838985       
    839986        return true;
     
    842989static void usage(void)
    843990{
    844         printf("Usage: console <input>\n");
     991        printf("Usage: console <input_dev> <framebuffer_dev>\n");
    845992}
    846993
    847994int main(int argc, char *argv[])
    848995{
    849         if (argc < 2) {
     996        if (argc < 3) {
    850997                usage();
    851998                return -1;
    852999        }
    8531000       
    854         printf(NAME ": HelenOS Console service\n");
    855        
    856         if (!console_init(argv[1]))
     1001        printf("%s: HelenOS Console service\n", NAME);
     1002       
     1003        if (!console_srv_init(argv[1], argv[2]))
    8571004                return -1;
    8581005       
    859         printf(NAME ": Accepting connections\n");
     1006        printf("%s: Accepting connections\n", NAME);
     1007        task_retval(0);
    8601008        async_manager();
    8611009       
Note: See TracChangeset for help on using the changeset viewer.