source: mainline/uspace/fb/fb.c@ 5035eeb7

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5035eeb7 was 5035eeb7, checked in by Jakub Jermar <jakub@…>, 19 years ago

Pass "fb.bpp-align" property to userspace so that our fb task works properly even on
framebuffers used in some Sun hardware.

  • Property mode set to 100644
File size: 29.5 KB
Line 
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/**
31 * @defgroup fb Graphical framebuffer
32 * @brief HelenOS graphical framebuffer.
33 * @ingroup fbs
34 * @{
35 */
36/** @file
37 */
38
39
40#include <stdlib.h>
41#include <unistd.h>
42#include <string.h>
43#include <ddi.h>
44#include <sysinfo.h>
45#include <align.h>
46#include <as.h>
47#include <ipc/fb.h>
48#include <ipc/ipc.h>
49#include <ipc/ns.h>
50#include <ipc/services.h>
51#include <kernel/errno.h>
52#include <async.h>
53
54#include "font-8x16.h"
55#include "fb.h"
56#include "main.h"
57#include "../console/screenbuffer.h"
58#include "ppm.h"
59
60#include "pointer.xbm"
61#include "pointer_mask.xbm"
62
63#define DEFAULT_BGCOLOR 0xf0f0f0
64#define DEFAULT_FGCOLOR 0x0
65
66/***************************************************************/
67/* Pixel specific fuctions */
68
69typedef void (*conv2scr_fn_t)(void *, int);
70typedef int (*conv2rgb_fn_t)(void *);
71
72struct {
73 uint8_t *fbaddress ;
74
75 unsigned int xres ;
76 unsigned int yres ;
77 unsigned int scanline ;
78 unsigned int pixelbytes ;
79
80 conv2scr_fn_t rgb2scr;
81 conv2rgb_fn_t scr2rgb;
82} screen;
83
84typedef struct {
85 int initialized;
86 unsigned int x, y;
87 unsigned int width, height;
88
89 /* Text support in window */
90 unsigned int rows, cols;
91 /* Style for text printing */
92 style_t style;
93 /* Auto-cursor position */
94 int cursor_active, cur_col, cur_row;
95 int cursor_shown;
96 /* Double buffering */
97 uint8_t *dbdata;
98 unsigned int dboffset;
99 unsigned int paused;
100} viewport_t;
101
102#define MAX_ANIM_LEN 8
103#define MAX_ANIMATIONS 4
104typedef struct {
105 int initialized;
106 int enabled;
107 unsigned int vp;
108
109 unsigned int pos;
110 unsigned int animlen;
111 unsigned int pixmaps[MAX_ANIM_LEN];
112} animation_t;
113static animation_t animations[MAX_ANIMATIONS];
114static int anims_enabled;
115
116/** Maximum number of saved pixmaps
117 * Pixmap is a saved rectangle
118 */
119#define MAX_PIXMAPS 256
120typedef struct {
121 unsigned int width;
122 unsigned int height;
123 uint8_t *data;
124} pixmap_t;
125static pixmap_t pixmaps[MAX_PIXMAPS];
126
127/* Viewport is a rectangular area on the screen */
128#define MAX_VIEWPORTS 128
129static viewport_t viewports[128];
130
131/* Allow only 1 connection */
132static int client_connected = 0;
133
134#define RED(x, bits) ((x >> (16 + 8 - bits)) & ((1 << bits) - 1))
135#define GREEN(x, bits) ((x >> (8 + 8 - bits)) & ((1 << bits) - 1))
136#define BLUE(x, bits) ((x >> (8 - bits)) & ((1 << bits) - 1))
137
138#define COL_WIDTH 8
139#define ROW_BYTES (screen.scanline * FONT_SCANLINES)
140
141#define POINTPOS(x, y) ((y) * screen.scanline + (x) * screen.pixelbytes)
142
143/* Conversion routines between different color representations */
144static void rgb_4byte(void *dst, int rgb)
145{
146 *(int *)dst = rgb;
147}
148
149static int byte4_rgb(void *src)
150{
151 return (*(int *)src) & 0xffffff;
152}
153
154static void rgb_3byte(void *dst, int rgb)
155{
156 uint8_t *scr = dst;
157#if (defined(BIG_ENDIAN) || defined(FB_BIG_ENDIAN))
158 scr[0] = RED(rgb, 8);
159 scr[1] = GREEN(rgb, 8);
160 scr[2] = BLUE(rgb, 8);
161#else
162 scr[2] = RED(rgb, 8);
163 scr[1] = GREEN(rgb, 8);
164 scr[0] = BLUE(rgb, 8);
165#endif
166
167
168}
169
170static int byte3_rgb(void *src)
171{
172 uint8_t *scr = src;
173#if (defined(BIG_ENDIAN) || defined(FB_BIG_ENDIAN))
174 return scr[0] << 16 | scr[1] << 8 | scr[2];
175#else
176 return scr[2] << 16 | scr[1] << 8 | scr[0];
177#endif
178}
179
180/** 16-bit depth (5:6:5) */
181static void rgb_2byte(void *dst, int rgb)
182{
183 /* 5-bit, 6-bits, 5-bits */
184 *((uint16_t *)(dst)) = RED(rgb, 5) << 11 | GREEN(rgb, 6) << 5 | BLUE(rgb, 5);
185}
186
187/** 16-bit depth (5:6:5) */
188static int byte2_rgb(void *src)
189{
190 int color = *(uint16_t *)(src);
191 return (((color >> 11) & 0x1f) << (16 + 3)) | (((color >> 5) & 0x3f) << (8 + 2)) | ((color & 0x1f) << 3);
192}
193
194/** Put pixel - 8-bit depth (3:2:3) */
195static void rgb_1byte(void *dst, int rgb)
196{
197 *(uint8_t *)dst = RED(rgb, 3) << 5 | GREEN(rgb, 2) << 3 | BLUE(rgb, 3);
198}
199
200/** Return pixel color - 8-bit depth (3:2:3) */
201static int byte1_rgb(void *src)
202{
203 int color = *(uint8_t *)src;
204 return (((color >> 5) & 0x7) << (16 + 5)) | (((color >> 3) & 0x3) << (8 + 6)) | ((color & 0x7) << 5);
205}
206
207/** Put pixel into viewport
208 *
209 * @param vport Viewport identification
210 * @param x X coord relative to viewport
211 * @param y Y coord relative to viewport
212 * @param color RGB color
213 */
214static void putpixel(viewport_t *vport, unsigned int x, unsigned int y, int color)
215{
216 int dx = vport->x + x;
217 int dy = vport->y + y;
218
219 if (! (vport->paused && vport->dbdata))
220 (*screen.rgb2scr)(&screen.fbaddress[POINTPOS(dx,dy)],color);
221
222 if (vport->dbdata) {
223 int dline = (y + vport->dboffset) % vport->height;
224 int doffset = screen.pixelbytes * (dline * vport->width + x);
225 (*screen.rgb2scr)(&vport->dbdata[doffset],color);
226 }
227}
228
229/** Get pixel from viewport */
230static int getpixel(viewport_t *vport, unsigned int x, unsigned int y)
231{
232 int dx = vport->x + x;
233 int dy = vport->y + y;
234
235 return (*screen.scr2rgb)(&screen.fbaddress[POINTPOS(dx,dy)]);
236}
237
238static inline void putpixel_mem(char *mem, unsigned int x, unsigned int y,
239 int color)
240{
241 (*screen.rgb2scr)(&mem[POINTPOS(x,y)],color);
242}
243
244static void draw_rectangle(viewport_t *vport, unsigned int sx, unsigned int sy,
245 unsigned int width, unsigned int height,
246 int color)
247{
248 unsigned int x, y;
249 static void *tmpline;
250
251 if (!tmpline)
252 tmpline = malloc(screen.scanline*screen.pixelbytes);
253
254 /* Clear first line */
255 for (x = 0; x < width; x++)
256 putpixel_mem(tmpline, x, 0, color);
257
258 if (!vport->paused) {
259 /* Recompute to screen coords */
260 sx += vport->x;
261 sy += vport->y;
262 /* Copy the rest */
263 for (y = sy;y < sy+height; y++)
264 memcpy(&screen.fbaddress[POINTPOS(sx,y)], tmpline,
265 screen.pixelbytes * width);
266 }
267 if (vport->dbdata) {
268 for (y=sy;y < sy+height; y++) {
269 int rline = (y + vport->dboffset) % vport->height;
270 int rpos = (rline * vport->width + sx) * screen.pixelbytes;
271 memcpy(&vport->dbdata[rpos], tmpline, screen.pixelbytes * width);
272 }
273 }
274
275}
276
277/** Fill viewport with background color */
278static void clear_port(viewport_t *vport)
279{
280 draw_rectangle(vport, 0, 0, vport->width, vport->height, vport->style.bg_color);
281}
282
283/** Scroll unbuffered viewport up/down
284 *
285 * @param vport Viewport to scroll
286 * @param lines Positive number - scroll up, negative - scroll down
287 */
288static void scroll_port_nodb(viewport_t *vport, int lines)
289{
290 int y;
291
292 if (lines > 0) {
293 for (y=vport->y; y < vport->y+vport->height - lines; y++)
294 memcpy(&screen.fbaddress[POINTPOS(vport->x,y)],
295 &screen.fbaddress[POINTPOS(vport->x,y + lines)],
296 screen.pixelbytes * vport->width);
297 draw_rectangle(vport, 0, vport->height - lines,
298 vport->width, lines, vport->style.bg_color);
299 } else if (lines < 0) {
300 lines = -lines;
301 for (y=vport->y + vport->height-1; y >= vport->y + lines; y--)
302 memcpy(&screen.fbaddress[POINTPOS(vport->x,y)],
303 &screen.fbaddress[POINTPOS(vport->x,y - lines)],
304 screen.pixelbytes * vport->width);
305 draw_rectangle(vport, 0, 0, vport->width, lines, vport->style.bg_color);
306 }
307}
308
309/** Refresh given viewport from double buffer */
310static void refresh_viewport_db(viewport_t *vport)
311{
312 unsigned int y, srcy, srcoff, dsty, dstx;
313
314 for (y = 0; y < vport->height; y++) {
315 srcy = (y + vport->dboffset) % vport->height;
316 srcoff = (vport->width * srcy) * screen.pixelbytes;
317
318 dstx = vport->x;
319 dsty = vport->y + y;
320
321 memcpy(&screen.fbaddress[POINTPOS(dstx,dsty)],
322 &vport->dbdata[srcoff],
323 vport->width*screen.pixelbytes);
324 }
325}
326
327/** Scroll viewport that has double buffering enabled */
328static void scroll_port_db(viewport_t *vport, int lines)
329{
330 ++vport->paused;
331 if (lines > 0) {
332 draw_rectangle(vport, 0, 0, vport->width, lines,
333 vport->style.bg_color);
334 vport->dboffset += lines;
335 vport->dboffset %= vport->height;
336 } else if (lines < 0) {
337 lines = -lines;
338 draw_rectangle(vport, 0, vport->height-lines,
339 vport->width, lines,
340 vport->style.bg_color);
341
342 if (vport->dboffset < lines)
343 vport->dboffset += vport->height;
344 vport->dboffset -= lines;
345 }
346
347 --vport->paused;
348
349 refresh_viewport_db(vport);
350}
351
352/** Scrolls viewport given number of lines */
353static void scroll_port(viewport_t *vport, int lines)
354{
355 if (vport->dbdata)
356 scroll_port_db(vport, lines);
357 else
358 scroll_port_nodb(vport, lines);
359
360}
361
362static void invert_pixel(viewport_t *vport, unsigned int x, unsigned int y)
363{
364 putpixel(vport, x, y, ~getpixel(vport, x, y));
365}
366
367
368/***************************************************************/
369/* Character-console functions */
370
371/** Draw character at given position
372 *
373 * @param vport Viewport where the character is printed
374 * @param sx Coordinates of top-left of the character
375 * @param sy Coordinates of top-left of the character
376 * @param style Color of the character
377 * @param transparent If false, print background color
378 */
379static void draw_glyph(viewport_t *vport,uint8_t glyph, unsigned int sx, unsigned int sy,
380 style_t style, int transparent)
381{
382 int i;
383 unsigned int y;
384 unsigned int glline;
385
386 for (y = 0; y < FONT_SCANLINES; y++) {
387 glline = fb_font[glyph * FONT_SCANLINES + y];
388 for (i = 0; i < 8; i++) {
389 if (glline & (1 << (7 - i)))
390 putpixel(vport, sx + i, sy + y, style.fg_color);
391 else if (!transparent)
392 putpixel(vport, sx + i, sy + y, style.bg_color);
393 }
394 }
395}
396
397/** Invert character at given position */
398static void invert_char(viewport_t *vport,unsigned int row, unsigned int col)
399{
400 unsigned int x;
401 unsigned int y;
402
403 for (x = 0; x < COL_WIDTH; x++)
404 for (y = 0; y < FONT_SCANLINES; y++)
405 invert_pixel(vport, col * COL_WIDTH + x, row * FONT_SCANLINES + y);
406}
407
408/***************************************************************/
409/* Stdout specific functions */
410
411
412/** Create new viewport
413 *
414 * @return New viewport number
415 */
416static int viewport_create(unsigned int x, unsigned int y,unsigned int width,
417 unsigned int height)
418{
419 int i;
420
421 for (i=0; i < MAX_VIEWPORTS; i++) {
422 if (!viewports[i].initialized)
423 break;
424 }
425 if (i == MAX_VIEWPORTS)
426 return ELIMIT;
427
428 viewports[i].x = x;
429 viewports[i].y = y;
430 viewports[i].width = width;
431 viewports[i].height = height;
432
433 viewports[i].rows = height / FONT_SCANLINES;
434 viewports[i].cols = width / COL_WIDTH;
435
436 viewports[i].style.bg_color = DEFAULT_BGCOLOR;
437 viewports[i].style.fg_color = DEFAULT_FGCOLOR;
438
439 viewports[i].cur_col = 0;
440 viewports[i].cur_row = 0;
441 viewports[i].cursor_active = 0;
442
443 viewports[i].initialized = 1;
444
445 return i;
446}
447
448
449/** Initialize framebuffer as a chardev output device
450 *
451 * @param addr Address of theframebuffer
452 * @param xres Screen width in pixels
453 * @param yres Screen height in pixels
454 * @param bpp Bits per pixel (8, 16, 24, 32)
455 * @param scan Bytes per one scanline
456 * @param align Alignment for 24bpp mode.
457 *
458 */
459static void
460screen_init(void *addr, unsigned int xres, unsigned int yres, unsigned int bpp, unsigned int scan, int align)
461{
462 switch (bpp) {
463 case 8:
464 screen.rgb2scr = rgb_1byte;
465 screen.scr2rgb = byte1_rgb;
466 screen.pixelbytes = 1;
467 break;
468 case 16:
469 screen.rgb2scr = rgb_2byte;
470 screen.scr2rgb = byte2_rgb;
471 screen.pixelbytes = 2;
472 break;
473 case 24:
474 screen.rgb2scr = rgb_3byte;
475 screen.scr2rgb = byte3_rgb;
476 if (!align)
477 screen.pixelbytes = 3;
478 else
479 screen.pixelbytes = 4;
480 break;
481 case 32:
482 screen.rgb2scr = rgb_4byte;
483 screen.scr2rgb = byte4_rgb;
484 screen.pixelbytes = 4;
485 break;
486 }
487
488
489 screen.fbaddress = (unsigned char *) addr;
490 screen.xres = xres;
491 screen.yres = yres;
492 screen.scanline = scan;
493
494 /* Create first viewport */
495 viewport_create(0,0,xres,yres);
496}
497
498/** Hide cursor if it is shown */
499static void cursor_hide(viewport_t *vport)
500{
501 if (vport->cursor_active && vport->cursor_shown) {
502 invert_char(vport, vport->cur_row, vport->cur_col);
503 vport->cursor_shown = 0;
504 }
505}
506
507/** Show cursor if cursor showing is enabled */
508static void cursor_print(viewport_t *vport)
509{
510 /* Do not check for cursor_shown */
511 if (vport->cursor_active) {
512 invert_char(vport, vport->cur_row, vport->cur_col);
513 vport->cursor_shown = 1;
514 }
515}
516
517/** Invert cursor, if it is enabled */
518static void cursor_blink(viewport_t *vport)
519{
520 if (vport->cursor_shown)
521 cursor_hide(vport);
522 else
523 cursor_print(vport);
524}
525
526/** Draw character at given position relative to viewport
527 *
528 * @param vport Viewport identification
529 * @param c Character to print
530 * @param row Screen position relative to viewport
531 * @param col Screen position relative to viewport
532 * @param transparent If false, print background color with character
533 */
534static void draw_char(viewport_t *vport, char c, unsigned int row, unsigned int col,
535 style_t style, int transparent)
536{
537 /* Optimize - do not hide cursor if we are going to overwrite it */
538 if (vport->cursor_active && vport->cursor_shown &&
539 (vport->cur_col != col || vport->cur_row != row))
540 invert_char(vport, vport->cur_row, vport->cur_col);
541
542 draw_glyph(vport, c, col * COL_WIDTH, row * FONT_SCANLINES, style, transparent);
543
544 vport->cur_col = col;
545 vport->cur_row = row;
546
547 vport->cur_col++;
548 if (vport->cur_col>= vport->cols) {
549 vport->cur_col = 0;
550 vport->cur_row++;
551 if (vport->cur_row >= vport->rows)
552 vport->cur_row--;
553 }
554 cursor_print(vport);
555}
556
557/** Draw text data to viewport
558 *
559 * @param vport Viewport id
560 * @param data Text data fitting exactly into viewport
561 */
562static void draw_text_data(viewport_t *vport, keyfield_t *data)
563{
564 int i;
565 int col,row;
566
567 clear_port(vport);
568 for (i=0; i < vport->cols * vport->rows; i++) {
569 if (data[i].character == ' ' && style_same(data[i].style,vport->style))
570 continue;
571 col = i % vport->cols;
572 row = i / vport->cols;
573 draw_glyph(vport, data[i].character, col * COL_WIDTH, row * FONT_SCANLINES,
574 data[i].style, style_same(data[i].style,vport->style));
575 }
576 cursor_print(vport);
577}
578
579
580/** Return first free pixmap */
581static int find_free_pixmap(void)
582{
583 int i;
584
585 for (i=0;i < MAX_PIXMAPS;i++)
586 if (!pixmaps[i].data)
587 return i;
588 return -1;
589}
590
591static void putpixel_pixmap(int pm, unsigned int x, unsigned int y, int color)
592{
593 pixmap_t *pmap = &pixmaps[pm];
594 int pos = (y * pmap->width + x) * screen.pixelbytes;
595
596 (*screen.rgb2scr)(&pmap->data[pos],color);
597}
598
599/** Create a new pixmap and return appropriate ID */
600static int shm2pixmap(unsigned char *shm, size_t size)
601{
602 int pm;
603 pixmap_t *pmap;
604
605 pm = find_free_pixmap();
606 if (pm == -1)
607 return ELIMIT;
608 pmap = &pixmaps[pm];
609
610 if (ppm_get_data(shm, size, &pmap->width, &pmap->height))
611 return EINVAL;
612
613 pmap->data = malloc(pmap->width * pmap->height * screen.pixelbytes);
614 if (!pmap->data)
615 return ENOMEM;
616
617 ppm_draw(shm, size, 0, 0, pmap->width, pmap->height,
618 (putpixel_cb_t)putpixel_pixmap, (void *)pm);
619
620 return pm;
621}
622
623/** Handle shared memory communication calls
624 *
625 * Protocol for drawing pixmaps:
626 * - FB_PREPARE_SHM(client shm identification)
627 * - IPC_M_SEND_AS_AREA
628 * - FB_DRAW_PPM(startx,starty)
629 * - FB_DROP_SHM
630 *
631 * Protocol for text drawing
632 * - IPC_M_SEND_AS_AREA
633 * - FB_DRAW_TEXT_DATA
634 *
635 * @param callid Callid of the current call
636 * @param call Current call data
637 * @param vp Active viewport
638 * @return 0 if the call was not handled byt this function, 1 otherwise
639 *
640 * note: this function is not threads safe, you would have
641 * to redefine static variables with __thread
642 */
643static int shm_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
644{
645 static keyfield_t *interbuffer = NULL;
646 static size_t intersize = 0;
647
648 static unsigned char *shm = NULL;
649 static ipcarg_t shm_id = 0;
650 static size_t shm_size;
651
652 int handled = 1;
653 int retval = 0;
654 viewport_t *vport = &viewports[vp];
655 unsigned int x,y;
656
657 switch (IPC_GET_METHOD(*call)) {
658 case IPC_M_AS_AREA_SEND:
659 /* We accept one area for data interchange */
660 if (IPC_GET_ARG1(*call) == shm_id) {
661 void *dest = as_get_mappable_page(IPC_GET_ARG2(*call));
662 shm_size = IPC_GET_ARG2(*call);
663 if (!ipc_answer_fast(callid, 0, (sysarg_t)dest, 0))
664 shm = dest;
665 else
666 shm_id = 0;
667 if (shm[0] != 'P')
668 while (1)
669 ;
670 return 1;
671 } else {
672 intersize = IPC_GET_ARG2(*call);
673 receive_comm_area(callid,call,(void *)&interbuffer);
674 }
675 return 1;
676 case FB_PREPARE_SHM:
677 if (shm_id)
678 retval = EBUSY;
679 else
680 shm_id = IPC_GET_ARG1(*call);
681 break;
682
683 case FB_DROP_SHM:
684 if (shm) {
685 as_area_destroy(shm);
686 shm = NULL;
687 }
688 shm_id = 0;
689 break;
690
691 case FB_SHM2PIXMAP:
692 if (!shm) {
693 retval = EINVAL;
694 break;
695 }
696 retval = shm2pixmap(shm, shm_size);
697 break;
698 case FB_DRAW_PPM:
699 if (!shm) {
700 retval = EINVAL;
701 break;
702 }
703 x = IPC_GET_ARG1(*call);
704 y = IPC_GET_ARG2(*call);
705 if (x > vport->width || y > vport->height) {
706 retval = EINVAL;
707 break;
708 }
709
710 ppm_draw(shm, shm_size, IPC_GET_ARG1(*call), IPC_GET_ARG2(*call),
711 vport->width - x, vport->height - y, (putpixel_cb_t)putpixel, vport);
712 break;
713 case FB_DRAW_TEXT_DATA:
714 if (!interbuffer) {
715 retval = EINVAL;
716 break;
717 }
718 if (intersize < vport->cols*vport->rows*sizeof(*interbuffer)) {
719 retval = EINVAL;
720 break;
721 }
722 draw_text_data(vport, interbuffer);
723 break;
724 default:
725 handled = 0;
726 }
727
728 if (handled)
729 ipc_answer_fast(callid, retval, 0, 0);
730 return handled;
731}
732
733static void copy_vp_to_pixmap(viewport_t *vport, pixmap_t *pmap)
734{
735 int y;
736 int rowsize;
737 int tmp;
738 int width = vport->width;
739 int height = vport->height;
740
741 if (width + vport->x > screen.xres)
742 width = screen.xres - vport->x;
743 if (height + vport->y > screen.yres)
744 height = screen.yres - vport->y;
745
746 rowsize = width * screen.pixelbytes;
747
748 for (y=0;y < height; y++) {
749 tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;
750 memcpy(pmap->data + rowsize*y, screen.fbaddress + tmp, rowsize);
751 }
752}
753
754/** Save viewport to pixmap */
755static int save_vp_to_pixmap(viewport_t *vport)
756{
757 int pm;
758 pixmap_t *pmap;
759
760 pm = find_free_pixmap();
761 if (pm == -1)
762 return ELIMIT;
763
764 pmap = &pixmaps[pm];
765 pmap->data = malloc(screen.pixelbytes * vport->width * vport->height);
766 if (!pmap->data)
767 return ENOMEM;
768
769 pmap->width = vport->width;
770 pmap->height = vport->height;
771
772 copy_vp_to_pixmap(vport, pmap);
773
774 return pm;
775}
776
777/** Draw pixmap on screen
778 *
779 * @param vp Viewport to draw on
780 * @param pm Pixmap identifier
781 */
782static int draw_pixmap(int vp, int pm)
783{
784 pixmap_t *pmap = &pixmaps[pm];
785 viewport_t *vport = &viewports[vp];
786 int y;
787 int tmp, srcrowsize;
788 int realwidth, realheight, realrowsize;
789 int width = vport->width;
790 int height = vport->height;
791
792 if (width + vport->x > screen.xres)
793 width = screen.xres - vport->x;
794 if (height + vport->y > screen.yres)
795 height = screen.yres - vport->y;
796
797 if (!pmap->data)
798 return EINVAL;
799
800 realwidth = pmap->width <= width ? pmap->width : width;
801 realheight = pmap->height <= height ? pmap->height : height;
802
803 srcrowsize = vport->width * screen.pixelbytes;
804 realrowsize = realwidth * screen.pixelbytes;
805
806 for (y=0; y < realheight; y++) {
807 tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;
808 memcpy(screen.fbaddress + tmp, pmap->data + y * srcrowsize, realrowsize);
809 }
810 return 0;
811}
812
813/** Tick animation one step forward */
814static void anims_tick(void)
815{
816 int i;
817 static int counts = 0;
818
819 /* Limit redrawing */
820 counts = (counts+1) % 8;
821 if (counts)
822 return;
823
824 for (i=0; i < MAX_ANIMATIONS; i++) {
825 if (!animations[i].animlen || !animations[i].initialized || !animations[i].enabled)
826 continue;
827 draw_pixmap(animations[i].vp, animations[i].pixmaps[animations[i].pos]);
828 animations[i].pos = (animations[i].pos+1) % animations[i].animlen;
829 }
830}
831
832
833static int pointer_x, pointer_y;
834static int pointer_shown, pointer_enabled;
835static int pointer_vport = -1;
836static int pointer_pixmap = -1;
837
838static void mouse_show(void)
839{
840 int i,j;
841 int visibility;
842 int color;
843 int bytepos;
844
845 if (pointer_shown || !pointer_enabled)
846 return;
847
848 /* Save image under the cursor */
849 if (pointer_vport == -1) {
850 pointer_vport = viewport_create(pointer_x, pointer_y, pointer_width, pointer_height);
851 if (pointer_vport < 0)
852 return;
853 } else {
854 viewports[pointer_vport].x = pointer_x;
855 viewports[pointer_vport].y = pointer_y;
856 }
857
858 if (pointer_pixmap == -1)
859 pointer_pixmap = save_vp_to_pixmap(&viewports[pointer_vport]);
860 else
861 copy_vp_to_pixmap(&viewports[pointer_vport], &pixmaps[pointer_pixmap]);
862
863 /* Draw cursor */
864 for (i=0; i < pointer_height; i++)
865 for (j=0;j < pointer_width; j++) {
866 bytepos = i*((pointer_width-1)/8+1) + j/8;
867 visibility = pointer_mask_bits[bytepos] & (1 << (j % 8));
868 if (visibility) {
869 color = pointer_bits[bytepos] & (1 << (j % 8)) ? 0 : 0xffffff;
870 if (pointer_x+j < screen.xres && pointer_y+i < screen.yres)
871 putpixel(&viewports[0], pointer_x+j, pointer_y+i, color);
872 }
873 }
874 pointer_shown = 1;
875}
876
877static void mouse_hide(void)
878{
879 /* Restore image under the cursor */
880 if (pointer_shown) {
881 draw_pixmap(pointer_vport, pointer_pixmap);
882 pointer_shown = 0;
883 }
884}
885
886static void mouse_move(unsigned int x, unsigned int y)
887{
888 mouse_hide();
889 pointer_x = x;
890 pointer_y = y;
891 mouse_show();
892}
893
894static int anim_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
895{
896 int handled = 1;
897 int retval = 0;
898 int i,nvp;
899 int newval;
900
901 switch (IPC_GET_METHOD(*call)) {
902 case FB_ANIM_CREATE:
903 nvp = IPC_GET_ARG1(*call);
904 if (nvp == -1)
905 nvp = vp;
906 if (nvp >= MAX_VIEWPORTS || nvp < 0 || !viewports[nvp].initialized) {
907 retval = EINVAL;
908 break;
909 }
910 for (i=0; i < MAX_ANIMATIONS; i++) {
911 if (! animations[i].initialized)
912 break;
913 }
914 if (i == MAX_ANIMATIONS) {
915 retval = ELIMIT;
916 break;
917 }
918 animations[i].initialized = 1;
919 animations[i].animlen = 0;
920 animations[i].pos = 0;
921 animations[i].enabled = 0;
922 animations[i].vp = nvp;
923 retval = i;
924 break;
925 case FB_ANIM_DROP:
926 i = IPC_GET_ARG1(*call);
927 if (i >= MAX_ANIMATIONS || i < 0) {
928 retval = EINVAL;
929 break;
930 }
931 animations[i].initialized = 0;
932 break;
933 case FB_ANIM_ADDPIXMAP:
934 i = IPC_GET_ARG1(*call);
935 if (i >= MAX_ANIMATIONS || i < 0 || !animations[i].initialized) {
936 retval = EINVAL;
937 break;
938 }
939 if (animations[i].animlen == MAX_ANIM_LEN) {
940 retval = ELIMIT;
941 break;
942 }
943 newval = IPC_GET_ARG2(*call);
944 if (newval < 0 || newval > MAX_PIXMAPS || !pixmaps[newval].data) {
945 retval = EINVAL;
946 break;
947 }
948 animations[i].pixmaps[animations[i].animlen++] = newval;
949 break;
950 case FB_ANIM_CHGVP:
951 i = IPC_GET_ARG1(*call);
952 if (i >= MAX_ANIMATIONS || i < 0) {
953 retval = EINVAL;
954 break;
955 }
956 nvp = IPC_GET_ARG2(*call);
957 if (nvp == -1)
958 nvp = vp;
959 if (nvp >= MAX_VIEWPORTS || nvp < 0 || !viewports[nvp].initialized) {
960 retval = EINVAL;
961 break;
962 }
963 animations[i].vp = nvp;
964 break;
965 case FB_ANIM_START:
966 case FB_ANIM_STOP:
967 i = IPC_GET_ARG1(*call);
968 if (i >= MAX_ANIMATIONS || i < 0) {
969 retval = EINVAL;
970 break;
971 }
972 newval = (IPC_GET_METHOD(*call) == FB_ANIM_START);
973 if (newval ^ animations[i].enabled) {
974 animations[i].enabled = newval;
975 anims_enabled += newval ? 1 : -1;
976 }
977 break;
978 default:
979 handled = 0;
980 }
981 if (handled)
982 ipc_answer_fast(callid, retval, 0, 0);
983 return handled;
984}
985
986/** Handler for messages concerning pixmap handling */
987static int pixmap_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
988{
989 int handled = 1;
990 int retval = 0;
991 int i,nvp;
992
993 switch (IPC_GET_METHOD(*call)) {
994 case FB_VP_DRAW_PIXMAP:
995 nvp = IPC_GET_ARG1(*call);
996 if (nvp == -1)
997 nvp = vp;
998 if (nvp < 0 || nvp >= MAX_VIEWPORTS || !viewports[nvp].initialized) {
999 retval = EINVAL;
1000 break;
1001 }
1002 i = IPC_GET_ARG2(*call);
1003 retval = draw_pixmap(nvp, i);
1004 break;
1005 case FB_VP2PIXMAP:
1006 nvp = IPC_GET_ARG1(*call);
1007 if (nvp == -1)
1008 nvp = vp;
1009 if (nvp < 0 || nvp >= MAX_VIEWPORTS || !viewports[nvp].initialized)
1010 retval = EINVAL;
1011 else
1012 retval = save_vp_to_pixmap(&viewports[nvp]);
1013 break;
1014 case FB_DROP_PIXMAP:
1015 i = IPC_GET_ARG1(*call);
1016 if (i >= MAX_PIXMAPS) {
1017 retval = EINVAL;
1018 break;
1019 }
1020 if (pixmaps[i].data) {
1021 free(pixmaps[i].data);
1022 pixmaps[i].data = NULL;
1023 }
1024 break;
1025 default:
1026 handled = 0;
1027 }
1028
1029 if (handled)
1030 ipc_answer_fast(callid, retval, 0, 0);
1031 return handled;
1032
1033}
1034
1035/** Function for handling connections to FB
1036 *
1037 */
1038static void fb_client_connection(ipc_callid_t iid, ipc_call_t *icall)
1039{
1040 ipc_callid_t callid;
1041 ipc_call_t call;
1042 int retval;
1043 int i;
1044 unsigned int row,col;
1045 char c;
1046
1047 int vp = 0;
1048 viewport_t *vport = &viewports[0];
1049
1050 if (client_connected) {
1051 ipc_answer_fast(iid, ELIMIT, 0,0);
1052 return;
1053 }
1054 client_connected = 1;
1055 ipc_answer_fast(iid, 0, 0, 0); /* Accept connection */
1056
1057 while (1) {
1058 if (vport->cursor_active || anims_enabled)
1059 callid = async_get_call_timeout(&call,250000);
1060 else
1061 callid = async_get_call(&call);
1062
1063 mouse_hide();
1064 if (!callid) {
1065 cursor_blink(vport);
1066 anims_tick();
1067 mouse_show();
1068 continue;
1069 }
1070 if (shm_handle(callid, &call, vp))
1071 continue;
1072 if (pixmap_handle(callid, &call, vp))
1073 continue;
1074 if (anim_handle(callid, &call, vp))
1075 continue;
1076
1077 switch (IPC_GET_METHOD(call)) {
1078 case IPC_M_PHONE_HUNGUP:
1079 client_connected = 0;
1080 /* cleanup other viewports */
1081 for (i=1; i < MAX_VIEWPORTS; i++)
1082 vport->initialized = 0;
1083 return; /* Exit thread */
1084
1085 case FB_PUTCHAR:
1086 case FB_TRANS_PUTCHAR:
1087 c = IPC_GET_ARG1(call);
1088 row = IPC_GET_ARG2(call);
1089 col = IPC_GET_ARG3(call);
1090 if (row >= vport->rows || col >= vport->cols) {
1091 retval = EINVAL;
1092 break;
1093 }
1094 ipc_answer_fast(callid,0,0,0);
1095
1096 draw_char(vport, c, row, col, vport->style, IPC_GET_METHOD(call) == FB_TRANS_PUTCHAR);
1097 continue; /* msg already answered */
1098 case FB_CLEAR:
1099 clear_port(vport);
1100 cursor_print(vport);
1101 retval = 0;
1102 break;
1103 case FB_CURSOR_GOTO:
1104 row = IPC_GET_ARG1(call);
1105 col = IPC_GET_ARG2(call);
1106 if (row >= vport->rows || col >= vport->cols) {
1107 retval = EINVAL;
1108 break;
1109 }
1110 retval = 0;
1111 cursor_hide(vport);
1112 vport->cur_col = col;
1113 vport->cur_row = row;
1114 cursor_print(vport);
1115 break;
1116 case FB_CURSOR_VISIBILITY:
1117 cursor_hide(vport);
1118 vport->cursor_active = IPC_GET_ARG1(call);
1119 cursor_print(vport);
1120 retval = 0;
1121 break;
1122 case FB_GET_CSIZE:
1123 ipc_answer_fast(callid, 0, vport->rows, vport->cols);
1124 continue;
1125 case FB_SCROLL:
1126 i = IPC_GET_ARG1(call);
1127 if (i > vport->rows || i < (- (int)vport->rows)) {
1128 retval = EINVAL;
1129 break;
1130 }
1131 cursor_hide(vport);
1132 scroll_port(vport, i*FONT_SCANLINES);
1133 cursor_print(vport);
1134 retval = 0;
1135 break;
1136 case FB_VIEWPORT_DB:
1137 /* Enable double buffering */
1138 i = IPC_GET_ARG1(call);
1139 if (i == -1)
1140 i = vp;
1141 if (i < 0 || i >= MAX_VIEWPORTS) {
1142 retval = EINVAL;
1143 break;
1144 }
1145 if (! viewports[i].initialized ) {
1146 retval = EADDRNOTAVAIL;
1147 break;
1148 }
1149 viewports[i].dboffset = 0;
1150 if (IPC_GET_ARG2(call) == 1 && !viewports[i].dbdata)
1151 viewports[i].dbdata = malloc(screen.pixelbytes*viewports[i].width * viewports[i].height);
1152 else if (IPC_GET_ARG2(call) == 0 && viewports[i].dbdata) {
1153 free(viewports[i].dbdata);
1154 viewports[i].dbdata = NULL;
1155 }
1156 retval = 0;
1157 break;
1158 case FB_VIEWPORT_SWITCH:
1159 i = IPC_GET_ARG1(call);
1160 if (i < 0 || i >= MAX_VIEWPORTS) {
1161 retval = EINVAL;
1162 break;
1163 }
1164 if (! viewports[i].initialized ) {
1165 retval = EADDRNOTAVAIL;
1166 break;
1167 }
1168 cursor_hide(vport);
1169 vp = i;
1170 vport = &viewports[vp];
1171 cursor_print(vport);
1172 retval = 0;
1173 break;
1174 case FB_VIEWPORT_CREATE:
1175 retval = viewport_create(IPC_GET_ARG1(call) >> 16,
1176 IPC_GET_ARG1(call) & 0xffff,
1177 IPC_GET_ARG2(call) >> 16,
1178 IPC_GET_ARG2(call) & 0xffff);
1179 break;
1180 case FB_VIEWPORT_DELETE:
1181 i = IPC_GET_ARG1(call);
1182 if (i < 0 || i >= MAX_VIEWPORTS) {
1183 retval = EINVAL;
1184 break;
1185 }
1186 if (! viewports[i].initialized ) {
1187 retval = EADDRNOTAVAIL;
1188 break;
1189 }
1190 viewports[i].initialized = 0;
1191 if (viewports[i].dbdata) {
1192 free(viewports[i].dbdata);
1193 viewports[i].dbdata = NULL;
1194 }
1195 retval = 0;
1196 break;
1197 case FB_SET_STYLE:
1198 vport->style.fg_color = IPC_GET_ARG1(call);
1199 vport->style.bg_color = IPC_GET_ARG2(call);
1200 retval = 0;
1201 break;
1202 case FB_GET_RESOLUTION:
1203 ipc_answer_fast(callid, 0, screen.xres,screen.yres);
1204 continue;
1205 case FB_POINTER_MOVE:
1206 pointer_enabled = 1;
1207 mouse_move(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
1208 retval = 0;
1209 break;
1210 default:
1211 retval = ENOENT;
1212 }
1213 ipc_answer_fast(callid,retval,0,0);
1214 }
1215}
1216
1217/** Initialization of framebuffer */
1218int fb_init(void)
1219{
1220 void *fb_ph_addr;
1221 unsigned int fb_width;
1222 unsigned int fb_height;
1223 unsigned int fb_bpp;
1224 unsigned int fb_bpp_align;
1225 unsigned int fb_scanline;
1226 void *fb_addr;
1227 size_t asz;
1228
1229 async_set_client_connection(fb_client_connection);
1230
1231 fb_ph_addr=(void *)sysinfo_value("fb.address.physical");
1232 fb_width=sysinfo_value("fb.width");
1233 fb_height=sysinfo_value("fb.height");
1234 fb_bpp=sysinfo_value("fb.bpp");
1235 fb_bpp_align=sysinfo_value("fb.bpp-align");
1236 fb_scanline=sysinfo_value("fb.scanline");
1237
1238 asz = fb_scanline*fb_height;
1239 fb_addr = as_get_mappable_page(asz);
1240
1241 map_physmem(fb_ph_addr, fb_addr, ALIGN_UP(asz,PAGE_SIZE) >>PAGE_WIDTH,
1242 AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE);
1243
1244 screen_init(fb_addr, fb_width, fb_height, fb_bpp, fb_scanline, fb_bpp_align);
1245
1246 return 0;
1247}
1248
1249
1250/**
1251 * @}
1252 */
Note: See TracBrowser for help on using the repository browser.