Subversion Repositories HelenOS-historic

Rev

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