Subversion Repositories HelenOS

Rev

Rev 4156 | Rev 4678 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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