source: mainline/uspace/srv/fb/fb.c@ e32b65a

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since e32b65a was 925fdd7, checked in by Pavel Rimsky <rimskyp@…>, 17 years ago

Fixed the bug when on SunBlade1500 we wrote to an address outside the framebuffer memory. A nasty hack to the 8-bit palette so that on sb1500 we do not have to turn black into white and white into black.

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