Subversion Repositories HelenOS-historic

Rev

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