Ignore:
File:
1 edited

Legend:

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

    rf302586 rb366a6f4  
    11/*
    2  * Copyright (c) 2011 Martin Decky
     2 * Copyright (c) 2006 Josef Cejka
     3 * Copyright (c) 2011 Jiri Svoboda
    34 * All rights reserved.
    45 *
     
    3334 */
    3435
    35 #include <async.h>
    36 #include <stdio.h>
    37 #include <adt/prodcons.h>
     36#include <libc.h>
    3837#include <ipc/input.h>
    39 #include <ipc/console.h>
    40 #include <ipc/vfs.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>
    4143#include <errno.h>
    4244#include <str_error.h>
    43 #include <loc.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>
    4454#include <event.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>
     55#include <devmap.h>
     56#include <fcntl.h>
     57#include <vfs/vfs.h>
    5258#include <fibril_synch.h>
    53 #include "images.h"
     59#include <io/style.h>
     60#include <io/screenbuffer.h>
     61
    5462#include "console.h"
     63#include "gcons.h"
     64#include "keybuffer.h"
    5565
    5666#define NAME       "console"
    5767#define NAMESPACE  "term"
    5868
    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 
    68 typedef 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;
     69/** Session with the input server. */
     70static async_sess_t *input_sess;
     71
     72/** Information about framebuffer */
     73struct {
     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;
    7779
    7880typedef 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 */
     81        size_t index;             /**< Console index */
     82        size_t refcount;          /**< Connection reference count */
     83        devmap_handle_t devmap_handle;  /**< Device handle */
     84        keybuffer_t keybuffer;    /**< Buffer for incoming keys. */
     85        screenbuffer_t scr;       /**< Screenbuffer for saving screen
     86                                       contents and related settings. */
    9587} console_t;
    96 
    97 typedef enum {
    98         GRAPHICS_NONE = 0,
    99         GRAPHICS_BASIC = 1,
    100         GRAPHICS_FULL = 2
    101 } graphics_state_t;
    102 
    103 /** Current console state */
    104 static graphics_state_t graphics_state = GRAPHICS_NONE;
    105 
    106 /** State icons */
    107 static imagemap_handle_t state_icons[CONS_LAST];
    108 
    109 /** Session to the input server */
    110 static async_sess_t *input_sess;
    111 
    112 /** Session to the framebuffer server */
    113 static async_sess_t *fb_sess;
    114 
    115 /** Framebuffer resolution */
    116 static sysarg_t xres;
    117 static sysarg_t yres;
    11888
    11989/** Array of data for virtual consoles */
    12090static console_t consoles[CONSOLE_COUNT];
    12191
    122 /** Mutex for console switching */
    123 static FIBRIL_MUTEX_INITIALIZE(switch_mtx);
    124 
     92static console_t *active_console = &consoles[0];
    12593static console_t *prev_console = &consoles[0];
    126 static console_t *active_console = &consoles[0];
    12794static console_t *kernel_console = &consoles[KERNEL_CONSOLE];
    12895
    129 static imgmap_t *logo_img;
    130 static imgmap_t *nameic_img;
    131 
    132 static imgmap_t *anim_1_img;
    133 static imgmap_t *anim_2_img;
    134 static imgmap_t *anim_3_img;
    135 static imgmap_t *anim_4_img;
    136 
    137 static imagemap_handle_t anim_1;
    138 static imagemap_handle_t anim_2;
    139 static imagemap_handle_t anim_3;
    140 static imagemap_handle_t anim_4;
    141 
    142 static sequence_handle_t anim_seq;
    143 
    144 static imgmap_t *cons_data_img;
    145 static imgmap_t *cons_dis_img;
    146 static imgmap_t *cons_dis_sel_img;
    147 static imgmap_t *cons_idle_img;
    148 static imgmap_t *cons_kernel_img;
    149 static imgmap_t *cons_sel_img;
    150 
    151 static vp_handle_t logo_vp;
    152 static imagemap_handle_t logo_handle;
    153 
    154 static vp_handle_t nameic_vp;
    155 static imagemap_handle_t nameic_handle;
    156 
    157 static vp_handle_t screen_vp;
    158 static vp_handle_t console_vp;
    159 
     96/** Pointer to memory shared with framebufer used for
     97    faster virtual console switching */
     98static keyfield_t *interbuffer = NULL;
     99
     100/** Information on row-span yet unsent to FB driver. */
    160101struct {
    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 
    170 static 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 
    192 static 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 
    205 static 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 
    222 static 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 
    232 static 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 
    244 static 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 
    256 static 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 
    270 static 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 
    282 static 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 
    291 static 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 
    306 static 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);
     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
     107static FIBRIL_MUTEX_INITIALIZE(input_mutex);
     108static FIBRIL_CONDVAR_INITIALIZE(input_cv);
     109
     110static FIBRIL_MUTEX_INITIALIZE(big_console_lock);
     111
     112static void console_serialize_start(void)
     113{
     114        fibril_mutex_lock(&big_console_lock);
     115}
     116
     117static void console_serialize_end(void)
     118{
     119        fibril_mutex_unlock(&big_console_lock);
     120}
     121
     122static void curs_visibility(bool visible)
     123{
     124        async_obsolete_msg_1(fb_info.phone, FB_CURSOR_VISIBILITY, visible);
     125}
     126
     127static void curs_hide_sync(void)
     128{
     129        async_obsolete_req_1_0(fb_info.phone, FB_CURSOR_VISIBILITY, false);
     130}
     131
     132static 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
     137static void screen_clear(void)
     138{
     139        async_obsolete_msg_0(fb_info.phone, FB_CLEAR);
     140}
     141
     142static void screen_yield(void)
     143{
     144        async_obsolete_req_0_0(fb_info.phone, FB_SCREEN_YIELD);
     145}
     146
     147static void screen_reclaim(void)
     148{
     149        async_obsolete_req_0_0(fb_info.phone, FB_SCREEN_RECLAIM);
     150}
     151
     152static 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);
    312158                return;
    313159        }
    314160       
    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 
    346 static 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 
    361 static 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 
    372 static 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 
    383 static 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
     161        async_req_0_0(exch, INPUT_YIELD);
     162        async_exchange_end(exch);
     163}
     164
     165static 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
     178static void set_style(uint8_t style)
     179{
     180        async_obsolete_msg_1(fb_info.phone, FB_SET_STYLE, style);
     181}
     182
     183static 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
     188static 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
     193static 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
     209static 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. */
     232static 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. */
     251static 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.
    409261 *
    410  * @param state Button state (true - pressed, false - depressed)
     262 * This adds the cell to the pending rowspan if possible. Otherwise
     263 * the old span is flushed first.
    411264 *
    412265 */
    413 static 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 
     266static 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. */
     284static 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);
     287}
     288
     289/** Process a character from the client (TTY emulation). */
     290static void write_char(console_t *cons, wchar_t ch)
     291{
     292        bool flush_cursor = false;
     293       
     294        switch (ch) {
     295        case '\n':
     296                fb_pending_flush();
     297                flush_cursor = true;
     298                cons->scr.position_y++;
     299                cons->scr.position_x = 0;
     300                break;
     301        case '\r':
     302                break;
     303        case '\t':
     304                cons->scr.position_x += 8;
     305                cons->scr.position_x -= cons->scr.position_x % 8;
     306                break;
     307        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, ' ');
     314                break;
     315        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 */
     344static 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 */
    440427static void input_events(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    441428{
     
    445432                ipc_callid_t callid = async_get_call(&call);
    446433               
     434                int retval;
     435                kbd_event_t ev;
     436               
    447437                if (!IPC_GET_IMETHOD(call)) {
    448438                        /* TODO: Handle hangup */
     
    451441                }
    452442               
    453                 kbd_event_type_t type;
    454                 keycode_t key;
    455                 keymod_t mods;
    456                 wchar_t c;
    457                
    458443                switch (IPC_GET_IMETHOD(call)) {
    459444                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);
     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);
    464451                       
    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                                 /*
    484                                  * Kernel console does not read events
    485                                  * from us, so we will redirect them
    486                                  * to the (last) active userspace console
    487                                  * if necessary.
    488                                  */
    489                                 console_t *target_console = cons_get_active_uspace();
    490                                
    491                                 prodcons_produce(&target_console->input_pc,
    492                                     &event->link);
     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;
    493459                        }
    494460                       
    495                         async_answer_0(callid, EOK);
     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);
    496465                        break;
    497466                case INPUT_EVENT_MOVE:
    498                         cons_mouse_move(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
    499                         async_answer_0(callid, EOK);
     467                        /* Got pointer move event */
     468                        gcons_mouse_move((int) IPC_GET_ARG1(call),
     469                            (int) IPC_GET_ARG2(call));
     470                        retval = 0;
    500471                        break;
    501472                case INPUT_EVENT_BUTTON:
    502473                        /* Got pointer button press/release event */
    503474                        if (IPC_GET_ARG1(call) == 1) {
    504                                 console_t *cons =
    505                                     cons_mouse_button((bool) IPC_GET_ARG2(call));
    506                                 if (cons != NULL)
    507                                         cons_switch(cons);
     475                                int newcon = gcons_mouse_btn((bool) IPC_GET_ARG2(call));
     476                                if (newcon != -1)
     477                                        change_console(&consoles[newcon]);
    508478                        }
    509                         async_answer_0(callid, EOK);
     479                        retval = 0;
    510480                        break;
    511481                default:
    512                         async_answer_0(callid, EINVAL);
    513                 }
    514         }
    515 }
    516 
    517 /** Process a character from the client (TTY emulation). */
    518 static void cons_write_char(console_t *cons, wchar_t ch)
    519 {
    520         sysarg_t updated = 0;
    521        
    522         fibril_mutex_lock(&cons->mtx);
    523        
    524         switch (ch) {
    525         case '\n':
    526                 updated = screenbuffer_newline(cons->frontbuf);
    527                 break;
    528         case '\r':
    529                 break;
    530         case '\t':
    531                 updated = screenbuffer_tabstop(cons->frontbuf, 8);
    532                 break;
    533         case '\b':
    534                 updated = screenbuffer_backspace(cons->frontbuf);
    535                 break;
    536         default:
    537                 updated = screenbuffer_putchar(cons->frontbuf, ch, true);
    538         }
    539        
    540         fibril_mutex_unlock(&cons->mtx);
    541        
    542         if (updated > 1)
    543                 cons_update(cons);
    544 }
    545 
    546 static void cons_set_cursor(console_t *cons, sysarg_t col, sysarg_t row)
    547 {
    548         fibril_mutex_lock(&cons->mtx);
    549         screenbuffer_set_cursor(cons->frontbuf, col, row);
    550         fibril_mutex_unlock(&cons->mtx);
    551        
    552         cons_update_cursor(cons);
    553 }
    554 
    555 static void cons_set_cursor_visibility(console_t *cons, bool visible)
    556 {
    557         fibril_mutex_lock(&cons->mtx);
    558         screenbuffer_set_cursor_visibility(cons->frontbuf, visible);
    559         fibril_mutex_unlock(&cons->mtx);
    560        
    561         cons_update_cursor(cons);
    562 }
    563 
    564 static void cons_get_cursor(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
    565 {
    566         sysarg_t col;
    567         sysarg_t row;
    568        
    569         fibril_mutex_lock(&cons->mtx);
    570         screenbuffer_get_cursor(cons->frontbuf, &col, &row);
    571         fibril_mutex_unlock(&cons->mtx);
    572        
    573         async_answer_2(iid, EOK, col, row);
    574 }
    575 
    576 static void cons_write(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
     482                        retval = ENOENT;
     483                }
     484
     485                async_answer_0(callid, retval);
     486        }
     487}
     488
     489static void cons_write(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
    577490{
    578491        void *buf;
     
    581494       
    582495        if (rc != EOK) {
    583                 async_answer_0(iid, rc);
     496                async_answer_0(rid, rc);
    584497                return;
    585498        }
    586499       
     500        console_serialize_start();
     501       
    587502        size_t off = 0;
    588         while (off < size)
    589                 cons_write_char(cons, str_decode(buf, &off, size));
    590        
    591         async_answer_1(iid, EOK, size);
     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       
    592513        free(buf);
    593        
    594         cons_notify_data(cons);
    595 }
    596 
    597 static void cons_read(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
     514}
     515
     516static void cons_read(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
    598517{
    599518        ipc_callid_t callid;
     
    601520        if (!async_data_read_receive(&callid, &size)) {
    602521                async_answer_0(callid, EINVAL);
    603                 async_answer_0(iid, EINVAL);
     522                async_answer_0(rid, EINVAL);
    604523                return;
    605524        }
     
    608527        if (buf == NULL) {
    609528                async_answer_0(callid, ENOMEM);
    610                 async_answer_0(iid, ENOMEM);
     529                async_answer_0(rid, ENOMEM);
    611530                return;
    612531        }
    613532       
    614533        size_t pos = 0;
    615         while (pos < size) {
    616                 link_t *link = prodcons_consume(&cons->input_pc);
    617                 kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
    618                
    619                 if (event->type == KEY_PRESS) {
    620                         buf[pos] = event->c;
     534        kbd_event_t ev;
     535        fibril_mutex_lock(&input_mutex);
     536       
     537recheck:
     538        while ((keybuffer_pop(&cons->keybuffer, &ev)) && (pos < size)) {
     539                if (ev.type == KEY_PRESS) {
     540                        buf[pos] = ev.c;
    621541                        pos++;
    622542                }
    623                
    624                 free(event);
    625         }
    626        
    627         (void) async_data_read_finalize(callid, buf, size);
    628         async_answer_1(iid, EOK, size);
    629         free(buf);
    630 }
    631 
    632 static void cons_set_style(console_t *cons, console_style_t style)
    633 {
    634         fibril_mutex_lock(&cons->mtx);
    635         screenbuffer_set_style(cons->frontbuf, style);
    636         fibril_mutex_unlock(&cons->mtx);
    637 }
    638 
    639 static void cons_set_color(console_t *cons, console_color_t bgcolor,
    640     console_color_t fgcolor, console_color_attr_t attr)
    641 {
    642         fibril_mutex_lock(&cons->mtx);
    643         screenbuffer_set_color(cons->frontbuf, bgcolor, fgcolor, attr);
    644         fibril_mutex_unlock(&cons->mtx);
    645 }
    646 
    647 static void cons_set_rgb_color(console_t *cons, pixel_t bgcolor,
    648     pixel_t fgcolor)
    649 {
    650         fibril_mutex_lock(&cons->mtx);
    651         screenbuffer_set_rgb_color(cons->frontbuf, bgcolor, fgcolor);
    652         fibril_mutex_unlock(&cons->mtx);
    653 }
    654 
    655 static void cons_get_event(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
    656 {
    657         link_t *link = prodcons_consume(&cons->input_pc);
    658         kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
    659        
    660         async_answer_4(iid, EOK, event->type, event->key, event->mods, event->c);
    661         free(event);
    662 }
    663 
     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
     557static 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       
     563recheck:
     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 */
    664575static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    665576{
    666577        console_t *cons = NULL;
    667578       
    668         for (size_t i = 0; i < CONSOLE_COUNT; i++) {
     579        size_t i;
     580        for (i = 0; i < CONSOLE_COUNT; i++) {
    669581                if (i == KERNEL_CONSOLE)
    670582                        continue;
    671583               
    672                 if (consoles[i].dsid == (service_id_t) IPC_GET_ARG1(*icall)) {
     584                if (consoles[i].devmap_handle == (devmap_handle_t) IPC_GET_ARG1(*icall)) {
    673585                        cons = &consoles[i];
    674586                        break;
     
    681593        }
    682594       
    683         if (atomic_postinc(&cons->refcnt) == 0) {
    684                 cons_set_cursor_visibility(cons, true);
    685                 cons_notify_connect(cons);
    686         }
     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++;
    687608       
    688609        /* Accept the connection */
     
    690611       
    691612        while (true) {
    692                 ipc_call_t call;
    693                 ipc_callid_t callid = async_get_call(&call);
     613                console_serialize_end();
     614                callid = async_get_call(&call);
     615                console_serialize_start();
     616               
     617                arg1 = 0;
     618                arg2 = 0;
     619                arg3 = 0;
    694620               
    695621                if (!IPC_GET_IMETHOD(call)) {
    696                         if (atomic_postdec(&cons->refcnt) == 1)
    697                                 cons_notify_disconnect(cons);
    698                        
     622                        cons->refcount--;
     623                        if (cons->refcount == 0)
     624                                gcons_notify_disconnect(cons->index);
     625                        console_serialize_end();
    699626                        return;
    700627                }
     
    702629                switch (IPC_GET_IMETHOD(call)) {
    703630                case VFS_OUT_READ:
     631                        console_serialize_end();
    704632                        cons_read(cons, callid, &call);
    705                         break;
     633                        console_serialize_start();
     634                        continue;
    706635                case VFS_OUT_WRITE:
     636                        console_serialize_end();
    707637                        cons_write(cons, callid, &call);
    708                         break;
     638                        console_serialize_start();
     639                        continue;
    709640                case VFS_OUT_SYNC:
    710                         cons_update(cons);
    711                         async_answer_0(callid, EOK);
     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                        }
    712646                        break;
    713647                case CONSOLE_CLEAR:
    714                         cons_clear(cons);
    715                         async_answer_0(callid, EOK);
     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                       
    716654                        break;
    717655                case CONSOLE_GOTO:
    718                         cons_set_cursor(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
    719                         async_answer_0(callid, EOK);
     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));
    720661                        break;
    721662                case CONSOLE_GET_POS:
    722                         cons_get_cursor(cons, callid, &call);
     663                        arg1 = cons->scr.position_x;
     664                        arg2 = cons->scr.position_y;
    723665                        break;
    724666                case CONSOLE_GET_SIZE:
    725                         async_answer_2(callid, EOK, cons->cols, cons->rows);
     667                        arg1 = fb_info.cols;
     668                        arg2 = fb_info.rows;
    726669                        break;
    727670                case CONSOLE_GET_COLOR_CAP:
    728                         async_answer_1(callid, EOK, cons->ccaps);
     671                        rc = ccap_fb_to_con(fb_info.color_cap, &arg1);
     672                        if (rc != EOK) {
     673                                async_answer_0(callid, rc);
     674                                continue;
     675                        }
    729676                        break;
    730677                case CONSOLE_SET_STYLE:
    731                         cons_set_style(cons, IPC_GET_ARG1(call));
    732                         async_answer_0(callid, EOK);
     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);
    733683                        break;
    734684                case CONSOLE_SET_COLOR:
    735                         cons_set_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call),
    736                             IPC_GET_ARG3(call));
    737                         async_answer_0(callid, EOK);
     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);
    738692                        break;
    739693                case CONSOLE_SET_RGB_COLOR:
    740                         cons_set_rgb_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
    741                         async_answer_0(callid, EOK);
     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);
    742700                        break;
    743701                case CONSOLE_CURSOR_VISIBILITY:
    744                         cons_set_cursor_visibility(cons, IPC_GET_ARG1(call));
    745                         async_answer_0(callid, EOK);
     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);
    746707                        break;
    747708                case CONSOLE_GET_EVENT:
     709                        console_serialize_end();
    748710                        cons_get_event(cons, callid, &call);
    749                         break;
    750                 default:
    751                         async_answer_0(callid, EINVAL);
    752                 }
    753         }
    754 }
    755 
    756 static async_sess_t *input_connect(const char *svc)
     711                        console_serialize_start();
     712                        continue;
     713                }
     714                async_answer_3(callid, EOK, arg1, arg2, arg3);
     715        }
     716}
     717
     718static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
     719{
     720        change_console(prev_console);
     721}
     722
     723static async_sess_t *connect_input(const char *dev_path)
    757724{
    758725        async_sess_t *sess;
    759         service_id_t dsid;
    760        
    761         int rc = loc_service_get_id(svc, &dsid, 0);
     726        async_exch_t *exch;
     727        devmap_handle_t handle;
     728       
     729        int rc = devmap_device_get_handle(dev_path, &handle, 0);
    762730        if (rc == EOK) {
    763                 sess = loc_service_connect(EXCHANGE_ATOMIC, dsid, 0);
     731                sess = devmap_device_connect(EXCHANGE_ATOMIC, handle, 0);
    764732                if (sess == NULL) {
    765                         printf("%s: Unable to connect to input service %s\n", NAME,
    766                             svc);
     733                        printf("%s: Failed to connect to input server\n", NAME);
    767734                        return NULL;
    768735                }
    769         } else
     736        } else {
    770737                return NULL;
    771        
    772         async_exch_t *exch = async_exchange_begin(sess);
     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 */
    773747        rc = async_connect_to_me(exch, 0, 0, 0, input_events, NULL);
     748
    774749        async_exchange_end(exch);
    775        
     750
    776751        if (rc != EOK) {
    777752                async_hangup(sess);
    778                 printf("%s: Unable to create callback connection to service %s (%s)\n",
    779                     NAME, svc, str_error(rc));
     753                printf("%s: Failed to create callback from input server (%s).\n",
     754                    NAME, str_error(rc));
    780755                return NULL;
    781756        }
     
    784759}
    785760
    786 static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
    787 {
    788         cons_switch(prev_console);
    789 }
    790 
    791 static async_sess_t *fb_connect(const char *svc)
    792 {
    793         async_sess_t *sess;
    794         service_id_t dsid;
    795        
    796         int rc = loc_service_get_id(svc, &dsid, 0);
    797         if (rc == EOK) {
    798                 sess = loc_service_connect(EXCHANGE_SERIALIZE, dsid, 0);
    799                 if (sess == NULL) {
    800                         printf("%s: Unable to connect to framebuffer service %s\n",
    801                             NAME, svc);
    802                         return NULL;
    803                 }
    804         } else
    805                 return NULL;
    806        
    807         return sess;
    808 }
    809 
    810 static bool console_srv_init(char *input_svc, char *fb_svc)
    811 {
    812         /* Avoid double initialization */
    813         if (graphics_state != GRAPHICS_NONE)
    814                 return false;
    815        
    816         /* Connect to input service */
    817         input_sess = input_connect(input_svc);
     761static bool console_srv_init(char *input_dev)
     762{
     763        /* Connect to input server */
     764        input_sess = connect_input(input_dev);
    818765        if (input_sess == NULL)
    819766                return false;
    820767       
    821         /* Connect to framebuffer service */
    822         fb_sess = fb_connect(fb_svc);
    823         if (fb_sess == NULL)
     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);
    824772                return false;
    825        
    826         /* Register server */
    827         async_set_client_connection(client_connection);
    828         int rc = loc_server_register(NAME);
     773        }
     774       
     775        /* Register driver */
     776        int rc = devmap_driver_register(NAME, client_connection);
    829777        if (rc < 0) {
    830                 printf("%s: Unable to register server (%s)\n", NAME,
    831                     str_error(rc));
     778                printf("%s: Unable to register driver (%d)\n", NAME, rc);
    832779                return false;
    833780        }
    834781       
    835         fb_get_resolution(fb_sess, &xres, &yres);
     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;
     807       
     808        /* Inititalize consoles */
     809        size_t i;
     810        for (i = 0; i < CONSOLE_COUNT; i++) {
     811                if (i != KERNEL_CONSOLE) {
     812                        if (screenbuffer_init(&consoles[i].scr,
     813                            fb_info.cols, fb_info.rows) == NULL) {
     814                                printf("%s: Unable to allocate screen buffer %zu\n", NAME, i);
     815                                return false;
     816                        }
     817                        screenbuffer_clear(&consoles[i].scr);
     818                        keybuffer_init(&consoles[i].keybuffer);
     819                        consoles[i].index = i;
     820                        consoles[i].refcount = 0;
     821                       
     822                        char vc[DEVMAP_NAME_MAXLEN + 1];
     823                        snprintf(vc, DEVMAP_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i);
     824                       
     825                        if (devmap_device_register(vc, &consoles[i].devmap_handle) != EOK) {
     826                                printf("%s: Unable to register device %s\n", NAME, vc);
     827                                return false;
     828                        }
     829                }
     830        }
    836831       
    837832        /* Initialize the screen */
    838         screen_vp = fb_vp_create(fb_sess, 0, 0, xres, yres);
    839        
    840         if ((xres >= 800) && (yres >= 600)) {
    841                 logo_vp = fb_vp_create(fb_sess, xres - 66, 2, 64, 60);
    842                 logo_img = imgmap_decode_tga((void *) helenos_tga,
    843                     helenos_tga_size, IMGMAP_FLAG_SHARED);
    844                 logo_handle = fb_imagemap_create(fb_sess, logo_img);
    845                
    846                 nameic_vp = fb_vp_create(fb_sess, 5, 17, 100, 26);
    847                 nameic_img = imgmap_decode_tga((void *) nameic_tga,
    848                     nameic_tga_size, IMGMAP_FLAG_SHARED);
    849                 nameic_handle = fb_imagemap_create(fb_sess, nameic_img);
    850                
    851                 cons_data_img = imgmap_decode_tga((void *) cons_data_tga,
    852                     cons_data_tga_size, IMGMAP_FLAG_SHARED);
    853                 cons_dis_img = imgmap_decode_tga((void *) cons_dis_tga,
    854                     cons_dis_tga_size, IMGMAP_FLAG_SHARED);
    855                 cons_dis_sel_img = imgmap_decode_tga((void *) cons_dis_sel_tga,
    856                     cons_dis_sel_tga_size, IMGMAP_FLAG_SHARED);
    857                 cons_idle_img = imgmap_decode_tga((void *) cons_idle_tga,
    858                     cons_idle_tga_size, IMGMAP_FLAG_SHARED);
    859                 cons_kernel_img = imgmap_decode_tga((void *) cons_kernel_tga,
    860                     cons_kernel_tga_size, IMGMAP_FLAG_SHARED);
    861                 cons_sel_img = imgmap_decode_tga((void *) cons_sel_tga,
    862                     cons_sel_tga_size, IMGMAP_FLAG_SHARED);
    863                
    864                 state_icons[CONS_DISCONNECTED] =
    865                     fb_imagemap_create(fb_sess, cons_dis_img);
    866                 state_icons[CONS_DISCONNECTED_SELECTED] =
    867                     fb_imagemap_create(fb_sess, cons_dis_sel_img);
    868                 state_icons[CONS_SELECTED] =
    869                     fb_imagemap_create(fb_sess, cons_sel_img);
    870                 state_icons[CONS_IDLE] =
    871                     fb_imagemap_create(fb_sess, cons_idle_img);
    872                 state_icons[CONS_DATA] =
    873                     fb_imagemap_create(fb_sess, cons_data_img);
    874                 state_icons[CONS_KERNEL] =
    875                     fb_imagemap_create(fb_sess, cons_kernel_img);
    876                
    877                 anim_1_img = imgmap_decode_tga((void *) anim_1_tga,
    878                     anim_1_tga_size, IMGMAP_FLAG_SHARED);
    879                 anim_2_img = imgmap_decode_tga((void *) anim_2_tga,
    880                     anim_2_tga_size, IMGMAP_FLAG_SHARED);
    881                 anim_3_img = imgmap_decode_tga((void *) anim_3_tga,
    882                     anim_3_tga_size, IMGMAP_FLAG_SHARED);
    883                 anim_4_img = imgmap_decode_tga((void *) anim_4_tga,
    884                     anim_4_tga_size, IMGMAP_FLAG_SHARED);
    885                
    886                 anim_1 = fb_imagemap_create(fb_sess, anim_1_img);
    887                 anim_2 = fb_imagemap_create(fb_sess, anim_2_img);
    888                 anim_3 = fb_imagemap_create(fb_sess, anim_3_img);
    889                 anim_4 = fb_imagemap_create(fb_sess, anim_4_img);
    890                
    891                 anim_seq = fb_sequence_create(fb_sess);
    892                 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_1);
    893                 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_2);
    894                 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_3);
    895                 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_4);
    896                
    897                 console_vp = fb_vp_create(fb_sess, CONSOLE_MARGIN, CONSOLE_TOP,
    898                     xres - 2 * CONSOLE_MARGIN, yres - (CONSOLE_TOP + CONSOLE_MARGIN));
    899                
    900                 fb_vp_clear(fb_sess, screen_vp);
    901                 fb_vp_imagemap_damage(fb_sess, logo_vp, logo_handle,
    902                     0, 0, 64, 60);
    903                 fb_vp_imagemap_damage(fb_sess, nameic_vp, nameic_handle,
    904                     0, 0, 100, 26);
    905                
    906                 graphics_state = GRAPHICS_FULL;
    907         } else {
    908                 console_vp = screen_vp;
    909                 graphics_state = GRAPHICS_BASIC;
    910         }
    911        
    912         fb_vp_set_style(fb_sess, console_vp, STYLE_NORMAL);
    913         fb_vp_clear(fb_sess, console_vp);
    914        
    915         sysarg_t cols;
    916         sysarg_t rows;
    917         fb_vp_get_dimensions(fb_sess, console_vp, &cols, &rows);
    918        
    919         console_caps_t ccaps;
    920         fb_vp_get_caps(fb_sess, console_vp, &ccaps);
    921        
    922         mouse.x = xres / 2;
    923         mouse.y = yres / 2;
    924         mouse.pressed = false;
    925        
    926         /* Inititalize consoles */
    927         for (size_t i = 0; i < CONSOLE_COUNT; i++) {
    928                 consoles[i].index = i;
    929                 atomic_set(&consoles[i].refcnt, 0);
    930                 fibril_mutex_initialize(&consoles[i].mtx);
    931                 prodcons_initialize(&consoles[i].input_pc);
    932                
    933                 if (graphics_state == GRAPHICS_FULL) {
    934                         /* Create state buttons */
    935                         consoles[i].state_vp =
    936                             fb_vp_create(fb_sess, STATE_START + (xres - 800) / 2 +
    937                             CONSOLE_MARGIN + i * (STATE_WIDTH + STATE_SPACE),
    938                             STATE_TOP, STATE_WIDTH, STATE_HEIGHT);
    939                 }
    940                
    941                 if (i == KERNEL_CONSOLE) {
    942                         consoles[i].state = CONS_KERNEL;
    943                         cons_redraw_state(&consoles[i]);
    944                         cons_kernel_sequence_start(&consoles[i]);
    945                         continue;
    946                 }
    947                
    948                 if (i == 0)
    949                         consoles[i].state = CONS_DISCONNECTED_SELECTED;
    950                 else
    951                         consoles[i].state = CONS_DISCONNECTED;
    952                
    953                 consoles[i].cols = cols;
    954                 consoles[i].rows = rows;
    955                 consoles[i].ccaps = ccaps;
    956                 consoles[i].frontbuf =
    957                     screenbuffer_create(cols, rows, SCREENBUFFER_FLAG_SHARED);
    958                
    959                 if (consoles[i].frontbuf == NULL) {
    960                         printf("%s: Unable to allocate frontbuffer %zu\n", NAME, i);
    961                         return false;
    962                 }
    963                
    964                 consoles[i].fbid = fb_frontbuf_create(fb_sess, consoles[i].frontbuf);
    965                 if (consoles[i].fbid == 0) {
    966                         printf("%s: Unable to create frontbuffer %zu\n", NAME, i);
    967                         return false;
    968                 }
    969                
    970                 cons_redraw_state(&consoles[i]);
    971                
    972                 char vc[LOC_NAME_MAXLEN + 1];
    973                 snprintf(vc, LOC_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i);
    974                
    975                 if (loc_service_register(vc, &consoles[i].dsid) != EOK) {
    976                         printf("%s: Unable to register device %s\n", NAME, vc);
    977                         return false;
    978                 }
    979         }
     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();
    980840       
    981841        /* Receive kernel notifications */
    982842        async_set_interrupt_received(interrupt_received);
    983         rc = event_subscribe(EVENT_KCONSOLE, 0);
    984         if (rc != EOK)
    985                 printf("%s: Failed to register kconsole notifications (%s)\n",
    986                     NAME, str_error(rc));
     843        if (event_subscribe(EVENT_KCONSOLE, 0) != EOK)
     844                printf("%s: Error registering kconsole notifications\n", NAME);
    987845       
    988846        return true;
     
    991849static void usage(void)
    992850{
    993         printf("Usage: console <input_dev> <framebuffer_dev>\n");
     851        printf("Usage: console <input_dev>\n");
    994852}
    995853
    996854int main(int argc, char *argv[])
    997855{
    998         if (argc < 3) {
     856        if (argc < 2) {
    999857                usage();
    1000858                return -1;
    1001859        }
    1002860       
    1003         printf("%s: HelenOS Console service\n", NAME);
    1004        
    1005         if (!console_srv_init(argv[1], argv[2]))
     861        printf(NAME ": HelenOS Console service\n");
     862       
     863        if (!console_srv_init(argv[1]))
    1006864                return -1;
    1007865       
    1008         printf("%s: Accepting connections\n", NAME);
    1009         task_retval(0);
     866        printf(NAME ": Accepting connections\n");
    1010867        async_manager();
    1011868       
Note: See TracChangeset for help on using the changeset viewer.