Subversion Repositories HelenOS-historic

Rev

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