Changeset 7c014d1 in mainline for uspace/srv/hid/console/console.c


Ignore:
Timestamp:
2011-09-09T15:46:21Z (13 years ago)
Author:
Martin Decky <martin@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
c69646f8
Parents:
14a60e3
Message:

console and framebuffer server rewrite

File:
1 edited

Legend:

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

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