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

Last change on this file since dfeb4e2 was 63e27ef, checked in by Jiri Svoboda <jiri@…>, 9 years ago

ASSERT → assert

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