Subversion Repositories HelenOS

Rev

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

  1. /*
  2.  * Copyright (C) 2006 Jakub Vana
  3.  * Copyright (C) 2006 Ondrej Palkovsky
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions
  8.  * are met:
  9.  *
  10.  * - Redistributions of source code must retain the above copyright
  11.  *   notice, this list of conditions and the following disclaimer.
  12.  * - Redistributions in binary form must reproduce the above copyright
  13.  *   notice, this list of conditions and the following disclaimer in the
  14.  *   documentation and/or other materials provided with the distribution.
  15.  * - The name of the author may not be used to endorse or promote products
  16.  *   derived from this software without specific prior written permission.
  17.  *
  18.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  19.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  20.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  21.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  22.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  23.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  24.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  25.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  27.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28.  */
  29.  
  30. /**
  31.  * @defgroup fb Graphical framebuffer
  32.  * @brief   HelenOS graphical framebuffer.
  33.  * @ingroup fbs
  34.  * @{
  35.  */
  36. /** @file
  37.  */
  38.  
  39.  
  40. #include <stdlib.h>
  41. #include <unistd.h>
  42. #include <string.h>
  43. #include <ddi.h>
  44. #include <sysinfo.h>
  45. #include <align.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 <kernel/errno.h>
  52. #include <async.h>
  53.  
  54. #include "font-8x16.h"
  55. #include "fb.h"
  56. #include "main.h"
  57. #include "../console/screenbuffer.h"
  58. #include "ppm.h"
  59.  
  60. #include "pointer.xbm"
  61. #include "pointer_mask.xbm"
  62.  
  63. #define DEFAULT_BGCOLOR                0xf0f0f0
  64. #define DEFAULT_FGCOLOR                0x0
  65.  
  66. /***************************************************************/
  67. /* Pixel specific fuctions */
  68.  
  69. typedef void (*conv2scr_fn_t)(void *, int);
  70. typedef int (*conv2rgb_fn_t)(void *);
  71.  
  72. struct {
  73.     uint8_t *fbaddress;
  74.  
  75.     unsigned int xres;
  76.     unsigned int yres;
  77.     unsigned int scanline;
  78.     unsigned int pixelbytes;
  79.     unsigned int invert_colors;
  80.  
  81.     conv2scr_fn_t rgb2scr;
  82.     conv2rgb_fn_t scr2rgb;
  83. } screen;
  84.  
  85. typedef struct {
  86.     int initialized;
  87.     unsigned int x, y;
  88.     unsigned int width, height;
  89.  
  90.     /* Text support in window */
  91.     unsigned int rows, cols;
  92.     /* Style for text printing */
  93.     style_t style;
  94.     /* Auto-cursor position */
  95.     int cursor_active, cur_col, cur_row;
  96.     int cursor_shown;
  97.     /* Double buffering */
  98.     uint8_t *dbdata;
  99.     unsigned int dboffset;
  100.     unsigned int paused;
  101. } viewport_t;
  102.  
  103. #define MAX_ANIM_LEN    8
  104. #define MAX_ANIMATIONS  4
  105. typedef struct {
  106.     int initialized;
  107.     int enabled;
  108.     unsigned int vp;
  109.  
  110.     unsigned int pos;
  111.     unsigned int animlen;
  112.     unsigned int pixmaps[MAX_ANIM_LEN];
  113. } animation_t;
  114. static animation_t animations[MAX_ANIMATIONS];
  115. static int anims_enabled;
  116.  
  117. /** Maximum number of saved pixmaps
  118.  * Pixmap is a saved rectangle
  119.  */
  120. #define MAX_PIXMAPS        256
  121. typedef struct {
  122.     unsigned int width;
  123.     unsigned int height;
  124.     uint8_t *data;
  125. } pixmap_t;
  126. static pixmap_t pixmaps[MAX_PIXMAPS];
  127.  
  128. /* Viewport is a rectangular area on the screen */
  129. #define MAX_VIEWPORTS 128
  130. static viewport_t viewports[128];
  131.  
  132. /* Allow only 1 connection */
  133. static int client_connected = 0;
  134.  
  135. #define RED(x, bits)    ((x >> (16 + 8 - bits)) & ((1 << bits) - 1))
  136. #define GREEN(x, bits)  ((x >> (8 + 8 - bits)) & ((1 << bits) - 1))
  137. #define BLUE(x, bits)   ((x >> (8 - bits)) & ((1 << bits) - 1))
  138.  
  139. #define COL_WIDTH   8
  140. #define ROW_BYTES   (screen.scanline * FONT_SCANLINES)
  141.  
  142. #define POINTPOS(x, y)  ((y) * screen.scanline + (x) * screen.pixelbytes)
  143.  
  144. static inline int COLOR(int color)
  145. {
  146.     return screen.invert_colors ? ~color : color;
  147. }
  148.  
  149. /* Conversion routines between different color representations */
  150. static void rgb_4byte(void *dst, int rgb)
  151. {
  152.     *(int *)dst = rgb;
  153. }
  154.  
  155. static int byte4_rgb(void *src)
  156. {
  157.     return (*(int *)src) & 0xffffff;
  158. }
  159.  
  160. static void rgb_3byte(void *dst, int rgb)
  161. {
  162.     uint8_t *scr = dst;
  163. #if defined(FB_INVERT_ENDIAN)
  164.     scr[0] = RED(rgb, 8);
  165.     scr[1] = GREEN(rgb, 8);
  166.     scr[2] = BLUE(rgb, 8);
  167. #else
  168.     scr[2] = RED(rgb, 8);
  169.     scr[1] = GREEN(rgb, 8);
  170.     scr[0] = BLUE(rgb, 8);
  171. #endif
  172. }
  173.  
  174. static int byte3_rgb(void *src)
  175. {
  176.     uint8_t *scr = src;
  177. #if defined(FB_INVERT_ENDIAN)
  178.     return scr[0] << 16 | scr[1] << 8 | scr[2];
  179. #else
  180.     return scr[2] << 16 | scr[1] << 8 | scr[0];
  181. #endif 
  182. }
  183.  
  184. /**  16-bit depth (5:6:5) */
  185. static void rgb_2byte(void *dst, int rgb)
  186. {
  187.     /* 5-bit, 6-bits, 5-bits */
  188.     *((uint16_t *)(dst)) = RED(rgb, 5) << 11 | GREEN(rgb, 6) << 5 | BLUE(rgb, 5);
  189. }
  190.  
  191. /** 16-bit depth (5:6:5) */
  192. static int byte2_rgb(void *src)
  193. {
  194.     int color = *(uint16_t *)(src);
  195.     return (((color >> 11) & 0x1f) << (16 + 3)) | (((color >> 5) & 0x3f) << (8 + 2)) | ((color & 0x1f) << 3);
  196. }
  197.  
  198. /** Put pixel - 8-bit depth (3:2:3) */
  199. static void rgb_1byte(void *dst, int rgb)
  200. {
  201.     *(uint8_t *)dst = RED(rgb, 3) << 5 | GREEN(rgb, 2) << 3 | BLUE(rgb, 3);
  202. }
  203.  
  204. /** Return pixel color - 8-bit depth (3:2:3) */
  205. static int byte1_rgb(void *src)
  206. {
  207.     int color = *(uint8_t *)src;
  208.     return (((color >> 5) & 0x7) << (16 + 5)) | (((color >> 3) & 0x3) << (8 + 6)) | ((color & 0x7) << 5);
  209. }
  210.  
  211. /** Put pixel into viewport
  212.  *
  213.  * @param vport Viewport identification
  214.  * @param x X coord relative to viewport
  215.  * @param y Y coord relative to viewport
  216.  * @param color RGB color
  217.  */
  218. static void putpixel(viewport_t *vport, unsigned int x, unsigned int y, int color)
  219. {
  220.     int dx = vport->x + x;
  221.     int dy = vport->y + y;
  222.  
  223.     if (! (vport->paused && vport->dbdata))
  224.         (*screen.rgb2scr)(&screen.fbaddress[POINTPOS(dx,dy)], COLOR(color));
  225.  
  226.     if (vport->dbdata) {
  227.         int dline = (y + vport->dboffset) % vport->height;
  228.         int doffset = screen.pixelbytes * (dline * vport->width + x);
  229.         (*screen.rgb2scr)(&vport->dbdata[doffset], COLOR(color));
  230.     }
  231. }
  232.  
  233. /** Get pixel from viewport */
  234. static int getpixel(viewport_t *vport, unsigned int x, unsigned int y)
  235. {
  236.     int dx = vport->x + x;
  237.     int dy = vport->y + y;
  238.  
  239.     return COLOR((*screen.scr2rgb)(&screen.fbaddress[POINTPOS(dx,dy)]));
  240. }
  241.  
  242. static inline void putpixel_mem(char *mem, unsigned int x, unsigned int y,
  243.                 int color)
  244. {
  245.     (*screen.rgb2scr)(&mem[POINTPOS(x,y)], COLOR(color));
  246. }
  247.  
  248. static void draw_rectangle(viewport_t *vport, unsigned int sx, unsigned int sy,
  249.                unsigned int width, unsigned int height,
  250.                int color)
  251. {
  252.     unsigned int x, y;
  253.     static void *tmpline;
  254.  
  255.     if (!tmpline)
  256.         tmpline = malloc(screen.scanline*screen.pixelbytes);
  257.  
  258.     /* Clear first line */
  259.     for (x = 0; x < width; x++)
  260.         putpixel_mem(tmpline, x, 0, color);
  261.  
  262.     if (!vport->paused) {
  263.         /* Recompute to screen coords */
  264.         sx += vport->x;
  265.         sy += vport->y;
  266.         /* Copy the rest */
  267.         for (y = sy;y < sy+height; y++)
  268.             memcpy(&screen.fbaddress[POINTPOS(sx,y)], tmpline,
  269.                    screen.pixelbytes * width);
  270.     }
  271.     if (vport->dbdata) {
  272.         for (y=sy;y < sy+height; y++) {
  273.             int rline = (y + vport->dboffset) % vport->height;
  274.             int rpos = (rline * vport->width + sx) * screen.pixelbytes;
  275.             memcpy(&vport->dbdata[rpos], tmpline, screen.pixelbytes * width);
  276.         }
  277.     }
  278.  
  279. }
  280.  
  281. /** Fill viewport with background color */
  282. static void clear_port(viewport_t *vport)
  283. {
  284.     draw_rectangle(vport, 0, 0, vport->width, vport->height, vport->style.bg_color);
  285. }
  286.  
  287. /** Scroll unbuffered viewport up/down
  288.  *
  289.  * @param vport Viewport to scroll
  290.  * @param lines Positive number - scroll up, negative - scroll down
  291.  */
  292. static void scroll_port_nodb(viewport_t *vport, int lines)
  293. {
  294.     int y;
  295.  
  296.     if (lines > 0) {
  297.         for (y=vport->y; y < vport->y+vport->height - lines; y++)
  298.             memcpy(&screen.fbaddress[POINTPOS(vport->x,y)],
  299.                    &screen.fbaddress[POINTPOS(vport->x,y + lines)],
  300.                    screen.pixelbytes * vport->width);
  301.         draw_rectangle(vport, 0, vport->height - lines,
  302.                    vport->width, lines, vport->style.bg_color);
  303.     } else if (lines < 0) {
  304.         lines = -lines;
  305.         for (y=vport->y + vport->height-1; y >= vport->y + lines; y--)
  306.             memcpy(&screen.fbaddress[POINTPOS(vport->x,y)],
  307.                    &screen.fbaddress[POINTPOS(vport->x,y - lines)],
  308.                    screen.pixelbytes * vport->width);
  309.         draw_rectangle(vport, 0, 0, vport->width, lines, vport->style.bg_color);
  310.     }
  311. }
  312.  
  313. /** Refresh given viewport from double buffer */
  314. static void refresh_viewport_db(viewport_t *vport)
  315. {
  316.     unsigned int y, srcy, srcoff, dsty, dstx;
  317.  
  318.     for (y = 0; y < vport->height; y++) {
  319.         srcy = (y + vport->dboffset) % vport->height;
  320.         srcoff = (vport->width * srcy) * screen.pixelbytes;
  321.  
  322.         dstx = vport->x;
  323.         dsty = vport->y + y;
  324.  
  325.         memcpy(&screen.fbaddress[POINTPOS(dstx,dsty)],
  326.                &vport->dbdata[srcoff],
  327.                vport->width*screen.pixelbytes);
  328.     }
  329. }
  330.  
  331. /** Scroll viewport that has double buffering enabled */
  332. static void scroll_port_db(viewport_t *vport, int lines)
  333. {
  334.     ++vport->paused;
  335.     if (lines > 0) {
  336.         draw_rectangle(vport, 0, 0, vport->width, lines,
  337.                    vport->style.bg_color);
  338.         vport->dboffset += lines;
  339.         vport->dboffset %= vport->height;
  340.     } else if (lines < 0) {
  341.         lines = -lines;
  342.         draw_rectangle(vport, 0, vport->height-lines,
  343.                    vport->width, lines,
  344.                    vport->style.bg_color);
  345.  
  346.         if (vport->dboffset < lines)
  347.             vport->dboffset += vport->height;
  348.         vport->dboffset -= lines;
  349.     }
  350.    
  351.     --vport->paused;
  352.    
  353.     refresh_viewport_db(vport);
  354. }
  355.  
  356. /** Scrolls viewport given number of lines */
  357. static void scroll_port(viewport_t *vport, int lines)
  358. {
  359.     if (vport->dbdata)
  360.         scroll_port_db(vport, lines);
  361.     else
  362.         scroll_port_nodb(vport, lines);
  363.    
  364. }
  365.  
  366. static void invert_pixel(viewport_t *vport, unsigned int x, unsigned int y)
  367. {
  368.     putpixel(vport, x, y, ~getpixel(vport, x, y));
  369. }
  370.  
  371.  
  372. /***************************************************************/
  373. /* Character-console functions */
  374.  
  375. /** Draw character at given position
  376.  *
  377.  * @param vport Viewport where the character is printed
  378.  * @param sx Coordinates of top-left of the character
  379.  * @param sy Coordinates of top-left of the character
  380.  * @param style Color of the character
  381.  * @param transparent If false, print background color
  382.  */
  383. static void draw_glyph(viewport_t *vport,uint8_t glyph, unsigned int sx, unsigned int sy,
  384.                style_t style, int transparent)
  385. {
  386.     int i;
  387.     unsigned int y;
  388.     unsigned int glline;
  389.  
  390.     for (y = 0; y < FONT_SCANLINES; y++) {
  391.         glline = fb_font[glyph * FONT_SCANLINES + y];
  392.         for (i = 0; i < 8; i++) {
  393.             if (glline & (1 << (7 - i)))
  394.                 putpixel(vport, sx + i, sy + y, style.fg_color);
  395.             else if (!transparent)
  396.                 putpixel(vport, sx + i, sy + y, style.bg_color);
  397.         }
  398.     }
  399. }
  400.  
  401. /** Invert character at given position */
  402. static void invert_char(viewport_t *vport,unsigned int row, unsigned int col)
  403. {
  404.     unsigned int x;
  405.     unsigned int y;
  406.  
  407.     for (x = 0; x < COL_WIDTH; x++)
  408.         for (y = 0; y < FONT_SCANLINES; y++)
  409.             invert_pixel(vport, col * COL_WIDTH + x, row * FONT_SCANLINES + y);
  410. }
  411.  
  412. /***************************************************************/
  413. /* Stdout specific functions */
  414.  
  415.  
  416. /** Create new viewport
  417.  *
  418.  * @return New viewport number
  419.  */
  420. static int viewport_create(unsigned int x, unsigned int y,unsigned int width,
  421.                unsigned int height)
  422. {
  423.     int i;
  424.  
  425.     for (i=0; i < MAX_VIEWPORTS; i++) {
  426.         if (!viewports[i].initialized)
  427.             break;
  428.     }
  429.     if (i == MAX_VIEWPORTS)
  430.         return ELIMIT;
  431.  
  432.     viewports[i].x = x;
  433.     viewports[i].y = y;
  434.     viewports[i].width = width;
  435.     viewports[i].height = height;
  436.    
  437.     viewports[i].rows = height / FONT_SCANLINES;
  438.     viewports[i].cols = width / COL_WIDTH;
  439.  
  440.     viewports[i].style.bg_color = DEFAULT_BGCOLOR;
  441.     viewports[i].style.fg_color = DEFAULT_FGCOLOR;
  442.    
  443.     viewports[i].cur_col = 0;
  444.     viewports[i].cur_row = 0;
  445.     viewports[i].cursor_active = 0;
  446.  
  447.     viewports[i].initialized = 1;
  448.  
  449.     return i;
  450. }
  451.  
  452.  
  453. /** Initialize framebuffer as a chardev output device
  454.  *
  455.  * @param addr Address of theframebuffer
  456.  * @param xres Screen width in pixels
  457.  * @param yres Screen height in pixels
  458.  * @param bpp  Bits per pixel (8, 16, 24, 32)
  459.  * @param scan Bytes per one scanline
  460.  * @param align Alignment for 24bpp mode.
  461.  * @param invert_colors Inverted colors.
  462.  *
  463.  */
  464. static void
  465. screen_init(void *addr, unsigned int xres, unsigned int yres, unsigned int bpp, unsigned int scan,
  466.     int align, int invert_colors)
  467. {
  468.     switch (bpp) {
  469.         case 8:
  470.             screen.rgb2scr = rgb_1byte;
  471.             screen.scr2rgb = byte1_rgb;
  472.             screen.pixelbytes = 1;
  473.             break;
  474.         case 16:
  475.             screen.rgb2scr = rgb_2byte;
  476.             screen.scr2rgb = byte2_rgb;
  477.             screen.pixelbytes = 2;
  478.             break;
  479.         case 24:
  480.             screen.rgb2scr = rgb_3byte;
  481.             screen.scr2rgb = byte3_rgb;
  482.             if (!align)
  483.                 screen.pixelbytes = 3;
  484.             else
  485.                 screen.pixelbytes = 4;
  486.             break;
  487.         case 32:
  488.             screen.rgb2scr = rgb_4byte;
  489.             screen.scr2rgb = byte4_rgb;
  490.             screen.pixelbytes = 4;
  491.             break;
  492.     }
  493.  
  494.        
  495.     screen.fbaddress = (unsigned char *) addr;
  496.     screen.xres = xres;
  497.     screen.yres = yres;
  498.     screen.scanline = scan;
  499.     screen.invert_colors = invert_colors;
  500.    
  501.     /* Create first viewport */
  502.     viewport_create(0,0,xres,yres);
  503. }
  504.  
  505. /** Hide cursor if it is shown */
  506. static void cursor_hide(viewport_t *vport)
  507. {
  508.     if (vport->cursor_active && vport->cursor_shown) {
  509.         invert_char(vport, vport->cur_row, vport->cur_col);
  510.         vport->cursor_shown = 0;
  511.     }
  512. }
  513.  
  514. /** Show cursor if cursor showing is enabled */
  515. static void cursor_print(viewport_t *vport)
  516. {
  517.     /* Do not check for cursor_shown */
  518.     if (vport->cursor_active) {
  519.         invert_char(vport, vport->cur_row, vport->cur_col);
  520.         vport->cursor_shown = 1;
  521.     }
  522. }
  523.  
  524. /** Invert cursor, if it is enabled */
  525. static void cursor_blink(viewport_t *vport)
  526. {
  527.     if (vport->cursor_shown)
  528.         cursor_hide(vport);
  529.     else
  530.         cursor_print(vport);
  531. }
  532.  
  533. /** Draw character at given position relative to viewport
  534.  *
  535.  * @param vport Viewport identification
  536.  * @param c Character to print
  537.  * @param row Screen position relative to viewport
  538.  * @param col Screen position relative to viewport
  539.  * @param transparent If false, print background color with character
  540.  */
  541. static void draw_char(viewport_t *vport, char c, unsigned int row, unsigned int col,
  542.               style_t style, int transparent)
  543. {
  544.     /* Optimize - do not hide cursor if we are going to overwrite it */
  545.     if (vport->cursor_active && vport->cursor_shown &&
  546.         (vport->cur_col != col || vport->cur_row != row))
  547.         invert_char(vport, vport->cur_row, vport->cur_col);
  548.    
  549.     draw_glyph(vport, c, col * COL_WIDTH, row * FONT_SCANLINES, style, transparent);
  550.  
  551.     vport->cur_col = col;
  552.     vport->cur_row = row;
  553.  
  554.     vport->cur_col++;
  555.     if (vport->cur_col>= vport->cols) {
  556.         vport->cur_col = 0;
  557.         vport->cur_row++;
  558.         if (vport->cur_row >= vport->rows)
  559.             vport->cur_row--;
  560.     }
  561.     cursor_print(vport);
  562. }
  563.  
  564. /** Draw text data to viewport
  565.  *
  566.  * @param vport Viewport id
  567.  * @param data Text data fitting exactly into viewport
  568.  */
  569. static void draw_text_data(viewport_t *vport, keyfield_t *data)
  570. {
  571.     int i;
  572.     int col,row;
  573.  
  574.     clear_port(vport);
  575.     for (i=0; i < vport->cols * vport->rows; i++) {
  576.         if (data[i].character == ' ' && style_same(data[i].style,vport->style))
  577.             continue;
  578.         col = i % vport->cols;
  579.         row = i / vport->cols;
  580.         draw_glyph(vport, data[i].character, col * COL_WIDTH, row * FONT_SCANLINES,
  581.                data[i].style, style_same(data[i].style,vport->style));
  582.     }
  583.     cursor_print(vport);
  584. }
  585.  
  586.  
  587. /** Return first free pixmap */
  588. static int find_free_pixmap(void)
  589. {
  590.     int i;
  591.    
  592.     for (i=0;i < MAX_PIXMAPS;i++)
  593.         if (!pixmaps[i].data)
  594.             return i;
  595.     return -1;
  596. }
  597.  
  598. static void putpixel_pixmap(int pm, unsigned int x, unsigned int y, int color)
  599. {
  600.     pixmap_t *pmap = &pixmaps[pm];
  601.     int pos = (y * pmap->width + x) * screen.pixelbytes;
  602.  
  603.     (*screen.rgb2scr)(&pmap->data[pos],COLOR(color));
  604. }
  605.  
  606. /** Create a new pixmap and return appropriate ID */
  607. static int shm2pixmap(unsigned char *shm, size_t size)
  608. {
  609.     int pm;
  610.     pixmap_t *pmap;
  611.  
  612.     pm = find_free_pixmap();
  613.     if (pm == -1)
  614.         return ELIMIT;
  615.     pmap = &pixmaps[pm];
  616.    
  617.     if (ppm_get_data(shm, size, &pmap->width, &pmap->height))
  618.         return EINVAL;
  619.    
  620.     pmap->data = malloc(pmap->width * pmap->height * screen.pixelbytes);
  621.     if (!pmap->data)
  622.         return ENOMEM;
  623.  
  624.     ppm_draw(shm, size, 0, 0, pmap->width, pmap->height,
  625.          (putpixel_cb_t)putpixel_pixmap, (void *)pm);
  626.  
  627.     return pm;
  628. }
  629.  
  630. /** Handle shared memory communication calls
  631.  *
  632.  * Protocol for drawing pixmaps:
  633.  * - FB_PREPARE_SHM(client shm identification)
  634.  * - IPC_M_SEND_AS_AREA
  635.  * - FB_DRAW_PPM(startx,starty)
  636.  * - FB_DROP_SHM
  637.  *
  638.  * Protocol for text drawing
  639.  * - IPC_M_SEND_AS_AREA
  640.  * - FB_DRAW_TEXT_DATA
  641.  *
  642.  * @param callid Callid of the current call
  643.  * @param call Current call data
  644.  * @param vp Active viewport
  645.  * @return 0 if the call was not handled byt this function, 1 otherwise
  646.  *
  647.  * note: this function is not threads safe, you would have
  648.  * to redefine static variables with __thread
  649.  */
  650. static int shm_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
  651. {
  652.     static keyfield_t *interbuffer = NULL;
  653.     static size_t intersize = 0;
  654.  
  655.     static unsigned char *shm = NULL;
  656.     static ipcarg_t shm_id = 0;
  657.     static size_t shm_size;
  658.  
  659.     int handled = 1;
  660.     int retval = 0;
  661.     viewport_t *vport = &viewports[vp];
  662.     unsigned int x,y;
  663.  
  664.     switch (IPC_GET_METHOD(*call)) {
  665.     case IPC_M_AS_AREA_SEND:
  666.         /* We accept one area for data interchange */
  667.         if (IPC_GET_ARG1(*call) == shm_id) {
  668.             void *dest = as_get_mappable_page(IPC_GET_ARG2(*call));
  669.             shm_size = IPC_GET_ARG2(*call);
  670.             if (!ipc_answer_fast(callid, 0, (sysarg_t)dest, 0))
  671.                 shm = dest;
  672.             else
  673.                 shm_id = 0;
  674.             if (shm[0] != 'P')
  675.                 while (1)
  676.                     ;
  677.             return 1;
  678.         } else {
  679.             intersize = IPC_GET_ARG2(*call);
  680.             receive_comm_area(callid,call,(void *)&interbuffer);
  681.         }
  682.         return 1;
  683.     case FB_PREPARE_SHM:
  684.         if (shm_id)
  685.             retval = EBUSY;
  686.         else
  687.             shm_id = IPC_GET_ARG1(*call);
  688.         break;
  689.        
  690.     case FB_DROP_SHM:
  691.         if (shm) {
  692.             as_area_destroy(shm);
  693.             shm = NULL;
  694.         }
  695.         shm_id = 0;
  696.         break;
  697.  
  698.     case FB_SHM2PIXMAP:
  699.         if (!shm) {
  700.             retval = EINVAL;
  701.             break;
  702.         }
  703.         retval = shm2pixmap(shm, shm_size);
  704.         break;
  705.     case FB_DRAW_PPM:
  706.         if (!shm) {
  707.             retval = EINVAL;
  708.             break;
  709.         }
  710.         x = IPC_GET_ARG1(*call);
  711.         y = IPC_GET_ARG2(*call);
  712.         if (x > vport->width || y > vport->height) {
  713.             retval = EINVAL;
  714.             break;
  715.         }
  716.        
  717.         ppm_draw(shm, shm_size, IPC_GET_ARG1(*call), IPC_GET_ARG2(*call),
  718.              vport->width - x, vport->height - y, (putpixel_cb_t)putpixel, vport);
  719.         break;
  720.     case FB_DRAW_TEXT_DATA:
  721.         if (!interbuffer) {
  722.             retval = EINVAL;
  723.             break;
  724.         }
  725.         if (intersize < vport->cols*vport->rows*sizeof(*interbuffer)) {
  726.             retval = EINVAL;
  727.             break;
  728.         }
  729.         draw_text_data(vport, interbuffer);
  730.         break;
  731.     default:
  732.         handled = 0;
  733.     }
  734.    
  735.     if (handled)
  736.         ipc_answer_fast(callid, retval, 0, 0);
  737.     return handled;
  738. }
  739.  
  740. static void copy_vp_to_pixmap(viewport_t *vport, pixmap_t *pmap)
  741. {
  742.     int y;
  743.     int rowsize;
  744.     int tmp;
  745.     int width = vport->width;
  746.     int height = vport->height;
  747.  
  748.     if (width + vport->x > screen.xres)
  749.         width = screen.xres - vport->x;
  750.     if (height + vport->y  > screen.yres)
  751.         height = screen.yres - vport->y;
  752.  
  753.     rowsize = width * screen.pixelbytes;
  754.  
  755.     for (y=0;y < height; y++) {
  756.         tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;
  757.         memcpy(pmap->data + rowsize*y, screen.fbaddress + tmp, rowsize);
  758.     }
  759. }
  760.  
  761. /** Save viewport to pixmap */
  762. static int save_vp_to_pixmap(viewport_t *vport)
  763. {
  764.     int pm;
  765.     pixmap_t *pmap;
  766.  
  767.     pm = find_free_pixmap();
  768.     if (pm == -1)
  769.         return ELIMIT;
  770.    
  771.     pmap = &pixmaps[pm];
  772.     pmap->data = malloc(screen.pixelbytes * vport->width * vport->height);
  773.     if (!pmap->data)
  774.         return ENOMEM;
  775.  
  776.     pmap->width = vport->width;
  777.     pmap->height = vport->height;
  778.  
  779.     copy_vp_to_pixmap(vport, pmap);
  780.    
  781.     return pm;
  782. }
  783.  
  784. /** Draw pixmap on screen
  785.  *
  786.  * @param vp Viewport to draw on
  787.  * @param pm Pixmap identifier
  788.  */
  789. static int draw_pixmap(int vp, int pm)
  790. {
  791.     pixmap_t *pmap = &pixmaps[pm];
  792.     viewport_t *vport = &viewports[vp];
  793.     int y;
  794.     int tmp, srcrowsize;
  795.     int realwidth, realheight, realrowsize;
  796.     int width = vport->width;
  797.     int height = vport->height;
  798.  
  799.     if (width + vport->x > screen.xres)
  800.         width = screen.xres - vport->x;
  801.     if (height + vport->y > screen.yres)
  802.         height = screen.yres - vport->y;
  803.  
  804.     if (!pmap->data)
  805.         return EINVAL;
  806.  
  807.     realwidth = pmap->width <= width ? pmap->width : width;
  808.     realheight = pmap->height <= height ? pmap->height : height;
  809.  
  810.     srcrowsize = vport->width * screen.pixelbytes;
  811.     realrowsize = realwidth * screen.pixelbytes;
  812.  
  813.     for (y=0; y < realheight; y++) {
  814.         tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;
  815.         memcpy(screen.fbaddress + tmp, pmap->data + y * srcrowsize, realrowsize);
  816.     }
  817.     return 0;
  818. }
  819.  
  820. /** Tick animation one step forward */
  821. static void anims_tick(void)
  822. {
  823.     int i;
  824.     static int counts = 0;
  825.    
  826.     /* Limit redrawing */
  827.     counts = (counts+1) % 8;
  828.     if (counts)
  829.         return;
  830.  
  831.     for (i=0; i < MAX_ANIMATIONS; i++) {
  832.         if (!animations[i].animlen || !animations[i].initialized || !animations[i].enabled)
  833.             continue;
  834.         draw_pixmap(animations[i].vp, animations[i].pixmaps[animations[i].pos]);
  835.         animations[i].pos = (animations[i].pos+1) % animations[i].animlen;
  836.     }
  837. }
  838.  
  839.  
  840. static int pointer_x, pointer_y;
  841. static int pointer_shown, pointer_enabled;
  842. static int pointer_vport = -1;
  843. static int pointer_pixmap = -1;
  844.  
  845. static void mouse_show(void)
  846. {
  847.     int i,j;
  848.     int visibility;
  849.     int color;
  850.     int bytepos;
  851.  
  852.     if (pointer_shown || !pointer_enabled)
  853.         return;
  854.  
  855.     /* Save image under the cursor */
  856.     if (pointer_vport == -1) {
  857.         pointer_vport = viewport_create(pointer_x, pointer_y, pointer_width, pointer_height);
  858.         if (pointer_vport < 0)
  859.             return;
  860.     } else {
  861.         viewports[pointer_vport].x = pointer_x;
  862.         viewports[pointer_vport].y = pointer_y;
  863.     }
  864.  
  865.     if (pointer_pixmap == -1)
  866.         pointer_pixmap = save_vp_to_pixmap(&viewports[pointer_vport]);
  867.     else
  868.         copy_vp_to_pixmap(&viewports[pointer_vport], &pixmaps[pointer_pixmap]);
  869.  
  870.     /* Draw cursor */
  871.     for (i=0; i < pointer_height; i++)
  872.         for (j=0;j < pointer_width; j++) {
  873.             bytepos = i*((pointer_width-1)/8+1) + j/8;
  874.             visibility = pointer_mask_bits[bytepos] & (1 << (j % 8));
  875.             if (visibility) {
  876.                 color = pointer_bits[bytepos] & (1 << (j % 8)) ? 0 : 0xffffff;
  877.                 if (pointer_x+j < screen.xres && pointer_y+i < screen.yres)
  878.                     putpixel(&viewports[0], pointer_x+j, pointer_y+i, color);
  879.             }
  880.         }
  881.     pointer_shown = 1;
  882. }
  883.  
  884. static void mouse_hide(void)
  885. {
  886.     /* Restore image under the cursor */
  887.     if (pointer_shown) {
  888.         draw_pixmap(pointer_vport, pointer_pixmap);
  889.         pointer_shown = 0;
  890.     }
  891. }
  892.  
  893. static void mouse_move(unsigned int x, unsigned int y)
  894. {
  895.     mouse_hide();
  896.     pointer_x = x;
  897.     pointer_y = y;
  898.     mouse_show();
  899. }
  900.  
  901. static int anim_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
  902. {
  903.     int handled = 1;
  904.     int retval = 0;
  905.     int i,nvp;
  906.     int newval;
  907.  
  908.     switch (IPC_GET_METHOD(*call)) {
  909.     case FB_ANIM_CREATE:
  910.         nvp = IPC_GET_ARG1(*call);
  911.         if (nvp == -1)
  912.             nvp = vp;
  913.         if (nvp >= MAX_VIEWPORTS || nvp < 0 || !viewports[nvp].initialized) {
  914.             retval = EINVAL;
  915.             break;
  916.         }
  917.         for (i=0; i < MAX_ANIMATIONS; i++) {
  918.             if (! animations[i].initialized)
  919.                 break;
  920.         }
  921.         if (i == MAX_ANIMATIONS) {
  922.             retval = ELIMIT;
  923.             break;
  924.         }
  925.         animations[i].initialized = 1;
  926.         animations[i].animlen = 0;
  927.         animations[i].pos = 0;
  928.         animations[i].enabled = 0;
  929.         animations[i].vp = nvp;
  930.         retval = i;
  931.         break;
  932.     case FB_ANIM_DROP:
  933.         i = IPC_GET_ARG1(*call);
  934.         if (i >= MAX_ANIMATIONS || i < 0) {
  935.             retval = EINVAL;
  936.             break;
  937.         }
  938.         animations[i].initialized = 0;
  939.         break;
  940.     case FB_ANIM_ADDPIXMAP:
  941.         i = IPC_GET_ARG1(*call);
  942.         if (i >= MAX_ANIMATIONS || i < 0 || !animations[i].initialized) {
  943.             retval = EINVAL;
  944.             break;
  945.         }
  946.         if (animations[i].animlen == MAX_ANIM_LEN) {
  947.             retval = ELIMIT;
  948.             break;
  949.         }
  950.         newval = IPC_GET_ARG2(*call);
  951.         if (newval < 0 || newval > MAX_PIXMAPS || !pixmaps[newval].data) {
  952.             retval = EINVAL;
  953.             break;
  954.         }
  955.         animations[i].pixmaps[animations[i].animlen++] = newval;
  956.         break;
  957.     case FB_ANIM_CHGVP:
  958.         i = IPC_GET_ARG1(*call);
  959.         if (i >= MAX_ANIMATIONS || i < 0) {
  960.             retval = EINVAL;
  961.             break;
  962.         }
  963.         nvp = IPC_GET_ARG2(*call);
  964.         if (nvp == -1)
  965.             nvp = vp;
  966.         if (nvp >= MAX_VIEWPORTS || nvp < 0 || !viewports[nvp].initialized) {
  967.             retval = EINVAL;
  968.             break;
  969.         }
  970.         animations[i].vp = nvp;
  971.         break;
  972.     case FB_ANIM_START:
  973.     case FB_ANIM_STOP:
  974.         i = IPC_GET_ARG1(*call);
  975.         if (i >= MAX_ANIMATIONS || i < 0) {
  976.             retval = EINVAL;
  977.             break;
  978.         }
  979.         newval = (IPC_GET_METHOD(*call) == FB_ANIM_START);
  980.         if (newval ^ animations[i].enabled) {
  981.             animations[i].enabled = newval;
  982.             anims_enabled += newval ? 1 : -1;
  983.         }
  984.         break;
  985.     default:
  986.         handled = 0;
  987.     }
  988.     if (handled)
  989.         ipc_answer_fast(callid, retval, 0, 0);
  990.     return handled;
  991. }
  992.  
  993. /** Handler for messages concerning pixmap handling */
  994. static int pixmap_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
  995. {
  996.     int handled = 1;
  997.     int retval = 0;
  998.     int i,nvp;
  999.  
  1000.     switch (IPC_GET_METHOD(*call)) {
  1001.     case FB_VP_DRAW_PIXMAP:
  1002.         nvp = IPC_GET_ARG1(*call);
  1003.         if (nvp == -1)
  1004.             nvp = vp;
  1005.         if (nvp < 0 || nvp >= MAX_VIEWPORTS || !viewports[nvp].initialized) {
  1006.             retval = EINVAL;
  1007.             break;
  1008.         }
  1009.         i = IPC_GET_ARG2(*call);
  1010.         retval = draw_pixmap(nvp, i);
  1011.         break;
  1012.     case FB_VP2PIXMAP:
  1013.         nvp = IPC_GET_ARG1(*call);
  1014.         if (nvp == -1)
  1015.             nvp = vp;
  1016.         if (nvp < 0 || nvp >= MAX_VIEWPORTS || !viewports[nvp].initialized)
  1017.             retval = EINVAL;
  1018.         else
  1019.             retval = save_vp_to_pixmap(&viewports[nvp]);
  1020.         break;
  1021.     case FB_DROP_PIXMAP:
  1022.         i = IPC_GET_ARG1(*call);
  1023.         if (i >= MAX_PIXMAPS) {
  1024.             retval = EINVAL;
  1025.             break;
  1026.         }
  1027.         if (pixmaps[i].data) {
  1028.             free(pixmaps[i].data);
  1029.             pixmaps[i].data = NULL;
  1030.         }
  1031.         break;
  1032.     default:
  1033.         handled = 0;
  1034.     }
  1035.  
  1036.     if (handled)
  1037.         ipc_answer_fast(callid, retval, 0, 0);
  1038.     return handled;
  1039.    
  1040. }
  1041.  
  1042. /** Function for handling connections to FB
  1043.  *
  1044.  */
  1045. static void fb_client_connection(ipc_callid_t iid, ipc_call_t *icall)
  1046. {
  1047.     ipc_callid_t callid;
  1048.     ipc_call_t call;
  1049.     int retval;
  1050.     int i;
  1051.     unsigned int row,col;
  1052.     char c;
  1053.  
  1054.     int vp = 0;
  1055.     viewport_t *vport = &viewports[0];
  1056.  
  1057.     if (client_connected) {
  1058.         ipc_answer_fast(iid, ELIMIT, 0,0);
  1059.         return;
  1060.     }
  1061.     client_connected = 1;
  1062.     ipc_answer_fast(iid, 0, 0, 0); /* Accept connection */
  1063.  
  1064.     while (1) {
  1065.         if (vport->cursor_active || anims_enabled)
  1066.             callid = async_get_call_timeout(&call,250000);
  1067.         else
  1068.             callid = async_get_call(&call);
  1069.  
  1070.         mouse_hide();
  1071.         if (!callid) {
  1072.             cursor_blink(vport);
  1073.             anims_tick();
  1074.             mouse_show();
  1075.             continue;
  1076.         }
  1077.         if (shm_handle(callid, &call, vp))
  1078.             continue;
  1079.         if (pixmap_handle(callid, &call, vp))
  1080.             continue;
  1081.         if (anim_handle(callid, &call, vp))
  1082.             continue;
  1083.  
  1084.         switch (IPC_GET_METHOD(call)) {
  1085.         case IPC_M_PHONE_HUNGUP:
  1086.             client_connected = 0;
  1087.             /* cleanup other viewports */
  1088.             for (i=1; i < MAX_VIEWPORTS; i++)
  1089.                 vport->initialized = 0;
  1090.             return; /* Exit thread */
  1091.  
  1092.         case FB_PUTCHAR:
  1093.         case FB_TRANS_PUTCHAR:
  1094.             c = IPC_GET_ARG1(call);
  1095.             row = IPC_GET_ARG2(call);
  1096.             col = IPC_GET_ARG3(call);
  1097.             if (row >= vport->rows || col >= vport->cols) {
  1098.                 retval = EINVAL;
  1099.                 break;
  1100.             }
  1101.             ipc_answer_fast(callid,0,0,0);
  1102.  
  1103.             draw_char(vport, c, row, col, vport->style, IPC_GET_METHOD(call) == FB_TRANS_PUTCHAR);
  1104.             continue; /* msg already answered */
  1105.         case FB_CLEAR:
  1106.             clear_port(vport);
  1107.             cursor_print(vport);
  1108.             retval = 0;
  1109.             break;
  1110.         case FB_CURSOR_GOTO:
  1111.             row = IPC_GET_ARG1(call);
  1112.             col = IPC_GET_ARG2(call);
  1113.             if (row >= vport->rows || col >= vport->cols) {
  1114.                 retval = EINVAL;
  1115.                 break;
  1116.             }
  1117.             retval = 0;
  1118.             cursor_hide(vport);
  1119.             vport->cur_col = col;
  1120.             vport->cur_row = row;
  1121.             cursor_print(vport);
  1122.             break;
  1123.         case FB_CURSOR_VISIBILITY:
  1124.             cursor_hide(vport);
  1125.             vport->cursor_active = IPC_GET_ARG1(call);
  1126.             cursor_print(vport);
  1127.             retval = 0;
  1128.             break;
  1129.         case FB_GET_CSIZE:
  1130.             ipc_answer_fast(callid, 0, vport->rows, vport->cols);
  1131.             continue;
  1132.         case FB_SCROLL:
  1133.             i = IPC_GET_ARG1(call);
  1134.             if (i > vport->rows || i < (- (int)vport->rows)) {
  1135.                 retval = EINVAL;
  1136.                 break;
  1137.             }
  1138.             cursor_hide(vport);
  1139.             scroll_port(vport, i*FONT_SCANLINES);
  1140.             cursor_print(vport);
  1141.             retval = 0;
  1142.             break;
  1143.         case FB_VIEWPORT_DB:
  1144.             /* Enable double buffering */
  1145.             i = IPC_GET_ARG1(call);
  1146.             if (i == -1)
  1147.                 i = vp;
  1148.             if (i < 0 || i >= MAX_VIEWPORTS) {
  1149.                 retval = EINVAL;
  1150.                 break;
  1151.             }
  1152.             if (! viewports[i].initialized ) {
  1153.                 retval = EADDRNOTAVAIL;
  1154.                 break;
  1155.             }
  1156.             viewports[i].dboffset = 0;
  1157.             if (IPC_GET_ARG2(call) == 1 && !viewports[i].dbdata)
  1158.                 viewports[i].dbdata = malloc(screen.pixelbytes*viewports[i].width * viewports[i].height);
  1159.             else if (IPC_GET_ARG2(call) == 0 && viewports[i].dbdata) {
  1160.                 free(viewports[i].dbdata);
  1161.                 viewports[i].dbdata = NULL;
  1162.             }
  1163.             retval = 0;
  1164.             break;
  1165.         case FB_VIEWPORT_SWITCH:
  1166.             i = IPC_GET_ARG1(call);
  1167.             if (i < 0 || i >= MAX_VIEWPORTS) {
  1168.                 retval = EINVAL;
  1169.                 break;
  1170.             }
  1171.             if (! viewports[i].initialized ) {
  1172.                 retval = EADDRNOTAVAIL;
  1173.                 break;
  1174.             }
  1175.             cursor_hide(vport);
  1176.             vp = i;
  1177.             vport = &viewports[vp];
  1178.             cursor_print(vport);
  1179.             retval = 0;
  1180.             break;
  1181.         case FB_VIEWPORT_CREATE:
  1182.             retval = viewport_create(IPC_GET_ARG1(call) >> 16,
  1183.                          IPC_GET_ARG1(call) & 0xffff,
  1184.                          IPC_GET_ARG2(call) >> 16,
  1185.                          IPC_GET_ARG2(call) & 0xffff);
  1186.             break;
  1187.         case FB_VIEWPORT_DELETE:
  1188.             i = IPC_GET_ARG1(call);
  1189.             if (i < 0 || i >= MAX_VIEWPORTS) {
  1190.                 retval = EINVAL;
  1191.                 break;
  1192.             }
  1193.             if (! viewports[i].initialized ) {
  1194.                 retval = EADDRNOTAVAIL;
  1195.                 break;
  1196.             }
  1197.             viewports[i].initialized = 0;
  1198.             if (viewports[i].dbdata) {
  1199.                 free(viewports[i].dbdata);
  1200.                 viewports[i].dbdata = NULL;
  1201.             }
  1202.             retval = 0;
  1203.             break;
  1204.         case FB_SET_STYLE:
  1205.             vport->style.fg_color = IPC_GET_ARG1(call);
  1206.             vport->style.bg_color = IPC_GET_ARG2(call);
  1207.             retval = 0;
  1208.             break;
  1209.         case FB_GET_RESOLUTION:
  1210.             ipc_answer_fast(callid, 0, screen.xres,screen.yres);
  1211.             continue;
  1212.         case FB_POINTER_MOVE:
  1213.             pointer_enabled = 1;
  1214.             mouse_move(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
  1215.             retval = 0;
  1216.             break;
  1217.         default:
  1218.             retval = ENOENT;
  1219.         }
  1220.         ipc_answer_fast(callid,retval,0,0);
  1221.     }
  1222. }
  1223.  
  1224. /** Initialization of framebuffer */
  1225. int fb_init(void)
  1226. {
  1227.     void *fb_ph_addr;
  1228.     unsigned int fb_width;
  1229.     unsigned int fb_height;
  1230.     unsigned int fb_bpp;
  1231.     unsigned int fb_bpp_align;
  1232.     unsigned int fb_scanline;
  1233.     unsigned int fb_invert_colors;
  1234.     void *fb_addr;
  1235.     size_t asz;
  1236.  
  1237.     async_set_client_connection(fb_client_connection);
  1238.  
  1239.     fb_ph_addr=(void *)sysinfo_value("fb.address.physical");
  1240.     fb_width=sysinfo_value("fb.width");
  1241.     fb_height=sysinfo_value("fb.height");
  1242.     fb_bpp=sysinfo_value("fb.bpp");
  1243.     fb_bpp_align=sysinfo_value("fb.bpp-align");
  1244.     fb_scanline=sysinfo_value("fb.scanline");
  1245.     fb_invert_colors=sysinfo_value("fb.invert-colors");
  1246.  
  1247.     asz = fb_scanline*fb_height;
  1248.     fb_addr = as_get_mappable_page(asz);
  1249.    
  1250.     map_physmem(fb_ph_addr, fb_addr, ALIGN_UP(asz,PAGE_SIZE) >>PAGE_WIDTH,
  1251.             AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE);
  1252.    
  1253.     screen_init(fb_addr, fb_width, fb_height, fb_bpp, fb_scanline, fb_bpp_align, fb_invert_colors);
  1254.  
  1255.     return 0;
  1256. }
  1257.  
  1258.  
  1259. /**
  1260.  * @}
  1261.  */
  1262.