~vojtech-horky/helenos/numa

« back to all changes in this revision

Viewing changes to kernel/genarch/src/fb/fb.c

  • Committer: Martin Decky
  • Date: 2009-08-04 11:19:19 UTC
  • Revision ID: martin@uranus.dsrg.hide.ms.mff.cuni.cz-20090804111919-evyclddlr3v5lhmp
Initial import

Show diffs side-by-side

added added

removed removed

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