Ignore:
File:
1 edited

Legend:

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

    r024fcc5 rffa2c8ef  
    11/*
    2  * Copyright (c) 2011 Martin Decky
     2 * Copyright (c) 2006 Josef Cejka
    33 * All rights reserved.
    44 *
     
    3333 */
    3434
     35#include <libc.h>
     36#include <ipc/kbd.h>
     37#include <io/keycode.h>
     38#include <ipc/mouse.h>
     39#include <ipc/fb.h>
     40#include <ipc/services.h>
     41#include <ipc/ns.h>
     42#include <errno.h>
     43#include <ipc/console.h>
     44#include <unistd.h>
    3545#include <async.h>
     46#include <adt/fifo.h>
     47#include <sys/mman.h>
    3648#include <stdio.h>
    37 #include <adt/prodcons.h>
    38 #include <ipc/input.h>
    39 #include <ipc/console.h>
    40 #include <ipc/vfs.h>
    41 #include <errno.h>
    42 #include <str_error.h>
    43 #include <loc.h>
     49#include <str.h>
     50#include <sysinfo.h>
    4451#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>
     52#include <devmap.h>
     53#include <fcntl.h>
     54#include <vfs/vfs.h>
    5255#include <fibril_synch.h>
    53 #include "images.h"
     56#include <io/style.h>
     57#include <io/screenbuffer.h>
     58
    5459#include "console.h"
     60#include "gcons.h"
     61#include "keybuffer.h"
     62
    5563
    5664#define NAME       "console"
    5765#define NAMESPACE  "term"
    5866
    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;
     67/** Phone to the keyboard driver. */
     68static int kbd_phone;
     69
     70/** Phone to the mouse driver. */
     71static int mouse_phone;
     72
     73/** Information about framebuffer */
     74struct {
     75        int phone;           /**< Framebuffer phone */
     76        sysarg_t cols;       /**< Framebuffer columns */
     77        sysarg_t rows;       /**< Framebuffer rows */
     78        sysarg_t color_cap;  /**< Color capabilities (FB_CCAP_xxx) */
     79} fb_info;
    7780
    7881typedef 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 */
     82        size_t index;             /**< Console index */
     83        size_t refcount;          /**< Connection reference count */
     84        devmap_handle_t devmap_handle;  /**< Device handle */
     85        keybuffer_t keybuffer;    /**< Buffer for incoming keys. */
     86        screenbuffer_t scr;       /**< Screenbuffer for saving screen
     87                                       contents and related settings. */
    9588} 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;
    11889
    11990/** Array of data for virtual consoles */
    12091static console_t consoles[CONSOLE_COUNT];
    12192
    122 /** Mutex for console switching */
    123 static FIBRIL_MUTEX_INITIALIZE(switch_mtx);
    124 
     93static console_t *active_console = &consoles[0];
    12594static console_t *prev_console = &consoles[0];
    126 static console_t *active_console = &consoles[0];
    12795static console_t *kernel_console = &consoles[KERNEL_CONSOLE];
    12896
    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 
     97/** Pointer to memory shared with framebufer used for
     98    faster virtual console switching */
     99static keyfield_t *interbuffer = NULL;
     100
     101/** Information on row-span yet unsent to FB driver. */
    160102struct {
    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);
    312                 return;
    313         }
    314        
    315         if (cons == kernel_console) {
    316                 fb_yield(fb_sess);
    317                 if (!console_kcon()) {
    318                         fb_claim(fb_sess);
    319                         fibril_mutex_unlock(&switch_mtx);
    320                         return;
    321                 }
    322         }
    323        
    324         if (active_console == kernel_console)
    325                 fb_claim(fb_sess);
    326        
    327         prev_console = active_console;
    328         active_console = cons;
    329        
    330         if (prev_console->state == CONS_DISCONNECTED_SELECTED)
    331                 cons_update_state(prev_console, CONS_DISCONNECTED);
    332         else
    333                 cons_update_state(prev_console, CONS_IDLE);
    334        
    335         if ((cons->state == CONS_DISCONNECTED) ||
    336             (cons->state == CONS_DISCONNECTED_SELECTED))
    337                 cons_update_state(cons, CONS_DISCONNECTED_SELECTED);
    338         else
    339                 cons_update_state(cons, CONS_SELECTED);
    340        
    341         fibril_mutex_unlock(&switch_mtx);
    342        
    343         cons_damage_all(cons);
    344 }
    345 
    346 static console_t *cons_get_active_uspace(void)
    347 {
    348         fibril_mutex_lock(&switch_mtx);
    349 
    350         console_t *active_uspace = active_console;
    351         if (active_uspace == kernel_console) {
    352                 active_uspace = prev_console;
    353         }
    354         assert(active_uspace != kernel_console);
    355 
    356         fibril_mutex_unlock(&switch_mtx);
    357 
    358         return active_uspace;
    359 }
    360 
    361 static ssize_t limit(ssize_t val, ssize_t lo, ssize_t hi)
    362 {
    363         if (val > hi)
    364                 return hi;
    365        
    366         if (val < lo)
    367                 return lo;
    368        
    369         return val;
    370 }
    371 
    372 static void cons_mouse_move(sysarg_t dx, sysarg_t dy)
    373 {
    374         ssize_t sx = (ssize_t) dx;
    375         ssize_t sy = (ssize_t) dy;
    376        
    377         mouse.x = limit(mouse.x + sx, 0, xres);
    378         mouse.y = limit(mouse.y + sy, 0, yres);
    379        
    380         fb_pointer_update(fb_sess, mouse.x, mouse.y, true);
    381 }
    382 
    383 static console_t *cons_find_icon(sysarg_t x, sysarg_t y)
    384 {
    385         sysarg_t status_start =
    386             STATE_START + (xres - 800) / 2 + CONSOLE_MARGIN;
    387        
    388         if ((y < STATE_TOP) || (y >= STATE_TOP + STATE_HEIGHT))
    389                 return NULL;
    390        
    391         if (x < status_start)
    392                 return NULL;
    393        
    394         if (x >= status_start + (STATE_WIDTH + STATE_SPACE) * CONSOLE_COUNT)
    395                 return NULL;
    396        
    397         if (((x - status_start) % (STATE_WIDTH + STATE_SPACE)) >= STATE_WIDTH)
    398                 return NULL;
    399        
    400         sysarg_t btn = (x - status_start) / (STATE_WIDTH + STATE_SPACE);
    401        
    402         if (btn < CONSOLE_COUNT)
    403                 return consoles + btn;
    404        
    405         return NULL;
    406 }
    407 
    408 /** Handle mouse click
     103        sysarg_t col;  /**< Leftmost column of the span. */
     104        sysarg_t row;  /**< Row where the span lies. */
     105        sysarg_t cnt;  /**< Width of the span. */
     106} fb_pending;
     107
     108static FIBRIL_MUTEX_INITIALIZE(input_mutex);
     109static FIBRIL_CONDVAR_INITIALIZE(input_cv);
     110
     111static void curs_visibility(bool visible)
     112{
     113        async_msg_1(fb_info.phone, FB_CURSOR_VISIBILITY, visible);
     114}
     115
     116static void curs_hide_sync(void)
     117{
     118        async_req_1_0(fb_info.phone, FB_CURSOR_VISIBILITY, false);
     119}
     120
     121static void curs_goto(sysarg_t x, sysarg_t y)
     122{
     123        async_msg_2(fb_info.phone, FB_CURSOR_GOTO, x, y);
     124}
     125
     126static void screen_clear(void)
     127{
     128        async_msg_0(fb_info.phone, FB_CLEAR);
     129}
     130
     131static void screen_yield(void)
     132{
     133        async_req_0_0(fb_info.phone, FB_SCREEN_YIELD);
     134}
     135
     136static void screen_reclaim(void)
     137{
     138        async_req_0_0(fb_info.phone, FB_SCREEN_RECLAIM);
     139}
     140
     141static void kbd_yield(void)
     142{
     143        async_req_0_0(kbd_phone, KBD_YIELD);
     144}
     145
     146static void kbd_reclaim(void)
     147{
     148        async_req_0_0(kbd_phone, KBD_RECLAIM);
     149}
     150
     151static void set_style(uint8_t style)
     152{
     153        async_msg_1(fb_info.phone, FB_SET_STYLE, style);
     154}
     155
     156static void set_color(uint8_t fgcolor, uint8_t bgcolor, uint8_t flags)
     157{
     158        async_msg_3(fb_info.phone, FB_SET_COLOR, fgcolor, bgcolor, flags);
     159}
     160
     161static void set_rgb_color(uint32_t fgcolor, uint32_t bgcolor)
     162{
     163        async_msg_2(fb_info.phone, FB_SET_RGB_COLOR, fgcolor, bgcolor);
     164}
     165
     166static void set_attrs(attrs_t *attrs)
     167{
     168        switch (attrs->t) {
     169        case at_style:
     170                set_style(attrs->a.s.style);
     171                break;
     172        case at_idx:
     173                set_color(attrs->a.i.fg_color, attrs->a.i.bg_color,
     174                    attrs->a.i.flags);
     175                break;
     176        case at_rgb:
     177                set_rgb_color(attrs->a.r.fg_color, attrs->a.r.bg_color);
     178                break;
     179        }
     180}
     181
     182static int ccap_fb_to_con(sysarg_t ccap_fb, sysarg_t *ccap_con)
     183{
     184        switch (ccap_fb) {
     185        case FB_CCAP_NONE:
     186                *ccap_con = CONSOLE_CCAP_NONE;
     187                break;
     188        case FB_CCAP_STYLE:
     189                *ccap_con = CONSOLE_CCAP_STYLE;
     190                break;
     191        case FB_CCAP_INDEXED:
     192                *ccap_con = CONSOLE_CCAP_INDEXED;
     193                break;
     194        case FB_CCAP_RGB:
     195                *ccap_con = CONSOLE_CCAP_RGB;
     196                break;
     197        default:
     198                return EINVAL;
     199        }
     200       
     201        return EOK;
     202}
     203
     204/** Send an area of screenbuffer to the FB driver. */
     205static void fb_update_area(console_t *cons, sysarg_t x0, sysarg_t y0, sysarg_t width, sysarg_t height)
     206{
     207        if (interbuffer) {
     208                sysarg_t x;
     209                sysarg_t y;
     210               
     211                for (y = 0; y < height; y++) {
     212                        for (x = 0; x < width; x++) {
     213                                interbuffer[y * width + x] =
     214                                    *get_field_at(&cons->scr, x0 + x, y0 + y);
     215                        }
     216                }
     217               
     218                async_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA,
     219                    x0, y0, width, height);
     220        }
     221}
     222
     223/** Flush pending cells to FB. */
     224static void fb_pending_flush(void)
     225{
     226        if (fb_pending.cnt > 0) {
     227                fb_update_area(active_console, fb_pending.col,
     228                    fb_pending.row, fb_pending.cnt, 1);
     229                fb_pending.cnt = 0;
     230        }
     231}
     232
     233/** Mark a character cell as changed.
    409234 *
    410  * @param state Button state (true - pressed, false - depressed)
     235 * This adds the cell to the pending rowspan if possible. Otherwise
     236 * the old span is flushed first.
    411237 *
    412238 */
    413 static console_t *cons_mouse_button(bool state)
    414 {
    415         if (graphics_state != GRAPHICS_FULL)
    416                 return NULL;
    417        
    418         if (state) {
    419                 console_t *cons = cons_find_icon(mouse.x, mouse.y);
    420                 if (cons != NULL) {
    421                         mouse.btn_x = mouse.x;
    422                         mouse.btn_y = mouse.y;
    423                         mouse.pressed = true;
    424                 }
    425                
    426                 return NULL;
    427         }
    428        
    429         if ((!state) && (!mouse.pressed))
    430                 return NULL;
    431        
    432         console_t *cons = cons_find_icon(mouse.x, mouse.y);
    433         if (cons == cons_find_icon(mouse.btn_x, mouse.btn_y))
    434                 return cons;
    435        
    436         mouse.pressed = false;
    437         return NULL;
    438 }
    439 
    440 static void input_events(ipc_callid_t iid, ipc_call_t *icall, void *arg)
     239static void cell_mark_changed(sysarg_t col, sysarg_t row)
     240{
     241        if (fb_pending.cnt != 0) {
     242                if ((col != fb_pending.col + fb_pending.cnt)
     243                    || (row != fb_pending.row)) {
     244                        fb_pending_flush();
     245                }
     246        }
     247       
     248        if (fb_pending.cnt == 0) {
     249                fb_pending.col = col;
     250                fb_pending.row = row;
     251        }
     252       
     253        fb_pending.cnt++;
     254}
     255
     256/** Print a character to the active VC with buffering. */
     257static void fb_putchar(wchar_t c, sysarg_t col, sysarg_t row)
     258{
     259        async_msg_3(fb_info.phone, FB_PUTCHAR, c, col, row);
     260}
     261
     262/** Process a character from the client (TTY emulation). */
     263static void write_char(console_t *cons, wchar_t ch)
     264{
     265        bool flush_cursor = false;
     266       
     267        switch (ch) {
     268        case '\n':
     269                fb_pending_flush();
     270                flush_cursor = true;
     271                cons->scr.position_y++;
     272                cons->scr.position_x = 0;
     273                break;
     274        case '\r':
     275                break;
     276        case '\t':
     277                cons->scr.position_x += 8;
     278                cons->scr.position_x -= cons->scr.position_x % 8;
     279                break;
     280        case '\b':
     281                if (cons->scr.position_x == 0)
     282                        break;
     283                cons->scr.position_x--;
     284                if (cons == active_console)
     285                        cell_mark_changed(cons->scr.position_x, cons->scr.position_y);
     286                screenbuffer_putchar(&cons->scr, ' ');
     287                break;
     288        default:
     289                if (cons == active_console)
     290                        cell_mark_changed(cons->scr.position_x, cons->scr.position_y);
     291               
     292                screenbuffer_putchar(&cons->scr, ch);
     293                cons->scr.position_x++;
     294        }
     295       
     296        if (cons->scr.position_x >= cons->scr.size_x) {
     297                flush_cursor = true;
     298                cons->scr.position_y++;
     299        }
     300       
     301        if (cons->scr.position_y >= cons->scr.size_y) {
     302                fb_pending_flush();
     303                cons->scr.position_y = cons->scr.size_y - 1;
     304                screenbuffer_clear_line(&cons->scr, cons->scr.top_line);
     305                cons->scr.top_line = (cons->scr.top_line + 1) % cons->scr.size_y;
     306               
     307                if (cons == active_console)
     308                        async_msg_1(fb_info.phone, FB_SCROLL, 1);
     309        }
     310       
     311        if (cons == active_console && flush_cursor)
     312                curs_goto(cons->scr.position_x, cons->scr.position_y);
     313        cons->scr.position_x = cons->scr.position_x % cons->scr.size_x;
     314}
     315
     316/** Switch to new console */
     317static void change_console(console_t *cons)
     318{
     319        if (cons == active_console)
     320                return;
     321       
     322        fb_pending_flush();
     323       
     324        if (cons == kernel_console) {
     325                async_serialize_start();
     326                curs_hide_sync();
     327                gcons_in_kernel();
     328                screen_yield();
     329                kbd_yield();
     330                async_serialize_end();
     331               
     332                if (__SYSCALL0(SYS_DEBUG_ENABLE_CONSOLE)) {
     333                        prev_console = active_console;
     334                        active_console = kernel_console;
     335                } else
     336                        cons = active_console;
     337        }
     338       
     339        if (cons != kernel_console) {
     340                async_serialize_start();
     341               
     342                if (active_console == kernel_console) {
     343                        screen_reclaim();
     344                        kbd_reclaim();
     345                        gcons_redraw_console();
     346                }
     347               
     348                active_console = cons;
     349                gcons_change_console(cons->index);
     350               
     351                set_attrs(&cons->scr.attrs);
     352                curs_visibility(false);
     353               
     354                sysarg_t x;
     355                sysarg_t y;
     356                int rc = 0;
     357               
     358                if (interbuffer) {
     359                        for (y = 0; y < cons->scr.size_y; y++) {
     360                                for (x = 0; x < cons->scr.size_x; x++) {
     361                                        interbuffer[y * cons->scr.size_x + x] =
     362                                            *get_field_at(&cons->scr, x, y);
     363                                }
     364                        }
     365                       
     366                        /* This call can preempt, but we are already at the end */
     367                        rc = async_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA,
     368                            0, 0, cons->scr.size_x,
     369                            cons->scr.size_y);
     370                }
     371               
     372                if ((!interbuffer) || (rc != 0)) {
     373                        set_attrs(&cons->scr.attrs);
     374                        screen_clear();
     375                       
     376                        for (y = 0; y < cons->scr.size_y; y++)
     377                                for (x = 0; x < cons->scr.size_x; x++) {
     378                                        keyfield_t *field = get_field_at(&cons->scr, x, y);
     379                                       
     380                                        if (!attrs_same(cons->scr.attrs, field->attrs))
     381                                                set_attrs(&field->attrs);
     382                                       
     383                                        cons->scr.attrs = field->attrs;
     384                                        if ((field->character == ' ') &&
     385                                            (attrs_same(field->attrs, cons->scr.attrs)))
     386                                                continue;
     387                                       
     388                                        fb_putchar(field->character, x, y);
     389                                }
     390                }
     391               
     392                curs_goto(cons->scr.position_x, cons->scr.position_y);
     393                curs_visibility(cons->scr.is_cursor_visible);
     394               
     395                async_serialize_end();
     396        }
     397}
     398
     399/** Handler for keyboard */
     400static void keyboard_events(ipc_callid_t iid, ipc_call_t *icall)
    441401{
    442402        /* Ignore parameters, the connection is already opened */
     
    445405                ipc_callid_t callid = async_get_call(&call);
    446406               
    447                 if (!IPC_GET_IMETHOD(call)) {
     407                int retval;
     408                console_event_t ev;
     409               
     410                switch (IPC_GET_IMETHOD(call)) {
     411                case IPC_M_PHONE_HUNGUP:
    448412                        /* TODO: Handle hangup */
    449                         async_hangup(input_sess);
    450413                        return;
    451                 }
    452                
    453                 kbd_event_type_t type;
    454                 keycode_t key;
    455                 keymod_t mods;
    456                 wchar_t c;
    457                
    458                 switch (IPC_GET_IMETHOD(call)) {
    459                 case INPUT_EVENT_KEY:
    460                         type = IPC_GET_ARG1(call);
    461                         key = IPC_GET_ARG2(call);
    462                         mods = IPC_GET_ARG3(call);
    463                         c = IPC_GET_ARG4(call);
     414                case KBD_EVENT:
     415                        /* Got event from keyboard driver. */
     416                        retval = 0;
     417                        ev.type = IPC_GET_ARG1(call);
     418                        ev.key = IPC_GET_ARG2(call);
     419                        ev.mods = IPC_GET_ARG3(call);
     420                        ev.c = IPC_GET_ARG4(call);
    464421                       
    465                         if ((key >= KC_F1) && (key < KC_F1 + CONSOLE_COUNT) &&
    466                             ((mods & KM_CTRL) == 0))
    467                                 cons_switch(&consoles[key - KC_F1]);
    468                         else {
    469                                 /* Got key press/release event */
    470                                 kbd_event_t *event =
    471                                     (kbd_event_t *) malloc(sizeof(kbd_event_t));
    472                                 if (event == NULL) {
    473                                         async_answer_0(callid, ENOMEM);
    474                                         break;
    475                                 }
    476                                
    477                                 link_initialize(&event->link);
    478                                 event->type = type;
    479                                 event->key = key;
    480                                 event->mods = mods;
    481                                 event->c = c;
    482                                
    483                                 /* Kernel console does not read events
    484                                  * from us, so we will redirect them
    485                                  * to the (last) active userspace console
    486                                  * if necessary.
    487                                  */
    488                                 console_t *target_console = cons_get_active_uspace();
    489 
    490                                 prodcons_produce(&target_console->input_pc,
    491                                     &event->link);
     422                        if ((ev.key >= KC_F1) && (ev.key < KC_F1 +
     423                            CONSOLE_COUNT) && ((ev.mods & KM_CTRL) == 0)) {
     424                                if (ev.key == KC_F1 + KERNEL_CONSOLE)
     425                                        change_console(kernel_console);
     426                                else
     427                                        change_console(&consoles[ev.key - KC_F1]);
     428                                break;
    492429                        }
    493430                       
    494                         async_answer_0(callid, EOK);
    495                         break;
    496                 case INPUT_EVENT_MOVE:
    497                         cons_mouse_move(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
    498                         async_answer_0(callid, EOK);
    499                         break;
    500                 case INPUT_EVENT_BUTTON:
    501                         /* Got pointer button press/release event */
     431                        fibril_mutex_lock(&input_mutex);
     432                        keybuffer_push(&active_console->keybuffer, &ev);
     433                        fibril_condvar_broadcast(&input_cv);
     434                        fibril_mutex_unlock(&input_mutex);
     435                        break;
     436                default:
     437                        retval = ENOENT;
     438                }
     439                async_answer_0(callid, retval);
     440        }
     441}
     442
     443/** Handler for mouse events */
     444static void mouse_events(ipc_callid_t iid, ipc_call_t *icall)
     445{
     446        /* Ignore parameters, the connection is already opened */
     447        while (true) {
     448                ipc_call_t call;
     449                ipc_callid_t callid = async_get_call(&call);
     450               
     451                int retval;
     452               
     453                switch (IPC_GET_IMETHOD(call)) {
     454                case IPC_M_PHONE_HUNGUP:
     455                        /* TODO: Handle hangup */
     456                        return;
     457                case MEVENT_BUTTON:
    502458                        if (IPC_GET_ARG1(call) == 1) {
    503                                 console_t *cons =
    504                                     cons_mouse_button((bool) IPC_GET_ARG2(call));
    505                                 if (cons != NULL)
    506                                         cons_switch(cons);
     459                                int newcon = gcons_mouse_btn((bool) IPC_GET_ARG2(call));
     460                                if (newcon != -1)
     461                                        change_console(&consoles[newcon]);
    507462                        }
    508                         async_answer_0(callid, EOK);
     463                        retval = 0;
     464                        break;
     465                case MEVENT_MOVE:
     466                        gcons_mouse_move((int) IPC_GET_ARG1(call),
     467                            (int) IPC_GET_ARG2(call));
     468                        retval = 0;
    509469                        break;
    510470                default:
    511                         async_answer_0(callid, EINVAL);
    512                 }
    513         }
    514 }
    515 
    516 /** Process a character from the client (TTY emulation). */
    517 static void cons_write_char(console_t *cons, wchar_t ch)
    518 {
    519         sysarg_t updated = 0;
    520        
    521         fibril_mutex_lock(&cons->mtx);
    522        
    523         switch (ch) {
    524         case '\n':
    525                 updated = screenbuffer_newline(cons->frontbuf);
    526                 break;
    527         case '\r':
    528                 break;
    529         case '\t':
    530                 updated = screenbuffer_tabstop(cons->frontbuf, 8);
    531                 break;
    532         case '\b':
    533                 updated = screenbuffer_backspace(cons->frontbuf);
    534                 break;
    535         default:
    536                 updated = screenbuffer_putchar(cons->frontbuf, ch, true);
    537         }
    538        
    539         fibril_mutex_unlock(&cons->mtx);
    540        
    541         if (updated > 1)
    542                 cons_update(cons);
    543 }
    544 
    545 static void cons_set_cursor(console_t *cons, sysarg_t col, sysarg_t row)
    546 {
    547         fibril_mutex_lock(&cons->mtx);
    548         screenbuffer_set_cursor(cons->frontbuf, col, row);
    549         fibril_mutex_unlock(&cons->mtx);
    550        
    551         cons_update_cursor(cons);
    552 }
    553 
    554 static void cons_set_cursor_visibility(console_t *cons, bool visible)
    555 {
    556         fibril_mutex_lock(&cons->mtx);
    557         screenbuffer_set_cursor_visibility(cons->frontbuf, visible);
    558         fibril_mutex_unlock(&cons->mtx);
    559        
    560         cons_update_cursor(cons);
    561 }
    562 
    563 static void cons_get_cursor(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
    564 {
    565         sysarg_t col;
    566         sysarg_t row;
    567        
    568         fibril_mutex_lock(&cons->mtx);
    569         screenbuffer_get_cursor(cons->frontbuf, &col, &row);
    570         fibril_mutex_unlock(&cons->mtx);
    571        
    572         async_answer_2(iid, EOK, col, row);
    573 }
    574 
    575 static void cons_write(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
     471                        retval = ENOENT;
     472                }
     473
     474                async_answer_0(callid, retval);
     475        }
     476}
     477
     478static void cons_write(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
    576479{
    577480        void *buf;
     
    580483       
    581484        if (rc != EOK) {
    582                 async_answer_0(iid, rc);
     485                async_answer_0(rid, rc);
    583486                return;
    584487        }
    585488       
     489        async_serialize_start();
     490       
    586491        size_t off = 0;
    587         while (off < size)
    588                 cons_write_char(cons, str_decode(buf, &off, size));
    589        
    590         async_answer_1(iid, EOK, size);
     492        while (off < size) {
     493                wchar_t ch = str_decode(buf, &off, size);
     494                write_char(cons, ch);
     495        }
     496       
     497        async_serialize_end();
     498       
     499        gcons_notify_char(cons->index);
     500        async_answer_1(rid, EOK, size);
     501       
    591502        free(buf);
    592        
    593         cons_notify_data(cons);
    594 }
    595 
    596 static void cons_read(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
     503}
     504
     505static void cons_read(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
    597506{
    598507        ipc_callid_t callid;
     
    600509        if (!async_data_read_receive(&callid, &size)) {
    601510                async_answer_0(callid, EINVAL);
    602                 async_answer_0(iid, EINVAL);
     511                async_answer_0(rid, EINVAL);
    603512                return;
    604513        }
     
    607516        if (buf == NULL) {
    608517                async_answer_0(callid, ENOMEM);
    609                 async_answer_0(iid, ENOMEM);
     518                async_answer_0(rid, ENOMEM);
    610519                return;
    611520        }
    612521       
    613522        size_t pos = 0;
    614         while (pos < size) {
    615                 link_t *link = prodcons_consume(&cons->input_pc);
    616                 kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
    617                
    618                 if (event->type == KEY_PRESS) {
    619                         buf[pos] = event->c;
     523        console_event_t ev;
     524        fibril_mutex_lock(&input_mutex);
     525       
     526recheck:
     527        while ((keybuffer_pop(&cons->keybuffer, &ev)) && (pos < size)) {
     528                if (ev.type == KEY_PRESS) {
     529                        buf[pos] = ev.c;
    620530                        pos++;
    621531                }
    622                
    623                 free(event);
    624         }
    625        
    626         (void) async_data_read_finalize(callid, buf, size);
    627         async_answer_1(iid, EOK, size);
    628         free(buf);
    629 }
    630 
    631 static void cons_set_style(console_t *cons, console_style_t style)
    632 {
    633         fibril_mutex_lock(&cons->mtx);
    634         screenbuffer_set_style(cons->frontbuf, style);
    635         fibril_mutex_unlock(&cons->mtx);
    636 }
    637 
    638 static void cons_set_color(console_t *cons, console_color_t bgcolor,
    639     console_color_t fgcolor, console_color_attr_t attr)
    640 {
    641         fibril_mutex_lock(&cons->mtx);
    642         screenbuffer_set_color(cons->frontbuf, bgcolor, fgcolor, attr);
    643         fibril_mutex_unlock(&cons->mtx);
    644 }
    645 
    646 static void cons_set_rgb_color(console_t *cons, pixel_t bgcolor,
    647     pixel_t fgcolor)
    648 {
    649         fibril_mutex_lock(&cons->mtx);
    650         screenbuffer_set_rgb_color(cons->frontbuf, bgcolor, fgcolor);
    651         fibril_mutex_unlock(&cons->mtx);
    652 }
    653 
    654 static void cons_get_event(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
    655 {
    656         link_t *link = prodcons_consume(&cons->input_pc);
    657         kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
    658        
    659         async_answer_4(iid, EOK, event->type, event->key, event->mods, event->c);
    660         free(event);
    661 }
    662 
    663 static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
     532        }
     533       
     534        if (pos == size) {
     535                (void) async_data_read_finalize(callid, buf, size);
     536                async_answer_1(rid, EOK, size);
     537                free(buf);
     538        } else {
     539                fibril_condvar_wait(&input_cv, &input_mutex);
     540                goto recheck;
     541        }
     542       
     543        fibril_mutex_unlock(&input_mutex);
     544}
     545
     546static void cons_get_event(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
     547{
     548        console_event_t ev;
     549       
     550        fibril_mutex_lock(&input_mutex);
     551       
     552recheck:
     553        if (keybuffer_pop(&cons->keybuffer, &ev)) {
     554                async_answer_4(rid, EOK, ev.type, ev.key, ev.mods, ev.c);
     555        } else {
     556                fibril_condvar_wait(&input_cv, &input_mutex);
     557                goto recheck;
     558        }
     559       
     560        fibril_mutex_unlock(&input_mutex);
     561}
     562
     563/** Default thread for new connections */
     564static void client_connection(ipc_callid_t iid, ipc_call_t *icall)
    664565{
    665566        console_t *cons = NULL;
    666567       
    667         for (size_t i = 0; i < CONSOLE_COUNT; i++) {
     568        size_t i;
     569        for (i = 0; i < CONSOLE_COUNT; i++) {
    668570                if (i == KERNEL_CONSOLE)
    669571                        continue;
    670572               
    671                 if (consoles[i].dsid == (service_id_t) IPC_GET_ARG1(*icall)) {
     573                if (consoles[i].devmap_handle == (devmap_handle_t) IPC_GET_ARG1(*icall)) {
    672574                        cons = &consoles[i];
    673575                        break;
     
    680582        }
    681583       
    682         if (atomic_postinc(&cons->refcnt) == 0) {
    683                 cons_set_cursor_visibility(cons, true);
    684                 cons_notify_connect(cons);
    685         }
     584        ipc_callid_t callid;
     585        ipc_call_t call;
     586        sysarg_t arg1;
     587        sysarg_t arg2;
     588        sysarg_t arg3;
     589       
     590        int rc;
     591       
     592        async_serialize_start();
     593        if (cons->refcount == 0)
     594                gcons_notify_connect(cons->index);
     595       
     596        cons->refcount++;
    686597       
    687598        /* Accept the connection */
     
    689600       
    690601        while (true) {
    691                 ipc_call_t call;
    692                 ipc_callid_t callid = async_get_call(&call);
    693                
    694                 if (!IPC_GET_IMETHOD(call)) {
    695                         if (atomic_postdec(&cons->refcnt) == 1)
    696                                 cons_notify_disconnect(cons);
     602                async_serialize_end();
     603                callid = async_get_call(&call);
     604                async_serialize_start();
     605               
     606                arg1 = 0;
     607                arg2 = 0;
     608                arg3 = 0;
     609               
     610                switch (IPC_GET_IMETHOD(call)) {
     611                case IPC_M_PHONE_HUNGUP:
     612                        cons->refcount--;
     613                        if (cons->refcount == 0)
     614                                gcons_notify_disconnect(cons->index);
     615                        return;
     616                case VFS_OUT_READ:
     617                        async_serialize_end();
     618                        cons_read(cons, callid, &call);
     619                        async_serialize_start();
     620                        continue;
     621                case VFS_OUT_WRITE:
     622                        async_serialize_end();
     623                        cons_write(cons, callid, &call);
     624                        async_serialize_start();
     625                        continue;
     626                case VFS_OUT_SYNC:
     627                        fb_pending_flush();
     628                        if (cons == active_console) {
     629                                async_req_0_0(fb_info.phone, FB_FLUSH);
     630                                curs_goto(cons->scr.position_x, cons->scr.position_y);
     631                        }
     632                        break;
     633                case CONSOLE_CLEAR:
     634                        /* Send message to fb */
     635                        if (cons == active_console)
     636                                async_msg_0(fb_info.phone, FB_CLEAR);
    697637                       
    698                         return;
    699                 }
    700                
    701                 switch (IPC_GET_IMETHOD(call)) {
    702                 case VFS_OUT_READ:
    703                         cons_read(cons, callid, &call);
    704                         break;
    705                 case VFS_OUT_WRITE:
    706                         cons_write(cons, callid, &call);
    707                         break;
    708                 case VFS_OUT_SYNC:
    709                         cons_update(cons);
    710                         async_answer_0(callid, EOK);
    711                         break;
    712                 case CONSOLE_CLEAR:
    713                         cons_clear(cons);
    714                         async_answer_0(callid, EOK);
     638                        screenbuffer_clear(&cons->scr);
     639                       
    715640                        break;
    716641                case CONSOLE_GOTO:
    717                         cons_set_cursor(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
    718                         async_answer_0(callid, EOK);
     642                        screenbuffer_goto(&cons->scr,
     643                            IPC_GET_ARG1(call), IPC_GET_ARG2(call));
     644                        if (cons == active_console)
     645                                curs_goto(IPC_GET_ARG1(call),
     646                                    IPC_GET_ARG2(call));
    719647                        break;
    720648                case CONSOLE_GET_POS:
    721                         cons_get_cursor(cons, callid, &call);
     649                        arg1 = cons->scr.position_x;
     650                        arg2 = cons->scr.position_y;
    722651                        break;
    723652                case CONSOLE_GET_SIZE:
    724                         async_answer_2(callid, EOK, cons->cols, cons->rows);
     653                        arg1 = fb_info.cols;
     654                        arg2 = fb_info.rows;
    725655                        break;
    726656                case CONSOLE_GET_COLOR_CAP:
    727                         async_answer_1(callid, EOK, cons->ccaps);
     657                        rc = ccap_fb_to_con(fb_info.color_cap, &arg1);
     658                        if (rc != EOK) {
     659                                async_answer_0(callid, rc);
     660                                continue;
     661                        }
    728662                        break;
    729663                case CONSOLE_SET_STYLE:
    730                         cons_set_style(cons, IPC_GET_ARG1(call));
    731                         async_answer_0(callid, EOK);
     664                        fb_pending_flush();
     665                        arg1 = IPC_GET_ARG1(call);
     666                        screenbuffer_set_style(&cons->scr, arg1);
     667                        if (cons == active_console)
     668                                set_style(arg1);
    732669                        break;
    733670                case CONSOLE_SET_COLOR:
    734                         cons_set_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call),
    735                             IPC_GET_ARG3(call));
    736                         async_answer_0(callid, EOK);
     671                        fb_pending_flush();
     672                        arg1 = IPC_GET_ARG1(call);
     673                        arg2 = IPC_GET_ARG2(call);
     674                        arg3 = IPC_GET_ARG3(call);
     675                        screenbuffer_set_color(&cons->scr, arg1, arg2, arg3);
     676                        if (cons == active_console)
     677                                set_color(arg1, arg2, arg3);
    737678                        break;
    738679                case CONSOLE_SET_RGB_COLOR:
    739                         cons_set_rgb_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
    740                         async_answer_0(callid, EOK);
     680                        fb_pending_flush();
     681                        arg1 = IPC_GET_ARG1(call);
     682                        arg2 = IPC_GET_ARG2(call);
     683                        screenbuffer_set_rgb_color(&cons->scr, arg1, arg2);
     684                        if (cons == active_console)
     685                                set_rgb_color(arg1, arg2);
    741686                        break;
    742687                case CONSOLE_CURSOR_VISIBILITY:
    743                         cons_set_cursor_visibility(cons, IPC_GET_ARG1(call));
    744                         async_answer_0(callid, EOK);
     688                        fb_pending_flush();
     689                        arg1 = IPC_GET_ARG1(call);
     690                        cons->scr.is_cursor_visible = arg1;
     691                        if (cons == active_console)
     692                                curs_visibility(arg1);
    745693                        break;
    746694                case CONSOLE_GET_EVENT:
     695                        async_serialize_end();
    747696                        cons_get_event(cons, callid, &call);
    748                         break;
    749                 default:
    750                         async_answer_0(callid, EINVAL);
    751                 }
    752         }
    753 }
    754 
    755 static async_sess_t *input_connect(const char *svc)
    756 {
    757         async_sess_t *sess;
    758         service_id_t dsid;
    759        
    760         int rc = loc_service_get_id(svc, &dsid, 0);
    761         if (rc == EOK) {
    762                 sess = loc_service_connect(EXCHANGE_ATOMIC, dsid, 0);
    763                 if (sess == NULL) {
    764                         printf("%s: Unable to connect to input service %s\n", NAME,
    765                             svc);
    766                         return NULL;
    767                 }
    768         } else
    769                 return NULL;
    770        
    771         async_exch_t *exch = async_exchange_begin(sess);
    772         rc = async_connect_to_me(exch, 0, 0, 0, input_events, NULL);
    773         async_exchange_end(exch);
    774        
    775         if (rc != EOK) {
    776                 async_hangup(sess);
    777                 printf("%s: Unable to create callback connection to service %s (%s)\n",
    778                     NAME, svc, str_error(rc));
    779                 return NULL;
    780         }
    781        
    782         return sess;
     697                        async_serialize_start();
     698                        continue;
     699                case CONSOLE_KCON_ENABLE:
     700                        change_console(kernel_console);
     701                        break;
     702                }
     703                async_answer_3(callid, EOK, arg1, arg2, arg3);
     704        }
    783705}
    784706
    785707static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
    786708{
    787         cons_switch(prev_console);
    788 }
    789 
    790 static async_sess_t *fb_connect(const char *svc)
    791 {
    792         async_sess_t *sess;
    793         service_id_t dsid;
    794        
    795         int rc = loc_service_get_id(svc, &dsid, 0);
    796         if (rc == EOK) {
    797                 sess = loc_service_connect(EXCHANGE_SERIALIZE, dsid, 0);
    798                 if (sess == NULL) {
    799                         printf("%s: Unable to connect to framebuffer service %s\n",
    800                             NAME, svc);
    801                         return NULL;
    802                 }
    803         } else
    804                 return NULL;
    805        
    806         return sess;
    807 }
    808 
    809 static bool console_srv_init(char *input_svc, char *fb_svc)
    810 {
    811         /* Avoid double initialization */
    812         if (graphics_state != GRAPHICS_NONE)
     709        change_console(prev_console);
     710}
     711
     712static bool console_init(char *input)
     713{
     714        /* Connect to input device */
     715        int input_fd = open(input, O_RDONLY);
     716        if (input_fd < 0) {
     717                printf(NAME ": Failed opening %s\n", input);
    813718                return false;
    814        
    815         /* Connect to input service */
    816         input_sess = input_connect(input_svc);
    817         if (input_sess == NULL)
     719        }
     720       
     721        kbd_phone = fd_phone(input_fd);
     722        if (kbd_phone < 0) {
     723                printf(NAME ": Failed to connect to input device\n");
    818724                return false;
    819        
    820         /* Connect to framebuffer service */
    821         fb_sess = fb_connect(fb_svc);
    822         if (fb_sess == NULL)
     725        }
     726       
     727        /* NB: The callback connection is slotted for removal */
     728        if (async_connect_to_me(kbd_phone, SERVICE_CONSOLE, 0, 0, keyboard_events)
     729            != 0) {
     730                printf(NAME ": Failed to create callback from input device\n");
    823731                return false;
    824        
    825         /* Register server */
    826         int rc = loc_server_register(NAME, client_connection);
     732        }
     733       
     734        /* Connect to mouse device */
     735        mouse_phone = -1;
     736        int mouse_fd = open("/dev/hid_in/mouse", O_RDONLY);
     737       
     738        if (mouse_fd < 0) {
     739                printf(NAME ": Notice - failed opening %s\n", "/dev/hid_in/mouse");
     740                goto skip_mouse;
     741        }
     742       
     743        mouse_phone = fd_phone(mouse_fd);
     744        if (mouse_phone < 0) {
     745                printf(NAME ": Failed to connect to mouse device\n");
     746                goto skip_mouse;
     747        }
     748       
     749        if (async_connect_to_me(mouse_phone, SERVICE_CONSOLE, 0, 0, mouse_events)
     750            != 0) {
     751                printf(NAME ": Failed to create callback from mouse device\n");
     752                mouse_phone = -1;
     753                goto skip_mouse;
     754        }
     755       
     756skip_mouse:
     757       
     758        /* Connect to framebuffer driver */
     759        fb_info.phone = service_connect_blocking(SERVICE_VIDEO, 0, 0);
     760        if (fb_info.phone < 0) {
     761                printf(NAME ": Failed to connect to video service\n");
     762                return -1;
     763        }
     764       
     765        /* Register driver */
     766        int rc = devmap_driver_register(NAME, client_connection);
    827767        if (rc < 0) {
    828                 printf("%s: Unable to register server (%s)\n", NAME,
    829                     str_error(rc));
     768                printf(NAME ": Unable to register driver (%d)\n", rc);
    830769                return false;
    831770        }
    832771       
    833         fb_get_resolution(fb_sess, &xres, &yres);
     772        /* Initialize gcons */
     773        gcons_init(fb_info.phone);
     774       
     775        /* Synchronize, the gcons could put something in queue */
     776        async_req_0_0(fb_info.phone, FB_FLUSH);
     777        async_req_0_2(fb_info.phone, FB_GET_CSIZE, &fb_info.cols, &fb_info.rows);
     778        async_req_0_1(fb_info.phone, FB_GET_COLOR_CAP, &fb_info.color_cap);
     779       
     780        /* Set up shared memory buffer. */
     781        size_t ib_size = sizeof(keyfield_t) * fb_info.cols * fb_info.rows;
     782        interbuffer = as_get_mappable_page(ib_size);
     783       
     784        if (as_area_create(interbuffer, ib_size, AS_AREA_READ |
     785            AS_AREA_WRITE | AS_AREA_CACHEABLE) != interbuffer)
     786                interbuffer = NULL;
     787       
     788        if (interbuffer) {
     789                if (async_share_out_start(fb_info.phone, interbuffer,
     790                    AS_AREA_READ) != EOK) {
     791                        as_area_destroy(interbuffer);
     792                        interbuffer = NULL;
     793                }
     794        }
     795       
     796        fb_pending.cnt = 0;
     797       
     798        /* Inititalize consoles */
     799        size_t i;
     800        for (i = 0; i < CONSOLE_COUNT; i++) {
     801                if (i != KERNEL_CONSOLE) {
     802                        if (screenbuffer_init(&consoles[i].scr,
     803                            fb_info.cols, fb_info.rows) == NULL) {
     804                                printf(NAME ": Unable to allocate screen buffer %zu\n", i);
     805                                return false;
     806                        }
     807                        screenbuffer_clear(&consoles[i].scr);
     808                        keybuffer_init(&consoles[i].keybuffer);
     809                        consoles[i].index = i;
     810                        consoles[i].refcount = 0;
     811                       
     812                        char vc[DEVMAP_NAME_MAXLEN + 1];
     813                        snprintf(vc, DEVMAP_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i);
     814                       
     815                        if (devmap_device_register(vc, &consoles[i].devmap_handle) != EOK) {
     816                                printf(NAME ": Unable to register device %s\n", vc);
     817                                return false;
     818                        }
     819                }
     820        }
     821       
     822        /* Disable kernel output to the console */
     823        __SYSCALL0(SYS_DEBUG_DISABLE_CONSOLE);
    834824       
    835825        /* Initialize the screen */
    836         screen_vp = fb_vp_create(fb_sess, 0, 0, xres, yres);
    837        
    838         if ((xres >= 800) && (yres >= 600)) {
    839                 logo_vp = fb_vp_create(fb_sess, xres - 66, 2, 64, 60);
    840                 logo_img = imgmap_decode_tga((void *) helenos_tga,
    841                     helenos_tga_size, IMGMAP_FLAG_SHARED);
    842                 logo_handle = fb_imagemap_create(fb_sess, logo_img);
    843                
    844                 nameic_vp = fb_vp_create(fb_sess, 5, 17, 100, 26);
    845                 nameic_img = imgmap_decode_tga((void *) nameic_tga,
    846                     nameic_tga_size, IMGMAP_FLAG_SHARED);
    847                 nameic_handle = fb_imagemap_create(fb_sess, nameic_img);
    848                
    849                 cons_data_img = imgmap_decode_tga((void *) cons_data_tga,
    850                     cons_data_tga_size, IMGMAP_FLAG_SHARED);
    851                 cons_dis_img = imgmap_decode_tga((void *) cons_dis_tga,
    852                     cons_dis_tga_size, IMGMAP_FLAG_SHARED);
    853                 cons_dis_sel_img = imgmap_decode_tga((void *) cons_dis_sel_tga,
    854                     cons_dis_sel_tga_size, IMGMAP_FLAG_SHARED);
    855                 cons_idle_img = imgmap_decode_tga((void *) cons_idle_tga,
    856                     cons_idle_tga_size, IMGMAP_FLAG_SHARED);
    857                 cons_kernel_img = imgmap_decode_tga((void *) cons_kernel_tga,
    858                     cons_kernel_tga_size, IMGMAP_FLAG_SHARED);
    859                 cons_sel_img = imgmap_decode_tga((void *) cons_sel_tga,
    860                     cons_sel_tga_size, IMGMAP_FLAG_SHARED);
    861                
    862                 state_icons[CONS_DISCONNECTED] =
    863                     fb_imagemap_create(fb_sess, cons_dis_img);
    864                 state_icons[CONS_DISCONNECTED_SELECTED] =
    865                     fb_imagemap_create(fb_sess, cons_dis_sel_img);
    866                 state_icons[CONS_SELECTED] =
    867                     fb_imagemap_create(fb_sess, cons_sel_img);
    868                 state_icons[CONS_IDLE] =
    869                     fb_imagemap_create(fb_sess, cons_idle_img);
    870                 state_icons[CONS_DATA] =
    871                     fb_imagemap_create(fb_sess, cons_data_img);
    872                 state_icons[CONS_KERNEL] =
    873                     fb_imagemap_create(fb_sess, cons_kernel_img);
    874                
    875                 anim_1_img = imgmap_decode_tga((void *) anim_1_tga,
    876                     anim_1_tga_size, IMGMAP_FLAG_SHARED);
    877                 anim_2_img = imgmap_decode_tga((void *) anim_2_tga,
    878                     anim_2_tga_size, IMGMAP_FLAG_SHARED);
    879                 anim_3_img = imgmap_decode_tga((void *) anim_3_tga,
    880                     anim_3_tga_size, IMGMAP_FLAG_SHARED);
    881                 anim_4_img = imgmap_decode_tga((void *) anim_4_tga,
    882                     anim_4_tga_size, IMGMAP_FLAG_SHARED);
    883                
    884                 anim_1 = fb_imagemap_create(fb_sess, anim_1_img);
    885                 anim_2 = fb_imagemap_create(fb_sess, anim_2_img);
    886                 anim_3 = fb_imagemap_create(fb_sess, anim_3_img);
    887                 anim_4 = fb_imagemap_create(fb_sess, anim_4_img);
    888                
    889                 anim_seq = fb_sequence_create(fb_sess);
    890                 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_1);
    891                 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_2);
    892                 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_3);
    893                 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_4);
    894                
    895                 console_vp = fb_vp_create(fb_sess, CONSOLE_MARGIN, CONSOLE_TOP,
    896                     xres - 2 * CONSOLE_MARGIN, yres - (CONSOLE_TOP + CONSOLE_MARGIN));
    897                
    898                 fb_vp_clear(fb_sess, screen_vp);
    899                 fb_vp_imagemap_damage(fb_sess, logo_vp, logo_handle,
    900                     0, 0, 64, 60);
    901                 fb_vp_imagemap_damage(fb_sess, nameic_vp, nameic_handle,
    902                     0, 0, 100, 26);
    903                
    904                 graphics_state = GRAPHICS_FULL;
    905         } else {
    906                 console_vp = screen_vp;
    907                 graphics_state = GRAPHICS_BASIC;
    908         }
    909        
    910         fb_vp_set_style(fb_sess, console_vp, STYLE_NORMAL);
    911         fb_vp_clear(fb_sess, console_vp);
    912        
    913         sysarg_t cols;
    914         sysarg_t rows;
    915         fb_vp_get_dimensions(fb_sess, console_vp, &cols, &rows);
    916        
    917         console_caps_t ccaps;
    918         fb_vp_get_caps(fb_sess, console_vp, &ccaps);
    919        
    920         mouse.x = xres / 2;
    921         mouse.y = yres / 2;
    922         mouse.pressed = false;
    923        
    924         /* Inititalize consoles */
    925         for (size_t i = 0; i < CONSOLE_COUNT; i++) {
    926                 consoles[i].index = i;
    927                 atomic_set(&consoles[i].refcnt, 0);
    928                 fibril_mutex_initialize(&consoles[i].mtx);
    929                 prodcons_initialize(&consoles[i].input_pc);
    930                
    931                 if (graphics_state == GRAPHICS_FULL) {
    932                         /* Create state buttons */
    933                         consoles[i].state_vp =
    934                             fb_vp_create(fb_sess, STATE_START + (xres - 800) / 2 +
    935                             CONSOLE_MARGIN + i * (STATE_WIDTH + STATE_SPACE),
    936                             STATE_TOP, STATE_WIDTH, STATE_HEIGHT);
    937                 }
    938                
    939                 if (i == KERNEL_CONSOLE) {
    940                         consoles[i].state = CONS_KERNEL;
    941                         cons_redraw_state(&consoles[i]);
    942                         cons_kernel_sequence_start(&consoles[i]);
    943                         continue;
    944                 }
    945                
    946                 if (i == 0)
    947                         consoles[i].state = CONS_DISCONNECTED_SELECTED;
    948                 else
    949                         consoles[i].state = CONS_DISCONNECTED;
    950                
    951                 consoles[i].cols = cols;
    952                 consoles[i].rows = rows;
    953                 consoles[i].ccaps = ccaps;
    954                 consoles[i].frontbuf =
    955                     screenbuffer_create(cols, rows, SCREENBUFFER_FLAG_SHARED);
    956                
    957                 if (consoles[i].frontbuf == NULL) {
    958                         printf("%s: Unable to allocate frontbuffer %zu\n", NAME, i);
    959                         return false;
    960                 }
    961                
    962                 consoles[i].fbid = fb_frontbuf_create(fb_sess, consoles[i].frontbuf);
    963                 if (consoles[i].fbid == 0) {
    964                         printf("%s: Unable to create frontbuffer %zu\n", NAME, i);
    965                         return false;
    966                 }
    967                
    968                 cons_redraw_state(&consoles[i]);
    969                
    970                 char vc[LOC_NAME_MAXLEN + 1];
    971                 snprintf(vc, LOC_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i);
    972                
    973                 if (loc_service_register(vc, &consoles[i].dsid) != EOK) {
    974                         printf("%s: Unable to register device %s\n", NAME, vc);
    975                         return false;
    976                 }
    977         }
     826        async_serialize_start();
     827        gcons_redraw_console();
     828        set_style(STYLE_NORMAL);
     829        screen_clear();
     830        curs_goto(0, 0);
     831        curs_visibility(active_console->scr.is_cursor_visible);
     832        async_serialize_end();
    978833       
    979834        /* Receive kernel notifications */
    980835        async_set_interrupt_received(interrupt_received);
    981         rc = event_subscribe(EVENT_KCONSOLE, 0);
    982         if (rc != EOK)
    983                 printf("%s: Failed to register kconsole notifications (%s)\n",
    984                     NAME, str_error(rc));
     836        if (event_subscribe(EVENT_KCONSOLE, 0) != EOK)
     837                printf(NAME ": Error registering kconsole notifications\n");
    985838       
    986839        return true;
     
    989842static void usage(void)
    990843{
    991         printf("Usage: console <input_dev> <framebuffer_dev>\n");
     844        printf("Usage: console <input>\n");
    992845}
    993846
    994847int main(int argc, char *argv[])
    995848{
    996         if (argc < 3) {
     849        if (argc < 2) {
    997850                usage();
    998851                return -1;
    999852        }
    1000853       
    1001         printf("%s: HelenOS Console service\n", NAME);
    1002        
    1003         if (!console_srv_init(argv[1], argv[2]))
     854        printf(NAME ": HelenOS Console service\n");
     855       
     856        if (!console_init(argv[1]))
    1004857                return -1;
    1005858       
    1006         printf("%s: Accepting connections\n", NAME);
    1007         task_retval(0);
     859        printf(NAME ": Accepting connections\n");
    1008860        async_manager();
    1009861       
Note: See TracChangeset for help on using the changeset viewer.