Subversion Repositories HelenOS

Rev

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