Ignore:
File:
1 edited

Legend:

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

    rcccc091 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 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 
    357 static 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 
    368 static console_t *cons_find_icon(sysarg_t x, sysarg_t y)
    369 {
    370         sysarg_t status_start =
    371             STATE_START + (xres - 800) / 2 + CONSOLE_MARGIN;
    372        
    373         if ((y < STATE_TOP) || (y >= STATE_TOP + STATE_HEIGHT))
    374                 return NULL;
    375        
    376         if (x < status_start)
    377                 return NULL;
    378        
    379         if (x >= status_start + (STATE_WIDTH + STATE_SPACE) * CONSOLE_COUNT)
    380                 return NULL;
    381        
    382         if (((x - status_start) % (STATE_WIDTH + STATE_SPACE)) >= STATE_WIDTH)
    383                 return NULL;
    384        
    385         sysarg_t btn = (x - status_start) / (STATE_WIDTH + STATE_SPACE);
    386        
    387         if (btn < CONSOLE_COUNT)
    388                 return consoles + btn;
    389        
    390         return NULL;
    391 }
    392 
    393 /** Handle mouse click
     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.
    394261 *
    395  * @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.
    396264 *
    397265 */
    398 static console_t *cons_mouse_button(bool state)
    399 {
    400         if (graphics_state != GRAPHICS_FULL)
    401                 return NULL;
    402        
    403         if (state) {
    404                 console_t *cons = cons_find_icon(mouse.x, mouse.y);
    405                 if (cons != NULL) {
    406                         mouse.btn_x = mouse.x;
    407                         mouse.btn_y = mouse.y;
    408                         mouse.pressed = true;
    409                 }
    410                
    411                 return NULL;
    412         }
    413        
    414         if ((!state) && (!mouse.pressed))
    415                 return NULL;
    416        
    417         console_t *cons = cons_find_icon(mouse.x, mouse.y);
    418         if (cons == cons_find_icon(mouse.btn_x, mouse.btn_y))
    419                 return cons;
    420        
    421         mouse.pressed = false;
    422         return NULL;
    423 }
    424 
     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 */
    425427static void input_events(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    426428{
     
    430432                ipc_callid_t callid = async_get_call(&call);
    431433               
     434                int retval;
     435                kbd_event_t ev;
     436               
    432437                if (!IPC_GET_IMETHOD(call)) {
    433438                        /* TODO: Handle hangup */
     
    436441                }
    437442               
    438                 kbd_event_type_t type;
    439                 keycode_t key;
    440                 keymod_t mods;
    441                 wchar_t c;
    442                
    443443                switch (IPC_GET_IMETHOD(call)) {
    444444                case INPUT_EVENT_KEY:
    445                         type = IPC_GET_ARG1(call);
    446                         key = IPC_GET_ARG2(call);
    447                         mods = IPC_GET_ARG3(call);
    448                         c = IPC_GET_ARG4(call);
     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);
    449451                       
    450                         if ((key >= KC_F1) && (key < KC_F1 + CONSOLE_COUNT) &&
    451                             ((mods & KM_CTRL) == 0))
    452                                 cons_switch(&consoles[key - KC_F1]);
    453                         else {
    454                                 /* Got key press/release event */
    455                                 kbd_event_t *event =
    456                                     (kbd_event_t *) malloc(sizeof(kbd_event_t));
    457                                 if (event == NULL) {
    458                                         async_answer_0(callid, ENOMEM);
    459                                         break;
    460                                 }
    461                                
    462                                 link_initialize(&event->link);
    463                                 event->type = type;
    464                                 event->key = key;
    465                                 event->mods = mods;
    466                                 event->c = c;
    467                                
    468                                 prodcons_produce(&active_console->input_pc, &event->link);
     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;
    469459                        }
    470460                       
    471                         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);
    472465                        break;
    473466                case INPUT_EVENT_MOVE:
    474                         cons_mouse_move(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
    475                         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;
    476471                        break;
    477472                case INPUT_EVENT_BUTTON:
    478473                        /* Got pointer button press/release event */
    479474                        if (IPC_GET_ARG1(call) == 1) {
    480                                 console_t *cons =
    481                                     cons_mouse_button((bool) IPC_GET_ARG2(call));
    482                                 if (cons != NULL)
    483                                         cons_switch(cons);
     475                                int newcon = gcons_mouse_btn((bool) IPC_GET_ARG2(call));
     476                                if (newcon != -1)
     477                                        change_console(&consoles[newcon]);
    484478                        }
    485                         async_answer_0(callid, EOK);
     479                        retval = 0;
    486480                        break;
    487481                default:
    488                         async_answer_0(callid, EINVAL);
    489                 }
    490         }
    491 }
    492 
    493 /** Process a character from the client (TTY emulation). */
    494 static void cons_write_char(console_t *cons, wchar_t ch)
    495 {
    496         sysarg_t updated = 0;
    497        
    498         fibril_mutex_lock(&cons->mtx);
    499        
    500         switch (ch) {
    501         case '\n':
    502                 updated = screenbuffer_newline(cons->frontbuf);
    503                 break;
    504         case '\r':
    505                 break;
    506         case '\t':
    507                 updated = screenbuffer_tabstop(cons->frontbuf, 8);
    508                 break;
    509         case '\b':
    510                 updated = screenbuffer_backspace(cons->frontbuf);
    511                 break;
    512         default:
    513                 updated = screenbuffer_putchar(cons->frontbuf, ch, true);
    514         }
    515        
    516         fibril_mutex_unlock(&cons->mtx);
    517        
    518         if (updated > 1)
    519                 cons_update(cons);
    520 }
    521 
    522 static void cons_set_cursor(console_t *cons, sysarg_t col, sysarg_t row)
    523 {
    524         fibril_mutex_lock(&cons->mtx);
    525         screenbuffer_set_cursor(cons->frontbuf, col, row);
    526         fibril_mutex_unlock(&cons->mtx);
    527        
    528         cons_update_cursor(cons);
    529 }
    530 
    531 static void cons_set_cursor_visibility(console_t *cons, bool visible)
    532 {
    533         fibril_mutex_lock(&cons->mtx);
    534         screenbuffer_set_cursor_visibility(cons->frontbuf, visible);
    535         fibril_mutex_unlock(&cons->mtx);
    536        
    537         cons_update_cursor(cons);
    538 }
    539 
    540 static void cons_get_cursor(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
    541 {
    542         sysarg_t col;
    543         sysarg_t row;
    544        
    545         fibril_mutex_lock(&cons->mtx);
    546         screenbuffer_get_cursor(cons->frontbuf, &col, &row);
    547         fibril_mutex_unlock(&cons->mtx);
    548        
    549         async_answer_2(iid, EOK, col, row);
    550 }
    551 
    552 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)
    553490{
    554491        void *buf;
     
    557494       
    558495        if (rc != EOK) {
    559                 async_answer_0(iid, rc);
     496                async_answer_0(rid, rc);
    560497                return;
    561498        }
    562499       
     500        console_serialize_start();
     501       
    563502        size_t off = 0;
    564         while (off < size)
    565                 cons_write_char(cons, str_decode(buf, &off, size));
    566        
    567         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       
    568513        free(buf);
    569        
    570         cons_notify_data(cons);
    571 }
    572 
    573 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)
    574517{
    575518        ipc_callid_t callid;
     
    577520        if (!async_data_read_receive(&callid, &size)) {
    578521                async_answer_0(callid, EINVAL);
    579                 async_answer_0(iid, EINVAL);
     522                async_answer_0(rid, EINVAL);
    580523                return;
    581524        }
     
    584527        if (buf == NULL) {
    585528                async_answer_0(callid, ENOMEM);
    586                 async_answer_0(iid, ENOMEM);
     529                async_answer_0(rid, ENOMEM);
    587530                return;
    588531        }
    589532       
    590533        size_t pos = 0;
    591         while (pos < size) {
    592                 link_t *link = prodcons_consume(&cons->input_pc);
    593                 kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
    594                
    595                 if (event->type == KEY_PRESS) {
    596                         buf[pos] = event->c;
     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;
    597541                        pos++;
    598542                }
    599                
    600                 free(event);
    601         }
    602        
    603         (void) async_data_read_finalize(callid, buf, size);
    604         async_answer_1(iid, EOK, size);
    605         free(buf);
    606 }
    607 
    608 static void cons_set_style(console_t *cons, console_style_t style)
    609 {
    610         fibril_mutex_lock(&cons->mtx);
    611         screenbuffer_set_style(cons->frontbuf, style);
    612         fibril_mutex_unlock(&cons->mtx);
    613 }
    614 
    615 static void cons_set_color(console_t *cons, console_color_t bgcolor,
    616     console_color_t fgcolor, console_color_attr_t attr)
    617 {
    618         fibril_mutex_lock(&cons->mtx);
    619         screenbuffer_set_color(cons->frontbuf, bgcolor, fgcolor, attr);
    620         fibril_mutex_unlock(&cons->mtx);
    621 }
    622 
    623 static void cons_set_rgb_color(console_t *cons, pixel_t bgcolor,
    624     pixel_t fgcolor)
    625 {
    626         fibril_mutex_lock(&cons->mtx);
    627         screenbuffer_set_rgb_color(cons->frontbuf, bgcolor, fgcolor);
    628         fibril_mutex_unlock(&cons->mtx);
    629 }
    630 
    631 static void cons_get_event(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
    632 {
    633         link_t *link = prodcons_consume(&cons->input_pc);
    634         kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
    635        
    636         async_answer_4(iid, EOK, event->type, event->key, event->mods, event->c);
    637         free(event);
    638 }
    639 
     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 */
    640575static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    641576{
    642577        console_t *cons = NULL;
    643578       
    644         for (size_t i = 0; i < CONSOLE_COUNT; i++) {
     579        size_t i;
     580        for (i = 0; i < CONSOLE_COUNT; i++) {
    645581                if (i == KERNEL_CONSOLE)
    646582                        continue;
    647583               
    648                 if (consoles[i].dsid == (service_id_t) IPC_GET_ARG1(*icall)) {
     584                if (consoles[i].devmap_handle == (devmap_handle_t) IPC_GET_ARG1(*icall)) {
    649585                        cons = &consoles[i];
    650586                        break;
     
    657593        }
    658594       
    659         if (atomic_postinc(&cons->refcnt) == 0) {
    660                 cons_set_cursor_visibility(cons, true);
    661                 cons_notify_connect(cons);
    662         }
     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++;
    663608       
    664609        /* Accept the connection */
     
    666611       
    667612        while (true) {
    668                 ipc_call_t call;
    669                 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;
    670620               
    671621                if (!IPC_GET_IMETHOD(call)) {
    672                         if (atomic_postdec(&cons->refcnt) == 1)
    673                                 cons_notify_disconnect(cons);
    674                        
     622                        cons->refcount--;
     623                        if (cons->refcount == 0)
     624                                gcons_notify_disconnect(cons->index);
     625                        console_serialize_end();
    675626                        return;
    676627                }
     
    678629                switch (IPC_GET_IMETHOD(call)) {
    679630                case VFS_OUT_READ:
     631                        console_serialize_end();
    680632                        cons_read(cons, callid, &call);
    681                         break;
     633                        console_serialize_start();
     634                        continue;
    682635                case VFS_OUT_WRITE:
     636                        console_serialize_end();
    683637                        cons_write(cons, callid, &call);
    684                         break;
     638                        console_serialize_start();
     639                        continue;
    685640                case VFS_OUT_SYNC:
    686                         cons_update(cons);
    687                         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                        }
    688646                        break;
    689647                case CONSOLE_CLEAR:
    690                         cons_clear(cons);
    691                         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                       
    692654                        break;
    693655                case CONSOLE_GOTO:
    694                         cons_set_cursor(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
    695                         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));
    696661                        break;
    697662                case CONSOLE_GET_POS:
    698                         cons_get_cursor(cons, callid, &call);
     663                        arg1 = cons->scr.position_x;
     664                        arg2 = cons->scr.position_y;
    699665                        break;
    700666                case CONSOLE_GET_SIZE:
    701                         async_answer_2(callid, EOK, cons->cols, cons->rows);
     667                        arg1 = fb_info.cols;
     668                        arg2 = fb_info.rows;
    702669                        break;
    703670                case CONSOLE_GET_COLOR_CAP:
    704                         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                        }
    705676                        break;
    706677                case CONSOLE_SET_STYLE:
    707                         cons_set_style(cons, IPC_GET_ARG1(call));
    708                         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);
    709683                        break;
    710684                case CONSOLE_SET_COLOR:
    711                         cons_set_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call),
    712                             IPC_GET_ARG3(call));
    713                         async_answer_0(callid, EOK);
     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);
    714692                        break;
    715693                case CONSOLE_SET_RGB_COLOR:
    716                         cons_set_rgb_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
    717                         async_answer_0(callid, EOK);
     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);
    718700                        break;
    719701                case CONSOLE_CURSOR_VISIBILITY:
    720                         cons_set_cursor_visibility(cons, IPC_GET_ARG1(call));
    721                         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);
    722707                        break;
    723708                case CONSOLE_GET_EVENT:
     709                        console_serialize_end();
    724710                        cons_get_event(cons, callid, &call);
    725                         break;
    726                 default:
    727                         async_answer_0(callid, EINVAL);
    728                 }
    729         }
    730 }
    731 
    732 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)
    733724{
    734725        async_sess_t *sess;
    735         service_id_t dsid;
    736        
    737         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);
    738730        if (rc == EOK) {
    739                 sess = loc_service_connect(EXCHANGE_ATOMIC, dsid, 0);
     731                sess = devmap_device_connect(EXCHANGE_ATOMIC, handle, 0);
    740732                if (sess == NULL) {
    741                         printf("%s: Unable to connect to input service %s\n", NAME,
    742                             svc);
     733                        printf("%s: Failed to connect to input server\n", NAME);
    743734                        return NULL;
    744735                }
    745         } else
     736        } else {
    746737                return NULL;
    747        
    748         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 */
    749747        rc = async_connect_to_me(exch, 0, 0, 0, input_events, NULL);
     748
    750749        async_exchange_end(exch);
    751        
     750
    752751        if (rc != EOK) {
    753752                async_hangup(sess);
    754                 printf("%s: Unable to create callback connection to service %s (%s)\n",
    755                     NAME, svc, str_error(rc));
     753                printf("%s: Failed to create callback from input server (%s).\n",
     754                    NAME, str_error(rc));
    756755                return NULL;
    757756        }
     
    760759}
    761760
    762 static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
    763 {
    764         cons_switch(prev_console);
    765 }
    766 
    767 static async_sess_t *fb_connect(const char *svc)
    768 {
    769         async_sess_t *sess;
    770         service_id_t dsid;
    771        
    772         int rc = loc_service_get_id(svc, &dsid, 0);
    773         if (rc == EOK) {
    774                 sess = loc_service_connect(EXCHANGE_SERIALIZE, dsid, 0);
    775                 if (sess == NULL) {
    776                         printf("%s: Unable to connect to framebuffer service %s\n",
    777                             NAME, svc);
    778                         return NULL;
    779                 }
    780         } else
    781                 return NULL;
    782        
    783         return sess;
    784 }
    785 
    786 static bool console_srv_init(char *input_svc, char *fb_svc)
    787 {
    788         /* Avoid double initialization */
    789         if (graphics_state != GRAPHICS_NONE)
    790                 return false;
    791        
    792         /* Connect to input service */
    793         input_sess = input_connect(input_svc);
     761static bool console_srv_init(char *input_dev)
     762{
     763        /* Connect to input server */
     764        input_sess = connect_input(input_dev);
    794765        if (input_sess == NULL)
    795766                return false;
    796767       
    797         /* Connect to framebuffer service */
    798         fb_sess = fb_connect(fb_svc);
    799         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);
    800772                return false;
    801        
    802         /* Register server */
    803         int rc = loc_server_register(NAME, client_connection);
     773        }
     774       
     775        /* Register driver */
     776        int rc = devmap_driver_register(NAME, client_connection);
    804777        if (rc < 0) {
    805                 printf("%s: Unable to register server (%s)\n", NAME,
    806                     str_error(rc));
     778                printf("%s: Unable to register driver (%d)\n", NAME, rc);
    807779                return false;
    808780        }
    809781       
    810         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        }
    811831       
    812832        /* Initialize the screen */
    813         screen_vp = fb_vp_create(fb_sess, 0, 0, xres, yres);
    814        
    815         if ((xres >= 800) && (yres >= 600)) {
    816                 logo_vp = fb_vp_create(fb_sess, xres - 66, 2, 64, 60);
    817                 logo_img = imgmap_decode_tga((void *) helenos_tga,
    818                     helenos_tga_size, IMGMAP_FLAG_SHARED);
    819                 logo_handle = fb_imagemap_create(fb_sess, logo_img);
    820                
    821                 nameic_vp = fb_vp_create(fb_sess, 5, 17, 100, 26);
    822                 nameic_img = imgmap_decode_tga((void *) nameic_tga,
    823                     nameic_tga_size, IMGMAP_FLAG_SHARED);
    824                 nameic_handle = fb_imagemap_create(fb_sess, nameic_img);
    825                
    826                 cons_data_img = imgmap_decode_tga((void *) cons_data_tga,
    827                     cons_data_tga_size, IMGMAP_FLAG_SHARED);
    828                 cons_dis_img = imgmap_decode_tga((void *) cons_dis_tga,
    829                     cons_dis_tga_size, IMGMAP_FLAG_SHARED);
    830                 cons_dis_sel_img = imgmap_decode_tga((void *) cons_dis_sel_tga,
    831                     cons_dis_sel_tga_size, IMGMAP_FLAG_SHARED);
    832                 cons_idle_img = imgmap_decode_tga((void *) cons_idle_tga,
    833                     cons_idle_tga_size, IMGMAP_FLAG_SHARED);
    834                 cons_kernel_img = imgmap_decode_tga((void *) cons_kernel_tga,
    835                     cons_kernel_tga_size, IMGMAP_FLAG_SHARED);
    836                 cons_sel_img = imgmap_decode_tga((void *) cons_sel_tga,
    837                     cons_sel_tga_size, IMGMAP_FLAG_SHARED);
    838                
    839                 state_icons[CONS_DISCONNECTED] =
    840                     fb_imagemap_create(fb_sess, cons_dis_img);
    841                 state_icons[CONS_DISCONNECTED_SELECTED] =
    842                     fb_imagemap_create(fb_sess, cons_dis_sel_img);
    843                 state_icons[CONS_SELECTED] =
    844                     fb_imagemap_create(fb_sess, cons_sel_img);
    845                 state_icons[CONS_IDLE] =
    846                     fb_imagemap_create(fb_sess, cons_idle_img);
    847                 state_icons[CONS_DATA] =
    848                     fb_imagemap_create(fb_sess, cons_data_img);
    849                 state_icons[CONS_KERNEL] =
    850                     fb_imagemap_create(fb_sess, cons_kernel_img);
    851                
    852                 anim_1_img = imgmap_decode_tga((void *) anim_1_tga,
    853                     anim_1_tga_size, IMGMAP_FLAG_SHARED);
    854                 anim_2_img = imgmap_decode_tga((void *) anim_2_tga,
    855                     anim_2_tga_size, IMGMAP_FLAG_SHARED);
    856                 anim_3_img = imgmap_decode_tga((void *) anim_3_tga,
    857                     anim_3_tga_size, IMGMAP_FLAG_SHARED);
    858                 anim_4_img = imgmap_decode_tga((void *) anim_4_tga,
    859                     anim_4_tga_size, IMGMAP_FLAG_SHARED);
    860                
    861                 anim_1 = fb_imagemap_create(fb_sess, anim_1_img);
    862                 anim_2 = fb_imagemap_create(fb_sess, anim_2_img);
    863                 anim_3 = fb_imagemap_create(fb_sess, anim_3_img);
    864                 anim_4 = fb_imagemap_create(fb_sess, anim_4_img);
    865                
    866                 anim_seq = fb_sequence_create(fb_sess);
    867                 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_1);
    868                 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_2);
    869                 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_3);
    870                 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_4);
    871                
    872                 console_vp = fb_vp_create(fb_sess, CONSOLE_MARGIN, CONSOLE_TOP,
    873                     xres - 2 * CONSOLE_MARGIN, yres - (CONSOLE_TOP + CONSOLE_MARGIN));
    874                
    875                 fb_vp_clear(fb_sess, screen_vp);
    876                 fb_vp_imagemap_damage(fb_sess, logo_vp, logo_handle,
    877                     0, 0, 64, 60);
    878                 fb_vp_imagemap_damage(fb_sess, nameic_vp, nameic_handle,
    879                     0, 0, 100, 26);
    880                
    881                 graphics_state = GRAPHICS_FULL;
    882         } else {
    883                 console_vp = screen_vp;
    884                 graphics_state = GRAPHICS_BASIC;
    885         }
    886        
    887         fb_vp_set_style(fb_sess, console_vp, STYLE_NORMAL);
    888         fb_vp_clear(fb_sess, console_vp);
    889        
    890         sysarg_t cols;
    891         sysarg_t rows;
    892         fb_vp_get_dimensions(fb_sess, console_vp, &cols, &rows);
    893        
    894         console_caps_t ccaps;
    895         fb_vp_get_caps(fb_sess, console_vp, &ccaps);
    896        
    897         mouse.x = xres / 2;
    898         mouse.y = yres / 2;
    899         mouse.pressed = false;
    900        
    901         /* Inititalize consoles */
    902         for (size_t i = 0; i < CONSOLE_COUNT; i++) {
    903                 consoles[i].index = i;
    904                 atomic_set(&consoles[i].refcnt, 0);
    905                 fibril_mutex_initialize(&consoles[i].mtx);
    906                
    907                 if (graphics_state == GRAPHICS_FULL) {
    908                         /* Create state buttons */
    909                         consoles[i].state_vp =
    910                             fb_vp_create(fb_sess, STATE_START + (xres - 800) / 2 +
    911                             CONSOLE_MARGIN + i * (STATE_WIDTH + STATE_SPACE),
    912                             STATE_TOP, STATE_WIDTH, STATE_HEIGHT);
    913                 }
    914                
    915                 if (i == KERNEL_CONSOLE) {
    916                         consoles[i].state = CONS_KERNEL;
    917                         cons_redraw_state(&consoles[i]);
    918                         cons_kernel_sequence_start(&consoles[i]);
    919                         continue;
    920                 }
    921                
    922                 if (i == 0)
    923                         consoles[i].state = CONS_DISCONNECTED_SELECTED;
    924                 else
    925                         consoles[i].state = CONS_DISCONNECTED;
    926                
    927                 consoles[i].cols = cols;
    928                 consoles[i].rows = rows;
    929                 consoles[i].ccaps = ccaps;
    930                 consoles[i].frontbuf =
    931                     screenbuffer_create(cols, rows, SCREENBUFFER_FLAG_SHARED);
    932                
    933                 if (consoles[i].frontbuf == NULL) {
    934                         printf("%s: Unable to allocate frontbuffer %zu\n", NAME, i);
    935                         return false;
    936                 }
    937                
    938                 consoles[i].fbid = fb_frontbuf_create(fb_sess, consoles[i].frontbuf);
    939                 if (consoles[i].fbid == 0) {
    940                         printf("%s: Unable to create frontbuffer %zu\n", NAME, i);
    941                         return false;
    942                 }
    943                
    944                 prodcons_initialize(&consoles[i].input_pc);
    945                 cons_redraw_state(&consoles[i]);
    946                
    947                 char vc[LOC_NAME_MAXLEN + 1];
    948                 snprintf(vc, LOC_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i);
    949                
    950                 if (loc_service_register(vc, &consoles[i].dsid) != EOK) {
    951                         printf("%s: Unable to register device %s\n", NAME, vc);
    952                         return false;
    953                 }
    954         }
     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();
    955840       
    956841        /* Receive kernel notifications */
    957842        async_set_interrupt_received(interrupt_received);
    958         rc = event_subscribe(EVENT_KCONSOLE, 0);
    959         if (rc != EOK)
    960                 printf("%s: Failed to register kconsole notifications (%s)\n",
    961                     NAME, str_error(rc));
     843        if (event_subscribe(EVENT_KCONSOLE, 0) != EOK)
     844                printf("%s: Error registering kconsole notifications\n", NAME);
    962845       
    963846        return true;
     
    966849static void usage(void)
    967850{
    968         printf("Usage: console <input_dev> <framebuffer_dev>\n");
     851        printf("Usage: console <input_dev>\n");
    969852}
    970853
    971854int main(int argc, char *argv[])
    972855{
    973         if (argc < 3) {
     856        if (argc < 2) {
    974857                usage();
    975858                return -1;
    976859        }
    977860       
    978         printf("%s: HelenOS Console service\n", NAME);
    979        
    980         if (!console_srv_init(argv[1], argv[2]))
     861        printf(NAME ": HelenOS Console service\n");
     862       
     863        if (!console_srv_init(argv[1]))
    981864                return -1;
    982865       
    983         printf("%s: Accepting connections\n", NAME);
    984         task_retval(0);
     866        printf(NAME ": Accepting connections\n");
    985867        async_manager();
    986868       
Note: See TracChangeset for help on using the changeset viewer.