source: mainline/uspace/fb/fb.c@ c9d20755

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

The Ultimate Solution To Illegal Virtual Aliases.
It is better to avoid them completely than to fight them.
Switch the sparc64 port to 16K pages. The TLBs and TSBs
continue to operate with 8K pages only. Page tables and
other generic parts operate with 16K pages.

Because the MMU doesn't support 16K directly, each 16K
page is emulated by a pair of 8K pages. With 16K pages,
illegal aliases cannot be created in 16K D-cache.

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