source: mainline/kernel/genarch/src/fb/fb.c@ a11099f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a11099f was 00a020d, checked in by Martin Decky <martin@…>, 17 years ago

declare unknown visual type and allow fb_init() to fail gracefully

  • Property mode set to 100644
File size: 13.6 KB
Line 
1/*
2 * Copyright (c) 2008 Martin Decky
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/** @addtogroup genarch
31 * @{
32 */
33/** @file
34 */
35
36#include <genarch/fb/font-8x16.h>
37#include <genarch/fb/logo-196x66.h>
38#include <genarch/fb/visuals.h>
39#include <genarch/fb/fb.h>
40#include <console/chardev.h>
41#include <console/console.h>
42#include <sysinfo/sysinfo.h>
43#include <mm/slab.h>
44#include <align.h>
45#include <panic.h>
46#include <memstr.h>
47#include <config.h>
48#include <bitops.h>
49#include <print.h>
50#include <string.h>
51#include <ddi/ddi.h>
52#include <arch/types.h>
53#include <byteorder.h>
54
55SPINLOCK_INITIALIZE(fb_lock);
56
57static uint8_t *fb_addr;
58static uint16_t *backbuf;
59static uint8_t *glyphs;
60static uint8_t *bgscan;
61
62static unsigned int xres;
63static unsigned int yres;
64
65static unsigned int ylogo;
66static unsigned int ytrim;
67static unsigned int rowtrim;
68
69static unsigned int scanline;
70static unsigned int glyphscanline;
71
72static unsigned int pixelbytes;
73static unsigned int glyphbytes;
74static unsigned int bgscanbytes;
75
76static unsigned int cols;
77static unsigned int rows;
78static unsigned int position = 0;
79
80#define BG_COLOR 0x000080
81#define FG_COLOR 0xffff00
82#define INV_COLOR 0xaaaaaa
83
84#define RED(x, bits) (((x) >> (8 + 8 + 8 - (bits))) & ((1 << (bits)) - 1))
85#define GREEN(x, bits) (((x) >> (8 + 8 - (bits))) & ((1 << (bits)) - 1))
86#define BLUE(x, bits) (((x) >> (8 - (bits))) & ((1 << (bits)) - 1))
87
88#define COL2X(col) ((col) * FONT_WIDTH)
89#define ROW2Y(row) ((row) * FONT_SCANLINES)
90
91#define X2COL(x) ((x) / FONT_WIDTH)
92#define Y2ROW(y) ((y) / FONT_SCANLINES)
93
94#define FB_POS(x, y) ((y) * scanline + (x) * pixelbytes)
95#define BB_POS(col, row) ((row) * cols + (col))
96#define GLYPH_POS(glyph, y) ((glyph) * glyphbytes + (y) * glyphscanline)
97
98
99static void (*rgb_conv)(void *, uint32_t);
100
101/*
102 * RGB conversion functions.
103 *
104 * These functions write an RGB value to some memory in some predefined format.
105 * The naming convention corresponds to the format created by these functions.
106 * The functions use the so called network order (i.e. big endian) with respect
107 * to their names.
108 */
109
110static void rgb_0888(void *dst, uint32_t rgb)
111{
112 *((uint32_t *) dst) = host2uint32_t_be((0 << 24) |
113 (RED(rgb, 8) << 16) | (GREEN(rgb, 8) << 8) | (BLUE(rgb, 8)));
114}
115
116static void bgr_0888(void *dst, uint32_t rgb)
117{
118 *((uint32_t *) dst) = host2uint32_t_be((0 << 24) |
119 (BLUE(rgb, 8) << 16) | (GREEN(rgb, 8) << 8) | (RED(rgb, 8)));
120}
121
122static void rgb_8880(void *dst, uint32_t rgb)
123{
124 *((uint32_t *) dst) = host2uint32_t_be((RED(rgb, 8) << 24) |
125 (GREEN(rgb, 8) << 16) | (BLUE(rgb, 8) << 8) | 0);
126}
127
128static void bgr_8880(void *dst, uint32_t rgb)
129{
130 *((uint32_t *) dst) = host2uint32_t_be((BLUE(rgb, 8) << 24) |
131 (GREEN(rgb, 8) << 16) | (RED(rgb, 8) << 8) | 0);
132}
133
134static void rgb_888(void *dst, uint32_t rgb)
135{
136 ((uint8_t *) dst)[0] = RED(rgb, 8);
137 ((uint8_t *) dst)[1] = GREEN(rgb, 8);
138 ((uint8_t *) dst)[2] = BLUE(rgb, 8);
139}
140
141static void bgr_888(void *dst, uint32_t rgb)
142{
143 ((uint8_t *) dst)[0] = BLUE(rgb, 8);
144 ((uint8_t *) dst)[1] = GREEN(rgb, 8);
145 ((uint8_t *) dst)[2] = RED(rgb, 8);
146}
147
148static void rgb_555_be(void *dst, uint32_t rgb)
149{
150 *((uint16_t *) dst) = host2uint16_t_be(RED(rgb, 5) << 10 |
151 GREEN(rgb, 5) << 5 | BLUE(rgb, 5));
152}
153
154static void rgb_555_le(void *dst, uint32_t rgb)
155{
156 *((uint16_t *) dst) = host2uint16_t_le(RED(rgb, 5) << 10 |
157 GREEN(rgb, 5) << 5 | BLUE(rgb, 5));
158}
159
160static void rgb_565_be(void *dst, uint32_t rgb)
161{
162 *((uint16_t *) dst) = host2uint16_t_be(RED(rgb, 5) << 11 |
163 GREEN(rgb, 6) << 5 | BLUE(rgb, 5));
164}
165
166static void rgb_565_le(void *dst, uint32_t rgb)
167{
168 *((uint16_t *) dst) = host2uint16_t_le(RED(rgb, 5) << 11 |
169 GREEN(rgb, 6) << 5 | BLUE(rgb, 5));
170}
171
172
173/** BGR 3:2:3
174 *
175 * Even though we try 3:2:3 color scheme here, an 8-bit framebuffer
176 * will most likely use a color palette. The color appearance
177 * will be pretty random and depend on the default installed
178 * palette. This could be fixed by supporting custom palette
179 * and setting it to simulate the 8-bit truecolor.
180 *
181 * Currently we set the palette on the ia32, amd64 and sparc64 port.
182 *
183 * Note that the byte is being inverted by this function. The reason is
184 * that we would like to use a color palette where the white color code
185 * is 0 and the black color code is 255, as some machines (Sun Blade 1500)
186 * use these codes for black and white and prevent to set codes
187 * 0 and 255 to other colors.
188 *
189 */
190static void bgr_323(void *dst, uint32_t rgb)
191{
192 *((uint8_t *) dst)
193 = ~((RED(rgb, 3) << 5) | (GREEN(rgb, 2) << 3) | BLUE(rgb, 3));
194}
195
196
197/** Hide logo and refresh screen
198 *
199 */
200static void logo_hide(bool silent)
201{
202 ylogo = 0;
203 ytrim = yres;
204 rowtrim = rows;
205 if (!silent)
206 fb_redraw();
207}
208
209
210/** Draw character at given position
211 *
212 */
213static void glyph_draw(uint16_t glyph, unsigned int col, unsigned int row, bool silent, bool overlay)
214{
215 unsigned int x = COL2X(col);
216 unsigned int y = ROW2Y(row);
217 unsigned int yd;
218
219 if (y >= ytrim)
220 logo_hide(silent);
221
222 if (!overlay)
223 backbuf[BB_POS(col, row)] = glyph;
224
225 if (!silent) {
226 for (yd = 0; yd < FONT_SCANLINES; yd++)
227 memcpy(&fb_addr[FB_POS(x, y + yd + ylogo)],
228 &glyphs[GLYPH_POS(glyph, yd)], glyphscanline);
229 }
230}
231
232
233/** Scroll screen down by one row
234 *
235 *
236 */
237static void screen_scroll(bool silent)
238{
239 if (ylogo > 0) {
240 logo_hide(silent);
241 return;
242 }
243
244 if (!silent) {
245 unsigned int row;
246
247 for (row = 0; row < rows; row++) {
248 unsigned int y = ROW2Y(row);
249 unsigned int yd;
250
251 for (yd = 0; yd < FONT_SCANLINES; yd++) {
252 unsigned int x;
253 unsigned int col;
254
255 for (col = 0, x = 0; col < cols; col++,
256 x += FONT_WIDTH) {
257 uint16_t glyph;
258
259 if (row < rows - 1) {
260 if (backbuf[BB_POS(col, row)] ==
261 backbuf[BB_POS(col, row + 1)])
262 continue;
263
264 glyph = backbuf[BB_POS(col, row + 1)];
265 } else
266 glyph = 0;
267
268 memcpy(&fb_addr[FB_POS(x, y + yd)],
269 &glyphs[GLYPH_POS(glyph, yd)],
270 glyphscanline);
271 }
272 }
273 }
274 }
275
276 memmove(backbuf, &backbuf[BB_POS(0, 1)], cols * (rows - 1) * sizeof(uint16_t));
277 memsetw(&backbuf[BB_POS(0, rows - 1)], cols, 0);
278}
279
280
281static void cursor_put(bool silent)
282{
283 unsigned int col = position % cols;
284 unsigned int row = position / cols;
285
286 glyph_draw(fb_font_glyph(U_CURSOR), col, row, silent, true);
287}
288
289
290static void cursor_remove(bool silent)
291{
292 unsigned int col = position % cols;
293 unsigned int row = position / cols;
294
295 glyph_draw(backbuf[BB_POS(col, row)], col, row, silent, true);
296}
297
298
299/** Print character to screen
300 *
301 * Emulate basic terminal commands.
302 *
303 */
304static void fb_putchar(outdev_t *dev, wchar_t ch, bool silent)
305{
306 spinlock_lock(&fb_lock);
307
308 switch (ch) {
309 case '\n':
310 cursor_remove(silent);
311 position += cols;
312 position -= position % cols;
313 break;
314 case '\r':
315 cursor_remove(silent);
316 position -= position % cols;
317 break;
318 case '\b':
319 cursor_remove(silent);
320 if (position % cols)
321 position--;
322 break;
323 case '\t':
324 cursor_remove(silent);
325 do {
326 glyph_draw(fb_font_glyph(' '), position % cols,
327 position / cols, silent, false);
328 position++;
329 } while ((position % 8) && (position < cols * rows));
330 break;
331 default:
332 glyph_draw(fb_font_glyph(ch), position % cols,
333 position / cols, silent, false);
334 position++;
335 }
336
337 if (position >= cols * rows) {
338 position -= cols;
339 screen_scroll(silent);
340 }
341
342 cursor_put(silent);
343
344 spinlock_unlock(&fb_lock);
345}
346
347static outdev_t fb_console;
348static outdev_operations_t fb_ops = {
349 .write = fb_putchar
350};
351
352
353/** Render glyphs
354 *
355 * Convert glyphs from device independent font
356 * description to current visual representation.
357 *
358 */
359static void glyphs_render(void)
360{
361 /* Prerender glyphs */
362 uint16_t glyph;
363
364 for (glyph = 0; glyph < FONT_GLYPHS; glyph++) {
365 uint32_t fg_color;
366
367 if (glyph == FONT_GLYPHS - 1)
368 fg_color = INV_COLOR;
369 else
370 fg_color = FG_COLOR;
371
372 unsigned int y;
373
374 for (y = 0; y < FONT_SCANLINES; y++) {
375 unsigned int x;
376
377 for (x = 0; x < FONT_WIDTH; x++) {
378 void *dst = &glyphs[GLYPH_POS(glyph, y) +
379 x * pixelbytes];
380 uint32_t rgb = (fb_font[glyph][y] &
381 (1 << (7 - x))) ? fg_color : BG_COLOR;
382 rgb_conv(dst, rgb);
383 }
384 }
385 }
386
387 /* Prerender background scanline */
388 unsigned int x;
389
390 for (x = 0; x < xres; x++)
391 rgb_conv(&bgscan[x * pixelbytes], BG_COLOR);
392}
393
394
395/** Refresh the screen
396 *
397 */
398void fb_redraw(void)
399{
400 if (ylogo > 0) {
401 unsigned int y;
402
403 for (y = 0; y < LOGO_HEIGHT; y++) {
404 unsigned int x;
405
406 for (x = 0; x < xres; x++)
407 rgb_conv(&fb_addr[FB_POS(x, y)],
408 (x < LOGO_WIDTH) ?
409 fb_logo[y * LOGO_WIDTH + x] :
410 LOGO_COLOR);
411 }
412 }
413
414 unsigned int row;
415
416 for (row = 0; row < rowtrim; row++) {
417 unsigned int y = ylogo + ROW2Y(row);
418 unsigned int yd;
419
420 for (yd = 0; yd < FONT_SCANLINES; yd++) {
421 unsigned int x;
422 unsigned int col;
423
424 for (col = 0, x = 0; col < cols;
425 col++, x += FONT_WIDTH) {
426 uint16_t glyph = backbuf[BB_POS(col, row)];
427 void *dst = &fb_addr[FB_POS(x, y + yd)];
428 void *src = &glyphs[GLYPH_POS(glyph, yd)];
429 memcpy(dst, src, glyphscanline);
430 }
431 }
432 }
433
434 if (COL2X(cols) < xres) {
435 unsigned int y;
436 unsigned int size = (xres - COL2X(cols)) * pixelbytes;
437
438 for (y = ylogo; y < yres; y++)
439 memcpy(&fb_addr[FB_POS(COL2X(cols), y)], bgscan, size);
440 }
441
442 if (ROW2Y(rowtrim) + ylogo < yres) {
443 unsigned int y;
444
445 for (y = ROW2Y(rowtrim) + ylogo; y < yres; y++)
446 memcpy(&fb_addr[FB_POS(0, y)], bgscan, bgscanbytes);
447 }
448}
449
450
451/** Initialize framebuffer as a output character device
452 *
453 * @param addr Physical address of the framebuffer
454 * @param x Screen width in pixels
455 * @param y Screen height in pixels
456 * @param scan Bytes per one scanline
457 * @param visual Color model
458 *
459 */
460bool fb_init(fb_properties_t *props)
461{
462 ASSERT(props);
463 ASSERT(props->x > 0);
464 ASSERT(props->y > 0);
465 ASSERT(props->scan > 0);
466
467 switch (props->visual) {
468 case VISUAL_INDIRECT_8:
469 rgb_conv = bgr_323;
470 pixelbytes = 1;
471 break;
472 case VISUAL_RGB_5_5_5_LE:
473 rgb_conv = rgb_555_le;
474 pixelbytes = 2;
475 break;
476 case VISUAL_RGB_5_5_5_BE:
477 rgb_conv = rgb_555_be;
478 pixelbytes = 2;
479 break;
480 case VISUAL_RGB_5_6_5_LE:
481 rgb_conv = rgb_565_le;
482 pixelbytes = 2;
483 break;
484 case VISUAL_RGB_5_6_5_BE:
485 rgb_conv = rgb_565_be;
486 pixelbytes = 2;
487 break;
488 case VISUAL_RGB_8_8_8:
489 rgb_conv = rgb_888;
490 pixelbytes = 3;
491 break;
492 case VISUAL_BGR_8_8_8:
493 rgb_conv = bgr_888;
494 pixelbytes = 3;
495 break;
496 case VISUAL_RGB_8_8_8_0:
497 rgb_conv = rgb_8880;
498 pixelbytes = 4;
499 break;
500 case VISUAL_RGB_0_8_8_8:
501 rgb_conv = rgb_0888;
502 pixelbytes = 4;
503 break;
504 case VISUAL_BGR_0_8_8_8:
505 rgb_conv = bgr_0888;
506 pixelbytes = 4;
507 break;
508 case VISUAL_BGR_8_8_8_0:
509 rgb_conv = bgr_8880;
510 pixelbytes = 4;
511 break;
512 default:
513 LOG("Unsupported visual.");
514 return false;
515 }
516
517 xres = props->x;
518 yres = props->y;
519 scanline = props->scan;
520
521 cols = X2COL(xres);
522 rows = Y2ROW(yres);
523
524 if (yres > ylogo) {
525 ylogo = LOGO_HEIGHT;
526 rowtrim = rows - Y2ROW(ylogo);
527 if (ylogo % FONT_SCANLINES > 0)
528 rowtrim--;
529 ytrim = ROW2Y(rowtrim);
530 } else {
531 ylogo = 0;
532 ytrim = yres;
533 rowtrim = rows;
534 }
535
536 glyphscanline = FONT_WIDTH * pixelbytes;
537 glyphbytes = ROW2Y(glyphscanline);
538 bgscanbytes = xres * pixelbytes;
539
540 size_t fbsize = scanline * yres;
541 size_t bbsize = cols * rows * sizeof(uint16_t);
542 size_t glyphsize = FONT_GLYPHS * glyphbytes;
543
544 fb_addr = (uint8_t *) hw_map((uintptr_t) props->addr, fbsize);
545 if (!fb_addr) {
546 LOG("Unable to map framebuffer.");
547 return false;
548 }
549
550 backbuf = (uint16_t *) malloc(bbsize, 0);
551 if (!backbuf) {
552 LOG("Unable to allocate backbuffer.");
553 return false;
554 }
555
556 glyphs = (uint8_t *) malloc(glyphsize, 0);
557 if (!glyphs) {
558 free(backbuf);
559 LOG("Unable to allocate glyphs.");
560 return false;
561 }
562
563 bgscan = malloc(bgscanbytes, 0);
564 if (!bgscan) {
565 free(glyphs);
566 free(backbuf);
567 LOG("Unable to allocate background pixel.");
568 return false;
569 }
570
571 memsetw(backbuf, cols * rows, 0);
572 glyphs_render();
573
574 sysinfo_set_item_val("fb", NULL, true);
575 sysinfo_set_item_val("fb.kind", NULL, 1);
576 sysinfo_set_item_val("fb.width", NULL, xres);
577 sysinfo_set_item_val("fb.height", NULL, yres);
578 sysinfo_set_item_val("fb.scanline", NULL, scanline);
579 sysinfo_set_item_val("fb.visual", NULL, props->visual);
580 sysinfo_set_item_val("fb.address.physical", NULL, props->addr);
581
582 fb_redraw();
583
584 outdev_initialize("fb", &fb_console, &fb_ops);
585 stdout = &fb_console;
586
587 return true;
588}
589
590/** @}
591 */
Note: See TracBrowser for help on using the repository browser.