Subversion Repositories HelenOS-historic

Rev

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