Subversion Repositories HelenOS

Rev

Rev 3908 | Rev 4164 | Go to most recent revision | Blame | Compare with Previous | 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. /** @defgroup egafb EGA framebuffer
  30.  * @brief   HelenOS EGA framebuffer.
  31.  * @ingroup fbs
  32.  * @{
  33.  */
  34. /** @file
  35.  */
  36.  
  37. #include <stdlib.h>
  38. #include <unistd.h>
  39. #include <align.h>
  40. #include <async.h>
  41. #include <ipc/ipc.h>
  42. #include <errno.h>
  43. #include <stdio.h>
  44. #include <ddi.h>
  45. #include <sysinfo.h>
  46. #include <as.h>
  47. #include <ipc/fb.h>
  48. #include <ipc/ipc.h>
  49. #include <ipc/ns.h>
  50. #include <ipc/services.h>
  51. #include <libarch/ddi.h>
  52. #include <console/style.h>
  53. #include <console/color.h>
  54.  
  55. #include "ega.h"
  56. #include "../console/screenbuffer.h"
  57. #include "main.h"
  58.  
  59. #define MAX_SAVED_SCREENS 256
  60. typedef struct saved_screen {
  61.     short *data;
  62. } saved_screen;
  63.  
  64. saved_screen saved_screens[MAX_SAVED_SCREENS];
  65.  
  66. #define EGA_IO_ADDRESS 0x3d4
  67. #define EGA_IO_SIZE 2
  68.  
  69. int ega_normal_color = 0x0f;
  70. int ega_inverted_color = 0xf0;
  71.  
  72. #define NORMAL_COLOR        ega_normal_color      
  73. #define INVERTED_COLOR      ega_inverted_color
  74.  
  75. /* Allow only 1 connection */
  76. static int client_connected = 0;
  77.  
  78. static unsigned int scr_width;
  79. static unsigned int scr_height;
  80. static char *scr_addr;
  81.  
  82. static unsigned int style;
  83.  
  84. static unsigned attr_to_ega_style(const attrs_t *a);
  85.  
  86. static void clrscr(void)
  87. {
  88.     int i;
  89.    
  90.     for (i = 0; i < scr_width * scr_height; i++) {
  91.         scr_addr[i * 2] = ' ';
  92.         scr_addr[i * 2 + 1] = style;
  93.     }
  94. }
  95.  
  96. static void cursor_goto(unsigned int row, unsigned int col)
  97. {
  98.     int ega_cursor;
  99.  
  100.     ega_cursor = col + scr_width * row;
  101.    
  102.     outb(EGA_IO_ADDRESS, 0xe);
  103.     outb(EGA_IO_ADDRESS + 1, (ega_cursor >> 8) & 0xff);
  104.     outb(EGA_IO_ADDRESS, 0xf);
  105.     outb(EGA_IO_ADDRESS + 1, ega_cursor & 0xff);
  106. }
  107.  
  108. static void cursor_disable(void)
  109. {
  110.     uint8_t stat;
  111.  
  112.     outb(EGA_IO_ADDRESS, 0xa);
  113.     stat=inb(EGA_IO_ADDRESS + 1);
  114.     outb(EGA_IO_ADDRESS, 0xa);
  115.     outb(EGA_IO_ADDRESS + 1, stat | (1 << 5));
  116. }
  117.  
  118. static void cursor_enable(void)
  119. {
  120.     uint8_t stat;
  121.  
  122.     outb(EGA_IO_ADDRESS, 0xa);
  123.     stat=inb(EGA_IO_ADDRESS + 1);
  124.     outb(EGA_IO_ADDRESS, 0xa);
  125.     outb(EGA_IO_ADDRESS + 1, stat & (~(1 << 5)));
  126. }
  127.  
  128. static void scroll(int rows)
  129. {
  130.     int i;
  131.     if (rows > 0) {
  132.         memmove(scr_addr, ((char *) scr_addr) + rows * scr_width * 2,
  133.             scr_width * scr_height * 2 - rows * scr_width * 2);
  134.         for (i = 0; i < rows * scr_width; i++)
  135.             (((short *) scr_addr) + scr_width * scr_height - rows *
  136.                 scr_width)[i] = ((style << 8) + ' ');
  137.     } else if (rows < 0) {
  138.         memmove(((char *)scr_addr) - rows * scr_width * 2, scr_addr,
  139.             scr_width * scr_height * 2 + rows * scr_width * 2);
  140.         for (i = 0; i < -rows * scr_width; i++)
  141.             ((short *)scr_addr)[i] = ((style << 8 ) + ' ');
  142.     }
  143. }
  144.  
  145. static void printchar(char c, unsigned int row, unsigned int col)
  146. {
  147.     scr_addr[(row * scr_width + col) * 2] = c;
  148.     scr_addr[(row * scr_width + col) * 2 + 1] = style;
  149.    
  150.     cursor_goto(row, col + 1);
  151. }
  152.  
  153. static void draw_text_data(keyfield_t *data)
  154. {
  155.     int i;
  156.  
  157.     for (i = 0; i < scr_width * scr_height; i++) {
  158.         scr_addr[i * 2] = data[i].character;
  159.         scr_addr[i * 2 + 1] = attr_to_ega_style(&data[i].attrs);
  160.     }
  161. }
  162.  
  163. static int save_screen(void)
  164. {
  165.     int i;
  166.  
  167.     for (i = 0; (i < MAX_SAVED_SCREENS) && (saved_screens[i].data); i++)
  168.         ;
  169.     if (i == MAX_SAVED_SCREENS)
  170.         return EINVAL;
  171.     if (!(saved_screens[i].data = malloc(2 * scr_width * scr_height)))
  172.         return ENOMEM;
  173.     memcpy(saved_screens[i].data, scr_addr, 2 * scr_width * scr_height);
  174.  
  175.     return i;
  176. }
  177.  
  178. static int print_screen(int i)
  179. {
  180.     if (saved_screens[i].data)
  181.         memcpy(scr_addr, saved_screens[i].data, 2 * scr_width *
  182.             scr_height);
  183.     else
  184.         return EINVAL;
  185.     return i;
  186. }
  187.  
  188. static int style_to_ega_style(int style)
  189. {
  190.     unsigned int ega_style;
  191.  
  192.     switch (style) {
  193.     case STYLE_NORMAL:
  194.         ega_style = INVERTED_COLOR;
  195.         break;
  196.     case STYLE_EMPHASIS:
  197.         ega_style = INVERTED_COLOR | 4;
  198.         break;
  199.     default:
  200.         return INVERTED_COLOR;
  201.     }
  202.  
  203.     return ega_style;
  204. }
  205.  
  206. static unsigned int color_to_ega_style(int fg_color, int bg_color, int attr)
  207. {
  208.     unsigned int style;
  209.  
  210.     style = (fg_color & 7) | ((bg_color & 7) << 4);
  211.     if (attr & CATTR_BRIGHT)
  212.         style = style | 0x08;
  213.  
  214.     return style;
  215. }
  216.  
  217. static unsigned int rgb_to_ega_style(uint32_t fg, uint32_t bg)
  218. {
  219.     return (fg > bg) ? NORMAL_COLOR : INVERTED_COLOR;
  220. }
  221.  
  222. static unsigned attr_to_ega_style(const attrs_t *a)
  223. {
  224.     switch (a->t) {
  225.     case at_style: return style_to_ega_style(a->a.s.style);
  226.     case at_rgb: return rgb_to_ega_style(a->a.r.fg_color, a->a.r.bg_color);
  227.     case at_idx: return color_to_ega_style(a->a.i.fg_color,
  228.         a->a.i.bg_color, a->a.i.flags);
  229.     default: return INVERTED_COLOR;
  230.     }
  231. }
  232.  
  233. static void ega_client_connection(ipc_callid_t iid, ipc_call_t *icall)
  234. {
  235.     int retval;
  236.     ipc_callid_t callid;
  237.     ipc_call_t call;
  238.     char c;
  239.     unsigned int row, col;
  240.     int bg_color, fg_color, attr;
  241.     uint32_t bg_rgb, fg_rgb;
  242.     keyfield_t *interbuf = NULL;
  243.     size_t intersize = 0;
  244.     int i;
  245.  
  246.     if (client_connected) {
  247.         ipc_answer_0(iid, ELIMIT);
  248.         return;
  249.     }
  250.     client_connected = 1;
  251.     ipc_answer_0(iid, EOK); /* Accept connection */
  252.  
  253.     while (1) {
  254.         callid = async_get_call(&call);
  255.         switch (IPC_GET_METHOD(call)) {
  256.         case IPC_M_PHONE_HUNGUP:
  257.             client_connected = 0;
  258.             ipc_answer_0(callid, EOK);
  259.             return; /* Exit thread */
  260.         case IPC_M_SHARE_OUT:
  261.             /* We accept one area for data interchange */
  262.             intersize = IPC_GET_ARG2(call);
  263.             if (intersize >= scr_width * scr_height *
  264.                 sizeof(*interbuf)) {
  265.                 receive_comm_area(callid, &call,
  266.                     (void *) &interbuf);
  267.                 continue;
  268.             }
  269.             retval = EINVAL;
  270.             break;
  271.         case FB_DRAW_TEXT_DATA:
  272.             if (!interbuf) {
  273.                 retval = EINVAL;
  274.                 break;
  275.             }
  276.             draw_text_data(interbuf);
  277.             retval = 0;
  278.             break;
  279.         case FB_GET_CSIZE:
  280.             ipc_answer_2(callid, EOK, scr_height, scr_width);
  281.             continue;
  282.         case FB_CLEAR:
  283.             clrscr();
  284.             retval = 0;
  285.             break;
  286.         case FB_PUTCHAR:
  287.             c = IPC_GET_ARG1(call);
  288.             row = IPC_GET_ARG2(call);
  289.             col = IPC_GET_ARG3(call);
  290.             if (col >= scr_width || row >= scr_height) {
  291.                 retval = EINVAL;
  292.                 break;
  293.             }
  294.             printchar(c, row, col);
  295.             retval = 0;
  296.             break;
  297.         case FB_CURSOR_GOTO:
  298.             row = IPC_GET_ARG1(call);
  299.             col = IPC_GET_ARG2(call);
  300.             if (row >= scr_height || col >= scr_width) {
  301.                 retval = EINVAL;
  302.                 break;
  303.             }
  304.             cursor_goto(row, col);
  305.             retval = 0;
  306.             break;
  307.         case FB_SCROLL:
  308.             i = IPC_GET_ARG1(call);
  309.             if (i > scr_height || i < -((int) scr_height)) {
  310.                 retval = EINVAL;
  311.                 break;
  312.             }
  313.             scroll(i);
  314.             retval = 0;
  315.             break;
  316.         case FB_CURSOR_VISIBILITY:
  317.             if (IPC_GET_ARG1(call))
  318.                 cursor_enable();
  319.             else
  320.                 cursor_disable();
  321.             retval = 0;
  322.             break;
  323.         case FB_SET_STYLE:
  324.             style = style_to_ega_style(IPC_GET_ARG1(call));
  325.             retval = 0;
  326.             break;
  327.         case FB_SET_COLOR:
  328.             fg_color = IPC_GET_ARG1(call);
  329.             bg_color = IPC_GET_ARG2(call);
  330.             attr = IPC_GET_ARG3(call);
  331.             style = color_to_ega_style(fg_color, bg_color, attr);
  332.             retval = 0;
  333.             break;
  334.         case FB_SET_RGB_COLOR:
  335.             fg_rgb = IPC_GET_ARG1(call);
  336.             bg_rgb = IPC_GET_ARG2(call);
  337.             style = rgb_to_ega_style(fg_rgb, bg_rgb);
  338.             retval = 0;
  339.             break;
  340.         case FB_VP_DRAW_PIXMAP:
  341.             i = IPC_GET_ARG2(call);
  342.             retval = print_screen(i);
  343.             break;
  344.         case FB_VP2PIXMAP:
  345.             retval = save_screen();
  346.             break;
  347.         case FB_DROP_PIXMAP:
  348.             i = IPC_GET_ARG1(call);
  349.             if (i >= MAX_SAVED_SCREENS) {
  350.                 retval = EINVAL;
  351.                 break;
  352.             }
  353.             if (saved_screens[i].data) {
  354.                 free(saved_screens[i].data);
  355.                 saved_screens[i].data = NULL;
  356.             }
  357.             retval = 0;
  358.             break;
  359.  
  360.         default:
  361.             retval = ENOENT;
  362.         }
  363.         ipc_answer_0(callid, retval);
  364.     }
  365. }
  366.  
  367. int ega_init(void)
  368. {
  369.     void *ega_ph_addr;
  370.     size_t sz;
  371.  
  372.     ega_ph_addr = (void *) sysinfo_value("fb.address.physical");
  373.     scr_width = sysinfo_value("fb.width");
  374.     scr_height = sysinfo_value("fb.height");
  375.  
  376.     if (sysinfo_value("fb.blinking")) {
  377.         ega_normal_color &= 0x77;
  378.         ega_inverted_color &= 0x77;
  379.     }
  380.  
  381.     style = NORMAL_COLOR;
  382.  
  383.     iospace_enable(task_get_id(), (void *) EGA_IO_ADDRESS, 2);
  384.  
  385.     sz = scr_width * scr_height * 2;
  386.     scr_addr = as_get_mappable_page(sz);
  387.  
  388.     if (physmem_map(ega_ph_addr, scr_addr, ALIGN_UP(sz, PAGE_SIZE) >>
  389.         PAGE_WIDTH, AS_AREA_READ | AS_AREA_WRITE) != 0)
  390.         return -1;
  391.  
  392.     async_set_client_connection(ega_client_connection);
  393.  
  394.     return 0;
  395. }
  396.  
  397.  
  398. /**
  399.  * @}
  400.  */
  401.