Subversion Repositories HelenOS-historic

Rev

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