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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since bab75df6 was bab75df6, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Let kernel code get printf via the standard stdio header. Clean up unused includes.

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