Subversion Repositories HelenOS

Rev

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

  1. /*
  2.  * Copyright (c) 2006 Ondrej Palkovsky
  3.  * Copyright (c) 2008 Martin Decky
  4.  * Copyright (c) 2008 Pavel Rimsky
  5.  * All rights reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  *
  11.  * - Redistributions of source code must retain the above copyright
  12.  *   notice, this list of conditions and the following disclaimer.
  13.  * - Redistributions in binary form must reproduce the above copyright
  14.  *   notice, this list of conditions and the following disclaimer in the
  15.  *   documentation and/or other materials provided with the distribution.
  16.  * - The name of the author may not be used to endorse or promote products
  17.  *   derived from this software without specific prior written permission.
  18.  *
  19.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  20.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  21.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  22.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  23.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  24.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  28.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29.  */
  30.  
  31. /**
  32.  * @defgroup serial Serial console
  33.  * @brief    Serial console services (putc, puts, clear screen, cursor goto,...)
  34.  * @{
  35.  */
  36.  
  37. /** @file
  38.  */
  39.  
  40. #include <stdio.h>
  41. #include <ipc/ipc.h>
  42. #include <async.h>
  43. #include <ipc/fb.h>
  44. #include <bool.h>
  45. #include <errno.h>
  46. #include <console/color.h>
  47. #include <console/style.h>
  48.  
  49. #include "serial_console.h"
  50.  
  51. #define MAX_CONTROL 20
  52.  
  53. static void serial_sgr(const unsigned int mode);
  54.  
  55. static int width;
  56. static int height;
  57. static bool color = true;   /** True if producing color output. */
  58. static putc_function_t putc_function;
  59.  
  60. /* Allow only 1 connection */
  61. static int client_connected = 0;
  62.  
  63. enum sgr_color_index {
  64.     CI_BLACK    = 0,
  65.     CI_RED      = 1,
  66.     CI_GREEN    = 2,
  67.     CI_BROWN    = 3,
  68.     CI_BLUE     = 4,
  69.     CI_MAGENTA  = 5,
  70.     CI_CYAN     = 6,
  71.     CI_WHITE    = 7,
  72. };
  73.  
  74. enum sgr_command {
  75.     SGR_RESET   = 0,
  76.     SGR_BOLD    = 1,
  77.     SGR_BLINK   = 5,
  78.     SGR_REVERSE = 7,
  79.     SGR_NORMAL_INT  = 22,
  80.     SGR_BLINK_OFF   = 25,
  81.     SGR_REVERSE_OFF = 27,
  82.     SGR_FGCOLOR = 30,
  83.     SGR_BGCOLOR = 40
  84. };
  85.  
  86. static int color_map[] = {
  87.     [COLOR_BLACK]   = CI_BLACK,
  88.     [COLOR_BLUE]    = CI_RED,
  89.     [COLOR_GREEN]   = CI_GREEN,
  90.     [COLOR_CYAN]    = CI_CYAN,
  91.     [COLOR_RED] = CI_RED,
  92.     [COLOR_MAGENTA] = CI_MAGENTA,
  93.     [COLOR_YELLOW]  = CI_BROWN,
  94.     [COLOR_WHITE]   = CI_WHITE
  95. };
  96.  
  97. void serial_puts(char *str)
  98. {
  99.     while (*str)
  100.         putc_function(*(str++));
  101. }
  102.  
  103. void serial_goto(const unsigned int row, const unsigned int col)
  104. {
  105.     if ((row > height) || (col > width))
  106.         return;
  107.    
  108.     char control[MAX_CONTROL];
  109.     snprintf(control, MAX_CONTROL, "\033[%u;%uf", row + 1, col + 1);
  110.     serial_puts(control);
  111. }
  112.  
  113. void serial_clrscr(void)
  114. {
  115.     /* Initialize graphic rendition attributes. */
  116.     serial_sgr(SGR_RESET);
  117.     if (color) {
  118.         serial_sgr(SGR_FGCOLOR + CI_BLACK);
  119.         serial_sgr(SGR_BGCOLOR + CI_WHITE);
  120.     }
  121.  
  122.     serial_puts("\033[2J");
  123. }
  124.  
  125. void serial_scroll(int i)
  126. {
  127.     if (i > 0) {
  128.         serial_goto(height - 1, 0);
  129.         while (i--)
  130.             serial_puts("\033D");
  131.     } else if (i < 0) {
  132.         serial_goto(0, 0);
  133.         while (i++)
  134.             serial_puts("\033M");
  135.     }
  136. }
  137.  
  138. /** ECMA-48 Set Graphics Rendition. */
  139. static void serial_sgr(const unsigned int mode)
  140. {
  141.     char control[MAX_CONTROL];
  142.     snprintf(control, MAX_CONTROL, "\033[%um", mode);
  143.     serial_puts(control);
  144. }
  145.  
  146. /** Set scrolling region. */
  147. void serial_set_scroll_region(unsigned last_row)
  148. {
  149.     char control[MAX_CONTROL];
  150.     snprintf(control, MAX_CONTROL, "\033[0;%ur", last_row);
  151.     serial_puts(control);
  152. }
  153.  
  154. void serial_cursor_disable(void)
  155. {
  156.     serial_puts("\033[?25l");
  157. }
  158.  
  159. void serial_cursor_enable(void)
  160. {
  161.     serial_puts("\033[?25h");
  162. }
  163.  
  164. void serial_console_init(putc_function_t putc_fn, uint32_t w, uint32_t h)
  165. {
  166.     width = w;
  167.     height = h;
  168.     putc_function = putc_fn;
  169. }
  170.  
  171. /**
  172.  * Main function of the thread serving client connections.
  173.  */
  174. void serial_client_connection(ipc_callid_t iid, ipc_call_t *icall)
  175. {
  176.     int retval;
  177.     ipc_callid_t callid;
  178.     ipc_call_t call;
  179.     char c;
  180.     int lastcol = 0;
  181.     int lastrow = 0;
  182.     int newcol;
  183.     int newrow;
  184.     int fgcolor;
  185.     int bgcolor;
  186.     int style;
  187.     int i;
  188.    
  189.     if (client_connected) {
  190.         ipc_answer_0(iid, ELIMIT);
  191.         return;
  192.     }
  193.    
  194.     client_connected = 1;
  195.     ipc_answer_0(iid, EOK);
  196.    
  197.     /* Clear the terminal, set scrolling region
  198.        to 0 - height rows. */
  199.     serial_clrscr();
  200.     serial_goto(0, 0);
  201.     serial_set_scroll_region(height);
  202.    
  203.     while (true) {
  204.         callid = async_get_call(&call);
  205.         switch (IPC_GET_METHOD(call)) {
  206.         case IPC_M_PHONE_HUNGUP:
  207.             client_connected = 0;
  208.             ipc_answer_0(callid, EOK);
  209.             return;
  210.         case FB_PUTCHAR:
  211.             c = IPC_GET_ARG1(call);
  212.             newrow = IPC_GET_ARG2(call);
  213.             newcol = IPC_GET_ARG3(call);
  214.             if ((lastcol != newcol) || (lastrow != newrow))
  215.                 serial_goto(newrow, newcol);
  216.             lastcol = newcol + 1;
  217.             lastrow = newrow;
  218.             (*putc_function)(c);
  219.             retval = 0;
  220.             break;
  221.         case FB_CURSOR_GOTO:
  222.             newrow = IPC_GET_ARG1(call);
  223.             newcol = IPC_GET_ARG2(call);
  224.             serial_goto(newrow, newcol);
  225.             lastrow = newrow;
  226.             lastcol = newcol;
  227.             retval = 0;
  228.             break;
  229.         case FB_GET_CSIZE:
  230.             ipc_answer_2(callid, EOK, height, width);
  231.             continue;
  232.         case FB_CLEAR:
  233.             serial_clrscr();
  234.             retval = 0;
  235.             break;
  236.         case FB_SET_STYLE:
  237.             style =  IPC_GET_ARG1(call);
  238.             if (style == STYLE_EMPHASIS) {
  239.                 if (color) {
  240.                     serial_sgr(SGR_RESET);
  241.                     serial_sgr(SGR_FGCOLOR + CI_RED);
  242.                     serial_sgr(SGR_BGCOLOR + CI_WHITE);
  243.                 }
  244.                 serial_sgr(SGR_BOLD);
  245.             } else {
  246.                 if (color) {
  247.                     serial_sgr(SGR_RESET);
  248.                     serial_sgr(SGR_FGCOLOR + CI_BLACK);
  249.                     serial_sgr(SGR_BGCOLOR + CI_WHITE);
  250.                 }
  251.                 serial_sgr(SGR_NORMAL_INT);
  252.             }
  253.             retval = 0;
  254.             break;
  255.         case FB_SET_COLOR:
  256.             fgcolor = IPC_GET_ARG1(call);
  257.             bgcolor = IPC_GET_ARG2(call);
  258.  
  259.             if (color) {
  260.                 serial_sgr(SGR_RESET);
  261.                 serial_sgr(SGR_FGCOLOR + color_map[fgcolor]);
  262.                 serial_sgr(SGR_BGCOLOR + color_map[bgcolor]);
  263.             } else {
  264.                 if (fgcolor < bgcolor)
  265.                     serial_sgr(SGR_RESET);
  266.                 else
  267.                     serial_sgr(SGR_REVERSE);
  268.             }
  269.             retval = 0;
  270.             break;
  271.         case FB_SET_RGB_COLOR:
  272.             fgcolor = IPC_GET_ARG1(call);
  273.             bgcolor = IPC_GET_ARG2(call);
  274.             if (fgcolor < bgcolor)
  275.                 serial_sgr(SGR_REVERSE_OFF);
  276.             else
  277.                 serial_sgr(SGR_REVERSE);
  278.             retval = 0;
  279.             break;
  280.         case FB_SCROLL:
  281.             i = IPC_GET_ARG1(call);
  282.             if ((i > height) || (i < -height)) {
  283.                 retval = EINVAL;
  284.                 break;
  285.             }
  286.             serial_scroll(i);
  287.             serial_goto(lastrow, lastcol);
  288.             retval = 0;
  289.             break;
  290.         case FB_CURSOR_VISIBILITY:
  291.             if(IPC_GET_ARG1(call))
  292.                 serial_cursor_enable();
  293.             else
  294.                 serial_cursor_disable();
  295.             retval = 0;
  296.             break;
  297.         default:
  298.             retval = ENOENT;
  299.         }
  300.         ipc_answer_0(callid, retval);
  301.     }
  302. }
  303.  
  304. /**
  305.  * @}
  306.  */
  307.