Subversion Repositories HelenOS-historic

Rev

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