Subversion Repositories HelenOS-historic

Rev

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