Ignore:
File:
1 edited

Legend:

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

    r7c014d1 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   110
    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 = STATE_START + (xres - 800) / 2;
    371        
    372         if ((y < STATE_TOP) || (y >= STATE_TOP + STATE_HEIGHT))
    373                 return NULL;
    374        
    375         if (x < status_start)
    376                 return NULL;
    377        
    378         if (x >= status_start + (STATE_WIDTH + STATE_SPACE) * CONSOLE_COUNT)
    379                 return NULL;
    380        
    381         if (((x - status_start) % (STATE_WIDTH + STATE_SPACE)) < STATE_SPACE)
    382                 return NULL;
    383        
    384         sysarg_t btn = (x - status_start) / (STATE_WIDTH + STATE_SPACE);
    385        
    386         if (btn < CONSOLE_COUNT)
    387                 return consoles + btn;
    388        
    389         return NULL;
    390 }
    391 
    392 /** Handle mouse click
     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.
    393261 *
    394  * @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.
    395264 *
    396265 */
    397 static console_t *cons_mouse_button(bool state)
    398 {
    399         if (graphics_state != GRAPHICS_FULL)
    400                 return NULL;
    401        
    402         if (state) {
    403                 console_t *cons = cons_find_icon(mouse.x, mouse.y);
    404                 if (cons != NULL) {
    405                         mouse.btn_x = mouse.x;
    406                         mouse.btn_y = mouse.y;
    407                         mouse.pressed = true;
    408                 }
    409                
    410                 return NULL;
    411         }
    412        
    413         if ((!state) && (!mouse.pressed))
    414                 return NULL;
    415        
    416         console_t *cons = cons_find_icon(mouse.x, mouse.y);
    417         if (cons == cons_find_icon(mouse.btn_x, mouse.btn_y))
    418                 return cons;
    419        
    420         mouse.pressed = false;
    421         return NULL;
    422 }
    423 
     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 */
    424427static void input_events(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    425428{
     
    429432                ipc_callid_t callid = async_get_call(&call);
    430433               
     434                int retval;
     435                kbd_event_t ev;
     436               
    431437                if (!IPC_GET_IMETHOD(call)) {
    432438                        /* TODO: Handle hangup */
     
    435441                }
    436442               
    437                 kbd_event_type_t type;
    438                 keycode_t key;
    439                 keymod_t mods;
    440                 wchar_t c;
    441                
    442443                switch (IPC_GET_IMETHOD(call)) {
    443444                case INPUT_EVENT_KEY:
    444                         type = IPC_GET_ARG1(call);
    445                         key = IPC_GET_ARG2(call);
    446                         mods = IPC_GET_ARG3(call);
    447                         c = IPC_GET_ARG4(call);
     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);
    448451                       
    449                         if ((key >= KC_F1) && (key < KC_F1 + CONSOLE_COUNT) &&
    450                             ((mods & KM_CTRL) == 0))
    451                                 cons_switch(&consoles[key - KC_F1]);
    452                         else {
    453                                 /* Got key press/release event */
    454                                 kbd_event_t *event =
    455                                     (kbd_event_t *) malloc(sizeof(kbd_event_t));
    456                                 if (event == NULL) {
    457                                         async_answer_0(callid, ENOMEM);
    458                                         break;
    459                                 }
    460                                
    461                                 link_initialize(&event->link);
    462                                 event->type = type;
    463                                 event->key = key;
    464                                 event->mods = mods;
    465                                 event->c = c;
    466                                
    467                                 prodcons_produce(&active_console->input_pc, &event->link);
     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;
    468459                        }
    469460                       
    470                         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);
    471465                        break;
    472466                case INPUT_EVENT_MOVE:
    473                         cons_mouse_move(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
    474                         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;
    475471                        break;
    476472                case INPUT_EVENT_BUTTON:
    477473                        /* Got pointer button press/release event */
    478474                        if (IPC_GET_ARG1(call) == 1) {
    479                                 console_t *cons =
    480                                     cons_mouse_button((bool) IPC_GET_ARG2(call));
    481                                 if (cons != NULL)
    482                                         cons_switch(cons);
     475                                int newcon = gcons_mouse_btn((bool) IPC_GET_ARG2(call));
     476                                if (newcon != -1)
     477                                        change_console(&consoles[newcon]);
    483478                        }
    484                         async_answer_0(callid, EOK);
     479                        retval = 0;
    485480                        break;
    486481                default:
    487                         async_answer_0(callid, EINVAL);
    488                 }
    489         }
    490 }
    491 
    492 /** Process a character from the client (TTY emulation). */
    493 static void cons_write_char(console_t *cons, wchar_t ch)
    494 {
    495         sysarg_t updated = 0;
    496        
    497         fibril_mutex_lock(&cons->mtx);
    498        
    499         switch (ch) {
    500         case '\n':
    501                 updated = screenbuffer_newline(cons->frontbuf);
    502                 break;
    503         case '\r':
    504                 break;
    505         case '\t':
    506                 updated = screenbuffer_tabstop(cons->frontbuf, 8);
    507                 break;
    508         case '\b':
    509                 updated = screenbuffer_backspace(cons->frontbuf);
    510                 break;
    511         default:
    512                 updated = screenbuffer_putchar(cons->frontbuf, ch, true);
    513         }
    514        
    515         fibril_mutex_unlock(&cons->mtx);
    516        
    517         if (updated > 1)
    518                 cons_update(cons);
    519 }
    520 
    521 static void cons_set_cursor(console_t *cons, sysarg_t col, sysarg_t row)
    522 {
    523         fibril_mutex_lock(&cons->mtx);
    524         screenbuffer_set_cursor(cons->frontbuf, col, row);
    525         fibril_mutex_unlock(&cons->mtx);
    526        
    527         cons_update_cursor(cons);
    528 }
    529 
    530 static void cons_set_cursor_visibility(console_t *cons, bool visible)
    531 {
    532         fibril_mutex_lock(&cons->mtx);
    533         screenbuffer_set_cursor_visibility(cons->frontbuf, visible);
    534         fibril_mutex_unlock(&cons->mtx);
    535        
    536         cons_update_cursor(cons);
    537 }
    538 
    539 static void cons_get_cursor(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
    540 {
    541         sysarg_t col;
    542         sysarg_t row;
    543        
    544         fibril_mutex_lock(&cons->mtx);
    545         screenbuffer_get_cursor(cons->frontbuf, &col, &row);
    546         fibril_mutex_unlock(&cons->mtx);
    547        
    548         async_answer_2(iid, EOK, col, row);
    549 }
    550 
    551 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)
    552490{
    553491        void *buf;
     
    556494       
    557495        if (rc != EOK) {
    558                 async_answer_0(iid, rc);
     496                async_answer_0(rid, rc);
    559497                return;
    560498        }
    561499       
     500        console_serialize_start();
     501       
    562502        size_t off = 0;
    563         while (off < size)
    564                 cons_write_char(cons, str_decode(buf, &off, size));
    565        
    566         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       
    567513        free(buf);
    568        
    569         cons_notify_data(cons);
    570 }
    571 
    572 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)
    573517{
    574518        ipc_callid_t callid;
     
    576520        if (!async_data_read_receive(&callid, &size)) {
    577521                async_answer_0(callid, EINVAL);
    578                 async_answer_0(iid, EINVAL);
     522                async_answer_0(rid, EINVAL);
    579523                return;
    580524        }
     
    583527        if (buf == NULL) {
    584528                async_answer_0(callid, ENOMEM);
    585                 async_answer_0(iid, ENOMEM);
     529                async_answer_0(rid, ENOMEM);
    586530                return;
    587531        }
    588532       
    589533        size_t pos = 0;
    590         while (pos < size) {
    591                 link_t *link = prodcons_consume(&cons->input_pc);
    592                 kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
    593                
    594                 if (event->type == KEY_PRESS) {
    595                         buf[pos] = event->c;
     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;
    596541                        pos++;
    597542                }
    598                
    599                 free(event);
    600         }
    601        
    602         (void) async_data_read_finalize(callid, buf, size);
    603         async_answer_1(iid, EOK, size);
    604         free(buf);
    605 }
    606 
    607 static void cons_set_style(console_t *cons, console_style_t style)
    608 {
    609         fibril_mutex_lock(&cons->mtx);
    610         screenbuffer_set_style(cons->frontbuf, style);
    611         fibril_mutex_unlock(&cons->mtx);
    612 }
    613 
    614 static void cons_set_color(console_t *cons, console_color_t bgcolor,
    615     console_color_t fgcolor, console_color_attr_t attr)
    616 {
    617         fibril_mutex_lock(&cons->mtx);
    618         screenbuffer_set_color(cons->frontbuf, bgcolor, fgcolor, attr);
    619         fibril_mutex_unlock(&cons->mtx);
    620 }
    621 
    622 static void cons_set_rgb_color(console_t *cons, pixel_t bgcolor,
    623     pixel_t fgcolor)
    624 {
    625         fibril_mutex_lock(&cons->mtx);
    626         screenbuffer_set_rgb_color(cons->frontbuf, bgcolor, fgcolor);
    627         fibril_mutex_unlock(&cons->mtx);
    628 }
    629 
    630 static void cons_get_event(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
    631 {
    632         link_t *link = prodcons_consume(&cons->input_pc);
    633         kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
    634        
    635         async_answer_4(iid, EOK, event->type, event->key, event->mods, event->c);
    636         free(event);
    637 }
    638 
     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 */
    639575static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    640576{
    641577        console_t *cons = NULL;
    642578       
    643         for (size_t i = 0; i < CONSOLE_COUNT; i++) {
     579        size_t i;
     580        for (i = 0; i < CONSOLE_COUNT; i++) {
    644581                if (i == KERNEL_CONSOLE)
    645582                        continue;
    646583               
    647                 if (consoles[i].dsid == (service_id_t) IPC_GET_ARG1(*icall)) {
     584                if (consoles[i].devmap_handle == (devmap_handle_t) IPC_GET_ARG1(*icall)) {
    648585                        cons = &consoles[i];
    649586                        break;
     
    656593        }
    657594       
    658         if (atomic_postinc(&cons->refcnt) == 0) {
    659                 cons_set_cursor_visibility(cons, true);
    660                 cons_notify_connect(cons);
    661         }
     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++;
    662608       
    663609        /* Accept the connection */
     
    665611       
    666612        while (true) {
    667                 ipc_call_t call;
    668                 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;
    669620               
    670621                if (!IPC_GET_IMETHOD(call)) {
    671                         if (atomic_postdec(&cons->refcnt) == 1)
    672                                 cons_notify_disconnect(cons);
    673                        
     622                        cons->refcount--;
     623                        if (cons->refcount == 0)
     624                                gcons_notify_disconnect(cons->index);
     625                        console_serialize_end();
    674626                        return;
    675627                }
     
    677629                switch (IPC_GET_IMETHOD(call)) {
    678630                case VFS_OUT_READ:
     631                        console_serialize_end();
    679632                        cons_read(cons, callid, &call);
    680                         break;
     633                        console_serialize_start();
     634                        continue;
    681635                case VFS_OUT_WRITE:
     636                        console_serialize_end();
    682637                        cons_write(cons, callid, &call);
    683                         break;
     638                        console_serialize_start();
     639                        continue;
    684640                case VFS_OUT_SYNC:
    685                         cons_update(cons);
    686                         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                        }
    687646                        break;
    688647                case CONSOLE_CLEAR:
    689                         cons_clear(cons);
    690                         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                       
    691654                        break;
    692655                case CONSOLE_GOTO:
    693                         cons_set_cursor(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
    694                         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));
    695661                        break;
    696662                case CONSOLE_GET_POS:
    697                         cons_get_cursor(cons, callid, &call);
     663                        arg1 = cons->scr.position_x;
     664                        arg2 = cons->scr.position_y;
    698665                        break;
    699666                case CONSOLE_GET_SIZE:
    700                         async_answer_2(callid, EOK, cons->cols, cons->rows);
     667                        arg1 = fb_info.cols;
     668                        arg2 = fb_info.rows;
    701669                        break;
    702670                case CONSOLE_GET_COLOR_CAP:
    703                         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                        }
    704676                        break;
    705677                case CONSOLE_SET_STYLE:
    706                         cons_set_style(cons, IPC_GET_ARG1(call));
    707                         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);
    708683                        break;
    709684                case CONSOLE_SET_COLOR:
    710                         cons_set_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call),
    711                             IPC_GET_ARG3(call));
    712                         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);
    713692                        break;
    714693                case CONSOLE_SET_RGB_COLOR:
    715                         cons_set_rgb_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
    716                         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);
    717700                        break;
    718701                case CONSOLE_CURSOR_VISIBILITY:
    719                         cons_set_cursor_visibility(cons, IPC_GET_ARG1(call));
    720                         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);
    721707                        break;
    722708                case CONSOLE_GET_EVENT:
     709                        console_serialize_end();
    723710                        cons_get_event(cons, callid, &call);
    724                         break;
    725                 default:
    726                         async_answer_0(callid, EINVAL);
    727                 }
    728         }
    729 }
    730 
    731 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)
    732724{
    733725        async_sess_t *sess;
    734         service_id_t dsid;
    735        
    736         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);
    737730        if (rc == EOK) {
    738                 sess = loc_service_connect(EXCHANGE_ATOMIC, dsid, 0);
     731                sess = devmap_device_connect(EXCHANGE_ATOMIC, handle, 0);
    739732                if (sess == NULL) {
    740                         printf("%s: Unable to connect to input service %s\n", NAME,
    741                             svc);
     733                        printf("%s: Failed to connect to input server\n", NAME);
    742734                        return NULL;
    743735                }
    744         } else
     736        } else {
    745737                return NULL;
    746        
    747         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 */
    748747        rc = async_connect_to_me(exch, 0, 0, 0, input_events, NULL);
     748
    749749        async_exchange_end(exch);
    750        
     750
    751751        if (rc != EOK) {
    752752                async_hangup(sess);
    753                 printf("%s: Unable to create callback connection to service %s (%s)\n",
    754                     NAME, svc, str_error(rc));
     753                printf("%s: Failed to create callback from input server (%s).\n",
     754                    NAME, str_error(rc));
    755755                return NULL;
    756756        }
     
    759759}
    760760
    761 static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
    762 {
    763         cons_switch(prev_console);
    764 }
    765 
    766 static async_sess_t *fb_connect(const char *svc)
    767 {
    768         async_sess_t *sess;
    769         service_id_t dsid;
    770        
    771         int rc = loc_service_get_id(svc, &dsid, 0);
    772         if (rc == EOK) {
    773                 sess = loc_service_connect(EXCHANGE_SERIALIZE, dsid, 0);
    774                 if (sess == NULL) {
    775                         printf("%s: Unable to connect to framebuffer service %s\n",
    776                             NAME, svc);
    777                         return NULL;
    778                 }
    779         } else
    780                 return NULL;
    781        
    782         return sess;
    783 }
    784 
    785 static bool console_srv_init(char *input_svc, char *fb_svc)
    786 {
    787         /* Avoid double initialization */
    788         if (graphics_state != GRAPHICS_NONE)
    789                 return false;
    790        
    791         /* Connect to input service */
    792         input_sess = input_connect(input_svc);
     761static bool console_srv_init(char *input_dev)
     762{
     763        /* Connect to input server */
     764        input_sess = connect_input(input_dev);
    793765        if (input_sess == NULL)
    794766                return false;
    795767       
    796         /* Connect to framebuffer service */
    797         fb_sess = fb_connect(fb_svc);
    798         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);
    799772                return false;
    800        
    801         /* Register server */
    802         int rc = loc_server_register(NAME, client_connection);
     773        }
     774       
     775        /* Register driver */
     776        int rc = devmap_driver_register(NAME, client_connection);
    803777        if (rc < 0) {
    804                 printf("%s: Unable to register server (%s)\n", NAME,
    805                     str_error(rc));
     778                printf("%s: Unable to register driver (%d)\n", NAME, rc);
    806779                return false;
    807780        }
    808781       
    809         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        }
    810831       
    811832        /* Initialize the screen */
    812         screen_vp = fb_vp_create(fb_sess, 0, 0, xres, yres);
    813        
    814         if ((xres >= 800) && (yres >= 600)) {
    815                 logo_vp = fb_vp_create(fb_sess, xres - 66, 2, 64, 60);
    816                 logo_img = imgmap_decode_tga((void *) helenos_tga,
    817                     helenos_tga_size, IMGMAP_FLAG_SHARED);
    818                 logo_handle = fb_imagemap_create(fb_sess, logo_img);
    819                
    820                 nameic_vp = fb_vp_create(fb_sess, 5, 17, 100, 26);
    821                 nameic_img = imgmap_decode_tga((void *) nameic_tga,
    822                     nameic_tga_size, IMGMAP_FLAG_SHARED);
    823                 nameic_handle = fb_imagemap_create(fb_sess, nameic_img);
    824                
    825                 cons_data_img = imgmap_decode_tga((void *) cons_data_tga,
    826                     cons_data_tga_size, IMGMAP_FLAG_SHARED);
    827                 cons_dis_img = imgmap_decode_tga((void *) cons_dis_tga,
    828                     cons_dis_tga_size, IMGMAP_FLAG_SHARED);
    829                 cons_dis_sel_img = imgmap_decode_tga((void *) cons_dis_sel_tga,
    830                     cons_dis_sel_tga_size, IMGMAP_FLAG_SHARED);
    831                 cons_idle_img = imgmap_decode_tga((void *) cons_idle_tga,
    832                     cons_idle_tga_size, IMGMAP_FLAG_SHARED);
    833                 cons_kernel_img = imgmap_decode_tga((void *) cons_kernel_tga,
    834                     cons_kernel_tga_size, IMGMAP_FLAG_SHARED);
    835                 cons_sel_img = imgmap_decode_tga((void *) cons_sel_tga,
    836                     cons_sel_tga_size, IMGMAP_FLAG_SHARED);
    837                
    838                 state_icons[CONS_DISCONNECTED] =
    839                     fb_imagemap_create(fb_sess, cons_dis_img);
    840                 state_icons[CONS_DISCONNECTED_SELECTED] =
    841                     fb_imagemap_create(fb_sess, cons_dis_sel_img);
    842                 state_icons[CONS_SELECTED] =
    843                     fb_imagemap_create(fb_sess, cons_sel_img);
    844                 state_icons[CONS_IDLE] =
    845                     fb_imagemap_create(fb_sess, cons_idle_img);
    846                 state_icons[CONS_DATA] =
    847                     fb_imagemap_create(fb_sess, cons_data_img);
    848                 state_icons[CONS_KERNEL] =
    849                     fb_imagemap_create(fb_sess, cons_kernel_img);
    850                
    851                 anim_1_img = imgmap_decode_tga((void *) anim_1_tga,
    852                     anim_1_tga_size, IMGMAP_FLAG_SHARED);
    853                 anim_2_img = imgmap_decode_tga((void *) anim_2_tga,
    854                     anim_2_tga_size, IMGMAP_FLAG_SHARED);
    855                 anim_3_img = imgmap_decode_tga((void *) anim_3_tga,
    856                     anim_3_tga_size, IMGMAP_FLAG_SHARED);
    857                 anim_4_img = imgmap_decode_tga((void *) anim_4_tga,
    858                     anim_4_tga_size, IMGMAP_FLAG_SHARED);
    859                
    860                 anim_1 = fb_imagemap_create(fb_sess, anim_1_img);
    861                 anim_2 = fb_imagemap_create(fb_sess, anim_2_img);
    862                 anim_3 = fb_imagemap_create(fb_sess, anim_3_img);
    863                 anim_4 = fb_imagemap_create(fb_sess, anim_4_img);
    864                
    865                 anim_seq = fb_sequence_create(fb_sess);
    866                 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_1);
    867                 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_2);
    868                 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_3);
    869                 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_4);
    870                
    871                 console_vp = fb_vp_create(fb_sess, CONSOLE_MARGIN, CONSOLE_TOP,
    872                     xres - 2 * CONSOLE_MARGIN, yres - (CONSOLE_TOP + CONSOLE_MARGIN));
    873                
    874                 fb_vp_clear(fb_sess, screen_vp);
    875                 fb_vp_imagemap_damage(fb_sess, logo_vp, logo_handle,
    876                     0, 0, 64, 60);
    877                 fb_vp_imagemap_damage(fb_sess, nameic_vp, nameic_handle,
    878                     0, 0, 100, 26);
    879                
    880                 graphics_state = GRAPHICS_FULL;
    881         } else {
    882                 console_vp = screen_vp;
    883                 graphics_state = GRAPHICS_BASIC;
    884         }
    885        
    886         fb_vp_set_style(fb_sess, console_vp, STYLE_NORMAL);
    887         fb_vp_clear(fb_sess, console_vp);
    888        
    889         sysarg_t cols;
    890         sysarg_t rows;
    891         fb_vp_get_dimensions(fb_sess, console_vp, &cols, &rows);
    892        
    893         console_caps_t ccaps;
    894         fb_vp_get_caps(fb_sess, console_vp, &ccaps);
    895        
    896         mouse.pressed = false;
    897        
    898         /* Inititalize consoles */
    899         for (size_t i = 0; i < CONSOLE_COUNT; i++) {
    900                 consoles[i].index = i;
    901                 atomic_set(&consoles[i].refcnt, 0);
    902                 fibril_mutex_initialize(&consoles[i].mtx);
    903                
    904                 if (graphics_state == GRAPHICS_FULL) {
    905                         /* Create state buttons */
    906                         consoles[i].state_vp =
    907                             fb_vp_create(fb_sess, STATE_START + (xres - 800) / 2 +
    908                             CONSOLE_MARGIN + i * (STATE_WIDTH + STATE_SPACE),
    909                             STATE_TOP, STATE_WIDTH, STATE_HEIGHT);
    910                 }
    911                
    912                 if (i == KERNEL_CONSOLE) {
    913                         consoles[i].state = CONS_KERNEL;
    914                         cons_redraw_state(&consoles[i]);
    915                         cons_kernel_sequence_start(&consoles[i]);
    916                         continue;
    917                 }
    918                
    919                 if (i == 0)
    920                         consoles[i].state = CONS_DISCONNECTED_SELECTED;
    921                 else
    922                         consoles[i].state = CONS_DISCONNECTED;
    923                
    924                 consoles[i].cols = cols;
    925                 consoles[i].rows = rows;
    926                 consoles[i].ccaps = ccaps;
    927                 consoles[i].frontbuf =
    928                     screenbuffer_create(cols, rows, SCREENBUFFER_FLAG_SHARED);
    929                
    930                 if (consoles[i].frontbuf == NULL) {
    931                         printf("%s: Unable to allocate frontbuffer %zu\n", NAME, i);
    932                         return false;
    933                 }
    934                
    935                 consoles[i].fbid = fb_frontbuf_create(fb_sess, consoles[i].frontbuf);
    936                 if (consoles[i].fbid == 0) {
    937                         printf("%s: Unable to create frontbuffer %zu\n", NAME, i);
    938                         return false;
    939                 }
    940                
    941                 prodcons_initialize(&consoles[i].input_pc);
    942                 cons_redraw_state(&consoles[i]);
    943                
    944                 char vc[LOC_NAME_MAXLEN + 1];
    945                 snprintf(vc, LOC_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i);
    946                
    947                 if (loc_service_register(vc, &consoles[i].dsid) != EOK) {
    948                         printf("%s: Unable to register device %s\n", NAME, vc);
    949                         return false;
    950                 }
    951         }
     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();
    952840       
    953841        /* Receive kernel notifications */
    954842        async_set_interrupt_received(interrupt_received);
    955         rc = event_subscribe(EVENT_KCONSOLE, 0);
    956         if (rc != EOK)
    957                 printf("%s: Failed to register kconsole notifications (%s)\n",
    958                     NAME, str_error(rc));
     843        if (event_subscribe(EVENT_KCONSOLE, 0) != EOK)
     844                printf("%s: Error registering kconsole notifications\n", NAME);
    959845       
    960846        return true;
     
    963849static void usage(void)
    964850{
    965         printf("Usage: console <input_dev> <framebuffer_dev>\n");
     851        printf("Usage: console <input_dev>\n");
    966852}
    967853
    968854int main(int argc, char *argv[])
    969855{
    970         if (argc < 3) {
     856        if (argc < 2) {
    971857                usage();
    972858                return -1;
    973859        }
    974860       
    975         printf("%s: HelenOS Console service\n", NAME);
    976        
    977         if (!console_srv_init(argv[1], argv[2]))
     861        printf(NAME ": HelenOS Console service\n");
     862       
     863        if (!console_srv_init(argv[1]))
    978864                return -1;
    979865       
    980         printf("%s: Accepting connections\n", NAME);
    981         task_retval(0);
     866        printf(NAME ": Accepting connections\n");
    982867        async_manager();
    983868       
Note: See TracChangeset for help on using the changeset viewer.