Add support for framebuffer LCDs
authorbetacentauri <betacentauri@arcor.de>
Thu, 22 Jan 2015 19:32:24 +0000 (20:32 +0100)
committerErik Slagter <erik@openpli.org>
Fri, 30 Jan 2015 19:06:18 +0000 (20:06 +0100)
et8500 has such framebuffer LCD

Signed-off-by: Erik Slagter <erik@openpli.org>

lib/gdi/Makefile.inc
lib/gdi/fblcd.cpp [new file with mode: 0644]
lib/gdi/fblcd.h [new file with mode: 0644]
lib/gdi/glcddc.cpp
lib/gdi/lcd.cpp
lib/gdi/lcd.h

index c23f05d..91db005 100644 (file)
@@ -9,6 +9,7 @@ gdi_libenigma_gdi_a_SOURCES = \
        gdi/epng.cpp \
        gdi/erect.cpp \
        gdi/fb.cpp \
+       gdi/fblcd.cpp \
        gdi/font.cpp \
        gdi/font_arabic.cpp \
        gdi/gfont.cpp \
@@ -30,6 +31,7 @@ gdiinclude_HEADERS = \
        gdi/erect.h \
        gdi/esize.h \
        gdi/fb.h \
+       gdi/fblcd.h \
        gdi/font.h \
        gdi/gfont.h \
        gdi/glcddc.h \
diff --git a/lib/gdi/fblcd.cpp b/lib/gdi/fblcd.cpp
new file mode 100644 (file)
index 0000000..6b7f0bc
--- /dev/null
@@ -0,0 +1,285 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <memory.h>
+#include <linux/kd.h>
+
+#include <lib/gdi/fblcd.h>
+
+#ifndef FBIO_BLIT
+#define FBIO_SET_MANUAL_BLIT _IOW('F', 0x21, __u8)
+#define FBIO_BLIT 0x22
+#endif
+
+eFbLCD::eFbLCD(const char *fb)
+{
+       m_manual_blit = -1;
+       instance = this;
+       locked = 0;
+       _buffer = 0;
+       m_available = 0;
+       m_cmap.start = 0;
+       m_cmap.len = 256;
+       m_cmap.red = m_red;
+       m_cmap.green = m_green;
+       m_cmap.blue = m_blue;
+       m_cmap.transp = m_trans;
+       m_alpha = 255;
+       m_gamma = 128;
+       m_brightness = 128;
+
+       lcdfd = open(fb, O_RDWR);
+       if (lcdfd < 0)
+       {
+               perror(fb);
+               goto nolfb;
+       }
+
+       if (ioctl(lcdfd, FBIOGET_VSCREENINFO, &m_screeninfo) < 0)
+       {
+               perror("FBIOGET_VSCREENINFO");
+               goto nolfb;
+       }
+
+       fb_fix_screeninfo fix;
+       if (ioctl(lcdfd, FBIOGET_FSCREENINFO, &fix) < 0)
+       {
+               perror("FBIOGET_FSCREENINFO");
+               goto nolfb;
+       }
+
+       m_available = fix.smem_len;
+       m_phys_mem = fix.smem_start;
+       eDebug("%dk video mem", m_available / 1024);
+       _buffer=(unsigned char*)mmap(0, m_available, PROT_WRITE|PROT_READ, MAP_SHARED, lcdfd, 0);
+       if (!_buffer)
+       {
+               perror("mmap");
+               goto nolfb;
+       }
+
+       lcd_type = 4;
+       calcRamp();
+       getMode();
+       setMode(m_xRes, m_yRes, m_bpp);
+       enableManualBlit();
+
+       return;
+nolfb:
+       if (lcdfd >= 0)
+       {
+               ::close(lcdfd);
+               lcdfd = -1;
+       }
+       printf("framebuffer not available.\n");
+       return;
+}
+
+eFbLCD::~eFbLCD()
+{
+       if (_buffer)
+       {
+               msync(_buffer, m_available, MS_SYNC);
+               munmap(_buffer, m_available);
+               _buffer = 0;
+       }
+       if (lcdfd >= 0)
+       {
+               ::close(lcdfd);
+               lcdfd = -1;
+       }
+}
+
+int eFbLCD::setMode(int nxRes, int nyRes, int nbpp)
+{
+       m_screeninfo.xres_virtual = m_screeninfo.xres = nxRes;
+       m_screeninfo.yres_virtual = (m_screeninfo.yres = nyRes) * 2;
+       m_screeninfo.height = 0;
+       m_screeninfo.width = 0;
+       m_screeninfo.xoffset = m_screeninfo.yoffset = 0;
+       m_screeninfo.bits_per_pixel = nbpp;
+
+       switch (nbpp) {
+       case 16:
+               // ARGB 1555
+               m_screeninfo.transp.offset = 15;
+               m_screeninfo.transp.length = 1;
+               m_screeninfo.red.offset = 10;
+               m_screeninfo.red.length = 5;
+               m_screeninfo.green.offset = 5;
+               m_screeninfo.green.length = 5;
+               m_screeninfo.blue.offset = 0;
+               m_screeninfo.blue.length = 5;
+               break;
+       case 32:
+               // ARGB 8888
+               m_screeninfo.transp.offset = 24;
+               m_screeninfo.transp.length = 8;
+               m_screeninfo.red.offset = 16;
+               m_screeninfo.red.length = 8;
+               m_screeninfo.green.offset = 8;
+               m_screeninfo.green.length = 8;
+               m_screeninfo.blue.offset = 0;
+               m_screeninfo.blue.length = 8;
+               break;
+       }
+
+       if (ioctl(lcdfd, FBIOPUT_VSCREENINFO, &m_screeninfo) < 0)
+       {
+               // try single buffering
+               m_screeninfo.yres_virtual = m_screeninfo.yres=nyRes;
+
+               if (ioctl(lcdfd, FBIOPUT_VSCREENINFO, &m_screeninfo) < 0)
+               {
+                       perror("FBIOPUT_VSCREENINFO");
+                       printf("fb failed\n");
+                       return -1;
+               }
+               eDebug(" - double buffering not available.");
+       }
+       else
+               eDebug(" - double buffering available!");
+
+       ioctl(lcdfd, FBIOGET_VSCREENINFO, &m_screeninfo);
+
+       if ((m_screeninfo.xres != nxRes) && (m_screeninfo.yres != nyRes) && (m_screeninfo.bits_per_pixel != nbpp))
+       {
+               eDebug("SetMode failed: wanted: %dx%dx%d, got %dx%dx%d",
+                       nxRes, nyRes, nbpp,
+                       m_screeninfo.xres, m_screeninfo.yres, m_screeninfo.bits_per_pixel);
+       }
+       m_xRes = m_screeninfo.xres;
+       m_yRes = m_screeninfo.yres;
+       m_bpp = m_screeninfo.bits_per_pixel;
+       fb_fix_screeninfo fix;
+       if (ioctl(lcdfd, FBIOGET_FSCREENINFO, &fix) < 0)
+       {
+               perror("FBIOGET_FSCREENINFO");
+               printf("fb failed\n");
+       }
+       _stride = fix.line_length;
+       memset(_buffer, 0, _stride * m_yRes);
+       update();
+       return 0;
+}
+
+void eFbLCD::getMode()
+{
+       m_xRes = m_screeninfo.xres;
+       m_yRes = m_screeninfo.yres;
+       m_bpp = m_screeninfo.bits_per_pixel;
+}
+
+int eFbLCD::waitVSync()
+{
+       int c = 0;
+       return ioctl(lcdfd, FBIO_WAITFORVSYNC, &c);
+}
+
+void eFbLCD::update() // blit
+{
+       if (m_manual_blit == 1)
+       {
+               if (ioctl(lcdfd, FBIO_BLIT) < 0)
+                       perror("FBIO_BLIT");
+       }
+}
+
+int eFbLCD::putCMAP()
+{
+       return ioctl(lcdfd, FBIOPUTCMAP, &m_cmap);
+}
+
+int eFbLCD::lock()
+{
+       if (locked)
+               return -1;
+       if (m_manual_blit == 1)
+       {
+               locked = 2;
+               disableManualBlit();
+       }
+       else
+               locked = 1;
+       return lcdfd;
+}
+
+void eFbLCD::unlock()
+{
+       if (!locked)
+               return;
+       if (locked == 2)  // re-enable manualBlit
+               enableManualBlit();
+       locked = 0;
+       setMode(m_xRes, m_yRes, m_bpp);
+       putCMAP();
+}
+
+void eFbLCD::calcRamp()
+{
+       for (int i = 0; i < 256; i++)
+       {
+               int d;
+               d = i;
+               d = (d-128)*(m_gamma+64)/(128+64)+128;
+               d += m_brightness-128; // brightness correction
+               if (d < 0)
+                       d = 0;
+               if (d > 255)
+                       d = 255;
+               m_ramp[i] = d;
+
+               m_rampalpha[i] = i*m_alpha/256;
+       }
+
+       m_rampalpha[255] = 255; // transparent BLEIBT bitte so.
+}
+
+void eFbLCD::setPalette(gUnmanagedSurface surface)
+{
+       if (!surface.clut.data)
+               return;
+
+       for (int i=0; i < 256; ++i)
+       {
+               m_cmap.red[i] = m_ramp[surface.clut.data[i].r]<<8;
+               m_cmap.green[i] = m_ramp[surface.clut.data[i].g]<<8;
+               m_cmap.blue[i] = m_ramp[surface.clut.data[i].b]<<8;
+               m_cmap.transp[i] = m_rampalpha[surface.clut.data[i].a]<<8;
+       }
+       putCMAP();
+}
+
+void eFbLCD::enableManualBlit()
+{
+       unsigned char tmp = 1;
+       if (ioctl(lcdfd, FBIO_SET_MANUAL_BLIT, &tmp) < 0)
+               perror("LCD FBIO_SET_MANUAL_BLIT");
+       else
+               m_manual_blit = 1;
+}
+
+void eFbLCD::disableManualBlit()
+{
+       unsigned char tmp = 0;
+       if (ioctl(lcdfd, FBIO_SET_MANUAL_BLIT, &tmp) < 0)
+               perror("LCD FBIO_SET_MANUAL_BLIT");
+       else
+               m_manual_blit = 0;
+}
+
+int eFbLCD::setLCDBrightness(int brightness)
+{
+       eDebug("setLCDBrightness %d", brightness);
+       FILE *f = fopen("/proc/stb/lcd/oled_brightness", "w");
+       if (f)
+       {
+               if (fprintf(f, "%d", brightness) == 0)
+                       eDebug("write /proc/stb/lcd/oled_brightness failed!! (%m)");
+               fclose(f);
+       }
+       return 0;
+}
\ No newline at end of file
diff --git a/lib/gdi/fblcd.h b/lib/gdi/fblcd.h
new file mode 100644 (file)
index 0000000..5b75226
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef __LCDFB_H
+#define __LCDFB_H
+
+#include <lib/base/eerror.h>
+#include <linux/fb.h>
+#include <lib/gdi/lcd.h>
+#include "gpixmap.h"
+
+class eFbLCD: public eLCD
+{
+       int m_xRes, m_yRes, m_bpp;
+       int m_brightness, m_gamma, m_alpha;
+       int m_available;
+       struct fb_var_screeninfo m_screeninfo;
+       fb_cmap m_cmap;
+       unsigned char m_ramp[256], m_rampalpha[256]; // RGB ramp 0..255
+       uint16_t m_red[256], m_green[256], m_blue[256], m_trans[256];
+       int m_phys_mem;
+       int m_manual_blit;
+
+       void calcRamp();
+       int setMode(int xRes, int yRes, int bpp);
+       void getMode();
+       void enableManualBlit();
+       void disableManualBlit();
+                       // low level gfx stuff
+       int putCMAP();
+public:
+       eFbLCD(const char *fb="/dev/fb1");
+       ~eFbLCD();
+       bool detected() { return m_available; }
+       eSize size() { return eSize(m_xRes, m_yRes); }
+       void setPalette(gUnmanagedSurface);
+       int waitVSync();
+       int setLCDContrast(int contrast) { return 0; };
+       int setLCDBrightness(int brightness);
+       void setInverted( unsigned char ) {};
+       void setFlipped(bool) {};
+       bool isOled() const { return 0; };
+       void update();  // blit
+       int lock();
+       void unlock();
+       int islocked() { return locked; }
+};
+
+#endif
index 45bccfb..25b47fc 100644 (file)
@@ -1,5 +1,6 @@
 #include <lib/gdi/glcddc.h>
 #include <lib/gdi/lcd.h>
+#include <lib/gdi/fblcd.h>
 #include <lib/base/init.h>
 #include <lib/base/init_num.h>
 
@@ -7,7 +8,12 @@ gLCDDC *gLCDDC::instance;
 
 gLCDDC::gLCDDC()
 {
-       lcd = new eDBoxLCD();
+       lcd = new eFbLCD();
+       if (!lcd->detected())
+       {
+               delete lcd;
+               lcd = new eDBoxLCD();
+       }
        instance = this;
 
        update = 1;
@@ -18,8 +24,18 @@ gLCDDC::gLCDDC()
        surface.bypp = surface.stride / surface.x;
        surface.bpp = surface.bypp*8;
        surface.data = lcd->buffer();
-       surface.clut.colors = 0;
-       surface.clut.data = 0;
+       surface.data_phys = 0;
+       if (lcd->getLcdType() == 4)
+       {
+               surface.clut.colors = 256;
+               surface.clut.data = new gRGB[surface.clut.colors];
+               memset(surface.clut.data, 0, sizeof(*surface.clut.data)*surface.clut.colors);
+       }
+       else
+       {
+               surface.clut.colors = 0;
+               surface.clut.data = 0;
+       }
        eDebug("LCD resolution: %d x %d x %d (stride: %d)", surface.x, surface.y, surface.bpp, surface.stride);
 
        m_pixmap = new gPixmap(&surface);
@@ -28,6 +44,8 @@ gLCDDC::gLCDDC()
 gLCDDC::~gLCDDC()
 {
        delete lcd;
+       if (surface.clut.data)
+               delete[] surface.clut.data;
        instance = 0;
 }
 
@@ -35,6 +53,12 @@ void gLCDDC::exec(const gOpcode *o)
 {
        switch (o->opcode)
        {
+       case gOpcode::setPalette:
+       {
+               gDC::exec(o);
+               lcd->setPalette(surface);
+               break;
+       }
 #ifdef HAVE_TEXTLCD
        case gOpcode::renderText:
                if (o->parm.renderText->text)
@@ -46,8 +70,7 @@ void gLCDDC::exec(const gOpcode *o)
                break;
 #endif
        case gOpcode::flush:
-//             if (update)
-                       lcd->update();
+               lcd->update();
        default:
                gDC::exec(o);
                break;
index 57dd0f8..dde9974 100644 (file)
 #endif
 #include <lib/gdi/glcddc.h>
 
-eDBoxLCD *eDBoxLCD::instance;
+eLCD *eLCD::instance;
 
 eLCD::eLCD()
 {
        lcdfd = -1;
        locked=0;
+       instance = this;
+}
+
+eLCD *eLCD::getInstance()
+{
+       return instance;
 }
 
 void eLCD::setSize(int xres, int yres, int bpp)
@@ -31,7 +37,8 @@ void eLCD::setSize(int xres, int yres, int bpp)
 
 eLCD::~eLCD()
 {
-       delete [] _buffer;
+       if (_buffer)
+               delete [] _buffer;
 }
 
 int eLCD::lock()
@@ -65,19 +72,19 @@ eDBoxLCD::eDBoxLCD()
        int xres=132, yres=64, bpp=8;
        flipped = false;
        inverted = 0;
-       is_oled = 0;
+       lcd_type = 0;
 #ifndef NO_LCD
        lcdfd = open("/dev/dbox/oled0", O_RDWR);
        if (lcdfd < 0)
        {
                if (!access("/proc/stb/lcd/oled_brightness", W_OK) ||
                    !access("/proc/stb/fp/oled_brightness", W_OK) )
-                       is_oled = 2;
+                       lcd_type = 2;
                lcdfd = open("/dev/dbox/lcd0", O_RDWR);
        } else
        {
                eDebug("found OLED display!");
-               is_oled = 1;
+               lcd_type = 1;
        }
 
        if (lcdfd < 0)
@@ -115,7 +122,7 @@ eDBoxLCD::eDBoxLCD()
                                        fclose(f);
                                }
                        }
-                       is_oled = 3;
+                       lcd_type = 3;
                }
        }
 #endif
@@ -202,17 +209,12 @@ eDBoxLCD::~eDBoxLCD()
        }
 }
 
-eDBoxLCD *eDBoxLCD::getInstance()
-{
-       return instance;
-}
-
 void eDBoxLCD::update()
 {
 #ifndef HAVE_TEXTLCD
        if (lcdfd >= 0)
        {
-               if (is_oled == 0 || is_oled == 2)
+               if (lcd_type == 0 || lcd_type == 2)
                {
                        unsigned char raw[132*8];
                        int x, y, yy;
@@ -239,7 +241,7 @@ void eDBoxLCD::update()
                        }
                        write(lcdfd, raw, 132*8);
                }
-               else if (is_oled == 3)
+               else if (lcd_type == 3)
                {
                        /* for now, only support flipping / inverting for 8bpp displays */
                        if ((flipped || inverted) && _stride == res.width())
@@ -269,7 +271,7 @@ void eDBoxLCD::update()
                                write(lcdfd, _buffer, _stride * res.height());
                        }
                }
-               else /* is_oled == 1 */
+               else /* lcd_type == 1 */
                {
                        unsigned char raw[64*64];
                        int x, y;
index 6044939..171383e 100644 (file)
@@ -4,6 +4,7 @@
 #include <asm/types.h>
 #include <lib/gdi/esize.h>
 #include <lib/gdi/erect.h>
+#include "gpixmap.h"
 
 #define LCD_CONTRAST_MIN 0
 #define LCD_CONTRAST_MAX 63
@@ -17,24 +18,35 @@ class eLCD
        ~eLCD();
 #else
 protected:
-       void setSize(int xres, int yres, int bpp);
        eSize res;
+       int lcd_type;
        unsigned char *_buffer;
        int lcdfd;
        int _stride;
        int locked;
+       static eLCD *instance;
+       void setSize(int xres, int yres, int bpp);
 #endif
 public:
-       int lock();
-       void unlock();
-       int islocked() { return locked; }
-       bool detected() { return lcdfd >= 0; }
+       static eLCD *getInstance();
+       virtual int lock();
+       virtual void unlock();
+       virtual int islocked() { return locked; };
+       virtual bool detected() { return lcdfd >= 0; };
+       virtual int setLCDContrast(int contrast)=0;
+       virtual int setLCDBrightness(int brightness)=0;
+       virtual void setInverted( unsigned char )=0;
+       virtual void setFlipped(bool)=0;
+       virtual int waitVSync()=0;
+       virtual bool isOled() const=0;
+       int getLcdType() { return lcd_type; };
+       virtual void setPalette(gUnmanagedSurface)=0;
 #ifndef SWIG
        eLCD();
        virtual ~eLCD();
-       uint8_t *buffer() { return (uint8_t*)_buffer; }
-       int stride() { return _stride; }
-       eSize size() { return res; }
+       uint8_t *buffer() { return (uint8_t*)_buffer; };
+       int stride() { return _stride; };
+       virtual eSize size() { return res; };
        virtual void update()=0;
 #ifdef HAVE_TEXTLCD
        virtual void renderText(ePoint start, const char *text);
@@ -44,10 +56,8 @@ public:
 
 class eDBoxLCD: public eLCD
 {
-       static eDBoxLCD *instance;
        unsigned char inverted;
        bool flipped;
-       int is_oled;
 #ifdef SWIG
        eDBoxLCD();
        ~eDBoxLCD();
@@ -57,13 +67,14 @@ public:
        eDBoxLCD();
        ~eDBoxLCD();
 #endif
-       static eDBoxLCD *getInstance();
        int setLCDContrast(int contrast);
        int setLCDBrightness(int brightness);
        void setInverted( unsigned char );
        void setFlipped(bool);
-       bool isOled() const { return !!is_oled; }
+       bool isOled() const { return !!lcd_type; };
+       void setPalette(gUnmanagedSurface) {};
        void update();
+       int waitVSync() { return 0; };
 };
 
 #endif