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

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

New, better-structured, directory layout for uspace.

  • Property mode set to 100644
File size: 31.3 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 tmp, srcrowsize;
837 int realwidth, realheight, realrowsize;
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 realwidth = pmap->width <= width ? pmap->width : width;
847 realheight = pmap->height <= height ? pmap->height : height;
848
849 srcrowsize = vport->width * screen.pixelbytes;
850 realrowsize = realwidth * screen.pixelbytes;
851
852 for (y = 0; y < realheight; y++) {
853 tmp = (vport->y + y) * screen.scanline +
854 vport->x * screen.pixelbytes;
855 memcpy(pmap->data + srcrowsize * y, screen.fbaddress + tmp,
856 realrowsize);
857 }
858}
859
860/** Save viewport to pixmap */
861static int
862save_vp_to_pixmap(viewport_t *vport)
863{
864 int pm;
865 pixmap_t *pmap;
866
867 pm = find_free_pixmap();
868 if (pm == -1)
869 return ELIMIT;
870
871 pmap = &pixmaps[pm];
872 pmap->data = malloc(screen.pixelbytes * vport->width * vport->height);
873 if (!pmap->data)
874 return ENOMEM;
875
876 pmap->width = vport->width;
877 pmap->height = vport->height;
878
879 copy_vp_to_pixmap(vport, pmap);
880
881 return pm;
882}
883
884/** Draw pixmap on screen
885 *
886 * @param vp Viewport to draw on
887 * @param pm Pixmap identifier
888 */
889static int draw_pixmap(int vp, int pm)
890{
891 pixmap_t *pmap = &pixmaps[pm];
892 viewport_t *vport = &viewports[vp];
893 int y;
894 int tmp, srcrowsize;
895 int realwidth, realheight, realrowsize;
896 int width = vport->width;
897 int height = vport->height;
898
899 if (width + vport->x > screen.xres)
900 width = screen.xres - vport->x;
901 if (height + vport->y > screen.yres)
902 height = screen.yres - vport->y;
903
904 if (!pmap->data)
905 return EINVAL;
906
907 realwidth = pmap->width <= width ? pmap->width : width;
908 realheight = pmap->height <= height ? pmap->height : height;
909
910 srcrowsize = vport->width * screen.pixelbytes;
911 realrowsize = realwidth * screen.pixelbytes;
912
913 for (y = 0; y < realheight; y++) {
914 tmp = (vport->y + y) * screen.scanline +
915 vport->x * screen.pixelbytes;
916 memcpy(screen.fbaddress + tmp, pmap->data + y * srcrowsize,
917 realrowsize);
918 }
919 return 0;
920}
921
922/** Tick animation one step forward */
923static void
924anims_tick(void)
925{
926 int i;
927 static int counts = 0;
928
929 /* Limit redrawing */
930 counts = (counts + 1) % 8;
931 if (counts)
932 return;
933
934 for (i = 0; i < MAX_ANIMATIONS; i++) {
935 if (!animations[i].animlen || !animations[i].initialized ||
936 !animations[i].enabled)
937 continue;
938 draw_pixmap(animations[i].vp,
939 animations[i].pixmaps[animations[i].pos]);
940 animations[i].pos = (animations[i].pos + 1) %
941 animations[i].animlen;
942 }
943}
944
945
946static int pointer_x, pointer_y;
947static int pointer_shown, pointer_enabled;
948static int pointer_vport = -1;
949static int pointer_pixmap = -1;
950
951static void
952mouse_show(void)
953{
954 int i, j;
955 int visibility;
956 int color;
957 int bytepos;
958
959 if (pointer_shown || !pointer_enabled)
960 return;
961
962 /* Save image under the cursor */
963 if (pointer_vport == -1) {
964 pointer_vport = viewport_create(pointer_x, pointer_y,
965 pointer_width, pointer_height);
966 if (pointer_vport < 0)
967 return;
968 } else {
969 viewports[pointer_vport].x = pointer_x;
970 viewports[pointer_vport].y = pointer_y;
971 }
972
973 if (pointer_pixmap == -1)
974 pointer_pixmap = save_vp_to_pixmap(&viewports[pointer_vport]);
975 else
976 copy_vp_to_pixmap(&viewports[pointer_vport],
977 &pixmaps[pointer_pixmap]);
978
979 /* Draw cursor */
980 for (i = 0; i < pointer_height; i++)
981 for (j = 0; j < pointer_width; j++) {
982 bytepos = i * ((pointer_width - 1) / 8 + 1) + j / 8;
983 visibility = pointer_mask_bits[bytepos] &
984 (1 << (j % 8));
985 if (visibility) {
986 color = pointer_bits[bytepos] & (1 << (j % 8))
987 ? 0 : 0xffffff;
988 if (pointer_x + j < screen.xres && pointer_y +
989 i < screen.yres)
990 putpixel(&viewports[0], pointer_x + j,
991 pointer_y + i, color);
992 }
993 }
994 pointer_shown = 1;
995}
996
997static void
998mouse_hide(void)
999{
1000 /* Restore image under the cursor */
1001 if (pointer_shown) {
1002 draw_pixmap(pointer_vport, pointer_pixmap);
1003 pointer_shown = 0;
1004 }
1005}
1006
1007static void
1008mouse_move(unsigned int x, unsigned int y)
1009{
1010 mouse_hide();
1011 pointer_x = x;
1012 pointer_y = y;
1013 mouse_show();
1014}
1015
1016static int
1017anim_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
1018{
1019 int handled = 1;
1020 int retval = 0;
1021 int i,nvp;
1022 int newval;
1023
1024 switch (IPC_GET_METHOD(*call)) {
1025 case FB_ANIM_CREATE:
1026 nvp = IPC_GET_ARG1(*call);
1027 if (nvp == -1)
1028 nvp = vp;
1029 if (nvp >= MAX_VIEWPORTS || nvp < 0 ||
1030 !viewports[nvp].initialized) {
1031 retval = EINVAL;
1032 break;
1033 }
1034 for (i = 0; i < MAX_ANIMATIONS; i++) {
1035 if (!animations[i].initialized)
1036 break;
1037 }
1038 if (i == MAX_ANIMATIONS) {
1039 retval = ELIMIT;
1040 break;
1041 }
1042 animations[i].initialized = 1;
1043 animations[i].animlen = 0;
1044 animations[i].pos = 0;
1045 animations[i].enabled = 0;
1046 animations[i].vp = nvp;
1047 retval = i;
1048 break;
1049 case FB_ANIM_DROP:
1050 i = IPC_GET_ARG1(*call);
1051 if (i >= MAX_ANIMATIONS || i < 0) {
1052 retval = EINVAL;
1053 break;
1054 }
1055 animations[i].initialized = 0;
1056 break;
1057 case FB_ANIM_ADDPIXMAP:
1058 i = IPC_GET_ARG1(*call);
1059 if (i >= MAX_ANIMATIONS || i < 0 ||
1060 !animations[i].initialized) {
1061 retval = EINVAL;
1062 break;
1063 }
1064 if (animations[i].animlen == MAX_ANIM_LEN) {
1065 retval = ELIMIT;
1066 break;
1067 }
1068 newval = IPC_GET_ARG2(*call);
1069 if (newval < 0 || newval > MAX_PIXMAPS ||
1070 !pixmaps[newval].data) {
1071 retval = EINVAL;
1072 break;
1073 }
1074 animations[i].pixmaps[animations[i].animlen++] = newval;
1075 break;
1076 case FB_ANIM_CHGVP:
1077 i = IPC_GET_ARG1(*call);
1078 if (i >= MAX_ANIMATIONS || i < 0) {
1079 retval = EINVAL;
1080 break;
1081 }
1082 nvp = IPC_GET_ARG2(*call);
1083 if (nvp == -1)
1084 nvp = vp;
1085 if (nvp >= MAX_VIEWPORTS || nvp < 0 ||
1086 !viewports[nvp].initialized) {
1087 retval = EINVAL;
1088 break;
1089 }
1090 animations[i].vp = nvp;
1091 break;
1092 case FB_ANIM_START:
1093 case FB_ANIM_STOP:
1094 i = IPC_GET_ARG1(*call);
1095 if (i >= MAX_ANIMATIONS || i < 0) {
1096 retval = EINVAL;
1097 break;
1098 }
1099 newval = (IPC_GET_METHOD(*call) == FB_ANIM_START);
1100 if (newval ^ animations[i].enabled) {
1101 animations[i].enabled = newval;
1102 anims_enabled += newval ? 1 : -1;
1103 }
1104 break;
1105 default:
1106 handled = 0;
1107 }
1108 if (handled)
1109 ipc_answer_fast(callid, retval, 0, 0);
1110 return handled;
1111}
1112
1113/** Handler for messages concerning pixmap handling */
1114static int
1115pixmap_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
1116{
1117 int handled = 1;
1118 int retval = 0;
1119 int i,nvp;
1120
1121 switch (IPC_GET_METHOD(*call)) {
1122 case FB_VP_DRAW_PIXMAP:
1123 nvp = IPC_GET_ARG1(*call);
1124 if (nvp == -1)
1125 nvp = vp;
1126 if (nvp < 0 || nvp >= MAX_VIEWPORTS ||
1127 !viewports[nvp].initialized) {
1128 retval = EINVAL;
1129 break;
1130 }
1131 i = IPC_GET_ARG2(*call);
1132 retval = draw_pixmap(nvp, i);
1133 break;
1134 case FB_VP2PIXMAP:
1135 nvp = IPC_GET_ARG1(*call);
1136 if (nvp == -1)
1137 nvp = vp;
1138 if (nvp < 0 || nvp >= MAX_VIEWPORTS ||
1139 !viewports[nvp].initialized)
1140 retval = EINVAL;
1141 else
1142 retval = save_vp_to_pixmap(&viewports[nvp]);
1143 break;
1144 case FB_DROP_PIXMAP:
1145 i = IPC_GET_ARG1(*call);
1146 if (i >= MAX_PIXMAPS) {
1147 retval = EINVAL;
1148 break;
1149 }
1150 if (pixmaps[i].data) {
1151 free(pixmaps[i].data);
1152 pixmaps[i].data = NULL;
1153 }
1154 break;
1155 default:
1156 handled = 0;
1157 }
1158
1159 if (handled)
1160 ipc_answer_fast(callid, retval, 0, 0);
1161 return handled;
1162
1163}
1164
1165/** Function for handling connections to FB
1166 *
1167 */
1168static void
1169fb_client_connection(ipc_callid_t iid, ipc_call_t *icall)
1170{
1171 ipc_callid_t callid;
1172 ipc_call_t call;
1173 int retval;
1174 int i;
1175 unsigned int row,col;
1176 char c;
1177
1178 int vp = 0;
1179 viewport_t *vport = &viewports[0];
1180
1181 if (client_connected) {
1182 ipc_answer_fast(iid, ELIMIT, 0,0);
1183 return;
1184 }
1185 client_connected = 1;
1186 ipc_answer_fast(iid, 0, 0, 0); /* Accept connection */
1187
1188 while (1) {
1189 if (vport->cursor_active || anims_enabled)
1190 callid = async_get_call_timeout(&call, 250000);
1191 else
1192 callid = async_get_call(&call);
1193
1194 mouse_hide();
1195 if (!callid) {
1196 cursor_blink(vport);
1197 anims_tick();
1198 mouse_show();
1199 continue;
1200 }
1201 if (shm_handle(callid, &call, vp))
1202 continue;
1203 if (pixmap_handle(callid, &call, vp))
1204 continue;
1205 if (anim_handle(callid, &call, vp))
1206 continue;
1207
1208 switch (IPC_GET_METHOD(call)) {
1209 case IPC_M_PHONE_HUNGUP:
1210 client_connected = 0;
1211 /* cleanup other viewports */
1212 for (i = 1; i < MAX_VIEWPORTS; i++)
1213 vport->initialized = 0;
1214 return; /* Exit thread */
1215
1216 case FB_PUTCHAR:
1217 case FB_TRANS_PUTCHAR:
1218 c = IPC_GET_ARG1(call);
1219 row = IPC_GET_ARG2(call);
1220 col = IPC_GET_ARG3(call);
1221 if (row >= vport->rows || col >= vport->cols) {
1222 retval = EINVAL;
1223 break;
1224 }
1225 ipc_answer_fast(callid, 0, 0, 0);
1226
1227 draw_char(vport, c, row, col, vport->style,
1228 IPC_GET_METHOD(call) == FB_TRANS_PUTCHAR);
1229 continue; /* msg already answered */
1230 case FB_CLEAR:
1231 clear_port(vport);
1232 cursor_print(vport);
1233 retval = 0;
1234 break;
1235 case FB_CURSOR_GOTO:
1236 row = IPC_GET_ARG1(call);
1237 col = IPC_GET_ARG2(call);
1238 if (row >= vport->rows || col >= vport->cols) {
1239 retval = EINVAL;
1240 break;
1241 }
1242 retval = 0;
1243 cursor_hide(vport);
1244 vport->cur_col = col;
1245 vport->cur_row = row;
1246 cursor_print(vport);
1247 break;
1248 case FB_CURSOR_VISIBILITY:
1249 cursor_hide(vport);
1250 vport->cursor_active = IPC_GET_ARG1(call);
1251 cursor_print(vport);
1252 retval = 0;
1253 break;
1254 case FB_GET_CSIZE:
1255 ipc_answer_fast(callid, 0, vport->rows, vport->cols);
1256 continue;
1257 case FB_SCROLL:
1258 i = IPC_GET_ARG1(call);
1259 if (i > vport->rows || i < (- (int)vport->rows)) {
1260 retval = EINVAL;
1261 break;
1262 }
1263 cursor_hide(vport);
1264 scroll_port(vport, i*FONT_SCANLINES);
1265 cursor_print(vport);
1266 retval = 0;
1267 break;
1268 case FB_VIEWPORT_DB:
1269 /* Enable double buffering */
1270 i = IPC_GET_ARG1(call);
1271 if (i == -1)
1272 i = vp;
1273 if (i < 0 || i >= MAX_VIEWPORTS) {
1274 retval = EINVAL;
1275 break;
1276 }
1277 if (! viewports[i].initialized ) {
1278 retval = EADDRNOTAVAIL;
1279 break;
1280 }
1281 viewports[i].dboffset = 0;
1282 if (IPC_GET_ARG2(call) == 1 && !viewports[i].dbdata)
1283 viewports[i].dbdata = malloc(screen.pixelbytes
1284 * viewports[i].width *
1285 viewports[i].height);
1286 else if (IPC_GET_ARG2(call) == 0 &&
1287 viewports[i].dbdata) {
1288 free(viewports[i].dbdata);
1289 viewports[i].dbdata = NULL;
1290 }
1291 retval = 0;
1292 break;
1293 case FB_VIEWPORT_SWITCH:
1294 i = IPC_GET_ARG1(call);
1295 if (i < 0 || i >= MAX_VIEWPORTS) {
1296 retval = EINVAL;
1297 break;
1298 }
1299 if (! viewports[i].initialized ) {
1300 retval = EADDRNOTAVAIL;
1301 break;
1302 }
1303 cursor_hide(vport);
1304 vp = i;
1305 vport = &viewports[vp];
1306 cursor_print(vport);
1307 retval = 0;
1308 break;
1309 case FB_VIEWPORT_CREATE:
1310 retval = viewport_create(IPC_GET_ARG1(call) >> 16,
1311 IPC_GET_ARG1(call) & 0xffff,
1312 IPC_GET_ARG2(call) >> 16,
1313 IPC_GET_ARG2(call) & 0xffff);
1314 break;
1315 case FB_VIEWPORT_DELETE:
1316 i = IPC_GET_ARG1(call);
1317 if (i < 0 || i >= MAX_VIEWPORTS) {
1318 retval = EINVAL;
1319 break;
1320 }
1321 if (! viewports[i].initialized ) {
1322 retval = EADDRNOTAVAIL;
1323 break;
1324 }
1325 viewports[i].initialized = 0;
1326 if (viewports[i].dbdata) {
1327 free(viewports[i].dbdata);
1328 viewports[i].dbdata = NULL;
1329 }
1330 retval = 0;
1331 break;
1332 case FB_SET_STYLE:
1333 vport->style.fg_color = IPC_GET_ARG1(call);
1334 vport->style.bg_color = IPC_GET_ARG2(call);
1335 retval = 0;
1336 break;
1337 case FB_GET_RESOLUTION:
1338 ipc_answer_fast(callid, 0, screen.xres,screen.yres);
1339 continue;
1340 case FB_POINTER_MOVE:
1341 pointer_enabled = 1;
1342 mouse_move(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
1343 retval = 0;
1344 break;
1345 default:
1346 retval = ENOENT;
1347 }
1348 ipc_answer_fast(callid,retval, 0, 0);
1349 }
1350}
1351
1352/** Initialization of framebuffer */
1353int
1354fb_init(void)
1355{
1356 void *fb_ph_addr;
1357 unsigned int fb_width;
1358 unsigned int fb_height;
1359 unsigned int fb_scanline;
1360 unsigned int fb_visual;
1361 bool fb_invert_colors;
1362 void *fb_addr;
1363 size_t asz;
1364
1365 async_set_client_connection(fb_client_connection);
1366
1367 fb_ph_addr = (void *) sysinfo_value("fb.address.physical");
1368 fb_width = sysinfo_value("fb.width");
1369 fb_height = sysinfo_value("fb.height");
1370 fb_scanline = sysinfo_value("fb.scanline");
1371 fb_visual = sysinfo_value("fb.visual");
1372 fb_invert_colors = sysinfo_value("fb.invert-colors");
1373
1374 asz = fb_scanline * fb_height;
1375 fb_addr = as_get_mappable_page(asz);
1376
1377 physmem_map(fb_ph_addr, fb_addr, ALIGN_UP(asz, PAGE_SIZE) >>
1378 PAGE_WIDTH, AS_AREA_READ | AS_AREA_WRITE);
1379
1380 if (screen_init(fb_addr, fb_width, fb_height, fb_scanline, fb_visual,
1381 fb_invert_colors))
1382 return 0;
1383
1384 return -1;
1385}
1386
1387/**
1388 * @}
1389 */
Note: See TracBrowser for help on using the repository browser.