2 * Copyright (c) 2008 Martin Decky
3 * Copyright (c) 2006 Ondrej Palkovsky
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
30 /** @addtogroup genarch
36 #include <genarch/fb/font-8x16.h>
37 #include <genarch/fb/logo-196x66.h>
38 #include <genarch/fb/fb.h>
39 #include <console/chardev.h>
40 #include <console/console.h>
41 #include <sysinfo/sysinfo.h>
53 #include <byteorder.h>
55 #define BG_COLOR 0x001620
56 #define FG_COLOR 0xf3cf65
57 #define INV_COLOR 0xaaaaaa
59 #define RED(x, bits) (((x) >> (8 + 8 + 8 - (bits))) & ((1 << (bits)) - 1))
60 #define GREEN(x, bits) (((x) >> (8 + 8 - (bits))) & ((1 << (bits)) - 1))
61 #define BLUE(x, bits) (((x) >> (8 - (bits))) & ((1 << (bits)) - 1))
63 #define COL2X(col) ((col) * FONT_WIDTH)
64 #define ROW2Y(row) ((row) * FONT_SCANLINES)
66 #define X2COL(x) ((x) / FONT_WIDTH)
67 #define Y2ROW(y) ((y) / FONT_SCANLINES)
69 #define FB_POS(instance, x, y) \
70 ((y) * (instance)->scanline + (x) * (instance)->pixelbytes)
72 #define BB_POS(instance, col, row) \
73 ((row) * (instance)->cols + (col))
75 #define GLYPH_POS(instance, glyph, y) \
76 ((glyph) * (instance)->glyphbytes + (y) * (instance)->glyphscanline)
78 typedef void (* rgb_conv_t
)(void *, uint32_t);
81 SPINLOCK_DECLARE(lock
);
99 unsigned int scanline
;
100 unsigned int glyphscanline
;
102 unsigned int pixelbytes
;
103 unsigned int glyphbytes
;
104 unsigned int bgscanbytes
;
109 unsigned int position
;
112 static void fb_putchar(outdev_t
*dev
, wchar_t ch
);
113 static void fb_redraw_internal(fb_instance_t
*instance
);
114 static void fb_redraw(outdev_t
*dev
);
116 static outdev_operations_t fbdev_ops
= {
122 * RGB conversion functions.
124 * These functions write an RGB value to some memory in some predefined format.
125 * The naming convention corresponds to the format created by these functions.
126 * The functions use the so called network order (i.e. big endian) with respect
130 static void rgb_0888(void *dst
, uint32_t rgb
)
132 *((uint32_t *) dst
) = host2uint32_t_be((0 << 24) |
133 (RED(rgb
, 8) << 16) | (GREEN(rgb
, 8) << 8) | (BLUE(rgb
, 8)));
136 static void bgr_0888(void *dst
, uint32_t rgb
)
138 *((uint32_t *) dst
) = host2uint32_t_be((0 << 24) |
139 (BLUE(rgb
, 8) << 16) | (GREEN(rgb
, 8) << 8) | (RED(rgb
, 8)));
142 static void rgb_8880(void *dst
, uint32_t rgb
)
144 *((uint32_t *) dst
) = host2uint32_t_be((RED(rgb
, 8) << 24) |
145 (GREEN(rgb
, 8) << 16) | (BLUE(rgb
, 8) << 8) | 0);
148 static void bgr_8880(void *dst
, uint32_t rgb
)
150 *((uint32_t *) dst
) = host2uint32_t_be((BLUE(rgb
, 8) << 24) |
151 (GREEN(rgb
, 8) << 16) | (RED(rgb
, 8) << 8) | 0);
154 static void rgb_888(void *dst
, uint32_t rgb
)
156 ((uint8_t *) dst
)[0] = RED(rgb
, 8);
157 ((uint8_t *) dst
)[1] = GREEN(rgb
, 8);
158 ((uint8_t *) dst
)[2] = BLUE(rgb
, 8);
161 static void bgr_888(void *dst
, uint32_t rgb
)
163 ((uint8_t *) dst
)[0] = BLUE(rgb
, 8);
164 ((uint8_t *) dst
)[1] = GREEN(rgb
, 8);
165 ((uint8_t *) dst
)[2] = RED(rgb
, 8);
168 static void rgb_555_be(void *dst
, uint32_t rgb
)
170 *((uint16_t *) dst
) = host2uint16_t_be(RED(rgb
, 5) << 10 |
171 GREEN(rgb
, 5) << 5 | BLUE(rgb
, 5));
174 static void rgb_555_le(void *dst
, uint32_t rgb
)
176 *((uint16_t *) dst
) = host2uint16_t_le(RED(rgb
, 5) << 10 |
177 GREEN(rgb
, 5) << 5 | BLUE(rgb
, 5));
180 static void rgb_565_be(void *dst
, uint32_t rgb
)
182 *((uint16_t *) dst
) = host2uint16_t_be(RED(rgb
, 5) << 11 |
183 GREEN(rgb
, 6) << 5 | BLUE(rgb
, 5));
186 static void rgb_565_le(void *dst
, uint32_t rgb
)
188 *((uint16_t *) dst
) = host2uint16_t_le(RED(rgb
, 5) << 11 |
189 GREEN(rgb
, 6) << 5 | BLUE(rgb
, 5));
194 * Even though we try 3:2:3 color scheme here, an 8-bit framebuffer
195 * will most likely use a color palette. The color appearance
196 * will be pretty random and depend on the default installed
197 * palette. This could be fixed by supporting custom palette
198 * and setting it to simulate the 8-bit truecolor.
200 * Currently we set the palette on the ia32, amd64, ppc32 and sparc64 port.
202 * Note that the byte is being inverted by this function. The reason is
203 * that we would like to use a color palette where the white color code
204 * is 0 and the black color code is 255, as some machines (Sun Blade 1500)
205 * use these codes for black and white and prevent to set codes
206 * 0 and 255 to other colors.
209 static void bgr_323(void *dst
, uint32_t rgb
)
212 = ~((RED(rgb
, 3) << 5) | (GREEN(rgb
, 2) << 3) | BLUE(rgb
, 3));
215 /** Hide logo and refresh screen
218 static void logo_hide(fb_instance_t
*instance
)
221 instance
->ytrim
= instance
->yres
;
222 instance
->rowtrim
= instance
->rows
;
224 if ((!instance
->parea
.mapped
) || (console_override
))
225 fb_redraw_internal(instance
);
228 /** Draw character at given position
231 static void glyph_draw(fb_instance_t
*instance
, uint16_t glyph
,
232 unsigned int col
, unsigned int row
, bool overlay
)
234 unsigned int x
= COL2X(col
);
235 unsigned int y
= ROW2Y(row
);
238 if (y
>= instance
->ytrim
)
242 instance
->backbuf
[BB_POS(instance
, col
, row
)] = glyph
;
244 if ((!instance
->parea
.mapped
) || (console_override
)) {
245 for (yd
= 0; yd
< FONT_SCANLINES
; yd
++)
246 memcpy(&instance
->addr
[FB_POS(instance
, x
, y
+ yd
+ instance
->ylogo
)],
247 &instance
->glyphs
[GLYPH_POS(instance
, glyph
, yd
)],
248 instance
->glyphscanline
);
252 /** Scroll screen down by one row
256 static void screen_scroll(fb_instance_t
*instance
)
258 if (instance
->ylogo
> 0) {
263 if ((!instance
->parea
.mapped
) || (console_override
)) {
266 for (row
= 0; row
< instance
->rows
; row
++) {
267 unsigned int y
= ROW2Y(row
);
270 for (yd
= 0; yd
< FONT_SCANLINES
; yd
++) {
274 for (col
= 0, x
= 0; col
< instance
->cols
;
275 col
++, x
+= FONT_WIDTH
) {
278 if (row
< instance
->rows
- 1) {
279 if (instance
->backbuf
[BB_POS(instance
, col
, row
)] ==
280 instance
->backbuf
[BB_POS(instance
, col
, row
+ 1)])
283 glyph
= instance
->backbuf
[BB_POS(instance
, col
, row
+ 1)];
287 memcpy(&instance
->addr
[FB_POS(instance
, x
, y
+ yd
)],
288 &instance
->glyphs
[GLYPH_POS(instance
, glyph
, yd
)],
289 instance
->glyphscanline
);
295 memmove(instance
->backbuf
, &instance
->backbuf
[BB_POS(instance
, 0, 1)],
296 instance
->cols
* (instance
->rows
- 1) * sizeof(uint16_t));
297 memsetw(&instance
->backbuf
[BB_POS(instance
, 0, instance
->rows
- 1)],
301 static void cursor_put(fb_instance_t
*instance
)
303 unsigned int col
= instance
->position
% instance
->cols
;
304 unsigned int row
= instance
->position
/ instance
->cols
;
306 glyph_draw(instance
, fb_font_glyph(U_CURSOR
), col
, row
, true);
309 static void cursor_remove(fb_instance_t
*instance
)
311 unsigned int col
= instance
->position
% instance
->cols
;
312 unsigned int row
= instance
->position
/ instance
->cols
;
314 glyph_draw(instance
, instance
->backbuf
[BB_POS(instance
, col
, row
)],
320 * Convert glyphs from device independent font
321 * description to current visual representation.
324 static void glyphs_render(fb_instance_t
*instance
)
326 /* Prerender glyphs */
329 for (glyph
= 0; glyph
< FONT_GLYPHS
; glyph
++) {
332 if (glyph
== FONT_GLYPHS
- 1)
333 fg_color
= INV_COLOR
;
339 for (y
= 0; y
< FONT_SCANLINES
; y
++) {
342 for (x
= 0; x
< FONT_WIDTH
; x
++) {
344 &instance
->glyphs
[GLYPH_POS(instance
, glyph
, y
) +
345 x
* instance
->pixelbytes
];
346 uint32_t rgb
= (fb_font
[glyph
][y
] &
347 (1 << (7 - x
))) ? fg_color
: BG_COLOR
;
348 instance
->rgb_conv(dst
, rgb
);
353 /* Prerender background scanline */
356 for (x
= 0; x
< instance
->xres
; x
++)
357 instance
->rgb_conv(&instance
->bgscan
[x
* instance
->pixelbytes
], BG_COLOR
);
360 /** Print character to screen
362 * Emulate basic terminal commands.
365 static void fb_putchar(outdev_t
*dev
, wchar_t ch
)
367 fb_instance_t
*instance
= (fb_instance_t
*) dev
->data
;
368 spinlock_lock(&instance
->lock
);
372 cursor_remove(instance
);
373 instance
->position
+= instance
->cols
;
374 instance
->position
-= instance
->position
% instance
->cols
;
377 cursor_remove(instance
);
378 instance
->position
-= instance
->position
% instance
->cols
;
381 cursor_remove(instance
);
382 if (instance
->position
% instance
->cols
)
383 instance
->position
--;
386 cursor_remove(instance
);
388 glyph_draw(instance
, fb_font_glyph(' '),
389 instance
->position
% instance
->cols
,
390 instance
->position
/ instance
->cols
, false);
391 instance
->position
++;
392 } while (((instance
->position
% instance
->cols
) % 8 != 0) &&
393 (instance
->position
< instance
->cols
* instance
->rows
));
396 glyph_draw(instance
, fb_font_glyph(ch
),
397 instance
->position
% instance
->cols
,
398 instance
->position
/ instance
->cols
, false);
399 instance
->position
++;
402 if (instance
->position
>= instance
->cols
* instance
->rows
) {
403 instance
->position
-= instance
->cols
;
404 screen_scroll(instance
);
407 cursor_put(instance
);
409 spinlock_unlock(&instance
->lock
);
412 static void fb_redraw_internal(fb_instance_t
*instance
)
414 if (instance
->ylogo
> 0) {
417 for (y
= 0; y
< LOGO_HEIGHT
; y
++) {
420 for (x
= 0; x
< instance
->xres
; x
++)
421 instance
->rgb_conv(&instance
->addr
[FB_POS(instance
, x
, y
)],
423 fb_logo
[y
* LOGO_WIDTH
+ x
] :
430 for (row
= 0; row
< instance
->rowtrim
; row
++) {
431 unsigned int y
= instance
->ylogo
+ ROW2Y(row
);
434 for (yd
= 0; yd
< FONT_SCANLINES
; yd
++) {
438 for (col
= 0, x
= 0; col
< instance
->cols
;
439 col
++, x
+= FONT_WIDTH
) {
441 instance
->backbuf
[BB_POS(instance
, col
, row
)];
442 void *dst
= &instance
->addr
[FB_POS(instance
, x
, y
+ yd
)];
443 void *src
= &instance
->glyphs
[GLYPH_POS(instance
, glyph
, yd
)];
444 memcpy(dst
, src
, instance
->glyphscanline
);
449 if (COL2X(instance
->cols
) < instance
->xres
) {
452 (instance
->xres
- COL2X(instance
->cols
)) * instance
->pixelbytes
;
454 for (y
= instance
->ylogo
; y
< instance
->yres
; y
++)
455 memcpy(&instance
->addr
[FB_POS(instance
, COL2X(instance
->cols
), y
)],
456 instance
->bgscan
, size
);
459 if (ROW2Y(instance
->rowtrim
) + instance
->ylogo
< instance
->yres
) {
462 for (y
= ROW2Y(instance
->rowtrim
) + instance
->ylogo
;
463 y
< instance
->yres
; y
++)
464 memcpy(&instance
->addr
[FB_POS(instance
, 0, y
)],
465 instance
->bgscan
, instance
->bgscanbytes
);
469 /** Refresh the screen
472 static void fb_redraw(outdev_t
*dev
)
474 fb_instance_t
*instance
= (fb_instance_t
*) dev
->data
;
476 spinlock_lock(&instance
->lock
);
477 fb_redraw_internal(instance
);
478 spinlock_unlock(&instance
->lock
);
481 /** Initialize framebuffer as a output character device
484 outdev_t
*fb_init(fb_properties_t
*props
)
487 ASSERT(props
->x
> 0);
488 ASSERT(props
->y
> 0);
489 ASSERT(props
->scan
> 0);
492 unsigned int pixelbytes
;
494 switch (props
->visual
) {
495 case VISUAL_INDIRECT_8
:
499 case VISUAL_RGB_5_5_5_LE
:
500 rgb_conv
= rgb_555_le
;
503 case VISUAL_RGB_5_5_5_BE
:
504 rgb_conv
= rgb_555_be
;
507 case VISUAL_RGB_5_6_5_LE
:
508 rgb_conv
= rgb_565_le
;
511 case VISUAL_RGB_5_6_5_BE
:
512 rgb_conv
= rgb_565_be
;
515 case VISUAL_RGB_8_8_8
:
519 case VISUAL_BGR_8_8_8
:
523 case VISUAL_RGB_8_8_8_0
:
527 case VISUAL_RGB_0_8_8_8
:
531 case VISUAL_BGR_0_8_8_8
:
535 case VISUAL_BGR_8_8_8_0
:
540 LOG("Unsupported visual.");
544 outdev_t
*fbdev
= malloc(sizeof(outdev_t
), FRAME_ATOMIC
);
548 fb_instance_t
*instance
= malloc(sizeof(fb_instance_t
), FRAME_ATOMIC
);
554 outdev_initialize("fbdev", fbdev
, &fbdev_ops
);
555 fbdev
->data
= instance
;
557 spinlock_initialize(&instance
->lock
, "*fb.instance.lock");
559 instance
->rgb_conv
= rgb_conv
;
560 instance
->pixelbytes
= pixelbytes
;
561 instance
->xres
= props
->x
;
562 instance
->yres
= props
->y
;
563 instance
->scanline
= props
->scan
;
564 instance
->position
= 0;
566 instance
->cols
= X2COL(instance
->xres
);
567 instance
->rows
= Y2ROW(instance
->yres
);
569 if (instance
->yres
> LOGO_HEIGHT
) {
570 instance
->ylogo
= LOGO_HEIGHT
;
571 instance
->rowtrim
= instance
->rows
- Y2ROW(instance
->ylogo
);
572 if (instance
->ylogo
% FONT_SCANLINES
> 0)
574 instance
->ytrim
= ROW2Y(instance
->rowtrim
);
577 instance
->ytrim
= instance
->yres
;
578 instance
->rowtrim
= instance
->rows
;
581 instance
->glyphscanline
= FONT_WIDTH
* instance
->pixelbytes
;
582 instance
->glyphbytes
= ROW2Y(instance
->glyphscanline
);
583 instance
->bgscanbytes
= instance
->xres
* instance
->pixelbytes
;
585 size_t fbsize
= instance
->scanline
* instance
->yres
;
586 size_t bbsize
= instance
->cols
* instance
->rows
* sizeof(uint16_t);
587 size_t glyphsize
= FONT_GLYPHS
* instance
->glyphbytes
;
589 instance
->addr
= (uint8_t *) km_map((uintptr_t) props
->addr
, fbsize
,
590 PAGE_WRITE
| PAGE_NOT_CACHEABLE
);
591 if (!instance
->addr
) {
592 LOG("Unable to map framebuffer.");
598 instance
->backbuf
= (uint16_t *) malloc(bbsize
, 0);
599 if (!instance
->backbuf
) {
600 LOG("Unable to allocate backbuffer.");
606 instance
->glyphs
= (uint8_t *) malloc(glyphsize
, 0);
607 if (!instance
->glyphs
) {
608 LOG("Unable to allocate glyphs.");
609 free(instance
->backbuf
);
615 instance
->bgscan
= malloc(instance
->bgscanbytes
, 0);
616 if (!instance
->bgscan
) {
617 LOG("Unable to allocate background pixel.");
618 free(instance
->glyphs
);
619 free(instance
->backbuf
);
625 memsetw(instance
->backbuf
, instance
->cols
* instance
->rows
, 0);
626 glyphs_render(instance
);
628 link_initialize(&instance
->parea
.link
);
629 instance
->parea
.pbase
= props
->addr
;
630 instance
->parea
.frames
= SIZE2FRAMES(fbsize
);
631 instance
->parea
.unpriv
= false;
632 instance
->parea
.mapped
= false;
633 ddi_parea_register(&instance
->parea
);
637 * We export the kernel framebuffer for uspace usage.
638 * This is used in the case the uspace framebuffer
639 * driver is not self-sufficient.
641 sysinfo_set_item_val("fb", NULL
, true);
642 sysinfo_set_item_val("fb.kind", NULL
, 1);
643 sysinfo_set_item_val("fb.width", NULL
, instance
->xres
);
644 sysinfo_set_item_val("fb.height", NULL
, instance
->yres
);
645 sysinfo_set_item_val("fb.scanline", NULL
, instance
->scanline
);
646 sysinfo_set_item_val("fb.visual", NULL
, props
->visual
);
647 sysinfo_set_item_val("fb.address.physical", NULL
, props
->addr
);