source: mainline/kernel/genarch/src/fb/fb.c@ 080ad7f

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

represent special keystrokes (cursor arrows, page up/down, delete, etc.) as appropriate Unicode characters
do not parse ANSI control sequences in kconsole, but in serial line driver

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