Subversion Repositories HelenOS

Rev

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