Subversion Repositories HelenOS

Rev

Rev 4327 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 2006 Josef Cejka
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * - Redistributions of source code must retain the above copyright
  10.  *   notice, this list of conditions and the following disclaimer.
  11.  * - Redistributions in binary form must reproduce the above copyright
  12.  *   notice, this list of conditions and the following disclaimer in the
  13.  *   documentation and/or other materials provided with the distribution.
  14.  * - The name of the author may not be used to endorse or promote products
  15.  *   derived from this software without specific prior written permission.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  */
  28.  
  29. /** @addtogroup console
  30.  * @{
  31.  */
  32. /** @file
  33.  */
  34.  
  35. #include <libc.h>
  36. #include <fb.h>
  37. #include <ipc/ipc.h>
  38. #include <kbd.h>
  39. #include <io/keycode.h>
  40. #include <ipc/fb.h>
  41. #include <ipc/services.h>
  42. #include <errno.h>
  43. #include <keybuffer.h>
  44. #include <ipc/console.h>
  45. #include <unistd.h>
  46. #include <async.h>
  47. #include <adt/fifo.h>
  48. #include <sys/mman.h>
  49. #include <stdio.h>
  50. #include <string.h>
  51. #include <sysinfo.h>
  52. #include <event.h>
  53. #include <devmap.h>
  54. #include <fibril_sync.h>
  55.  
  56. #include "console.h"
  57. #include "gcons.h"
  58. #include "screenbuffer.h"
  59.  
  60. #define NAME  "console"
  61.  
  62. #define MAX_DEVICE_NAME  32
  63.  
  64. /** Phone to the keyboard driver. */
  65. static int kbd_phone;
  66.  
  67. /** Information about framebuffer */
  68. struct {
  69.     int phone;      /**< Framebuffer phone */
  70.     ipcarg_t cols;  /**< Framebuffer columns */
  71.     ipcarg_t rows;  /**< Framebuffer rows */
  72. } fb_info;
  73.  
  74. typedef struct {
  75.     size_t index;             /**< Console index */
  76.     size_t refcount;          /**< Connection reference count */
  77.     dev_handle_t dev_handle;  /**< Device handle */
  78.     keybuffer_t keybuffer;    /**< Buffer for incoming keys. */
  79.     screenbuffer_t scr;       /**< Screenbuffer for saving screen
  80.                                    contents and related settings. */
  81. } console_t;
  82.  
  83. /** Array of data for virtual consoles */
  84. static console_t consoles[CONSOLE_COUNT];
  85.  
  86. static console_t *active_console = &consoles[0];
  87. static console_t *prev_console = &consoles[0];
  88. static console_t *kernel_console = &consoles[KERNEL_CONSOLE];
  89.  
  90. /** Pointer to memory shared with framebufer used for
  91.     faster virtual console switching */
  92. static keyfield_t *interbuffer = NULL;
  93.  
  94. /** Information on row-span yet unsent to FB driver. */
  95. struct {
  96.     size_t col;  /**< Leftmost column of the span. */
  97.     size_t row;  /**< Row where the span lies. */
  98.     size_t cnt;  /**< Width of the span. */
  99. } fb_pending;
  100.  
  101. static FIBRIL_MUTEX_INITIALIZE(input_mutex);
  102. static FIBRIL_CONDVAR_INITIALIZE(input_cv);
  103.  
  104. static void curs_visibility(bool visible)
  105. {
  106.     async_msg_1(fb_info.phone, FB_CURSOR_VISIBILITY, visible);
  107. }
  108.  
  109. static void curs_hide_sync(void)
  110. {
  111.     ipc_call_sync_1_0(fb_info.phone, FB_CURSOR_VISIBILITY, false);
  112. }
  113.  
  114. static void curs_goto(size_t x, size_t y)
  115. {
  116.     async_msg_2(fb_info.phone, FB_CURSOR_GOTO, x, y);
  117. }
  118.  
  119. static void screen_clear(void)
  120. {
  121.     async_msg_0(fb_info.phone, FB_CLEAR);
  122. }
  123.  
  124. static void screen_yield(void)
  125. {
  126.     ipc_call_sync_0_0(fb_info.phone, FB_SCREEN_YIELD);
  127. }
  128.  
  129. static void screen_reclaim(void)
  130. {
  131.     ipc_call_sync_0_0(fb_info.phone, FB_SCREEN_RECLAIM);
  132. }
  133.  
  134. static void kbd_yield(void)
  135. {
  136.     ipc_call_sync_0_0(kbd_phone, KBD_YIELD);
  137. }
  138.  
  139. static void kbd_reclaim(void)
  140. {
  141.     ipc_call_sync_0_0(kbd_phone, KBD_RECLAIM);
  142. }
  143.  
  144. static void set_style(int style)
  145. {
  146.     async_msg_1(fb_info.phone, FB_SET_STYLE, style);
  147. }
  148.  
  149. static void set_color(int fgcolor, int bgcolor, int flags)
  150. {
  151.     async_msg_3(fb_info.phone, FB_SET_COLOR, fgcolor, bgcolor, flags);
  152. }
  153.  
  154. static void set_rgb_color(int fgcolor, int bgcolor)
  155. {
  156.     async_msg_2(fb_info.phone, FB_SET_RGB_COLOR, fgcolor, bgcolor);
  157. }
  158.  
  159. static void set_attrs(attrs_t *attrs)
  160. {
  161.     switch (attrs->t) {
  162.     case at_style:
  163.         set_style(attrs->a.s.style);
  164.         break;
  165.     case at_idx:
  166.         set_color(attrs->a.i.fg_color, attrs->a.i.bg_color,
  167.             attrs->a.i.flags);
  168.         break;
  169.     case at_rgb:
  170.         set_rgb_color(attrs->a.r.fg_color, attrs->a.r.bg_color);
  171.         break;
  172.     }
  173. }
  174.  
  175. /** Send an area of screenbuffer to the FB driver. */
  176. static void fb_update_area(console_t *cons, ipcarg_t x0, ipcarg_t y0, ipcarg_t width, ipcarg_t height)
  177. {
  178.     if (interbuffer) {
  179.         ipcarg_t x;
  180.         ipcarg_t y;
  181.        
  182.         for (y = 0; y < height; y++) {
  183.             for (x = 0; x < width; x++) {
  184.                 interbuffer[y * width + x] =
  185.                     *get_field_at(&cons->scr, x0 + x, y0 + y);
  186.             }
  187.         }
  188.        
  189.         async_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA,
  190.             x0, y0, width, height);
  191.     }
  192. }
  193.  
  194. /** Flush pending cells to FB. */
  195. static void fb_pending_flush(void)
  196. {
  197.     if (fb_pending.cnt > 0) {
  198.         fb_update_area(active_console, fb_pending.col,
  199.             fb_pending.row, fb_pending.cnt, 1);
  200.         fb_pending.cnt = 0;
  201.     }
  202. }
  203.  
  204. /** Mark a character cell as changed.
  205.  *
  206.  * This adds the cell to the pending rowspan if possible. Otherwise
  207.  * the old span is flushed first.
  208.  *
  209.  */
  210. static void cell_mark_changed(size_t col, size_t row)
  211. {
  212.     if (fb_pending.cnt != 0) {
  213.         if ((col != fb_pending.col + fb_pending.cnt)
  214.             || (row != fb_pending.row)) {
  215.             fb_pending_flush();
  216.         }
  217.     }
  218.    
  219.     if (fb_pending.cnt == 0) {
  220.         fb_pending.col = col;
  221.         fb_pending.row = row;
  222.     }
  223.    
  224.     fb_pending.cnt++;
  225. }
  226.  
  227. /** Print a character to the active VC with buffering. */
  228. static void fb_putchar(wchar_t c, ipcarg_t col, ipcarg_t row)
  229. {
  230.     async_msg_3(fb_info.phone, FB_PUTCHAR, c, col, row);
  231. }
  232.  
  233. /** Process a character from the client (TTY emulation). */
  234. static void write_char(console_t *cons, wchar_t ch)
  235. {
  236.     bool flush_cursor = false;
  237.  
  238.     switch (ch) {
  239.     case '\n':
  240.         fb_pending_flush();
  241.         flush_cursor = true;
  242.         cons->scr.position_y++;
  243.         cons->scr.position_x = 0;
  244.         break;
  245.     case '\r':
  246.         break;
  247.     case '\t':
  248.         cons->scr.position_x += 8;
  249.         cons->scr.position_x -= cons->scr.position_x % 8;
  250.         break;
  251.     case '\b':
  252.         if (cons->scr.position_x == 0)
  253.             break;
  254.         cons->scr.position_x--;
  255.         if (cons == active_console)
  256.             cell_mark_changed(cons->scr.position_x, cons->scr.position_y);
  257.         screenbuffer_putchar(&cons->scr, ' ');
  258.         break;
  259.     default:
  260.         if (cons == active_console)
  261.             cell_mark_changed(cons->scr.position_x, cons->scr.position_y);
  262.        
  263.         screenbuffer_putchar(&cons->scr, ch);
  264.         cons->scr.position_x++;
  265.     }
  266.    
  267.     if (cons->scr.position_x >= cons->scr.size_x) {
  268.         flush_cursor = true;
  269.         cons->scr.position_y++;
  270.     }
  271.    
  272.     if (cons->scr.position_y >= cons->scr.size_y) {
  273.         fb_pending_flush();
  274.         cons->scr.position_y = cons->scr.size_y - 1;
  275.         screenbuffer_clear_line(&cons->scr, cons->scr.top_line);
  276.         cons->scr.top_line = (cons->scr.top_line + 1) % cons->scr.size_y;
  277.        
  278.         if (cons == active_console)
  279.             async_msg_1(fb_info.phone, FB_SCROLL, 1);
  280.     }
  281.  
  282.     if (cons == active_console && flush_cursor)
  283.         curs_goto(cons->scr.position_x, cons->scr.position_y);
  284.     cons->scr.position_x = cons->scr.position_x % cons->scr.size_x;
  285. }
  286.  
  287. /** Switch to new console */
  288. static void change_console(console_t *cons)
  289. {
  290.     if (cons == active_console)
  291.         return;
  292.    
  293.     fb_pending_flush();
  294.    
  295.     if (cons == kernel_console) {
  296.         async_serialize_start();
  297.         curs_hide_sync();
  298.         gcons_in_kernel();
  299.         screen_yield();
  300.         kbd_yield();
  301.         async_serialize_end();
  302.        
  303.         if (__SYSCALL0(SYS_DEBUG_ENABLE_CONSOLE)) {
  304.             prev_console = active_console;
  305.             active_console = kernel_console;
  306.         } else
  307.             cons = active_console;
  308.     }
  309.    
  310.     if (cons != kernel_console) {
  311.         size_t x;
  312.         size_t y;
  313.         int rc = 0;
  314.        
  315.         async_serialize_start();
  316.        
  317.         if (active_console == kernel_console) {
  318.             screen_reclaim();
  319.             kbd_reclaim();
  320.             gcons_redraw_console();
  321.         }
  322.        
  323.         active_console = cons;
  324.         gcons_change_console(cons->index);
  325.        
  326.         set_attrs(&cons->scr.attrs);
  327.         curs_visibility(false);
  328.         if (interbuffer) {
  329.             for (y = 0; y < cons->scr.size_y; y++) {
  330.                 for (x = 0; x < cons->scr.size_x; x++) {
  331.                     interbuffer[y * cons->scr.size_x + x] =
  332.                         *get_field_at(&cons->scr, x, y);
  333.                 }
  334.             }
  335.            
  336.             /* This call can preempt, but we are already at the end */
  337.             rc = async_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA,
  338.                 0, 0, cons->scr.size_x,
  339.                 cons->scr.size_y);
  340.         }
  341.        
  342.         if ((!interbuffer) || (rc != 0)) {
  343.             set_attrs(&cons->scr.attrs);
  344.             screen_clear();
  345.            
  346.             for (y = 0; y < cons->scr.size_y; y++)
  347.                 for (x = 0; x < cons->scr.size_x; x++) {
  348.                     keyfield_t *field = get_field_at(&cons->scr, x, y);
  349.                    
  350.                     if (!attrs_same(cons->scr.attrs, field->attrs))
  351.                         set_attrs(&field->attrs);
  352.                    
  353.                     cons->scr.attrs = field->attrs;
  354.                     if ((field->character == ' ') &&
  355.                         (attrs_same(field->attrs, cons->scr.attrs)))
  356.                         continue;
  357.                    
  358.                     fb_putchar(field->character, x, y);
  359.                 }
  360.         }
  361.        
  362.         curs_goto(cons->scr.position_x, cons->scr.position_y);
  363.         curs_visibility(cons->scr.is_cursor_visible);
  364.        
  365.         async_serialize_end();
  366.     }
  367. }
  368.  
  369. /** Handler for keyboard */
  370. static void keyboard_events(ipc_callid_t iid, ipc_call_t *icall)
  371. {
  372.     /* Ignore parameters, the connection is already opened */
  373.     while (true) {
  374.        
  375.         ipc_call_t call;
  376.         ipc_callid_t callid = async_get_call(&call);
  377.        
  378.         int retval;
  379.         console_event_t ev;
  380.        
  381.         switch (IPC_GET_METHOD(call)) {
  382.         case IPC_M_PHONE_HUNGUP:
  383.             /* TODO: Handle hangup */
  384.             return;
  385.         case KBD_EVENT:
  386.             /* Got event from keyboard driver. */
  387.             retval = 0;
  388.             ev.type = IPC_GET_ARG1(call);
  389.             ev.key = IPC_GET_ARG2(call);
  390.             ev.mods = IPC_GET_ARG3(call);
  391.             ev.c = IPC_GET_ARG4(call);
  392.            
  393.             if ((ev.key >= KC_F1) && (ev.key < KC_F1 +
  394.                 CONSOLE_COUNT) && ((ev.mods & KM_CTRL) == 0)) {
  395.                 if (ev.key == KC_F1 + KERNEL_CONSOLE)
  396.                     change_console(kernel_console);
  397.                 else
  398.                     change_console(&consoles[ev.key - KC_F1]);
  399.                 break;
  400.             }
  401.            
  402.             fibril_mutex_lock(&input_mutex);
  403.             keybuffer_push(&active_console->keybuffer, &ev);
  404.             fibril_condvar_broadcast(&input_cv);
  405.             fibril_mutex_unlock(&input_mutex);
  406.             break;
  407.         default:
  408.             retval = ENOENT;
  409.         }
  410.         ipc_answer_0(callid, retval);
  411.     }
  412. }
  413.  
  414. static void cons_write(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
  415. {
  416.     ipc_callid_t callid;
  417.     size_t size;
  418.     if (!ipc_data_write_receive(&callid, &size)) {
  419.         ipc_answer_0(callid, EINVAL);
  420.         ipc_answer_0(rid, EINVAL);
  421.         return;
  422.     }
  423.    
  424.     char *buf = (char *) malloc(size);
  425.     if (buf == NULL) {
  426.         ipc_answer_0(callid, ENOMEM);
  427.         ipc_answer_0(rid, ENOMEM);
  428.         return;
  429.     }
  430.    
  431.     (void) ipc_data_write_finalize(callid, buf, size);
  432.    
  433.     async_serialize_start();
  434.    
  435.     size_t off = 0;
  436.     while (off < size) {
  437.         wchar_t ch = str_decode(buf, &off, size);
  438.         write_char(cons, ch);
  439.     }
  440.    
  441.     async_serialize_end();
  442.    
  443.     gcons_notify_char(cons->index);
  444.     ipc_answer_1(rid, EOK, size);
  445.    
  446.     free(buf);
  447. }
  448.  
  449. static void cons_read(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
  450. {
  451.     ipc_callid_t callid;
  452.     size_t size;
  453.     if (!ipc_data_read_receive(&callid, &size)) {
  454.         ipc_answer_0(callid, EINVAL);
  455.         ipc_answer_0(rid, EINVAL);
  456.         return;
  457.     }
  458.    
  459.     char *buf = (char *) malloc(size);
  460.     if (buf == NULL) {
  461.         ipc_answer_0(callid, ENOMEM);
  462.         ipc_answer_0(rid, ENOMEM);
  463.         return;
  464.     }
  465.    
  466.     size_t pos = 0;
  467.     console_event_t ev;
  468.     fibril_mutex_lock(&input_mutex);
  469. recheck:
  470.     while ((keybuffer_pop(&cons->keybuffer, &ev)) && (pos < size)) {
  471.         if (ev.type == KEY_PRESS) {
  472.             buf[pos] = ev.c;
  473.             pos++;
  474.         }
  475.     }
  476.    
  477.     if (pos == size) {
  478.         (void) ipc_data_read_finalize(callid, buf, size);
  479.         ipc_answer_1(rid, EOK, size);
  480.         free(buf);
  481.     } else {
  482.         fibril_condvar_wait(&input_cv, &input_mutex);
  483.         goto recheck;
  484.     }
  485.     fibril_mutex_unlock(&input_mutex);
  486. }
  487.  
  488. static void cons_get_event(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
  489. {
  490.     console_event_t ev;
  491.  
  492.     fibril_mutex_lock(&input_mutex);
  493. recheck:
  494.     if (keybuffer_pop(&cons->keybuffer, &ev)) {
  495.         ipc_answer_4(rid, EOK, ev.type, ev.key, ev.mods, ev.c);
  496.     } else {
  497.         fibril_condvar_wait(&input_cv, &input_mutex);
  498.         goto recheck;
  499.     }
  500.     fibril_mutex_unlock(&input_mutex);
  501. }
  502.  
  503. /** Default thread for new connections */
  504. static void client_connection(ipc_callid_t iid, ipc_call_t *icall)
  505. {
  506.     console_t *cons = NULL;
  507.    
  508.     size_t i;
  509.     for (i = 0; i < CONSOLE_COUNT; i++) {
  510.         if (i == KERNEL_CONSOLE)
  511.             continue;
  512.        
  513.         if (consoles[i].dev_handle == (dev_handle_t) IPC_GET_ARG1(*icall)) {
  514.             cons = &consoles[i];
  515.             break;
  516.         }
  517.     }
  518.    
  519.     if (cons == NULL) {
  520.         ipc_answer_0(iid, ENOENT);
  521.         return;
  522.     }
  523.    
  524.     ipc_callid_t callid;
  525.     ipc_call_t call;
  526.     ipcarg_t arg1;
  527.     ipcarg_t arg2;
  528.     ipcarg_t arg3;
  529.    
  530.     async_serialize_start();
  531.     if (cons->refcount == 0)
  532.         gcons_notify_connect(cons->index);
  533.    
  534.     cons->refcount++;
  535.    
  536.     /* Accept the connection */
  537.     ipc_answer_0(iid, EOK);
  538.    
  539.     while (true) {
  540.         async_serialize_end();
  541.         callid = async_get_call(&call);
  542.         async_serialize_start();
  543.        
  544.         arg1 = 0;
  545.         arg2 = 0;
  546.         arg3 = 0;
  547.        
  548.         switch (IPC_GET_METHOD(call)) {
  549.         case IPC_M_PHONE_HUNGUP:
  550.             cons->refcount--;
  551.             if (cons->refcount == 0)
  552.                 gcons_notify_disconnect(cons->index);
  553.             return;
  554.         case VFS_READ:
  555.             async_serialize_end();
  556.             cons_read(cons, callid, &call);
  557.             async_serialize_start();
  558.             continue;
  559.         case VFS_WRITE:
  560.             async_serialize_end();
  561.             cons_write(cons, callid, &call);
  562.             async_serialize_start();
  563.             continue;
  564.         case VFS_SYNC:
  565.             fb_pending_flush();
  566.             if (cons == active_console) {
  567.                 async_req_0_0(fb_info.phone, FB_FLUSH);
  568.                
  569.                 curs_goto(cons->scr.position_x, cons->scr.position_y);
  570.             }
  571.             break;
  572.         case CONSOLE_CLEAR:
  573.             /* Send message to fb */
  574.             if (cons == active_console)
  575.                 async_msg_0(fb_info.phone, FB_CLEAR);
  576.            
  577.             screenbuffer_clear(&cons->scr);
  578.            
  579.             break;
  580.         case CONSOLE_GOTO:
  581.             screenbuffer_goto(&cons->scr,
  582.                 IPC_GET_ARG1(call), IPC_GET_ARG2(call));
  583.             if (cons == active_console)
  584.                 curs_goto(IPC_GET_ARG1(call),
  585.                     IPC_GET_ARG2(call));
  586.             break;
  587.         case CONSOLE_GET_SIZE:
  588.             arg1 = fb_info.cols;
  589.             arg2 = fb_info.rows;
  590.             break;
  591.         case CONSOLE_SET_STYLE:
  592.             fb_pending_flush();
  593.             arg1 = IPC_GET_ARG1(call);
  594.             screenbuffer_set_style(&cons->scr, arg1);
  595.             if (cons == active_console)
  596.                 set_style(arg1);
  597.             break;
  598.         case CONSOLE_SET_COLOR:
  599.             fb_pending_flush();
  600.             arg1 = IPC_GET_ARG1(call);
  601.             arg2 = IPC_GET_ARG2(call);
  602.             arg3 = IPC_GET_ARG3(call);
  603.             screenbuffer_set_color(&cons->scr, arg1, arg2, arg3);
  604.             if (cons == active_console)
  605.                 set_color(arg1, arg2, arg3);
  606.             break;
  607.         case CONSOLE_SET_RGB_COLOR:
  608.             fb_pending_flush();
  609.             arg1 = IPC_GET_ARG1(call);
  610.             arg2 = IPC_GET_ARG2(call);
  611.             screenbuffer_set_rgb_color(&cons->scr, arg1, arg2);
  612.             if (cons == active_console)
  613.                 set_rgb_color(arg1, arg2);
  614.             break;
  615.         case CONSOLE_CURSOR_VISIBILITY:
  616.             fb_pending_flush();
  617.             arg1 = IPC_GET_ARG1(call);
  618.             cons->scr.is_cursor_visible = arg1;
  619.             if (cons == active_console)
  620.                 curs_visibility(arg1);
  621.             break;
  622.         case CONSOLE_GET_EVENT:
  623.             async_serialize_end();
  624.             cons_get_event(cons, callid, &call);
  625.             async_serialize_start();
  626.             continue;
  627.         case CONSOLE_KCON_ENABLE:
  628.             change_console(kernel_console);
  629.             break;
  630.         }
  631.         ipc_answer_3(callid, EOK, arg1, arg2, arg3);
  632.     }
  633. }
  634.  
  635. static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
  636. {
  637.     change_console(prev_console);
  638. }
  639.  
  640. static bool console_init(void)
  641. {
  642.     /* Connect to keyboard driver */
  643.     kbd_phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_KEYBOARD, 0, 0);
  644.     if (kbd_phone < 0) {
  645.         printf(NAME ": Failed to connect to keyboard service\n");
  646.         return false;
  647.     }
  648.    
  649.     ipcarg_t phonehash;
  650.     if (ipc_connect_to_me(kbd_phone, SERVICE_CONSOLE, 0, 0, &phonehash) != 0) {
  651.         printf(NAME ": Failed to create callback from keyboard service\n");
  652.         return false;
  653.     }
  654.    
  655.     async_new_connection(phonehash, 0, NULL, keyboard_events);
  656.  
  657.     /* Connect to framebuffer driver */
  658.     fb_info.phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_VIDEO, 0, 0);
  659.     if (fb_info.phone < 0) {
  660.         printf(NAME ": Failed to connect to video service\n");
  661.         return -1;
  662.     }
  663.    
  664.     /* Register driver */
  665.     int rc = devmap_driver_register(NAME, client_connection);
  666.     if (rc < 0) {
  667.         printf(NAME ": Unable to register driver (%d)\n", rc);
  668.         return false;
  669.     }
  670.    
  671.     /* Initialize gcons */
  672.     gcons_init(fb_info.phone);
  673.    
  674.     /* Synchronize, the gcons could put something in queue */
  675.     async_req_0_0(fb_info.phone, FB_FLUSH);
  676.     async_req_0_2(fb_info.phone, FB_GET_CSIZE, &fb_info.cols, &fb_info.rows);
  677.    
  678.     /* Set up shared memory buffer. */
  679.     size_t ib_size = sizeof(keyfield_t) * fb_info.cols * fb_info.rows;
  680.     interbuffer = as_get_mappable_page(ib_size);
  681.    
  682.     if (as_area_create(interbuffer, ib_size, AS_AREA_READ |
  683.         AS_AREA_WRITE | AS_AREA_CACHEABLE) != interbuffer)
  684.         interbuffer = NULL;
  685.    
  686.     if (interbuffer) {
  687.         if (ipc_share_out_start(fb_info.phone, interbuffer,
  688.             AS_AREA_READ) != EOK) {
  689.             as_area_destroy(interbuffer);
  690.             interbuffer = NULL;
  691.         }
  692.     }
  693.    
  694.     fb_pending.cnt = 0;
  695.    
  696.     /* Inititalize consoles */
  697.     size_t i;
  698.     for (i = 0; i < CONSOLE_COUNT; i++) {
  699.         if (i != KERNEL_CONSOLE) {
  700.             if (screenbuffer_init(&consoles[i].scr,
  701.                 fb_info.cols, fb_info.rows) == NULL) {
  702.                 printf(NAME ": Unable to allocate screen buffer %u\n", i);
  703.                 return false;
  704.             }
  705.             screenbuffer_clear(&consoles[i].scr);
  706.             keybuffer_init(&consoles[i].keybuffer);
  707.             consoles[i].index = i;
  708.             consoles[i].refcount = 0;
  709.            
  710.             char vc[MAX_DEVICE_NAME];
  711.             snprintf(vc, MAX_DEVICE_NAME, "vc%u", i);
  712.            
  713.             if (devmap_device_register(vc, &consoles[i].dev_handle) != EOK) {
  714.                 devmap_hangup_phone(DEVMAP_DRIVER);
  715.                 printf(NAME ": Unable to register device %s\n", vc);
  716.                 return false;
  717.             }
  718.         }
  719.     }
  720.    
  721.     /* Disable kernel output to the console */
  722.     __SYSCALL0(SYS_DEBUG_DISABLE_CONSOLE);
  723.    
  724.     /* Initialize the screen */
  725.     async_serialize_start();
  726.     gcons_redraw_console();
  727.     set_rgb_color(DEFAULT_FOREGROUND, DEFAULT_BACKGROUND);
  728.     screen_clear();
  729.     curs_goto(0, 0);
  730.     curs_visibility(active_console->scr.is_cursor_visible);
  731.     async_serialize_end();
  732.    
  733.     /* Receive kernel notifications */
  734.     if (event_subscribe(EVENT_KCONSOLE, 0) != EOK)
  735.         printf(NAME ": Error registering kconsole notifications\n");
  736.    
  737.     async_set_interrupt_received(interrupt_received);
  738.    
  739.     return true;
  740. }
  741.  
  742. int main(int argc, char *argv[])
  743. {
  744.     printf(NAME ": HelenOS Console service\n");
  745.    
  746.     if (!console_init())
  747.         return -1;
  748.    
  749.     printf(NAME ": Accepting connections\n");
  750.     async_manager();
  751.    
  752.     return 0;
  753. }
  754.  
  755. /** @}
  756.  */
  757.