fb.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 Jakub Vana
00003  * Copyright (C) 2006 Ondrej Palkovsky
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  *
00010  * - Redistributions of source code must retain the above copyright
00011  *   notice, this list of conditions and the following disclaimer.
00012  * - Redistributions in binary form must reproduce the above copyright
00013  *   notice, this list of conditions and the following disclaimer in the
00014  *   documentation and/or other materials provided with the distribution.
00015  * - The name of the author may not be used to endorse or promote products
00016  *   derived from this software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00019  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00020  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00021  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00023  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00024  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00025  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00026  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00027  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00040 #include <stdlib.h>
00041 #include <unistd.h>
00042 #include <string.h>
00043 #include <ddi.h>
00044 #include <sysinfo.h>
00045 #include <align.h>
00046 #include <as.h>
00047 #include <ipc/fb.h>
00048 #include <ipc/ipc.h>
00049 #include <ipc/ns.h>
00050 #include <ipc/services.h>
00051 #include <kernel/errno.h>
00052 #include <async.h>
00053 
00054 #include "font-8x16.h"
00055 #include "fb.h"
00056 #include "main.h"
00057 #include "../console/screenbuffer.h"
00058 #include "ppm.h"
00059 
00060 #include "pointer.xbm"
00061 #include "pointer_mask.xbm"
00062 
00063 #define DEFAULT_BGCOLOR                0xf0f0f0
00064 #define DEFAULT_FGCOLOR                0x0
00065 
00066 /***************************************************************/
00067 /* Pixel specific fuctions */
00068 
00069 typedef void (*conv2scr_fn_t)(void *, int);
00070 typedef int (*conv2rgb_fn_t)(void *);
00071 
00072 struct {
00073         __u8 *fbaddress ;
00074 
00075         unsigned int xres ;
00076         unsigned int yres ;
00077         unsigned int scanline ;
00078         unsigned int pixelbytes ;
00079 
00080         conv2scr_fn_t rgb2scr;
00081         conv2rgb_fn_t scr2rgb;
00082 } screen;
00083 
00084 typedef struct {
00085         int initialized;
00086         unsigned int x, y;
00087         unsigned int width, height;
00088 
00089         /* Text support in window */
00090         unsigned int rows, cols;
00091         /* Style for text printing */
00092         style_t style;
00093         /* Auto-cursor position */
00094         int cursor_active, cur_col, cur_row;
00095         int cursor_shown;
00096         /* Double buffering */
00097         __u8 *dbdata;
00098         unsigned int dboffset;
00099         unsigned int paused;
00100 } viewport_t;
00101 
00102 #define MAX_ANIM_LEN    8
00103 #define MAX_ANIMATIONS  4
00104 typedef struct {
00105         int initialized;
00106         int enabled;
00107         unsigned int vp;
00108 
00109         unsigned int pos;
00110         unsigned int animlen;
00111         unsigned int pixmaps[MAX_ANIM_LEN];
00112 } animation_t;
00113 static animation_t animations[MAX_ANIMATIONS];
00114 static int anims_enabled;
00115 
00119 #define MAX_PIXMAPS        256
00120 typedef struct {
00121         unsigned int width;
00122         unsigned int height;
00123         __u8 *data;
00124 } pixmap_t;
00125 static pixmap_t pixmaps[MAX_PIXMAPS];
00126 
00127 /* Viewport is a rectangular area on the screen */
00128 #define MAX_VIEWPORTS 128
00129 static viewport_t viewports[128];
00130 
00131 /* Allow only 1 connection */
00132 static int client_connected = 0;
00133 
00134 #define RED(x, bits)    ((x >> (16 + 8 - bits)) & ((1 << bits) - 1))
00135 #define GREEN(x, bits)  ((x >> (8 + 8 - bits)) & ((1 << bits) - 1))
00136 #define BLUE(x, bits)   ((x >> (8 - bits)) & ((1 << bits) - 1))
00137 
00138 #define COL_WIDTH       8
00139 #define ROW_BYTES       (screen.scanline * FONT_SCANLINES)
00140 
00141 #define POINTPOS(x, y)  ((y) * screen.scanline + (x) * screen.pixelbytes)
00142 
00143 /* Conversion routines between different color representations */
00144 static void rgb_4byte(void *dst, int rgb)
00145 {
00146         *(int *)dst = rgb;
00147 }
00148 
00149 static int byte4_rgb(void *src)
00150 {
00151         return (*(int *)src) & 0xffffff;
00152 }
00153 
00154 static void rgb_3byte(void *dst, int rgb)
00155 {
00156         __u8 *scr = dst;
00157 #if (defined(BIG_ENDIAN) || defined(FB_BIG_ENDIAN))
00158         scr[0] = RED(rgb, 8);
00159         scr[1] = GREEN(rgb, 8);
00160         scr[2] = BLUE(rgb, 8);
00161 #else
00162         scr[2] = RED(rgb, 8);
00163         scr[1] = GREEN(rgb, 8);
00164         scr[0] = BLUE(rgb, 8);
00165 #endif
00166 
00167 
00168 }
00169 
00170 static int byte3_rgb(void *src)
00171 {
00172         __u8 *scr = src;
00173 #if (defined(BIG_ENDIAN) || defined(FB_BIG_ENDIAN))
00174         return scr[0] << 16 | scr[1] << 8 | scr[2];
00175 #else
00176         return scr[2] << 16 | scr[1] << 8 | scr[0];
00177 #endif  
00178 }
00179 
00181 static void rgb_2byte(void *dst, int rgb)
00182 {
00183         /* 5-bit, 6-bits, 5-bits */ 
00184         *((__u16 *)(dst)) = RED(rgb, 5) << 11 | GREEN(rgb, 6) << 5 | BLUE(rgb, 5);
00185 }
00186 
00188 static int byte2_rgb(void *src)
00189 {
00190         int color = *(__u16 *)(src);
00191         return (((color >> 11) & 0x1f) << (16 + 3)) | (((color >> 5) & 0x3f) << (8 + 2)) | ((color & 0x1f) << 3);
00192 }
00193 
00195 static void rgb_1byte(void *dst, int rgb)
00196 {
00197         *(__u8 *)dst = RED(rgb, 3) << 5 | GREEN(rgb, 2) << 3 | BLUE(rgb, 3);
00198 }
00199 
00201 static int byte1_rgb(void *src)
00202 {
00203         int color = *(__u8 *)src;
00204         return (((color >> 5) & 0x7) << (16 + 5)) | (((color >> 3) & 0x3) << (8 + 6)) | ((color & 0x7) << 5);
00205 }
00206 
00214 static void putpixel(viewport_t *vport, unsigned int x, unsigned int y, int color)
00215 {
00216         int dx = vport->x + x;
00217         int dy = vport->y + y;
00218 
00219         if (! (vport->paused && vport->dbdata))
00220                 (*screen.rgb2scr)(&screen.fbaddress[POINTPOS(dx,dy)],color);
00221 
00222         if (vport->dbdata) {
00223                 int dline = (y + vport->dboffset) % vport->height;
00224                 int doffset = screen.pixelbytes * (dline * vport->width + x);
00225                 (*screen.rgb2scr)(&vport->dbdata[doffset],color);
00226         }
00227 }
00228 
00230 static int getpixel(viewport_t *vport, unsigned int x, unsigned int y)
00231 {
00232         int dx = vport->x + x;
00233         int dy = vport->y + y;
00234 
00235         return (*screen.scr2rgb)(&screen.fbaddress[POINTPOS(dx,dy)]);
00236 }
00237 
00238 static inline void putpixel_mem(char *mem, unsigned int x, unsigned int y, 
00239                                 int color)
00240 {
00241         (*screen.rgb2scr)(&mem[POINTPOS(x,y)],color);
00242 }
00243 
00244 static void draw_rectangle(viewport_t *vport, unsigned int sx, unsigned int sy,
00245                            unsigned int width, unsigned int height,
00246                            int color)
00247 {
00248         unsigned int x, y;
00249         static void *tmpline;
00250 
00251         if (!tmpline)
00252                 tmpline = malloc(screen.scanline*screen.pixelbytes);
00253 
00254         /* Clear first line */
00255         for (x = 0; x < width; x++)
00256                 putpixel_mem(tmpline, x, 0, color);
00257 
00258         if (!vport->paused) {
00259                 /* Recompute to screen coords */
00260                 sx += vport->x;
00261                 sy += vport->y;
00262                 /* Copy the rest */
00263                 for (y = sy;y < sy+height; y++)
00264                         memcpy(&screen.fbaddress[POINTPOS(sx,y)], tmpline, 
00265                                screen.pixelbytes * width);
00266         }
00267         if (vport->dbdata) {
00268                 for (y=sy;y < sy+height; y++) {
00269                         int rline = (y + vport->dboffset) % vport->height;
00270                         int rpos = (rline * vport->width + sx) * screen.pixelbytes;
00271                         memcpy(&vport->dbdata[rpos], tmpline, screen.pixelbytes * width);
00272                 }
00273         }
00274 
00275 }
00276 
00278 static void clear_port(viewport_t *vport)
00279 {
00280         draw_rectangle(vport, 0, 0, vport->width, vport->height, vport->style.bg_color);
00281 }
00282 
00288 static void scroll_port_nodb(viewport_t *vport, int lines)
00289 {
00290         int y;
00291 
00292         if (lines > 0) {
00293                 for (y=vport->y; y < vport->y+vport->height - lines; y++)
00294                         memcpy(&screen.fbaddress[POINTPOS(vport->x,y)],
00295                                &screen.fbaddress[POINTPOS(vport->x,y + lines)],
00296                                screen.pixelbytes * vport->width);
00297                 draw_rectangle(vport, 0, vport->height - lines,
00298                                vport->width, lines, vport->style.bg_color);
00299         } else if (lines < 0) {
00300                 lines = -lines;
00301                 for (y=vport->y + vport->height-1; y >= vport->y + lines; y--)
00302                         memcpy(&screen.fbaddress[POINTPOS(vport->x,y)],
00303                                &screen.fbaddress[POINTPOS(vport->x,y - lines)],
00304                                screen.pixelbytes * vport->width);
00305                 draw_rectangle(vport, 0, 0, vport->width, lines, vport->style.bg_color);
00306         }
00307 }
00308 
00310 static void refresh_viewport_db(viewport_t *vport)
00311 {
00312         unsigned int y, srcy, srcoff, dsty, dstx;
00313 
00314         for (y = 0; y < vport->height; y++) {
00315                 srcy = (y + vport->dboffset) % vport->height;
00316                 srcoff = (vport->width * srcy) * screen.pixelbytes;
00317 
00318                 dstx = vport->x;
00319                 dsty = vport->y + y;
00320 
00321                 memcpy(&screen.fbaddress[POINTPOS(dstx,dsty)],
00322                        &vport->dbdata[srcoff], 
00323                        vport->width*screen.pixelbytes);
00324         }
00325 }
00326 
00328 static void scroll_port_db(viewport_t *vport, int lines)
00329 {
00330         ++vport->paused;
00331         if (lines > 0) {
00332                 draw_rectangle(vport, 0, 0, vport->width, lines,
00333                                vport->style.bg_color);
00334                 vport->dboffset += lines;
00335                 vport->dboffset %= vport->height;
00336         } else if (lines < 0) {
00337                 lines = -lines;
00338                 draw_rectangle(vport, 0, vport->height-lines, 
00339                                vport->width, lines,
00340                                vport->style.bg_color);
00341 
00342                 if (vport->dboffset < lines)
00343                         vport->dboffset += vport->height;
00344                 vport->dboffset -= lines;
00345         }
00346         
00347         --vport->paused;
00348         
00349         refresh_viewport_db(vport);
00350 }
00351 
00353 static void scroll_port(viewport_t *vport, int lines)
00354 {
00355         if (vport->dbdata)
00356                 scroll_port_db(vport, lines);
00357         else
00358                 scroll_port_nodb(vport, lines);
00359         
00360 }
00361 
00362 static void invert_pixel(viewport_t *vport, unsigned int x, unsigned int y)
00363 {
00364         putpixel(vport, x, y, ~getpixel(vport, x, y));
00365 }
00366 
00367 
00368 /***************************************************************/
00369 /* Character-console functions */
00370 
00379 static void draw_glyph(viewport_t *vport,__u8 glyph, unsigned int sx, unsigned int sy, 
00380                        style_t style, int transparent)
00381 {
00382         int i;
00383         unsigned int y;
00384         unsigned int glline;
00385 
00386         for (y = 0; y < FONT_SCANLINES; y++) {
00387                 glline = fb_font[glyph * FONT_SCANLINES + y];
00388                 for (i = 0; i < 8; i++) {
00389                         if (glline & (1 << (7 - i)))
00390                                 putpixel(vport, sx + i, sy + y, style.fg_color);
00391                         else if (!transparent)
00392                                 putpixel(vport, sx + i, sy + y, style.bg_color);
00393                 }
00394         }
00395 }
00396 
00398 static void invert_char(viewport_t *vport,unsigned int row, unsigned int col)
00399 {
00400         unsigned int x;
00401         unsigned int y;
00402 
00403         for (x = 0; x < COL_WIDTH; x++)
00404                 for (y = 0; y < FONT_SCANLINES; y++)
00405                         invert_pixel(vport, col * COL_WIDTH + x, row * FONT_SCANLINES + y);
00406 }
00407 
00408 /***************************************************************/
00409 /* Stdout specific functions */
00410 
00411 
00416 static int viewport_create(unsigned int x, unsigned int y,unsigned int width, 
00417                            unsigned int height)
00418 {
00419         int i;
00420 
00421         for (i=0; i < MAX_VIEWPORTS; i++) {
00422                 if (!viewports[i].initialized)
00423                         break;
00424         }
00425         if (i == MAX_VIEWPORTS)
00426                 return ELIMIT;
00427 
00428         viewports[i].x = x;
00429         viewports[i].y = y;
00430         viewports[i].width = width;
00431         viewports[i].height = height;
00432         
00433         viewports[i].rows = height / FONT_SCANLINES;
00434         viewports[i].cols = width / COL_WIDTH;
00435 
00436         viewports[i].style.bg_color = DEFAULT_BGCOLOR;
00437         viewports[i].style.fg_color = DEFAULT_FGCOLOR;
00438         
00439         viewports[i].cur_col = 0;
00440         viewports[i].cur_row = 0;
00441         viewports[i].cursor_active = 0;
00442 
00443         viewports[i].initialized = 1;
00444 
00445         return i;
00446 }
00447 
00448 
00458 static void screen_init(void *addr, unsigned int xres, unsigned int yres, unsigned int bpp, unsigned int scan)
00459 {
00460         switch (bpp) {
00461                 case 8:
00462                         screen.rgb2scr = rgb_1byte;
00463                         screen.scr2rgb = byte1_rgb;
00464                         screen.pixelbytes = 1;
00465                         break;
00466                 case 16:
00467                         screen.rgb2scr = rgb_2byte;
00468                         screen.scr2rgb = byte2_rgb;
00469                         screen.pixelbytes = 2;
00470                         break;
00471                 case 24:
00472                         screen.rgb2scr = rgb_3byte;
00473                         screen.scr2rgb = byte3_rgb;
00474                         screen.pixelbytes = 3;
00475                         break;
00476                 case 32:
00477                         screen.rgb2scr = rgb_4byte;
00478                         screen.scr2rgb = byte4_rgb;
00479                         screen.pixelbytes = 4;
00480                         break;
00481         }
00482 
00483                 
00484         screen.fbaddress = (unsigned char *) addr;
00485         screen.xres = xres;
00486         screen.yres = yres;
00487         screen.scanline = scan;
00488         
00489         /* Create first viewport */
00490         viewport_create(0,0,xres,yres);
00491 }
00492 
00494 static void cursor_hide(viewport_t *vport)
00495 {
00496         if (vport->cursor_active && vport->cursor_shown) {
00497                 invert_char(vport, vport->cur_row, vport->cur_col);
00498                 vport->cursor_shown = 0;
00499         }
00500 }
00501 
00503 static void cursor_print(viewport_t *vport)
00504 {
00505         /* Do not check for cursor_shown */
00506         if (vport->cursor_active) {
00507                 invert_char(vport, vport->cur_row, vport->cur_col);
00508                 vport->cursor_shown = 1;
00509         }
00510 }
00511 
00513 static void cursor_blink(viewport_t *vport)
00514 {
00515         if (vport->cursor_shown)
00516                 cursor_hide(vport);
00517         else
00518                 cursor_print(vport);
00519 }
00520 
00529 static void draw_char(viewport_t *vport, char c, unsigned int row, unsigned int col, 
00530                       style_t style, int transparent)
00531 {
00532         /* Optimize - do not hide cursor if we are going to overwrite it */
00533         if (vport->cursor_active && vport->cursor_shown && 
00534             (vport->cur_col != col || vport->cur_row != row))
00535                 invert_char(vport, vport->cur_row, vport->cur_col);
00536         
00537         draw_glyph(vport, c, col * COL_WIDTH, row * FONT_SCANLINES, style, transparent);
00538 
00539         vport->cur_col = col;
00540         vport->cur_row = row;
00541 
00542         vport->cur_col++;
00543         if (vport->cur_col>= vport->cols) {
00544                 vport->cur_col = 0;
00545                 vport->cur_row++;
00546                 if (vport->cur_row >= vport->rows)
00547                         vport->cur_row--;
00548         }
00549         cursor_print(vport);
00550 }
00551 
00557 static void draw_text_data(viewport_t *vport, keyfield_t *data)
00558 {
00559         int i;
00560         int col,row;
00561 
00562         clear_port(vport);
00563         for (i=0; i < vport->cols * vport->rows; i++) {
00564                 if (data[i].character == ' ' && style_same(data[i].style,vport->style))
00565                         continue;
00566                 col = i % vport->cols;
00567                 row = i / vport->cols;
00568                 draw_glyph(vport, data[i].character, col * COL_WIDTH, row * FONT_SCANLINES, 
00569                            data[i].style, style_same(data[i].style,vport->style));
00570         }
00571         cursor_print(vport);
00572 }
00573 
00574 
00576 static int find_free_pixmap(void)
00577 {
00578         int i;
00579         
00580         for (i=0;i < MAX_PIXMAPS;i++)
00581                 if (!pixmaps[i].data)
00582                         return i;
00583         return -1;
00584 }
00585 
00586 static void putpixel_pixmap(int pm, unsigned int x, unsigned int y, int color)
00587 {
00588         pixmap_t *pmap = &pixmaps[pm];
00589         int pos = (y * pmap->width + x) * screen.pixelbytes;
00590 
00591         (*screen.rgb2scr)(&pmap->data[pos],color);
00592 }
00593 
00595 static int shm2pixmap(unsigned char *shm, size_t size)
00596 {
00597         int pm;
00598         pixmap_t *pmap;
00599 
00600         pm = find_free_pixmap();
00601         if (pm == -1)
00602                 return ELIMIT;
00603         pmap = &pixmaps[pm];
00604         
00605         if (ppm_get_data(shm, size, &pmap->width, &pmap->height))
00606                 return EINVAL;
00607         
00608         pmap->data = malloc(pmap->width * pmap->height * screen.pixelbytes);
00609         if (!pmap->data)
00610                 return ENOMEM;
00611 
00612         ppm_draw(shm, size, 0, 0, pmap->width, pmap->height, 
00613                  (putpixel_cb_t)putpixel_pixmap, (void *)pm);
00614 
00615         return pm;
00616 }
00617 
00638 static int shm_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
00639 {
00640         static keyfield_t *interbuffer = NULL;
00641         static size_t intersize = 0;
00642 
00643         static unsigned char *shm = NULL;
00644         static ipcarg_t shm_id = 0;
00645         static size_t shm_size;
00646 
00647         int handled = 1;
00648         int retval = 0;
00649         viewport_t *vport = &viewports[vp];
00650         unsigned int x,y;
00651 
00652         switch (IPC_GET_METHOD(*call)) {
00653         case IPC_M_AS_AREA_SEND:
00654                 /* We accept one area for data interchange */
00655                 if (IPC_GET_ARG1(*call) == shm_id) {
00656                         void *dest = as_get_mappable_page(IPC_GET_ARG2(*call));
00657                         shm_size = IPC_GET_ARG2(*call);
00658                         if (!ipc_answer_fast(callid, 0, (sysarg_t)dest, 0)) 
00659                                 shm = dest;
00660                         else
00661                                 shm_id = 0;
00662                         if (shm[0] != 'P')
00663                                 while (1)
00664                                         ;
00665                         return 1;
00666                 } else {
00667                         intersize = IPC_GET_ARG2(*call);
00668                         receive_comm_area(callid,call,(void *)&interbuffer);
00669                 }
00670                 return 1;
00671         case FB_PREPARE_SHM:
00672                 if (shm_id)
00673                         retval = EBUSY;
00674                 else 
00675                         shm_id = IPC_GET_ARG1(*call);
00676                 break;
00677                 
00678         case FB_DROP_SHM:
00679                 if (shm) {
00680                         as_area_destroy(shm);
00681                         shm = NULL;
00682                 }
00683                 shm_id = 0;
00684                 break;
00685 
00686         case FB_SHM2PIXMAP:
00687                 if (!shm) {
00688                         retval = EINVAL;
00689                         break;
00690                 }
00691                 retval = shm2pixmap(shm, shm_size);
00692                 break;
00693         case FB_DRAW_PPM:
00694                 if (!shm) {
00695                         retval = EINVAL;
00696                         break;
00697                 }
00698                 x = IPC_GET_ARG1(*call);
00699                 y = IPC_GET_ARG2(*call);
00700                 if (x > vport->width || y > vport->height) {
00701                         retval = EINVAL;
00702                         break;
00703                 }
00704                 
00705                 ppm_draw(shm, shm_size, IPC_GET_ARG1(*call), IPC_GET_ARG2(*call),
00706                          vport->width - x, vport->height - y, (putpixel_cb_t)putpixel, vport);
00707                 break;
00708         case FB_DRAW_TEXT_DATA:
00709                 if (!interbuffer) {
00710                         retval = EINVAL;
00711                         break;
00712                 }
00713                 if (intersize < vport->cols*vport->rows*sizeof(*interbuffer)) {
00714                         retval = EINVAL;
00715                         break;
00716                 }
00717                 draw_text_data(vport, interbuffer);
00718                 break;
00719         default:
00720                 handled = 0;
00721         }
00722         
00723         if (handled)
00724                 ipc_answer_fast(callid, retval, 0, 0);
00725         return handled;
00726 }
00727 
00728 static void copy_vp_to_pixmap(viewport_t *vport, pixmap_t *pmap)
00729 {
00730         int y;
00731         int rowsize;
00732         int tmp;
00733         int width = vport->width;
00734         int height = vport->height;
00735 
00736         if (width + vport->x > screen.xres)
00737                 width = screen.xres - vport->x;
00738         if (height + vport->y  > screen.yres)
00739                 height = screen.yres - vport->y;
00740 
00741         rowsize = width * screen.pixelbytes;
00742 
00743         for (y=0;y < height; y++) {
00744                 tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;
00745                 memcpy(pmap->data + rowsize*y, screen.fbaddress + tmp, rowsize); 
00746         }
00747 }
00748 
00750 static int save_vp_to_pixmap(viewport_t *vport)
00751 {
00752         int pm;
00753         pixmap_t *pmap;
00754 
00755         pm = find_free_pixmap();
00756         if (pm == -1)
00757                 return ELIMIT;
00758         
00759         pmap = &pixmaps[pm];
00760         pmap->data = malloc(screen.pixelbytes * vport->width * vport->height);
00761         if (!pmap->data)
00762                 return ENOMEM;
00763 
00764         pmap->width = vport->width;
00765         pmap->height = vport->height;
00766 
00767         copy_vp_to_pixmap(vport, pmap);
00768         
00769         return pm;
00770 }
00771 
00777 static int draw_pixmap(int vp, int pm)
00778 {
00779         pixmap_t *pmap = &pixmaps[pm];
00780         viewport_t *vport = &viewports[vp];
00781         int y;
00782         int tmp, srcrowsize;
00783         int realwidth, realheight, realrowsize;
00784         int width = vport->width;
00785         int height = vport->height;
00786 
00787         if (width + vport->x > screen.xres)
00788                 width = screen.xres - vport->x;
00789         if (height + vport->y > screen.yres)
00790                 height = screen.yres - vport->y;
00791 
00792         if (!pmap->data)
00793                 return EINVAL;
00794 
00795         realwidth = pmap->width <= width ? pmap->width : width;
00796         realheight = pmap->height <= height ? pmap->height : height;
00797 
00798         srcrowsize = vport->width * screen.pixelbytes;
00799         realrowsize = realwidth * screen.pixelbytes;
00800 
00801         for (y=0; y < realheight; y++) {
00802                 tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;
00803                 memcpy(screen.fbaddress + tmp, pmap->data + y * srcrowsize, realrowsize);
00804         }
00805         return 0;
00806 }
00807 
00809 static void anims_tick(void)
00810 {
00811         int i;
00812         static int counts = 0;
00813         
00814         /* Limit redrawing */
00815         counts = (counts+1) % 8;
00816         if (counts)
00817                 return;
00818 
00819         for (i=0; i < MAX_ANIMATIONS; i++) {
00820                 if (!animations[i].animlen || !animations[i].initialized || !animations[i].enabled)
00821                         continue;
00822                 draw_pixmap(animations[i].vp, animations[i].pixmaps[animations[i].pos]);
00823                 animations[i].pos = (animations[i].pos+1) % animations[i].animlen;
00824         }
00825 }
00826 
00827 
00828 static int pointer_x, pointer_y;
00829 static int pointer_shown, pointer_enabled;
00830 static int pointer_vport = -1;
00831 static int pointer_pixmap = -1;
00832 
00833 static void mouse_show(void)
00834 {
00835         int i,j;
00836         int visibility;
00837         int color;
00838         int bytepos;
00839 
00840         if (pointer_shown || !pointer_enabled)
00841                 return;
00842 
00843         /* Save image under the cursor */
00844         if (pointer_vport == -1) {
00845                 pointer_vport = viewport_create(pointer_x, pointer_y, pointer_width, pointer_height);
00846                 if (pointer_vport < 0)
00847                         return;
00848         } else {
00849                 viewports[pointer_vport].x = pointer_x;
00850                 viewports[pointer_vport].y = pointer_y;
00851         }
00852 
00853         if (pointer_pixmap == -1)
00854                 pointer_pixmap = save_vp_to_pixmap(&viewports[pointer_vport]);
00855         else
00856                 copy_vp_to_pixmap(&viewports[pointer_vport], &pixmaps[pointer_pixmap]);
00857 
00858         /* Draw cursor */
00859         for (i=0; i < pointer_height; i++)
00860                 for (j=0;j < pointer_width; j++) {
00861                         bytepos = i*((pointer_width-1)/8+1) + j/8;
00862                         visibility = pointer_mask_bits[bytepos] & (1 << (j % 8));
00863                         if (visibility) {
00864                                 color = pointer_bits[bytepos] & (1 << (j % 8)) ? 0 : 0xffffff;
00865                                 if (pointer_x+j < screen.xres && pointer_y+i < screen.yres)
00866                                         putpixel(&viewports[0], pointer_x+j, pointer_y+i, color);
00867                         }
00868                 }
00869         pointer_shown = 1;
00870 }
00871 
00872 static void mouse_hide(void)
00873 {
00874         /* Restore image under the cursor */
00875         if (pointer_shown) {
00876                 draw_pixmap(pointer_vport, pointer_pixmap);
00877                 pointer_shown = 0;
00878         }
00879 }
00880 
00881 static void mouse_move(unsigned int x, unsigned int y)
00882 {
00883         mouse_hide();
00884         pointer_x = x;
00885         pointer_y = y;
00886         mouse_show();
00887 }
00888 
00889 static int anim_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
00890 {
00891         int handled = 1;
00892         int retval = 0;
00893         int i,nvp;
00894         int newval;
00895 
00896         switch (IPC_GET_METHOD(*call)) {
00897         case FB_ANIM_CREATE:
00898                 nvp = IPC_GET_ARG1(*call);
00899                 if (nvp == -1)
00900                         nvp = vp;
00901                 if (nvp >= MAX_VIEWPORTS || nvp < 0 || !viewports[nvp].initialized) {
00902                         retval = EINVAL;
00903                         break;
00904                 }
00905                 for (i=0; i < MAX_ANIMATIONS; i++) {
00906                         if (! animations[i].initialized)
00907                                 break;
00908                 }
00909                 if (i == MAX_ANIMATIONS) {
00910                         retval = ELIMIT;
00911                         break;
00912                 }
00913                 animations[i].initialized = 1;
00914                 animations[i].animlen = 0;
00915                 animations[i].pos = 0;
00916                 animations[i].enabled = 0;
00917                 animations[i].vp = nvp;
00918                 retval = i;
00919                 break;
00920         case FB_ANIM_DROP:
00921                 i = IPC_GET_ARG1(*call);
00922                 if (i >= MAX_ANIMATIONS || i < 0) {
00923                         retval = EINVAL;
00924                         break;
00925                 }
00926                 animations[i].initialized = 0;
00927                 break;
00928         case FB_ANIM_ADDPIXMAP:
00929                 i = IPC_GET_ARG1(*call);
00930                 if (i >= MAX_ANIMATIONS || i < 0 || !animations[i].initialized) {
00931                         retval = EINVAL;
00932                         break;
00933                 }
00934                 if (animations[i].animlen == MAX_ANIM_LEN) {
00935                         retval = ELIMIT;
00936                         break;
00937                 }
00938                 newval = IPC_GET_ARG2(*call);
00939                 if (newval < 0 || newval > MAX_PIXMAPS || !pixmaps[newval].data) {
00940                         retval = EINVAL;
00941                         break;
00942                 }
00943                 animations[i].pixmaps[animations[i].animlen++] = newval;
00944                 break;
00945         case FB_ANIM_CHGVP:
00946                 i = IPC_GET_ARG1(*call);
00947                 if (i >= MAX_ANIMATIONS || i < 0) {
00948                         retval = EINVAL;
00949                         break;
00950                 }
00951                 nvp = IPC_GET_ARG2(*call);
00952                 if (nvp == -1)
00953                         nvp = vp;
00954                 if (nvp >= MAX_VIEWPORTS || nvp < 0 || !viewports[nvp].initialized) {
00955                         retval = EINVAL;
00956                         break;
00957                 }
00958                 animations[i].vp = nvp;
00959                 break;
00960         case FB_ANIM_START:
00961         case FB_ANIM_STOP:
00962                 i = IPC_GET_ARG1(*call);
00963                 if (i >= MAX_ANIMATIONS || i < 0) {
00964                         retval = EINVAL;
00965                         break;
00966                 }
00967                 newval = (IPC_GET_METHOD(*call) == FB_ANIM_START);
00968                 if (newval ^ animations[i].enabled) {
00969                         animations[i].enabled = newval;
00970                         anims_enabled += newval ? 1 : -1;
00971                 }
00972                 break;
00973         default:
00974                 handled = 0;
00975         }
00976         if (handled)
00977                 ipc_answer_fast(callid, retval, 0, 0);
00978         return handled;
00979 }
00980 
00982 static int pixmap_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
00983 {
00984         int handled = 1;
00985         int retval = 0;
00986         int i,nvp;
00987 
00988         switch (IPC_GET_METHOD(*call)) {
00989         case FB_VP_DRAW_PIXMAP:
00990                 nvp = IPC_GET_ARG1(*call);
00991                 if (nvp == -1)
00992                         nvp = vp;
00993                 if (nvp < 0 || nvp >= MAX_VIEWPORTS || !viewports[nvp].initialized) {
00994                         retval = EINVAL;
00995                         break;
00996                 }
00997                 i = IPC_GET_ARG2(*call);
00998                 retval = draw_pixmap(nvp, i);
00999                 break;
01000         case FB_VP2PIXMAP:
01001                 nvp = IPC_GET_ARG1(*call);
01002                 if (nvp == -1)
01003                         nvp = vp;
01004                 if (nvp < 0 || nvp >= MAX_VIEWPORTS || !viewports[nvp].initialized)
01005                         retval = EINVAL;
01006                 else
01007                         retval = save_vp_to_pixmap(&viewports[nvp]);
01008                 break;
01009         case FB_DROP_PIXMAP:
01010                 i = IPC_GET_ARG1(*call);
01011                 if (i >= MAX_PIXMAPS) {
01012                         retval = EINVAL;
01013                         break;
01014                 }
01015                 if (pixmaps[i].data) {
01016                         free(pixmaps[i].data);
01017                         pixmaps[i].data = NULL;
01018                 }
01019                 break;
01020         default:
01021                 handled = 0;
01022         }
01023 
01024         if (handled)
01025                 ipc_answer_fast(callid, retval, 0, 0);
01026         return handled;
01027         
01028 }
01029 
01033 static void fb_client_connection(ipc_callid_t iid, ipc_call_t *icall)
01034 {
01035         ipc_callid_t callid;
01036         ipc_call_t call;
01037         int retval;
01038         int i;
01039         unsigned int row,col;
01040         char c;
01041 
01042         int vp = 0;
01043         viewport_t *vport = &viewports[0];
01044 
01045         if (client_connected) {
01046                 ipc_answer_fast(iid, ELIMIT, 0,0);
01047                 return;
01048         }
01049         client_connected = 1;
01050         ipc_answer_fast(iid, 0, 0, 0); /* Accept connection */
01051 
01052         while (1) {
01053                 if (vport->cursor_active || anims_enabled)
01054                         callid = async_get_call_timeout(&call,250000);
01055                 else
01056                         callid = async_get_call(&call);
01057 
01058                 mouse_hide();
01059                 if (!callid) {
01060                         cursor_blink(vport);
01061                         anims_tick();
01062                         mouse_show();
01063                         continue;
01064                 }
01065                 if (shm_handle(callid, &call, vp))
01066                         continue;
01067                 if (pixmap_handle(callid, &call, vp))
01068                         continue;
01069                 if (anim_handle(callid, &call, vp))
01070                         continue;
01071 
01072                 switch (IPC_GET_METHOD(call)) {
01073                 case IPC_M_PHONE_HUNGUP:
01074                         client_connected = 0;
01075                         /* cleanup other viewports */
01076                         for (i=1; i < MAX_VIEWPORTS; i++)
01077                                 vport->initialized = 0;
01078                         return; /* Exit thread */
01079 
01080                 case FB_PUTCHAR:
01081                 case FB_TRANS_PUTCHAR:
01082                         c = IPC_GET_ARG1(call);
01083                         row = IPC_GET_ARG2(call);
01084                         col = IPC_GET_ARG3(call);
01085                         if (row >= vport->rows || col >= vport->cols) {
01086                                 retval = EINVAL;
01087                                 break;
01088                         }
01089                         ipc_answer_fast(callid,0,0,0);
01090 
01091                         draw_char(vport, c, row, col, vport->style, IPC_GET_METHOD(call) == FB_TRANS_PUTCHAR);
01092                         continue; /* msg already answered */
01093                 case FB_CLEAR:
01094                         clear_port(vport);
01095                         cursor_print(vport);
01096                         retval = 0;
01097                         break;
01098                 case FB_CURSOR_GOTO:
01099                         row = IPC_GET_ARG1(call);
01100                         col = IPC_GET_ARG2(call);
01101                         if (row >= vport->rows || col >= vport->cols) {
01102                                 retval = EINVAL;
01103                                 break;
01104                         }
01105                         retval = 0;
01106                         cursor_hide(vport);
01107                         vport->cur_col = col;
01108                         vport->cur_row = row;
01109                         cursor_print(vport);
01110                         break;
01111                 case FB_CURSOR_VISIBILITY:
01112                         cursor_hide(vport);
01113                         vport->cursor_active = IPC_GET_ARG1(call);
01114                         cursor_print(vport);
01115                         retval = 0;
01116                         break;
01117                 case FB_GET_CSIZE:
01118                         ipc_answer_fast(callid, 0, vport->rows, vport->cols);
01119                         continue;
01120                 case FB_SCROLL:
01121                         i = IPC_GET_ARG1(call);
01122                         if (i > vport->rows || i < (- (int)vport->rows)) {
01123                                 retval = EINVAL;
01124                                 break;
01125                         }
01126                         cursor_hide(vport);
01127                         scroll_port(vport, i*FONT_SCANLINES);
01128                         cursor_print(vport);
01129                         retval = 0;
01130                         break;
01131                 case FB_VIEWPORT_DB:
01132                         /* Enable double buffering */
01133                         i = IPC_GET_ARG1(call);
01134                         if (i == -1)
01135                                 i = vp;
01136                         if (i < 0 || i >= MAX_VIEWPORTS) {
01137                                 retval = EINVAL;
01138                                 break;
01139                         }
01140                         if (! viewports[i].initialized ) {
01141                                 retval = EADDRNOTAVAIL;
01142                                 break;
01143                         }
01144                         viewports[i].dboffset = 0;
01145                         if (IPC_GET_ARG2(call) == 1 && !viewports[i].dbdata)
01146                                 viewports[i].dbdata = malloc(screen.pixelbytes*viewports[i].width * viewports[i].height);
01147                         else if (IPC_GET_ARG2(call) == 0 && viewports[i].dbdata) {
01148                                 free(viewports[i].dbdata);
01149                                 viewports[i].dbdata = NULL;
01150                         }
01151                         retval = 0;
01152                         break;
01153                 case FB_VIEWPORT_SWITCH:
01154                         i = IPC_GET_ARG1(call);
01155                         if (i < 0 || i >= MAX_VIEWPORTS) {
01156                                 retval = EINVAL;
01157                                 break;
01158                         }
01159                         if (! viewports[i].initialized ) {
01160                                 retval = EADDRNOTAVAIL;
01161                                 break;
01162                         }
01163                         cursor_hide(vport);
01164                         vp = i;
01165                         vport = &viewports[vp];
01166                         cursor_print(vport);
01167                         retval = 0;
01168                         break;
01169                 case FB_VIEWPORT_CREATE:
01170                         retval = viewport_create(IPC_GET_ARG1(call) >> 16,
01171                                                  IPC_GET_ARG1(call) & 0xffff,
01172                                                  IPC_GET_ARG2(call) >> 16,
01173                                                  IPC_GET_ARG2(call) & 0xffff);
01174                         break;
01175                 case FB_VIEWPORT_DELETE:
01176                         i = IPC_GET_ARG1(call);
01177                         if (i < 0 || i >= MAX_VIEWPORTS) {
01178                                 retval = EINVAL;
01179                                 break;
01180                         }
01181                         if (! viewports[i].initialized ) {
01182                                 retval = EADDRNOTAVAIL;
01183                                 break;
01184                         }
01185                         viewports[i].initialized = 0;
01186                         if (viewports[i].dbdata) {
01187                                 free(viewports[i].dbdata);
01188                                 viewports[i].dbdata = NULL;
01189                         }
01190                         retval = 0;
01191                         break;
01192                 case FB_SET_STYLE:
01193                         vport->style.fg_color = IPC_GET_ARG1(call);
01194                         vport->style.bg_color = IPC_GET_ARG2(call);
01195                         retval = 0;
01196                         break;
01197                 case FB_GET_RESOLUTION:
01198                         ipc_answer_fast(callid, 0, screen.xres,screen.yres);
01199                         continue;
01200                 case FB_POINTER_MOVE:
01201                         pointer_enabled = 1;
01202                         mouse_move(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
01203                         retval = 0;
01204                         break;
01205                 default:
01206                         retval = ENOENT;
01207                 }
01208                 ipc_answer_fast(callid,retval,0,0);
01209         }
01210 }
01211 
01213 int fb_init(void)
01214 {
01215         void *fb_ph_addr;
01216         unsigned int fb_width;
01217         unsigned int fb_height;
01218         unsigned int fb_bpp;
01219         unsigned int fb_scanline;
01220         void *fb_addr;
01221         size_t asz;
01222 
01223         async_set_client_connection(fb_client_connection);
01224 
01225         fb_ph_addr=(void *)sysinfo_value("fb.address.physical");
01226         fb_width=sysinfo_value("fb.width");
01227         fb_height=sysinfo_value("fb.height");
01228         fb_bpp=sysinfo_value("fb.bpp");
01229         fb_scanline=sysinfo_value("fb.scanline");
01230 
01231         asz = fb_scanline*fb_height;
01232         fb_addr = as_get_mappable_page(asz);
01233         
01234         map_physmem(fb_ph_addr, fb_addr, ALIGN_UP(asz,PAGE_SIZE) >>PAGE_WIDTH,
01235                     AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE);
01236         
01237         screen_init(fb_addr, fb_width, fb_height, fb_bpp, fb_scanline);
01238 
01239         return 0;
01240 }
01241 
01242 

Generated on Sun Jun 18 17:54:20 2006 for HelenOS Userspace (ia32) by  doxygen 1.4.6