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

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

kernel output devices now suport multiple instances (except ski and sgcn, which respect the same interface, but behave as singletons)
if more than one output device gets initialized, the output is cloned to all of them
get rid of arch_grab_console() and arch_release_console() (output devices can implement a generic "redraw" method, input devices respect the "silent" global variable)
related cleanups and modifications

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