Subversion Repositories HelenOS

Rev

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