Subversion Repositories HelenOS

Rev

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