Indentation, formatting and minor changes.
[helenos.git] / kernel / genarch / src / fb / fb.c
blob976e4d401ef7dea98f7b2e15bb39dd720e11d622
1 /*
2 * Copyright (C) 2006 Ondrej Palkovsky
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 /** @addtogroup genarch
30 * @{
32 /** @file
35 #include <genarch/fb/font-8x16.h>
36 #include <genarch/fb/fb.h>
37 #include <console/chardev.h>
38 #include <console/console.h>
39 #include <sysinfo/sysinfo.h>
40 #include <mm/slab.h>
41 #include <align.h>
42 #include <panic.h>
43 #include <memstr.h>
44 #include <config.h>
45 #include <bitops.h>
46 #include <print.h>
48 #include "helenos.xbm"
50 SPINLOCK_INITIALIZE(fb_lock);
52 static uint8_t *fbaddress = NULL;
54 static uint8_t *blankline = NULL;
55 static uint8_t *dbbuffer = NULL; /* Buffer for fast scrolling console */
56 static int dboffset;
58 static unsigned int xres = 0;
59 static unsigned int yres = 0;
60 static unsigned int scanline = 0;
61 static unsigned int bitspp = 0;
62 static unsigned int pixelbytes = 0;
63 #ifdef FB_INVERT_COLORS
64 static bool invert_colors = true;
65 #else
66 static bool invert_colors = false;
67 #endif
69 static unsigned int position = 0;
70 static unsigned int columns = 0;
71 static unsigned int rows = 0;
73 #define COL_WIDTH 8
74 #define ROW_BYTES (scanline * FONT_SCANLINES)
76 #define BGCOLOR 0x000080
77 #define FGCOLOR 0xffff00
78 #define LOGOCOLOR 0x2020b0
80 #define RED(x, bits) ((x >> (16 + 8 - bits)) & ((1 << bits) - 1))
81 #define GREEN(x, bits) ((x >> (8 + 8 - bits)) & ((1 << bits) - 1))
82 #define BLUE(x, bits) ((x >> (8 - bits)) & ((1 << bits) - 1))
84 #define POINTPOS(x, y) ((y) * scanline + (x) * pixelbytes)
86 /***************************************************************/
87 /* Pixel specific fuctions */
89 static void (*rgb2scr)(void *, int);
90 static int (*scr2rgb)(void *);
92 static inline int COLOR(int color)
94 return invert_colors ? ~color : color;
97 /* Conversion routines between different color representations */
98 static void rgb_4byte(void *dst, int rgb)
100 *(int *)dst = rgb;
103 static int byte4_rgb(void *src)
105 return (*(int *)src) & 0xffffff;
108 static void rgb_3byte(void *dst, int rgb)
110 uint8_t *scr = dst;
111 #if defined(FB_INVERT_ENDIAN)
112 scr[0] = RED(rgb, 8);
113 scr[1] = GREEN(rgb, 8);
114 scr[2] = BLUE(rgb, 8);
115 #else
116 scr[2] = RED(rgb, 8);
117 scr[1] = GREEN(rgb, 8);
118 scr[0] = BLUE(rgb, 8);
119 #endif
122 static int byte3_rgb(void *src)
124 uint8_t *scr = src;
125 #if defined(FB_INVERT_ENDIAN)
126 return scr[0] << 16 | scr[1] << 8 | scr[2];
127 #else
128 return scr[2] << 16 | scr[1] << 8 | scr[0];
129 #endif
132 /** 16-bit depth (5:6:5) */
133 static void rgb_2byte(void *dst, int rgb)
135 /* 5-bit, 6-bits, 5-bits */
136 *((uint16_t *)(dst)) = RED(rgb, 5) << 11 | GREEN(rgb, 6) << 5 | BLUE(rgb, 5);
139 /** 16-bit depth (5:6:5) */
140 static int byte2_rgb(void *src)
142 int color = *(uint16_t *)(src);
143 return (((color >> 11) & 0x1f) << (16 + 3)) | (((color >> 5) & 0x3f) << (8 + 2)) | ((color & 0x1f) << 3);
146 /** Put pixel - 8-bit depth (color palette/3:2:3)
148 * Even though we try 3:2:3 color scheme here, an 8-bit framebuffer
149 * will most likely use a color palette. The color appearance
150 * will be pretty random and depend on the default installed
151 * palette. This could be fixed by supporting custom palette
152 * and setting it to simulate the 8-bit truecolor.
154 static void rgb_1byte(void *dst, int rgb)
156 *(uint8_t *)dst = RED(rgb, 3) << 5 | GREEN(rgb, 2) << 3 | BLUE(rgb, 3);
159 /** Return pixel color - 8-bit depth (color palette/3:2:3)
161 * See the comment for rgb_1byte().
163 static int byte1_rgb(void *src)
165 int color = *(uint8_t *)src;
166 return (((color >> 5) & 0x7) << (16 + 5)) | (((color >> 3) & 0x3) << (8 + 6)) | ((color & 0x7) << 5);
169 static void putpixel(unsigned int x, unsigned int y, int color)
171 (*rgb2scr)(&fbaddress[POINTPOS(x,y)], COLOR(color));
173 if (dbbuffer) {
174 int dline = (y + dboffset) % yres;
175 (*rgb2scr)(&dbbuffer[POINTPOS(x,dline)], COLOR(color));
179 /** Get pixel from viewport */
180 static int getpixel(unsigned int x, unsigned int y)
182 if (dbbuffer) {
183 int dline = (y + dboffset) % yres;
184 return COLOR((*scr2rgb)(&dbbuffer[POINTPOS(x,dline)]));
186 return COLOR((*scr2rgb)(&fbaddress[POINTPOS(x,y)]));
190 /** Fill screen with background color */
191 static void clear_screen(void)
193 unsigned int y;
195 for (y = 0; y < yres; y++) {
196 memcpy(&fbaddress[scanline*y], blankline, xres*pixelbytes);
197 if (dbbuffer)
198 memcpy(&dbbuffer[scanline*y], blankline, xres*pixelbytes);
203 /** Scroll screen one row up */
204 static void scroll_screen(void)
206 uint8_t *lastline = &fbaddress[(rows - 1) * ROW_BYTES];
207 int firstsz;
209 if (dbbuffer) {
210 memcpy(&dbbuffer[dboffset*scanline], blankline, FONT_SCANLINES*scanline);
212 dboffset = (dboffset + FONT_SCANLINES) % yres;
213 firstsz = yres-dboffset;
215 memcpy(fbaddress, &dbbuffer[scanline*dboffset], firstsz*scanline);
216 memcpy(&fbaddress[firstsz*scanline], dbbuffer, dboffset*scanline);
217 } else {
218 memcpy((void *) fbaddress, (void *) &fbaddress[ROW_BYTES], scanline * yres - ROW_BYTES);
219 /* Clear last row */
220 memcpy((void *) lastline, (void *) blankline, ROW_BYTES);
225 static void invert_pixel(unsigned int x, unsigned int y)
227 putpixel(x, y, ~getpixel(x, y));
231 /** Draw one line of glyph at a given position */
232 static void draw_glyph_line(unsigned int glline, unsigned int x, unsigned int y)
234 unsigned int i;
236 for (i = 0; i < 8; i++)
237 if (glline & (1 << (7 - i))) {
238 putpixel(x + i, y, FGCOLOR);
239 } else
240 putpixel(x + i, y, BGCOLOR);
243 /***************************************************************/
244 /* Character-console functions */
246 /** Draw character at given position */
247 static void draw_glyph(uint8_t glyph, unsigned int col, unsigned int row)
249 unsigned int y;
251 for (y = 0; y < FONT_SCANLINES; y++)
252 draw_glyph_line(fb_font[glyph * FONT_SCANLINES + y], col * COL_WIDTH, row * FONT_SCANLINES + y);
255 /** Invert character at given position */
256 static void invert_char(unsigned int col, unsigned int row)
258 unsigned int x;
259 unsigned int y;
261 for (x = 0; x < COL_WIDTH; x++)
262 for (y = 0; y < FONT_SCANLINES; y++)
263 invert_pixel(col * COL_WIDTH + x, row * FONT_SCANLINES + y);
266 /** Draw character at default position */
267 static void draw_char(char chr)
269 draw_glyph(chr, position % columns, position / columns);
272 static void draw_logo(unsigned int startx, unsigned int starty)
274 unsigned int x;
275 unsigned int y;
276 unsigned int byte;
277 unsigned int rowbytes;
279 rowbytes = (helenos_width - 1) / 8 + 1;
281 for (y = 0; y < helenos_height; y++)
282 for (x = 0; x < helenos_width; x++) {
283 byte = helenos_bits[rowbytes * y + x / 8];
284 byte >>= x % 8;
285 if (byte & 1)
286 putpixel(startx + x, starty + y, COLOR(LOGOCOLOR));
290 /***************************************************************/
291 /* Stdout specific functions */
293 static void invert_cursor(void)
295 invert_char(position % columns, position / columns);
298 /** Print character to screen
300 * Emulate basic terminal commands
302 static void fb_putchar(chardev_t *dev, char ch)
304 spinlock_lock(&fb_lock);
306 switch (ch) {
307 case '\n':
308 invert_cursor();
309 position += columns;
310 position -= position % columns;
311 break;
312 case '\r':
313 invert_cursor();
314 position -= position % columns;
315 break;
316 case '\b':
317 invert_cursor();
318 if (position % columns)
319 position--;
320 break;
321 case '\t':
322 invert_cursor();
323 do {
324 draw_char(' ');
325 position++;
326 } while ((position % 8) && position < columns * rows);
327 break;
328 default:
329 draw_char(ch);
330 position++;
333 if (position >= columns * rows) {
334 position -= columns;
335 scroll_screen();
338 invert_cursor();
340 spinlock_unlock(&fb_lock);
343 static chardev_t framebuffer;
344 static chardev_operations_t fb_ops = {
345 .write = fb_putchar,
349 /** Initialize framebuffer as a chardev output device
351 * @param addr Physical address of the framebuffer
352 * @param x Screen width in pixels
353 * @param y Screen height in pixels
354 * @param bpp Bits per pixel (8, 16, 24, 32)
355 * @param scan Bytes per one scanline
356 * @param align Request alignment for 24bpp mode.
358 void fb_init(uintptr_t addr, unsigned int x, unsigned int y, unsigned int bpp, unsigned int scan, bool align)
360 switch (bpp) {
361 case 8:
362 rgb2scr = rgb_1byte;
363 scr2rgb = byte1_rgb;
364 pixelbytes = 1;
365 break;
366 case 16:
367 rgb2scr = rgb_2byte;
368 scr2rgb = byte2_rgb;
369 pixelbytes = 2;
370 break;
371 case 24:
372 rgb2scr = rgb_3byte;
373 scr2rgb = byte3_rgb;
374 if (align)
375 pixelbytes = 4;
376 else
377 pixelbytes = 3;
378 break;
379 case 32:
380 rgb2scr = rgb_4byte;
381 scr2rgb = byte4_rgb;
382 pixelbytes = 4;
383 break;
384 default:
385 panic("Unsupported bpp.\n");
388 unsigned int fbsize = scan * y;
390 /* Map the framebuffer */
391 fbaddress = (uint8_t *) hw_map((uintptr_t) addr, fbsize);
393 xres = x;
394 yres = y;
395 bitspp = bpp;
396 scanline = scan;
398 rows = y / FONT_SCANLINES;
399 columns = x / COL_WIDTH;
401 sysinfo_set_item_val("fb", NULL, true);
402 sysinfo_set_item_val("fb.kind", NULL, 1);
403 sysinfo_set_item_val("fb.width", NULL, xres);
404 sysinfo_set_item_val("fb.height", NULL, yres);
405 sysinfo_set_item_val("fb.bpp", NULL, bpp);
406 sysinfo_set_item_val("fb.bpp-align", NULL, align);
407 sysinfo_set_item_val("fb.scanline", NULL, scan);
408 sysinfo_set_item_val("fb.address.physical", NULL, addr);
409 sysinfo_set_item_val("fb.invert-colors", NULL, invert_colors);
411 /* Allocate double buffer */
412 int totsize = scanline * yres;
413 int pages = SIZE2FRAMES(totsize);
414 int order;
415 if (pages == 1)
416 order = 0;
417 else
418 order = fnzb(pages - 1) + 1;
420 dbbuffer = frame_alloc(order, FRAME_ATOMIC | FRAME_KA);
421 if (!dbbuffer)
422 printf("Failed to allocate scroll buffer.\n");
423 dboffset = 0;
425 /* Initialized blank line */
426 blankline = (uint8_t *) malloc(ROW_BYTES, FRAME_ATOMIC);
427 if (!blankline)
428 panic("Failed to allocate blank line for framebuffer.");
429 for (y=0; y < FONT_SCANLINES; y++) {
430 for (x=0; x < xres; x++) {
431 (*rgb2scr)(&blankline[POINTPOS(x,y)], COLOR(BGCOLOR));
435 clear_screen();
437 /* Update size of screen to match text area */
438 yres = rows * FONT_SCANLINES;
440 draw_logo(xres - helenos_width, 0);
441 invert_cursor();
443 chardev_initialize("fb", &framebuffer, &fb_ops);
444 stdout = &framebuffer;
448 /** @}