Subversion Repositories HelenOS-historic

Rev

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