Subversion Repositories HelenOS

Rev

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