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

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

rename spinlocks to be more descriptive

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