Subversion Repositories HelenOS

Rev

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