Subversion Repositories HelenOS

Rev

Rev 1787 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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