Subversion Repositories HelenOS

Rev

Rev 4668 | 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.     int color_cap;  /**< Color capabilities (FB_CCAP_xxx) */
  73. } fb_info;
  74.  
  75. typedef struct {
  76.     size_t index;             /**< Console index */
  77.     size_t refcount;          /**< Connection reference count */
  78.     dev_handle_t dev_handle;  /**< Device handle */
  79.     keybuffer_t keybuffer;    /**< Buffer for incoming keys. */
  80.     screenbuffer_t scr;       /**< Screenbuffer for saving screen
  81.                                    contents and related settings. */
  82. } console_t;
  83.  
  84. /** Array of data for virtual consoles */
  85. static console_t consoles[CONSOLE_COUNT];
  86.  
  87. static console_t *active_console = &consoles[0];
  88. static console_t *prev_console = &consoles[0];
  89. static console_t *kernel_console = &consoles[KERNEL_CONSOLE];
  90.  
  91. /** Pointer to memory shared with framebufer used for
  92.     faster virtual console switching */
  93. static keyfield_t *interbuffer = NULL;
  94.  
  95. /** Information on row-span yet unsent to FB driver. */
  96. struct {
  97.     size_t col;  /**< Leftmost column of the span. */
  98.     size_t row;  /**< Row where the span lies. */
  99.     size_t cnt;  /**< Width of the span. */
  100. } fb_pending;
  101.  
  102. static FIBRIL_MUTEX_INITIALIZE(input_mutex);
  103. static FIBRIL_CONDVAR_INITIALIZE(input_cv);
  104.  
  105. static void curs_visibility(bool visible)
  106. {
  107.     async_msg_1(fb_info.phone, FB_CURSOR_VISIBILITY, visible);
  108. }
  109.  
  110. static void curs_hide_sync(void)
  111. {
  112.     ipc_call_sync_1_0(fb_info.phone, FB_CURSOR_VISIBILITY, false);
  113. }
  114.  
  115. static void curs_goto(size_t x, size_t y)
  116. {
  117.     async_msg_2(fb_info.phone, FB_CURSOR_GOTO, x, y);
  118. }
  119.  
  120. static void screen_clear(void)
  121. {
  122.     async_msg_0(fb_info.phone, FB_CLEAR);
  123. }
  124.  
  125. static void screen_yield(void)
  126. {
  127.     ipc_call_sync_0_0(fb_info.phone, FB_SCREEN_YIELD);
  128. }
  129.  
  130. static void screen_reclaim(void)
  131. {
  132.     ipc_call_sync_0_0(fb_info.phone, FB_SCREEN_RECLAIM);
  133. }
  134.  
  135. static void kbd_yield(void)
  136. {
  137.     ipc_call_sync_0_0(kbd_phone, KBD_YIELD);
  138. }
  139.  
  140. static void kbd_reclaim(void)
  141. {
  142.     ipc_call_sync_0_0(kbd_phone, KBD_RECLAIM);
  143. }
  144.  
  145. static void set_style(int style)
  146. {
  147.     async_msg_1(fb_info.phone, FB_SET_STYLE, style);
  148. }
  149.  
  150. static void set_color(int fgcolor, int bgcolor, int flags)
  151. {
  152.     async_msg_3(fb_info.phone, FB_SET_COLOR, fgcolor, bgcolor, flags);
  153. }
  154.  
  155. static void set_rgb_color(int fgcolor, int bgcolor)
  156. {
  157.     async_msg_2(fb_info.phone, FB_SET_RGB_COLOR, fgcolor, bgcolor);
  158. }
  159.  
  160. static void set_attrs(attrs_t *attrs)
  161. {
  162.     switch (attrs->t) {
  163.     case at_style:
  164.         set_style(attrs->a.s.style);
  165.         break;
  166.     case at_idx:
  167.         set_color(attrs->a.i.fg_color, attrs->a.i.bg_color,
  168.             attrs->a.i.flags);
  169.         break;
  170.     case at_rgb:
  171.         set_rgb_color(attrs->a.r.fg_color, attrs->a.r.bg_color);
  172.         break;
  173.     }
  174. }
  175.  
  176. static int ccap_fb_to_con(int ccap_fb, int *ccap_con)
  177. {
  178.     switch (ccap_fb) {
  179.     case FB_CCAP_NONE: *ccap_con = CONSOLE_CCAP_NONE; break;
  180.     case FB_CCAP_STYLE: *ccap_con = CONSOLE_CCAP_STYLE; break;
  181.     case FB_CCAP_INDEXED: *ccap_con = CONSOLE_CCAP_INDEXED; break;
  182.     case FB_CCAP_RGB: *ccap_con = CONSOLE_CCAP_RGB; break;
  183.     default: return EINVAL;
  184.     }
  185.  
  186.     return EOK;
  187. }
  188.  
  189. /** Send an area of screenbuffer to the FB driver. */
  190. static void fb_update_area(console_t *cons, ipcarg_t x0, ipcarg_t y0, ipcarg_t width, ipcarg_t height)
  191. {
  192.     if (interbuffer) {
  193.         ipcarg_t x;
  194.         ipcarg_t y;
  195.        
  196.         for (y = 0; y < height; y++) {
  197.             for (x = 0; x < width; x++) {
  198.                 interbuffer[y * width + x] =
  199.                     *get_field_at(&cons->scr, x0 + x, y0 + y);
  200.             }
  201.         }
  202.        
  203.         async_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA,
  204.             x0, y0, width, height);
  205.     }
  206. }
  207.  
  208. /** Flush pending cells to FB. */
  209. static void fb_pending_flush(void)
  210. {
  211.     if (fb_pending.cnt > 0) {
  212.         fb_update_area(active_console, fb_pending.col,
  213.             fb_pending.row, fb_pending.cnt, 1);
  214.         fb_pending.cnt = 0;
  215.     }
  216. }
  217.  
  218. /** Mark a character cell as changed.
  219.  *
  220.  * This adds the cell to the pending rowspan if possible. Otherwise
  221.  * the old span is flushed first.
  222.  *
  223.  */
  224. static void cell_mark_changed(size_t col, size_t row)
  225. {
  226.     if (fb_pending.cnt != 0) {
  227.         if ((col != fb_pending.col + fb_pending.cnt)
  228.             || (row != fb_pending.row)) {
  229.             fb_pending_flush();
  230.         }
  231.     }
  232.    
  233.     if (fb_pending.cnt == 0) {
  234.         fb_pending.col = col;
  235.         fb_pending.row = row;
  236.     }
  237.    
  238.     fb_pending.cnt++;
  239. }
  240.  
  241. /** Print a character to the active VC with buffering. */
  242. static void fb_putchar(wchar_t c, ipcarg_t col, ipcarg_t row)
  243. {
  244.     async_msg_3(fb_info.phone, FB_PUTCHAR, c, col, row);
  245. }
  246.  
  247. /** Process a character from the client (TTY emulation). */
  248. static void write_char(console_t *cons, wchar_t ch)
  249. {
  250.     bool flush_cursor = false;
  251.  
  252.     switch (ch) {
  253.     case '\n':
  254.         fb_pending_flush();
  255.         flush_cursor = true;
  256.         cons->scr.position_y++;
  257.         cons->scr.position_x = 0;
  258.         break;
  259.     case '\r':
  260.         break;
  261.     case '\t':
  262.         cons->scr.position_x += 8;
  263.         cons->scr.position_x -= cons->scr.position_x % 8;
  264.         break;
  265.     case '\b':
  266.         if (cons->scr.position_x == 0)
  267.             break;
  268.         cons->scr.position_x--;
  269.         if (cons == active_console)
  270.             cell_mark_changed(cons->scr.position_x, cons->scr.position_y);
  271.         screenbuffer_putchar(&cons->scr, ' ');
  272.         break;
  273.     default:
  274.         if (cons == active_console)
  275.             cell_mark_changed(cons->scr.position_x, cons->scr.position_y);
  276.        
  277.         screenbuffer_putchar(&cons->scr, ch);
  278.         cons->scr.position_x++;
  279.     }
  280.    
  281.     if (cons->scr.position_x >= cons->scr.size_x) {
  282.         flush_cursor = true;
  283.         cons->scr.position_y++;
  284.     }
  285.    
  286.     if (cons->scr.position_y >= cons->scr.size_y) {
  287.         fb_pending_flush();
  288.         cons->scr.position_y = cons->scr.size_y - 1;
  289.         screenbuffer_clear_line(&cons->scr, cons->scr.top_line);
  290.         cons->scr.top_line = (cons->scr.top_line + 1) % cons->scr.size_y;
  291.        
  292.         if (cons == active_console)
  293.             async_msg_1(fb_info.phone, FB_SCROLL, 1);
  294.     }
  295.  
  296.     if (cons == active_console && flush_cursor)
  297.         curs_goto(cons->scr.position_x, cons->scr.position_y);
  298.     cons->scr.position_x = cons->scr.position_x % cons->scr.size_x;
  299. }
  300.  
  301. /** Switch to new console */
  302. static void change_console(console_t *cons)
  303. {
  304.     if (cons == active_console)
  305.         return;
  306.    
  307.     fb_pending_flush();
  308.    
  309.     if (cons == kernel_console) {
  310.         async_serialize_start();
  311.         curs_hide_sync();
  312.         gcons_in_kernel();
  313.         screen_yield();
  314.         kbd_yield();
  315.         async_serialize_end();
  316.        
  317.         if (__SYSCALL0(SYS_DEBUG_ENABLE_CONSOLE)) {
  318.             prev_console = active_console;
  319.             active_console = kernel_console;
  320.         } else
  321.             cons = active_console;
  322.     }
  323.    
  324.     if (cons != kernel_console) {
  325.         size_t x;
  326.         size_t y;
  327.         int rc = 0;
  328.        
  329.         async_serialize_start();
  330.        
  331.         if (active_console == kernel_console) {
  332.             screen_reclaim();
  333.             kbd_reclaim();
  334.             gcons_redraw_console();
  335.         }
  336.        
  337.         active_console = cons;
  338.         gcons_change_console(cons->index);
  339.        
  340.         set_attrs(&cons->scr.attrs);
  341.         curs_visibility(false);
  342.         if (interbuffer) {
  343.             for (y = 0; y < cons->scr.size_y; y++) {
  344.                 for (x = 0; x < cons->scr.size_x; x++) {
  345.                     interbuffer[y * cons->scr.size_x + x] =
  346.                         *get_field_at(&cons->scr, x, y);
  347.                 }
  348.             }
  349.            
  350.             /* This call can preempt, but we are already at the end */
  351.             rc = async_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA,
  352.                 0, 0, cons->scr.size_x,
  353.                 cons->scr.size_y);
  354.         }
  355.        
  356.         if ((!interbuffer) || (rc != 0)) {
  357.             set_attrs(&cons->scr.attrs);
  358.             screen_clear();
  359.            
  360.             for (y = 0; y < cons->scr.size_y; y++)
  361.                 for (x = 0; x < cons->scr.size_x; x++) {
  362.                     keyfield_t *field = get_field_at(&cons->scr, x, y);
  363.                    
  364.                     if (!attrs_same(cons->scr.attrs, field->attrs))
  365.                         set_attrs(&field->attrs);
  366.                    
  367.                     cons->scr.attrs = field->attrs;
  368.                     if ((field->character == ' ') &&
  369.                         (attrs_same(field->attrs, cons->scr.attrs)))
  370.                         continue;
  371.                    
  372.                     fb_putchar(field->character, x, y);
  373.                 }
  374.         }
  375.        
  376.         curs_goto(cons->scr.position_x, cons->scr.position_y);
  377.         curs_visibility(cons->scr.is_cursor_visible);
  378.        
  379.         async_serialize_end();
  380.     }
  381. }
  382.  
  383. /** Handler for keyboard */
  384. static void keyboard_events(ipc_callid_t iid, ipc_call_t *icall)
  385. {
  386.     /* Ignore parameters, the connection is already opened */
  387.     while (true) {
  388.        
  389.         ipc_call_t call;
  390.         ipc_callid_t callid = async_get_call(&call);
  391.        
  392.         int retval;
  393.         console_event_t ev;
  394.        
  395.         switch (IPC_GET_METHOD(call)) {
  396.         case IPC_M_PHONE_HUNGUP:
  397.             /* TODO: Handle hangup */
  398.             return;
  399.         case KBD_EVENT:
  400.             /* Got event from keyboard driver. */
  401.             retval = 0;
  402.             ev.type = IPC_GET_ARG1(call);
  403.             ev.key = IPC_GET_ARG2(call);
  404.             ev.mods = IPC_GET_ARG3(call);
  405.             ev.c = IPC_GET_ARG4(call);
  406.            
  407.             if ((ev.key >= KC_F1) && (ev.key < KC_F1 +
  408.                 CONSOLE_COUNT) && ((ev.mods & KM_CTRL) == 0)) {
  409.                 if (ev.key == KC_F1 + KERNEL_CONSOLE)
  410.                     change_console(kernel_console);
  411.                 else
  412.                     change_console(&consoles[ev.key - KC_F1]);
  413.                 break;
  414.             }
  415.            
  416.             fibril_mutex_lock(&input_mutex);
  417.             keybuffer_push(&active_console->keybuffer, &ev);
  418.             fibril_condvar_broadcast(&input_cv);
  419.             fibril_mutex_unlock(&input_mutex);
  420.             break;
  421.         default:
  422.             retval = ENOENT;
  423.         }
  424.         ipc_answer_0(callid, retval);
  425.     }
  426. }
  427.  
  428. static void cons_write(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
  429. {
  430.     ipc_callid_t callid;
  431.     size_t size;
  432.     if (!ipc_data_write_receive(&callid, &size)) {
  433.         ipc_answer_0(callid, EINVAL);
  434.         ipc_answer_0(rid, EINVAL);
  435.         return;
  436.     }
  437.    
  438.     char *buf = (char *) malloc(size);
  439.     if (buf == NULL) {
  440.         ipc_answer_0(callid, ENOMEM);
  441.         ipc_answer_0(rid, ENOMEM);
  442.         return;
  443.     }
  444.    
  445.     (void) ipc_data_write_finalize(callid, buf, size);
  446.    
  447.     async_serialize_start();
  448.    
  449.     size_t off = 0;
  450.     while (off < size) {
  451.         wchar_t ch = str_decode(buf, &off, size);
  452.         write_char(cons, ch);
  453.     }
  454.    
  455.     async_serialize_end();
  456.    
  457.     gcons_notify_char(cons->index);
  458.     ipc_answer_1(rid, EOK, size);
  459.    
  460.     free(buf);
  461. }
  462.  
  463. static void cons_read(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
  464. {
  465.     ipc_callid_t callid;
  466.     size_t size;
  467.     if (!ipc_data_read_receive(&callid, &size)) {
  468.         ipc_answer_0(callid, EINVAL);
  469.         ipc_answer_0(rid, EINVAL);
  470.         return;
  471.     }
  472.    
  473.     char *buf = (char *) malloc(size);
  474.     if (buf == NULL) {
  475.         ipc_answer_0(callid, ENOMEM);
  476.         ipc_answer_0(rid, ENOMEM);
  477.         return;
  478.     }
  479.    
  480.     size_t pos = 0;
  481.     console_event_t ev;
  482.     fibril_mutex_lock(&input_mutex);
  483. recheck:
  484.     while ((keybuffer_pop(&cons->keybuffer, &ev)) && (pos < size)) {
  485.         if (ev.type == KEY_PRESS) {
  486.             buf[pos] = ev.c;
  487.             pos++;
  488.         }
  489.     }
  490.    
  491.     if (pos == size) {
  492.         (void) ipc_data_read_finalize(callid, buf, size);
  493.         ipc_answer_1(rid, EOK, size);
  494.         free(buf);
  495.     } else {
  496.         fibril_condvar_wait(&input_cv, &input_mutex);
  497.         goto recheck;
  498.     }
  499.     fibril_mutex_unlock(&input_mutex);
  500. }
  501.  
  502. static void cons_get_event(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
  503. {
  504.     console_event_t ev;
  505.  
  506.     fibril_mutex_lock(&input_mutex);
  507. recheck:
  508.     if (keybuffer_pop(&cons->keybuffer, &ev)) {
  509.         ipc_answer_4(rid, EOK, ev.type, ev.key, ev.mods, ev.c);
  510.     } else {
  511.         fibril_condvar_wait(&input_cv, &input_mutex);
  512.         goto recheck;
  513.     }
  514.     fibril_mutex_unlock(&input_mutex);
  515. }
  516.  
  517. /** Default thread for new connections */
  518. static void client_connection(ipc_callid_t iid, ipc_call_t *icall)
  519. {
  520.     console_t *cons = NULL;
  521.    
  522.     size_t i;
  523.     for (i = 0; i < CONSOLE_COUNT; i++) {
  524.         if (i == KERNEL_CONSOLE)
  525.             continue;
  526.        
  527.         if (consoles[i].dev_handle == (dev_handle_t) IPC_GET_ARG1(*icall)) {
  528.             cons = &consoles[i];
  529.             break;
  530.         }
  531.     }
  532.    
  533.     if (cons == NULL) {
  534.         ipc_answer_0(iid, ENOENT);
  535.         return;
  536.     }
  537.    
  538.     ipc_callid_t callid;
  539.     ipc_call_t call;
  540.     ipcarg_t arg1;
  541.     ipcarg_t arg2;
  542.     ipcarg_t arg3;
  543.  
  544.     int cons_ccap;
  545.     int rc;
  546.    
  547.     async_serialize_start();
  548.     if (cons->refcount == 0)
  549.         gcons_notify_connect(cons->index);
  550.    
  551.     cons->refcount++;
  552.    
  553.     /* Accept the connection */
  554.     ipc_answer_0(iid, EOK);
  555.    
  556.     while (true) {
  557.         async_serialize_end();
  558.         callid = async_get_call(&call);
  559.         async_serialize_start();
  560.        
  561.         arg1 = 0;
  562.         arg2 = 0;
  563.         arg3 = 0;
  564.        
  565.         switch (IPC_GET_METHOD(call)) {
  566.         case IPC_M_PHONE_HUNGUP:
  567.             cons->refcount--;
  568.             if (cons->refcount == 0)
  569.                 gcons_notify_disconnect(cons->index);
  570.             return;
  571.         case VFS_OUT_READ:
  572.             async_serialize_end();
  573.             cons_read(cons, callid, &call);
  574.             async_serialize_start();
  575.             continue;
  576.         case VFS_OUT_WRITE:
  577.             async_serialize_end();
  578.             cons_write(cons, callid, &call);
  579.             async_serialize_start();
  580.             continue;
  581.         case VFS_OUT_SYNC:
  582.             fb_pending_flush();
  583.             if (cons == active_console) {
  584.                 async_req_0_0(fb_info.phone, FB_FLUSH);
  585.                
  586.                 curs_goto(cons->scr.position_x, cons->scr.position_y);
  587.             }
  588.             break;
  589.         case CONSOLE_CLEAR:
  590.             /* Send message to fb */
  591.             if (cons == active_console)
  592.                 async_msg_0(fb_info.phone, FB_CLEAR);
  593.            
  594.             screenbuffer_clear(&cons->scr);
  595.            
  596.             break;
  597.         case CONSOLE_GOTO:
  598.             screenbuffer_goto(&cons->scr,
  599.                 IPC_GET_ARG1(call), IPC_GET_ARG2(call));
  600.             if (cons == active_console)
  601.                 curs_goto(IPC_GET_ARG1(call),
  602.                     IPC_GET_ARG2(call));
  603.             break;
  604.         case CONSOLE_GET_SIZE:
  605.             arg1 = fb_info.cols;
  606.             arg2 = fb_info.rows;
  607.             break;
  608.         case CONSOLE_GET_COLOR_CAP:
  609.             rc = ccap_fb_to_con(fb_info.color_cap, &cons_ccap);
  610.             if (rc != EOK) {
  611.                 ipc_answer_0(callid, rc);
  612.                 continue;
  613.             }
  614.             arg1 = cons_ccap;
  615.             break;
  616.         case CONSOLE_SET_STYLE:
  617.             fb_pending_flush();
  618.             arg1 = IPC_GET_ARG1(call);
  619.             screenbuffer_set_style(&cons->scr, arg1);
  620.             if (cons == active_console)
  621.                 set_style(arg1);
  622.             break;
  623.         case CONSOLE_SET_COLOR:
  624.             fb_pending_flush();
  625.             arg1 = IPC_GET_ARG1(call);
  626.             arg2 = IPC_GET_ARG2(call);
  627.             arg3 = IPC_GET_ARG3(call);
  628.             screenbuffer_set_color(&cons->scr, arg1, arg2, arg3);
  629.             if (cons == active_console)
  630.                 set_color(arg1, arg2, arg3);
  631.             break;
  632.         case CONSOLE_SET_RGB_COLOR:
  633.             fb_pending_flush();
  634.             arg1 = IPC_GET_ARG1(call);
  635.             arg2 = IPC_GET_ARG2(call);
  636.             screenbuffer_set_rgb_color(&cons->scr, arg1, arg2);
  637.             if (cons == active_console)
  638.                 set_rgb_color(arg1, arg2);
  639.             break;
  640.         case CONSOLE_CURSOR_VISIBILITY:
  641.             fb_pending_flush();
  642.             arg1 = IPC_GET_ARG1(call);
  643.             cons->scr.is_cursor_visible = arg1;
  644.             if (cons == active_console)
  645.                 curs_visibility(arg1);
  646.             break;
  647.         case CONSOLE_GET_EVENT:
  648.             async_serialize_end();
  649.             cons_get_event(cons, callid, &call);
  650.             async_serialize_start();
  651.             continue;
  652.         case CONSOLE_KCON_ENABLE:
  653.             change_console(kernel_console);
  654.             break;
  655.         }
  656.         ipc_answer_3(callid, EOK, arg1, arg2, arg3);
  657.     }
  658. }
  659.  
  660. static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
  661. {
  662.     change_console(prev_console);
  663. }
  664.  
  665. static bool console_init(void)
  666. {
  667.     ipcarg_t color_cap;
  668.  
  669.     /* Connect to keyboard driver */
  670.     kbd_phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_KEYBOARD, 0, 0);
  671.     if (kbd_phone < 0) {
  672.         printf(NAME ": Failed to connect to keyboard service\n");
  673.         return false;
  674.     }
  675.    
  676.     ipcarg_t phonehash;
  677.     if (ipc_connect_to_me(kbd_phone, SERVICE_CONSOLE, 0, 0, &phonehash) != 0) {
  678.         printf(NAME ": Failed to create callback from keyboard service\n");
  679.         return false;
  680.     }
  681.    
  682.     async_new_connection(phonehash, 0, NULL, keyboard_events);
  683.  
  684.     /* Connect to framebuffer driver */
  685.     fb_info.phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_VIDEO, 0, 0);
  686.     if (fb_info.phone < 0) {
  687.         printf(NAME ": Failed to connect to video service\n");
  688.         return -1;
  689.     }
  690.    
  691.     /* Register driver */
  692.     int rc = devmap_driver_register(NAME, client_connection);
  693.     if (rc < 0) {
  694.         printf(NAME ": Unable to register driver (%d)\n", rc);
  695.         return false;
  696.     }
  697.    
  698.     /* Initialize gcons */
  699.     gcons_init(fb_info.phone);
  700.    
  701.     /* Synchronize, the gcons could put something in queue */
  702.     async_req_0_0(fb_info.phone, FB_FLUSH);
  703.     async_req_0_2(fb_info.phone, FB_GET_CSIZE, &fb_info.cols, &fb_info.rows);
  704.     async_req_0_1(fb_info.phone, FB_GET_COLOR_CAP, &color_cap);
  705.     fb_info.color_cap = color_cap;
  706.    
  707.     /* Set up shared memory buffer. */
  708.     size_t ib_size = sizeof(keyfield_t) * fb_info.cols * fb_info.rows;
  709.     interbuffer = as_get_mappable_page(ib_size);
  710.    
  711.     if (as_area_create(interbuffer, ib_size, AS_AREA_READ |
  712.         AS_AREA_WRITE | AS_AREA_CACHEABLE) != interbuffer)
  713.         interbuffer = NULL;
  714.    
  715.     if (interbuffer) {
  716.         if (ipc_share_out_start(fb_info.phone, interbuffer,
  717.             AS_AREA_READ) != EOK) {
  718.             as_area_destroy(interbuffer);
  719.             interbuffer = NULL;
  720.         }
  721.     }
  722.    
  723.     fb_pending.cnt = 0;
  724.    
  725.     /* Inititalize consoles */
  726.     size_t i;
  727.     for (i = 0; i < CONSOLE_COUNT; i++) {
  728.         if (i != KERNEL_CONSOLE) {
  729.             if (screenbuffer_init(&consoles[i].scr,
  730.                 fb_info.cols, fb_info.rows) == NULL) {
  731.                 printf(NAME ": Unable to allocate screen buffer %u\n", i);
  732.                 return false;
  733.             }
  734.             screenbuffer_clear(&consoles[i].scr);
  735.             keybuffer_init(&consoles[i].keybuffer);
  736.             consoles[i].index = i;
  737.             consoles[i].refcount = 0;
  738.            
  739.             char vc[MAX_DEVICE_NAME];
  740.             snprintf(vc, MAX_DEVICE_NAME, "vc%u", i);
  741.            
  742.             if (devmap_device_register(vc, &consoles[i].dev_handle) != EOK) {
  743.                 devmap_hangup_phone(DEVMAP_DRIVER);
  744.                 printf(NAME ": Unable to register device %s\n", vc);
  745.                 return false;
  746.             }
  747.         }
  748.     }
  749.    
  750.     /* Disable kernel output to the console */
  751.     __SYSCALL0(SYS_DEBUG_DISABLE_CONSOLE);
  752.    
  753.     /* Initialize the screen */
  754.     async_serialize_start();
  755.     gcons_redraw_console();
  756.     set_rgb_color(DEFAULT_FOREGROUND, DEFAULT_BACKGROUND);
  757.     screen_clear();
  758.     curs_goto(0, 0);
  759.     curs_visibility(active_console->scr.is_cursor_visible);
  760.     async_serialize_end();
  761.    
  762.     /* Receive kernel notifications */
  763.     if (event_subscribe(EVENT_KCONSOLE, 0) != EOK)
  764.         printf(NAME ": Error registering kconsole notifications\n");
  765.    
  766.     async_set_interrupt_received(interrupt_received);
  767.    
  768.     return true;
  769. }
  770.  
  771. int main(int argc, char *argv[])
  772. {
  773.     printf(NAME ": HelenOS Console service\n");
  774.    
  775.     if (!console_init())
  776.         return -1;
  777.    
  778.     printf(NAME ": Accepting connections\n");
  779.     async_manager();
  780.    
  781.     return 0;
  782. }
  783.  
  784. /** @}
  785.  */
  786.