source: mainline/kernel/genarch/src/fb/fb.c@ 8cbf1c3

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

remove the HelenOS logo in the kernel console
(it was hardly ever seen nowadays, not serving any real purpose anymore and we instantly save 50 KB on debug kernels)

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