src/gui/embedded/qscreenlinuxfb_qws.cpp
changeset 30 5dc02b23752f
parent 18 2f34d5167611
--- a/src/gui/embedded/qscreenlinuxfb_qws.cpp	Wed Jun 23 19:07:03 2010 +0300
+++ b/src/gui/embedded/qscreenlinuxfb_qws.cpp	Tue Jul 06 15:10:48 2010 +0300
@@ -91,6 +91,7 @@
     int startuph;
     int startupd;
     bool blank;
+    QLinuxFbScreen::DriverTypes driverType;
 
     bool doGraphicsMode;
 #ifdef QT_QWS_DEPTH_GENERIC
@@ -165,6 +166,36 @@
 }
 
 /*!
+    \enum QLinuxFbScreen::DriverTypes
+
+    This enum describes the driver type.
+
+    \value GenericDriver Generic Linux framebuffer driver
+    \value EInk8Track e-Ink framebuffer driver using the 8Track chipset
+ */
+
+/*!
+    \fn QLinuxFbScreen::fixupScreenInfo(fb_fix_screeninfo &finfo, fb_var_screeninfo &vinfo)
+
+    Adjust the values returned by the framebuffer driver, to work
+    around driver bugs or nonstandard behavior in certain drivers.
+    \a finfo and \a vinfo specify the fixed and variable screen info
+    returned by the driver.
+ */
+void QLinuxFbScreen::fixupScreenInfo(fb_fix_screeninfo &finfo, fb_var_screeninfo &vinfo)
+{
+    // 8Track e-ink devices (as found in Sony PRS-505) lie
+    // about their bit depth -- they claim they're 1 bit per
+    // pixel while the only supported mode is 8 bit per pixel
+    // grayscale.
+    // Caused by this, they also miscalculate their line length.
+    if(!strcmp(finfo.id, "8TRACKFB") && vinfo.bits_per_pixel == 1) {
+        vinfo.bits_per_pixel = 8;
+        finfo.line_length = vinfo.xres;
+    }
+}
+
+/*!
     \internal
 
     \class QLinuxFbScreen
@@ -306,6 +337,8 @@
         return false;
     }
 
+    d_ptr->driverType = strcmp(finfo.id, "8TRACKFB") ? GenericDriver : EInk8Track;
+
     if (finfo.type == FB_TYPE_VGA_PLANES) {
         qWarning("VGA16 video mode not supported");
         return false;
@@ -318,6 +351,8 @@
         return false;
     }
 
+    fixupScreenInfo(finfo, vinfo);
+
     grayscale = vinfo.grayscale;
     d = vinfo.bits_per_pixel;
     if (d == 24) {
@@ -664,11 +699,6 @@
            vinfo.transp.msb_right);
 #endif
 
-    d_ptr->startupw=vinfo.xres;
-    d_ptr->startuph=vinfo.yres;
-    d_ptr->startupd=vinfo.bits_per_pixel;
-    grayscale = vinfo.grayscale;
-
     if (ioctl(d_ptr->fd, FBIOGET_FSCREENINFO, &finfo)) {
         perror("QLinuxFbScreen::initDevice");
         qCritical("Error reading fixed information in card init");
@@ -677,6 +707,13 @@
         return true;
     }
 
+    fixupScreenInfo(finfo, vinfo);
+
+    d_ptr->startupw=vinfo.xres;
+    d_ptr->startuph=vinfo.yres;
+    d_ptr->startupd=vinfo.bits_per_pixel;
+    grayscale = vinfo.grayscale;
+
 #ifdef __i386__
     // Now init mtrr
     if(!::getenv("QWS_NOMTRR")) {
@@ -1122,6 +1159,7 @@
         qFatal("Error reading fixed information");
     }
 
+    fixupScreenInfo(finfo, vinfo);
     disconnect();
     connect(d_ptr->displaySpec);
     exposeRegion(region(), 0);
@@ -1200,6 +1238,26 @@
 /*!
     \reimp
 */
+void QLinuxFbScreen::setDirty(const QRect &r)
+{
+    if(d_ptr->driverType == EInk8Track) {
+        // e-Ink displays need a trigger to actually show what is
+        // in their framebuffer memory. The 8-Track driver does this
+        // by adding custom IOCTLs - FBIO_EINK_DISP_PIC (0x46a2) takes
+        // an argument specifying whether or not to flash the screen
+        // while updating.
+        // There doesn't seem to be a way to tell it to just update
+        // a subset of the screen.
+        if(r.left() == 0 && r.top() == 0 && r.width() == dw && r.height() == dh)
+            ioctl(d_ptr->fd, 0x46a2, 1);
+        else
+            ioctl(d_ptr->fd, 0x46a2, 0);
+    }
+}
+
+/*!
+    \reimp
+*/
 void QLinuxFbScreen::blank(bool on)
 {
     if (d_ptr->blank == on)
@@ -1315,7 +1373,9 @@
 
 bool QLinuxFbScreen::useOffscreen()
 {
-    if ((mapsize - size) < 16*1024)
+    // Not done for 8Track because on e-Ink displays,
+    // everything is offscreen anyway
+    if (d_ptr->driverType == EInk8Track || ((mapsize - size) < 16*1024))
         return false;
 
     return true;