Subversion Repositories HelenOS

Rev

Rev 1867 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (C) 2006 Ondrej Palkovsky
  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 <ipc/fb.h>
  36. #include <ipc/ipc.h>
  37. #include <async.h>
  38. #include <stdio.h>
  39. #include <sys/mman.h>
  40. #include <string.h>
  41. #include <align.h>
  42.  
  43. #include "console.h"
  44. #include "gcons.h"
  45.  
  46. #define CONSOLE_TOP      66
  47. #define CONSOLE_MARGIN   6
  48.  
  49. #define STATUS_START    110
  50. #define STATUS_TOP      8
  51. #define STATUS_SPACE    4
  52. #define STATUS_WIDTH    48
  53. #define STATUS_HEIGHT   48
  54.  
  55. #define MAIN_COLOR      0xffffff
  56.  
  57. static int use_gcons = 0;
  58. static ipcarg_t xres,yres;
  59.  
  60. enum butstate {
  61.     CONS_DISCONNECTED = 0,
  62.     CONS_SELECTED,
  63.     CONS_IDLE,
  64.     CONS_HAS_DATA,
  65.     CONS_KERNEL,
  66.     CONS_DISCONNECTED_SEL,
  67.     CONS_LAST
  68. };
  69.  
  70. static int console_vp;
  71. static int cstatus_vp[CONSOLE_COUNT];
  72. static enum butstate console_state[CONSOLE_COUNT];
  73.  
  74. static int fbphone;
  75.  
  76. /** List of pixmaps identifying these icons */
  77. static int ic_pixmaps[CONS_LAST] = {-1, -1, -1, -1, -1, -1};
  78. static int animation = -1;
  79.  
  80. static int active_console = 0;
  81.  
  82. static void vp_switch(int vp)
  83. {
  84.     async_msg(fbphone,FB_VIEWPORT_SWITCH, vp);
  85. }
  86.  
  87. /** Create view port */
  88. static int vp_create(unsigned int x, unsigned int y,
  89.              unsigned int width, unsigned int height)
  90. {
  91.     return async_req_2(fbphone, FB_VIEWPORT_CREATE,
  92.                (x << 16) | y, (width << 16) | height,
  93.                NULL, NULL);
  94. }
  95.  
  96. static void clear(void)
  97. {
  98.     async_msg(fbphone, FB_CLEAR, 0);
  99.    
  100. }
  101.  
  102. static void set_style(int fgcolor, int bgcolor)
  103. {
  104.     async_msg_2(fbphone, FB_SET_STYLE, fgcolor, bgcolor);
  105. }
  106.  
  107. /** Transparent putchar */
  108. static void tran_putch(char c, int row, int col)
  109. {
  110.     async_msg_3(fbphone, FB_TRANS_PUTCHAR, c, row, col);
  111. }
  112.  
  113. /** Redraw the button showing state of a given console */
  114. static void redraw_state(int consnum)
  115. {
  116.     char data[5];
  117.     int i;
  118.     enum butstate state = console_state[consnum];
  119.  
  120.     vp_switch(cstatus_vp[consnum]);
  121.     if (ic_pixmaps[state] != -1)
  122.         async_msg_2(fbphone, FB_VP_DRAW_PIXMAP, cstatus_vp[consnum],
  123.             ic_pixmaps[state]);
  124.  
  125.     if (state != CONS_DISCONNECTED && state != CONS_KERNEL && state !=
  126.         CONS_DISCONNECTED_SEL) {
  127.         snprintf(data, 5, "%d", consnum + 1);
  128.         for (i=0; data[i]; i++)
  129.             tran_putch(data[i], 1, 2 + i);
  130.     }
  131. }
  132.  
  133. /** Notification run on changing console (except kernel console) */
  134. void gcons_change_console(int consnum)
  135. {
  136.     int i;
  137.  
  138.     if (!use_gcons)
  139.         return;
  140.  
  141.     if (active_console == KERNEL_CONSOLE) {
  142.         for (i = 0; i < CONSOLE_COUNT; i++)
  143.             redraw_state(i);
  144.         if (animation != -1)
  145.             async_msg(fbphone, FB_ANIM_START, animation);
  146.     } else {
  147.         if (console_state[active_console] == CONS_DISCONNECTED_SEL)
  148.             console_state[active_console] = CONS_DISCONNECTED;
  149.         else
  150.             console_state[active_console] = CONS_IDLE;
  151.         redraw_state(active_console);
  152.     }
  153.     active_console = consnum;
  154.  
  155.     if (console_state[consnum] == CONS_DISCONNECTED) {
  156.         console_state[consnum] = CONS_DISCONNECTED_SEL;
  157.         redraw_state(consnum);
  158.     } else
  159.         console_state[consnum] = CONS_SELECTED;
  160.     redraw_state(consnum);
  161.  
  162.     vp_switch(console_vp);
  163. }
  164.  
  165. /** Notification function that gets called on new output to virtual console */
  166. void gcons_notify_char(int consnum)
  167. {
  168.     if (!use_gcons)
  169.         return;
  170.  
  171.     if (consnum == active_console || console_state[consnum] ==
  172.         CONS_HAS_DATA)
  173.         return;
  174.  
  175.     console_state[consnum] = CONS_HAS_DATA;
  176.  
  177.     if (active_console == KERNEL_CONSOLE)
  178.         return;
  179.  
  180.     redraw_state(consnum);
  181.    
  182.     vp_switch(console_vp);
  183. }
  184.  
  185. /** Notification function called on service disconnect from console */
  186. void gcons_notify_disconnect(int consnum)
  187. {
  188.     if (!use_gcons)
  189.         return;
  190.     if (active_console == consnum)
  191.         console_state[consnum] = CONS_DISCONNECTED_SEL;
  192.     else
  193.         console_state[consnum] = CONS_DISCONNECTED;
  194.  
  195.     if (active_console == KERNEL_CONSOLE)
  196.         return;
  197.  
  198.     redraw_state(consnum);
  199.     vp_switch(console_vp);
  200. }
  201.  
  202. /** Notification function called on console connect */
  203. void gcons_notify_connect(int consnum)
  204. {
  205.     if (!use_gcons)
  206.         return;
  207.     if (active_console == consnum)
  208.         console_state[consnum] = CONS_SELECTED;
  209.     else
  210.         console_state[consnum] = CONS_IDLE;
  211.  
  212.     if (active_console == KERNEL_CONSOLE)
  213.         return;
  214.  
  215.     redraw_state(consnum);
  216.     vp_switch(console_vp);
  217. }
  218.  
  219. /** Change to kernel console */
  220. void gcons_in_kernel(void)
  221. {
  222.     if (console_state[active_console] == CONS_DISCONNECTED_SEL)
  223.         console_state[active_console] = CONS_DISCONNECTED;
  224.     else
  225.         console_state[active_console] = CONS_IDLE;
  226.     redraw_state(active_console);
  227.  
  228.     if (animation != -1)
  229.         async_msg(fbphone, FB_ANIM_STOP, animation);
  230.  
  231.     active_console = KERNEL_CONSOLE; /* Set to kernel console */
  232.     vp_switch(0);
  233. }
  234.  
  235. /** Return x, where left <= x <= right && |a-x|==min(|a-x|) is smallest */
  236. static inline int limit(int a,int left, int right)
  237. {
  238.     if (a < left)
  239.         a = left;
  240.     if (a >= right)
  241.         a = right - 1;
  242.     return a;
  243. }
  244.  
  245. int mouse_x, mouse_y;
  246. int btn_pressed, btn_x, btn_y;
  247.  
  248. /** Handle mouse move
  249.  *
  250.  * @param dx Delta X of mouse move
  251.  * @param dy Delta Y of mouse move
  252.  */
  253. void gcons_mouse_move(int dx, int dy)
  254. {
  255.     mouse_x = limit(mouse_x+dx, 0, xres);
  256.     mouse_y = limit(mouse_y+dy, 0, yres);
  257.  
  258.     async_msg_2(fbphone, FB_POINTER_MOVE, mouse_x, mouse_y);
  259. }
  260.  
  261. static int gcons_find_conbut(int x, int y)
  262. {
  263.     int status_start = STATUS_START + (xres - 800) / 2;;
  264.  
  265.     if (y < STATUS_TOP || y >= STATUS_TOP + STATUS_HEIGHT)
  266.         return -1;
  267.    
  268.     if (x < status_start)
  269.         return -1;
  270.    
  271.     if (x >= status_start + (STATUS_WIDTH + STATUS_SPACE) * CONSOLE_COUNT)
  272.         return -1;
  273.     if (((x - status_start) % (STATUS_WIDTH+STATUS_SPACE)) < STATUS_SPACE)
  274.         return -1;
  275.    
  276.     return (x - status_start) / (STATUS_WIDTH+STATUS_SPACE);
  277. }
  278.  
  279. /** Handle mouse click
  280.  *
  281.  * @param state New state (1-pressed, 0-depressed)
  282.  */
  283. int gcons_mouse_btn(int state)
  284. {
  285.     int conbut;
  286.  
  287.     if (state) {
  288.         conbut = gcons_find_conbut(mouse_x, mouse_y);
  289.         if (conbut != -1) {
  290.             btn_pressed = 1;
  291.             btn_x = mouse_x;
  292.             btn_y = mouse_y;
  293.         }
  294.         return -1;
  295.     }
  296.     if (!state && !btn_pressed)
  297.         return -1;
  298.     btn_pressed = 0;
  299.  
  300.     conbut = gcons_find_conbut(mouse_x, mouse_y);
  301.     if (conbut == gcons_find_conbut(btn_x, btn_y))
  302.         return conbut;
  303.     return -1;
  304. }
  305.  
  306.  
  307. /** Draw a PPM pixmap to framebuffer
  308.  *
  309.  * @param logo Pointer to PPM data
  310.  * @param size Size of PPM data
  311.  * @param x Coordinate of upper left corner
  312.  * @param y Coordinate of upper left corner
  313.  */
  314. static void draw_pixmap(char *logo, size_t size, int x, int y)
  315. {
  316.     char *shm;
  317.     int rc;
  318.  
  319.     /* Create area */
  320.     shm = mmap(NULL, size, PROTO_READ | PROTO_WRITE, MAP_SHARED |
  321.         MAP_ANONYMOUS, 0, 0);
  322.     if (shm == MAP_FAILED)
  323.         return;
  324.  
  325.     memcpy(shm, logo, size);
  326.     /* Send area */
  327.     rc = async_req_2(fbphone, FB_PREPARE_SHM, (ipcarg_t) shm, 0, NULL,
  328.         NULL);
  329.     if (rc)
  330.         goto exit;
  331.     rc = async_req_3(fbphone, IPC_M_AS_AREA_SEND, (ipcarg_t) shm, 0,
  332.         PROTO_READ, NULL, NULL, NULL);
  333.     if (rc)
  334.         goto drop;
  335.     /* Draw logo */
  336.     async_msg_2(fbphone, FB_DRAW_PPM, x, y);
  337. drop:
  338.     /* Drop area */
  339.     async_msg(fbphone, FB_DROP_SHM, 0);
  340. exit:      
  341.     /* Remove area */
  342.     munmap(shm, size);
  343. }
  344.  
  345. extern char _binary_helenos_ppm_start[0];
  346. extern int _binary_helenos_ppm_size;
  347. extern char _binary_nameic_ppm_start[0];
  348. extern int _binary_nameic_ppm_size;
  349. /** Redraws console graphics  */
  350. static void gcons_redraw_console(void)
  351. {
  352.     int i;
  353.  
  354.     if (!use_gcons)
  355.         return;
  356.    
  357.     vp_switch(0);
  358.     set_style(MAIN_COLOR, MAIN_COLOR);
  359.     clear();
  360.     draw_pixmap(_binary_helenos_ppm_start, (size_t)
  361.         &_binary_helenos_ppm_size, xres - 66, 2);
  362.     draw_pixmap(_binary_nameic_ppm_start, (size_t)
  363.         &_binary_nameic_ppm_size, 5, 17);
  364.  
  365.     for (i=0;i < CONSOLE_COUNT; i++)
  366.         redraw_state(i);
  367.     vp_switch(console_vp);
  368. }
  369.  
  370. /** Creates a pixmap on framebuffer
  371.  *
  372.  * @param data PPM data
  373.  * @param size PPM data size
  374.  * @return Pixmap identification
  375.  */
  376. static int make_pixmap(char *data, int size)
  377. {
  378.     char *shm;
  379.     int rc;
  380.     int pxid = -1;
  381.  
  382.     /* Create area */
  383.     shm = mmap(NULL, size, PROTO_READ | PROTO_WRITE, MAP_SHARED |
  384.         MAP_ANONYMOUS, 0, 0);
  385.     if (shm == MAP_FAILED)
  386.         return -1;
  387.  
  388.     memcpy(shm, data, size);
  389.     /* Send area */
  390.     rc = async_req_2(fbphone, FB_PREPARE_SHM, (ipcarg_t) shm, 0, NULL,
  391.         NULL);
  392.     if (rc)
  393.         goto exit;
  394.     rc = async_req_3(fbphone, IPC_M_AS_AREA_SEND, (ipcarg_t) shm, 0,
  395.         PROTO_READ, NULL, NULL, NULL);
  396.     if (rc)
  397.         goto drop;
  398.  
  399.     /* Obtain pixmap */
  400.     rc = async_req(fbphone, FB_SHM2PIXMAP, 0, NULL);
  401.     if (rc < 0)
  402.         goto drop;
  403.     pxid = rc;
  404. drop:
  405.     /* Drop area */
  406.     async_msg(fbphone, FB_DROP_SHM, 0);
  407. exit:      
  408.     /* Remove area */
  409.     munmap(shm, size);
  410.  
  411.     return pxid;
  412. }
  413.  
  414. extern char _binary_anim_1_ppm_start[0];
  415. extern int _binary_anim_1_ppm_size;
  416. extern char _binary_anim_2_ppm_start[0];
  417. extern int _binary_anim_2_ppm_size;
  418. extern char _binary_anim_3_ppm_start[0];
  419. extern int _binary_anim_3_ppm_size;
  420. extern char _binary_anim_4_ppm_start[0];
  421. extern int _binary_anim_4_ppm_size;
  422.  
  423. static void make_anim(void)
  424. {
  425.     int an;
  426.     int pm;
  427.  
  428.     an = async_req(fbphone, FB_ANIM_CREATE, cstatus_vp[KERNEL_CONSOLE],
  429.         NULL);
  430.     if (an < 0)
  431.         return;
  432.  
  433.     pm = make_pixmap(_binary_anim_1_ppm_start, (int)
  434.         &_binary_anim_1_ppm_size);
  435.     async_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
  436.  
  437.     pm = make_pixmap(_binary_anim_2_ppm_start, (int)
  438.         &_binary_anim_2_ppm_size);
  439.     async_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
  440.  
  441.     pm = make_pixmap(_binary_anim_3_ppm_start, (int)
  442.         &_binary_anim_3_ppm_size);
  443.     async_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
  444.  
  445.     pm = make_pixmap(_binary_anim_4_ppm_start, (int)
  446.         &_binary_anim_4_ppm_size);
  447.     async_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
  448.  
  449.     async_msg(fbphone, FB_ANIM_START, an);
  450.  
  451.     animation = an;
  452. }
  453.  
  454. extern char _binary_cons_selected_ppm_start[0];
  455. extern int _binary_cons_selected_ppm_size;
  456. extern char _binary_cons_idle_ppm_start[0];
  457. extern int _binary_cons_idle_ppm_size;
  458. extern char _binary_cons_has_data_ppm_start[0];
  459. extern int _binary_cons_has_data_ppm_size;
  460. extern char _binary_cons_kernel_ppm_start[0];
  461. extern int _binary_cons_kernel_ppm_size;
  462.  
  463. /** Initialize nice graphical console environment */
  464. void gcons_init(int phone)
  465. {
  466.     int rc;
  467.     int i;
  468.     int status_start = STATUS_START;
  469.  
  470.     fbphone = phone;
  471.  
  472.     rc = async_req_2(phone, FB_GET_RESOLUTION, 0, 0, &xres, &yres);
  473.     if (rc)
  474.         return;
  475.    
  476.     if (xres < 800 || yres < 600)
  477.         return;
  478.  
  479.     /* create console viewport */
  480.     /* Align width & height to character size */
  481.     console_vp = vp_create(CONSOLE_MARGIN, CONSOLE_TOP, ALIGN_DOWN(xres -
  482.         2 * CONSOLE_MARGIN, 8), ALIGN_DOWN(yres - (CONSOLE_TOP +
  483.         CONSOLE_MARGIN), 16));
  484.     if (console_vp < 0)
  485.         return;
  486.    
  487.     /* Create status buttons */
  488.     status_start += (xres - 800) / 2;
  489.     for (i = 0; i < CONSOLE_COUNT; i++) {
  490.         cstatus_vp[i] = vp_create(status_start + CONSOLE_MARGIN + i *
  491.             (STATUS_WIDTH + STATUS_SPACE), STATUS_TOP,
  492.             STATUS_WIDTH, STATUS_HEIGHT);
  493.         if (cstatus_vp[i] < 0)
  494.             return;
  495.         vp_switch(cstatus_vp[i]);
  496.         set_style(0x202020, 0xffffff);
  497.     }
  498.    
  499.     /* Initialize icons */
  500.     ic_pixmaps[CONS_SELECTED] =
  501.         make_pixmap(_binary_cons_selected_ppm_start, (int)
  502.         &_binary_cons_selected_ppm_size);
  503.     ic_pixmaps[CONS_IDLE] = make_pixmap(_binary_cons_idle_ppm_start, (int)
  504.         &_binary_cons_idle_ppm_size);
  505.     ic_pixmaps[CONS_HAS_DATA] =
  506.         make_pixmap(_binary_cons_has_data_ppm_start, (int)
  507.         &_binary_cons_has_data_ppm_size);
  508.     ic_pixmaps[CONS_DISCONNECTED] =
  509.         make_pixmap(_binary_cons_idle_ppm_start, (int)
  510.         &_binary_cons_idle_ppm_size);
  511.     ic_pixmaps[CONS_KERNEL] = make_pixmap(_binary_cons_kernel_ppm_start,
  512.         (int) &_binary_cons_kernel_ppm_size);
  513.     ic_pixmaps[CONS_DISCONNECTED_SEL] = ic_pixmaps[CONS_SELECTED];
  514.    
  515.     make_anim();
  516.  
  517.     use_gcons = 1;
  518.     console_state[0] = CONS_DISCONNECTED_SEL;
  519.     console_state[KERNEL_CONSOLE] = CONS_KERNEL;
  520.     gcons_redraw_console();
  521. }
  522.  
  523. /** @}
  524.  */
  525.  
  526.