Subversion Repositories HelenOS

Rev

Rev 2025 | 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. /** @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.  
  53. #include "ega.h"
  54. #include "../console/screenbuffer.h"
  55. #include "main.h"
  56.  
  57. #define MAX_SAVED_SCREENS 256
  58. typedef struct saved_screen {
  59.     short *data;
  60. } saved_screen;
  61.  
  62. saved_screen saved_screens[MAX_SAVED_SCREENS];
  63.  
  64. #define EGA_IO_ADDRESS 0x3d4
  65. #define EGA_IO_SIZE 2
  66.  
  67. #define NORMAL_COLOR       0x0f
  68. #define INVERTED_COLOR     0xf0
  69.  
  70. #define EGA_STYLE(fg,bg) ((fg) > (bg) ? NORMAL_COLOR : INVERTED_COLOR)
  71.  
  72. /* Allow only 1 connection */
  73. static int client_connected = 0;
  74.  
  75. static unsigned int scr_width;
  76. static unsigned int scr_height;
  77. static char *scr_addr;
  78.  
  79. static unsigned int style = NORMAL_COLOR;
  80.  
  81. static void clrscr(void)
  82. {
  83.     int i;
  84.    
  85.     for (i = 0; i < scr_width*scr_height; i++) {
  86.         scr_addr[i * 2] = ' ';
  87.         scr_addr[i * 2 + 1] = style;
  88.     }
  89. }
  90.  
  91. static void cursor_goto(unsigned int row, unsigned int col)
  92. {
  93.     int ega_cursor;
  94.  
  95.     ega_cursor = col + scr_width * row;
  96.    
  97.     outb(EGA_IO_ADDRESS, 0xe);
  98.     outb(EGA_IO_ADDRESS + 1, (ega_cursor >> 8) & 0xff);
  99.     outb(EGA_IO_ADDRESS, 0xf);
  100.     outb(EGA_IO_ADDRESS + 1, ega_cursor & 0xff);
  101. }
  102.  
  103. static void cursor_disable(void)
  104. {
  105.     uint8_t stat;
  106.  
  107.     outb(EGA_IO_ADDRESS, 0xa);
  108.     stat=inb(EGA_IO_ADDRESS + 1);
  109.     outb(EGA_IO_ADDRESS, 0xa);
  110.     outb(EGA_IO_ADDRESS + 1, stat | (1 << 5));
  111. }
  112.  
  113. static void cursor_enable(void)
  114. {
  115.     uint8_t stat;
  116.  
  117.     outb(EGA_IO_ADDRESS, 0xa);
  118.     stat=inb(EGA_IO_ADDRESS + 1);
  119.     outb(EGA_IO_ADDRESS, 0xa);
  120.     outb(EGA_IO_ADDRESS + 1, stat & (~(1 << 5)));
  121. }
  122.  
  123. static void scroll(int rows)
  124. {
  125.     int i;
  126.     if (rows > 0) {
  127.         memcpy(scr_addr, ((char *) scr_addr) + rows * scr_width * 2,
  128.             scr_width * scr_height * 2 - rows * scr_width * 2);
  129.         for (i = 0; i < rows * scr_width; i++)
  130.             (((short *) scr_addr) + scr_width * scr_height - rows *
  131.                 scr_width)[i] = ((style << 8) + ' ');
  132.     } else if (rows < 0) {
  133.         memcpy(((char *)scr_addr) - rows * scr_width * 2, scr_addr,
  134.             scr_width * scr_height * 2 + rows * scr_width * 2);
  135.         for (i = 0; i < -rows * scr_width; i++)
  136.             ((short *)scr_addr)[i] = ((style << 8 ) + ' ');
  137.     }
  138. }
  139.  
  140. static void printchar(char c, unsigned int row, unsigned int col)
  141. {
  142.     scr_addr[(row * scr_width + col) * 2] = c;
  143.     scr_addr[(row * scr_width + col) * 2 + 1] = style;
  144.    
  145.     cursor_goto(row, col + 1);
  146. }
  147.  
  148. static void draw_text_data(keyfield_t *data)
  149. {
  150.     int i;
  151.  
  152.     for (i = 0; i < scr_width * scr_height; i++) {
  153.         scr_addr[i * 2] = data[i].character;
  154.         scr_addr[i * 2 + 1] = EGA_STYLE(data[i].style.fg_color,
  155.             data[i].style.bg_color);
  156.     }
  157. }
  158.  
  159. static int save_screen(void)
  160. {
  161.     int i;
  162.  
  163.     for (i=0; (i < MAX_SAVED_SCREENS) && (saved_screens[i].data); i++)
  164.         ;
  165.     if (i == MAX_SAVED_SCREENS)
  166.         return EINVAL;
  167.     if (!(saved_screens[i].data = malloc(2 * scr_width * scr_height)))
  168.         return ENOMEM;
  169.     memcpy(saved_screens[i].data, scr_addr, 2 * scr_width * scr_height);
  170.  
  171.     return i;
  172. }
  173.  
  174. static int print_screen(int i)
  175. {
  176.     if (saved_screens[i].data)
  177.         memcpy(scr_addr, saved_screens[i].data, 2 * scr_width *
  178.             scr_height);
  179.     else
  180.         return EINVAL;
  181.     return i;
  182. }
  183.  
  184.  
  185. static void ega_client_connection(ipc_callid_t iid, ipc_call_t *icall)
  186. {
  187.     int retval;
  188.     ipc_callid_t callid;
  189.     ipc_call_t call;
  190.     char c;
  191.     unsigned int row, col;
  192.     int bgcolor,fgcolor;
  193.     keyfield_t *interbuf = NULL;
  194.     size_t intersize = 0;
  195.     int i;
  196.  
  197.     if (client_connected) {
  198.         ipc_answer_fast(iid, ELIMIT, 0,0);
  199.         return;
  200.     }
  201.     client_connected = 1;
  202.     ipc_answer_fast(iid, 0, 0, 0); /* Accept connection */
  203.  
  204.     while (1) {
  205.         callid = async_get_call(&call);
  206.         switch (IPC_GET_METHOD(call)) {
  207.         case IPC_M_PHONE_HUNGUP:
  208.             client_connected = 0;
  209.             ipc_answer_fast(callid, 0, 0, 0);
  210.             return; /* Exit thread */
  211.         case IPC_M_AS_AREA_SEND:
  212.             /* We accept one area for data interchange */
  213.             intersize = IPC_GET_ARG2(call);
  214.             if (intersize >= scr_width * scr_height *
  215.                 sizeof(*interbuf)) {
  216.                 receive_comm_area(callid, &call, (void *)
  217.                     &interbuf);
  218.                 continue;
  219.             }
  220.             retval = EINVAL;
  221.             break;
  222.         case FB_DRAW_TEXT_DATA:
  223.             if (!interbuf) {
  224.                 retval = EINVAL;
  225.                 break;
  226.             }
  227.             draw_text_data(interbuf);
  228.             retval = 0;
  229.             break;
  230.         case FB_GET_CSIZE:
  231.             ipc_answer_fast(callid, 0, scr_height, scr_width);
  232.             continue;
  233.         case FB_CLEAR:
  234.             clrscr();
  235.             retval = 0;
  236.             break;
  237.         case FB_PUTCHAR:
  238.             c = IPC_GET_ARG1(call);
  239.             row = IPC_GET_ARG2(call);
  240.             col = IPC_GET_ARG3(call);
  241.             if (col >= scr_width || row >= scr_height) {
  242.                 retval = EINVAL;
  243.                 break;
  244.             }
  245.             printchar(c, row, col);
  246.             retval = 0;
  247.             break;
  248.         case FB_CURSOR_GOTO:
  249.             row = IPC_GET_ARG1(call);
  250.             col = IPC_GET_ARG2(call);
  251.             if (row >= scr_height || col >= scr_width) {
  252.                 retval = EINVAL;
  253.                 break;
  254.             }
  255.             cursor_goto(row, col);
  256.             retval = 0;
  257.             break;
  258.         case FB_SCROLL:
  259.             i = IPC_GET_ARG1(call);
  260.             if (i > scr_height || i < -((int) scr_height)) {
  261.                 retval = EINVAL;
  262.                 break;
  263.             }
  264.             scroll(i);
  265.             retval = 0;
  266.             break;
  267.         case FB_CURSOR_VISIBILITY:
  268.             if(IPC_GET_ARG1(call))
  269.                 cursor_enable();
  270.             else
  271.                 cursor_disable();
  272.             retval = 0;
  273.             break;
  274.         case FB_SET_STYLE:
  275.             fgcolor = IPC_GET_ARG1(call);
  276.             bgcolor = IPC_GET_ARG2(call);
  277.             style = EGA_STYLE(fgcolor, bgcolor);
  278.             retval = 0;
  279.             break;
  280.         case FB_VP_DRAW_PIXMAP:
  281.             i = IPC_GET_ARG2(call);
  282.             retval = print_screen(i);
  283.             break;
  284.         case FB_VP2PIXMAP:
  285.             retval = save_screen();
  286.             break;
  287.         case FB_DROP_PIXMAP:
  288.             i = IPC_GET_ARG1(call);
  289.             if (i >= MAX_SAVED_SCREENS) {
  290.                 retval = EINVAL;
  291.                 break;
  292.             }
  293.             if (saved_screens[i].data) {
  294.                 free(saved_screens[i].data);
  295.                 saved_screens[i].data = NULL;
  296.             }
  297.             retval = 0;
  298.             break;
  299.  
  300.         default:
  301.             retval = ENOENT;
  302.         }
  303.         ipc_answer_fast(callid, retval, 0, 0);
  304.     }
  305. }
  306.  
  307. int ega_init(void)
  308. {
  309.     void *ega_ph_addr;
  310.     size_t sz;
  311.  
  312.     ega_ph_addr = (void *) sysinfo_value("fb.address.physical");
  313.     scr_width = sysinfo_value("fb.width");
  314.     scr_height = sysinfo_value("fb.height");
  315.     iospace_enable(task_get_id(), (void *) EGA_IO_ADDRESS, 2);
  316.  
  317.     sz = scr_width * scr_height * 2;
  318.     scr_addr = as_get_mappable_page(sz, (int)
  319.         sysinfo_value("fb.address.color"));
  320.  
  321.     physmem_map(ega_ph_addr, scr_addr, ALIGN_UP(sz, PAGE_SIZE) >>
  322.         PAGE_WIDTH, AS_AREA_READ | AS_AREA_WRITE);
  323.  
  324.     async_set_client_connection(ega_client_connection);
  325.  
  326.     return 0;
  327. }
  328.  
  329.  
  330. /**
  331.  * @}
  332.  */
  333.