summaryrefslogtreecommitdiffstats
path: root/src/gui/embedded/qscreenlinuxfb_qws.cpp
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /src/gui/embedded/qscreenlinuxfb_qws.cpp
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'src/gui/embedded/qscreenlinuxfb_qws.cpp')
-rw-r--r--src/gui/embedded/qscreenlinuxfb_qws.cpp1386
1 files changed, 1386 insertions, 0 deletions
diff --git a/src/gui/embedded/qscreenlinuxfb_qws.cpp b/src/gui/embedded/qscreenlinuxfb_qws.cpp
new file mode 100644
index 0000000000..a566f5294c
--- /dev/null
+++ b/src/gui/embedded/qscreenlinuxfb_qws.cpp
@@ -0,0 +1,1386 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qscreenlinuxfb_qws.h"
+
+#ifndef QT_NO_QWS_LINUXFB
+//#include "qmemorymanager_qws.h"
+#include "qwsdisplay_qws.h"
+#include "qpixmap.h"
+#include <private/qwssignalhandler_p.h>
+#include <private/qcore_unix_p.h> // overrides QT_OPEN
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/kd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <limits.h>
+#include <signal.h>
+
+#include "qwindowsystem_qws.h"
+
+#if !defined(Q_OS_DARWIN) && !defined(Q_OS_FREEBSD)
+#include <linux/fb.h>
+
+#ifdef __i386__
+#include <asm/mtrr.h>
+#endif
+#endif
+
+QT_BEGIN_NAMESPACE
+
+extern int qws_client_id;
+
+//#define DEBUG_CACHE
+
+class QLinuxFbScreenPrivate : public QObject
+{
+public:
+ QLinuxFbScreenPrivate();
+ ~QLinuxFbScreenPrivate();
+
+ void openTty();
+ void closeTty();
+
+ int fd;
+ int startupw;
+ int startuph;
+ int startupd;
+ bool blank;
+ QLinuxFbScreen::DriverTypes driverType;
+
+ bool doGraphicsMode;
+#ifdef QT_QWS_DEPTH_GENERIC
+ bool doGenericColors;
+#endif
+ int ttyfd;
+ long oldKdMode;
+ QString ttyDevice;
+ QString displaySpec;
+};
+
+QLinuxFbScreenPrivate::QLinuxFbScreenPrivate()
+ : fd(-1), blank(true), doGraphicsMode(true),
+#ifdef QT_QWS_DEPTH_GENERIC
+ doGenericColors(false),
+#endif
+ ttyfd(-1), oldKdMode(KD_TEXT)
+{
+ QWSSignalHandler::instance()->addObject(this);
+}
+
+QLinuxFbScreenPrivate::~QLinuxFbScreenPrivate()
+{
+ closeTty();
+}
+
+void QLinuxFbScreenPrivate::openTty()
+{
+ const char *const devs[] = {"/dev/tty0", "/dev/tty", "/dev/console", 0};
+
+ if (ttyDevice.isEmpty()) {
+ for (const char * const *dev = devs; *dev; ++dev) {
+ ttyfd = QT_OPEN(*dev, O_RDWR);
+ if (ttyfd != -1)
+ break;
+ }
+ } else {
+ ttyfd = QT_OPEN(ttyDevice.toAscii().constData(), O_RDWR);
+ }
+
+ if (ttyfd == -1)
+ return;
+
+ if (doGraphicsMode) {
+ ioctl(ttyfd, KDGETMODE, &oldKdMode);
+ if (oldKdMode != KD_GRAPHICS) {
+ int ret = ioctl(ttyfd, KDSETMODE, KD_GRAPHICS);
+ if (ret == -1)
+ doGraphicsMode = false;
+ }
+ }
+
+ // No blankin' screen, no blinkin' cursor!, no cursor!
+ const char termctl[] = "\033[9;0]\033[?33l\033[?25l\033[?1c";
+ QT_WRITE(ttyfd, termctl, sizeof(termctl));
+}
+
+void QLinuxFbScreenPrivate::closeTty()
+{
+ if (ttyfd == -1)
+ return;
+
+ if (doGraphicsMode)
+ ioctl(ttyfd, KDSETMODE, oldKdMode);
+
+ // Blankin' screen, blinkin' cursor!
+ const char termctl[] = "\033[9;15]\033[?33h\033[?25h\033[?0c";
+ QT_WRITE(ttyfd, termctl, sizeof(termctl));
+
+ QT_CLOSE(ttyfd);
+ ttyfd = -1;
+}
+
+/*!
+ \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
+ \ingroup qws
+
+ \brief The QLinuxFbScreen class implements a screen driver for the
+ Linux framebuffer.
+
+ Note that this class is only available in \l{Qt for Embedded Linux}.
+ Custom screen drivers can be added by subclassing the
+ QScreenDriverPlugin class, using the QScreenDriverFactory class to
+ dynamically load the driver into the application, but there should
+ only be one screen object per application.
+
+ The QLinuxFbScreen class provides the cache() function allocating
+ off-screen graphics memory, and the complementary uncache()
+ function releasing the allocated memory. The latter function will
+ first sync the graphics card to ensure the memory isn't still
+ being used by a command in the graphics card FIFO queue. The
+ deleteEntry() function deletes the given memory block without such
+ synchronization. Given the screen instance and client id, the
+ memory can also be released using the clearCache() function, but
+ this should only be necessary if a client exits abnormally.
+
+ In addition, when in paletted graphics modes, the set() function
+ provides the possibility of setting a specified color index to a
+ given RGB value.
+
+ The QLinuxFbScreen class also acts as a factory for the
+ unaccelerated screen cursor and the unaccelerated raster-based
+ implementation of QPaintEngine (\c QRasterPaintEngine);
+ accelerated drivers for Linux should derive from this class.
+
+ \sa QScreen, QScreenDriverPlugin, {Running Applications}
+*/
+
+/*!
+ \fn bool QLinuxFbScreen::useOffscreen()
+ \internal
+*/
+
+// Unaccelerated screen/driver setup. Can be overridden by accelerated
+// drivers
+
+/*!
+ \fn QLinuxFbScreen::QLinuxFbScreen(int displayId)
+
+ Constructs a QLinuxFbScreen object. The \a displayId argument
+ identifies the Qt for Embedded Linux server to connect to.
+*/
+
+QLinuxFbScreen::QLinuxFbScreen(int display_id)
+ : QScreen(display_id, LinuxFBClass), d_ptr(new QLinuxFbScreenPrivate)
+{
+ canaccel=false;
+ clearCacheFunc = &clearCache;
+#ifdef QT_QWS_CLIENTBLIT
+ setSupportsBlitInClients(true);
+#endif
+}
+
+/*!
+ Destroys this QLinuxFbScreen object.
+*/
+
+QLinuxFbScreen::~QLinuxFbScreen()
+{
+}
+
+/*!
+ \reimp
+
+ This is called by \l{Qt for Embedded Linux} clients to map in the framebuffer.
+ It should be reimplemented by accelerated drivers to map in
+ graphics card registers; those drivers should then call this
+ function in order to set up offscreen memory management. The
+ device is specified in \a displaySpec; e.g. "/dev/fb".
+
+ \sa disconnect()
+*/
+
+bool QLinuxFbScreen::connect(const QString &displaySpec)
+{
+ d_ptr->displaySpec = displaySpec;
+
+ const QStringList args = displaySpec.split(QLatin1Char(':'));
+
+ if (args.contains(QLatin1String("nographicsmodeswitch")))
+ d_ptr->doGraphicsMode = false;
+
+#ifdef QT_QWS_DEPTH_GENERIC
+ if (args.contains(QLatin1String("genericcolors")))
+ d_ptr->doGenericColors = true;
+#endif
+
+ QRegExp ttyRegExp(QLatin1String("tty=(.*)"));
+ if (args.indexOf(ttyRegExp) != -1)
+ d_ptr->ttyDevice = ttyRegExp.cap(1);
+
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+#ifndef QT_QWS_FRAMEBUFFER_LITTLE_ENDIAN
+ if (args.contains(QLatin1String("littleendian")))
+#endif
+ QScreen::setFrameBufferLittleEndian(true);
+#endif
+
+ QString dev = QLatin1String("/dev/fb0");
+ foreach(QString d, args) {
+ if (d.startsWith(QLatin1Char('/'))) {
+ dev = d;
+ break;
+ }
+ }
+
+ if (access(dev.toLatin1().constData(), R_OK|W_OK) == 0)
+ d_ptr->fd = QT_OPEN(dev.toLatin1().constData(), O_RDWR);
+ if (d_ptr->fd == -1) {
+ if (QApplication::type() == QApplication::GuiServer) {
+ perror("QScreenLinuxFb::connect");
+ qCritical("Error opening framebuffer device %s", qPrintable(dev));
+ return false;
+ }
+ if (access(dev.toLatin1().constData(), R_OK) == 0)
+ d_ptr->fd = QT_OPEN(dev.toLatin1().constData(), O_RDONLY);
+ }
+
+ ::fb_fix_screeninfo finfo;
+ ::fb_var_screeninfo vinfo;
+ //#######################
+ // Shut up Valgrind
+ memset(&vinfo, 0, sizeof(vinfo));
+ memset(&finfo, 0, sizeof(finfo));
+ //#######################
+
+ /* Get fixed screen information */
+ if (d_ptr->fd != -1 && ioctl(d_ptr->fd, FBIOGET_FSCREENINFO, &finfo)) {
+ perror("QLinuxFbScreen::connect");
+ qWarning("Error reading fixed information");
+ 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;
+ }
+
+ /* Get variable screen information */
+ if (d_ptr->fd != -1 && ioctl(d_ptr->fd, FBIOGET_VSCREENINFO, &vinfo)) {
+ perror("QLinuxFbScreen::connect");
+ qWarning("Error reading variable information");
+ return false;
+ }
+
+ fixupScreenInfo(finfo, vinfo);
+
+ grayscale = vinfo.grayscale;
+ d = vinfo.bits_per_pixel;
+ if (d == 24) {
+ d = vinfo.red.length + vinfo.green.length + vinfo.blue.length;
+ if (d <= 0)
+ d = 24; // reset if color component lengths are not reported
+ } else if (d == 16) {
+ d = vinfo.red.length + vinfo.green.length + vinfo.blue.length;
+ if (d <= 0)
+ d = 16;
+ }
+ lstep = finfo.line_length;
+
+ int xoff = vinfo.xoffset;
+ int yoff = vinfo.yoffset;
+ const char* qwssize;
+ if((qwssize=::getenv("QWS_SIZE")) && sscanf(qwssize,"%dx%d",&w,&h)==2) {
+ if (d_ptr->fd != -1) {
+ if ((uint)w > vinfo.xres) w = vinfo.xres;
+ if ((uint)h > vinfo.yres) h = vinfo.yres;
+ }
+ dw=w;
+ dh=h;
+ int xxoff, yyoff;
+ if (sscanf(qwssize, "%*dx%*d+%d+%d", &xxoff, &yyoff) == 2) {
+ if (xxoff < 0 || xxoff + w > vinfo.xres)
+ xxoff = vinfo.xres - w;
+ if (yyoff < 0 || yyoff + h > vinfo.yres)
+ yyoff = vinfo.yres - h;
+ xoff += xxoff;
+ yoff += yyoff;
+ } else {
+ xoff += (vinfo.xres - w)/2;
+ yoff += (vinfo.yres - h)/2;
+ }
+ } else {
+ dw=w=vinfo.xres;
+ dh=h=vinfo.yres;
+ }
+
+ if (w == 0 || h == 0) {
+ qWarning("QScreenLinuxFb::connect(): Unable to find screen geometry, "
+ "will use 320x240.");
+ dw = w = 320;
+ dh = h = 240;
+ }
+
+ setPixelFormat(vinfo);
+
+ // Handle display physical size spec.
+ QStringList displayArgs = displaySpec.split(QLatin1Char(':'));
+ QRegExp mmWidthRx(QLatin1String("mmWidth=?(\\d+)"));
+ int dimIdxW = displayArgs.indexOf(mmWidthRx);
+ QRegExp mmHeightRx(QLatin1String("mmHeight=?(\\d+)"));
+ int dimIdxH = displayArgs.indexOf(mmHeightRx);
+ if (dimIdxW >= 0) {
+ mmWidthRx.exactMatch(displayArgs.at(dimIdxW));
+ physWidth = mmWidthRx.cap(1).toInt();
+ if (dimIdxH < 0)
+ physHeight = dh*physWidth/dw;
+ }
+ if (dimIdxH >= 0) {
+ mmHeightRx.exactMatch(displayArgs.at(dimIdxH));
+ physHeight = mmHeightRx.cap(1).toInt();
+ if (dimIdxW < 0)
+ physWidth = dw*physHeight/dh;
+ }
+ if (dimIdxW < 0 && dimIdxH < 0) {
+ if (vinfo.width != 0 && vinfo.height != 0
+ && vinfo.width != UINT_MAX && vinfo.height != UINT_MAX) {
+ physWidth = vinfo.width;
+ physHeight = vinfo.height;
+ } else {
+ const int dpi = 72;
+ physWidth = qRound(dw * 25.4 / dpi);
+ physHeight = qRound(dh * 25.4 / dpi);
+ }
+ }
+
+ dataoffset = yoff * lstep + xoff * d / 8;
+ //qDebug("Using %dx%dx%d screen",w,h,d);
+
+ /* Figure out the size of the screen in bytes */
+ size = h * lstep;
+
+ mapsize = finfo.smem_len;
+
+ data = (unsigned char *)-1;
+ if (d_ptr->fd != -1)
+ data = (unsigned char *)mmap(0, mapsize, PROT_READ | PROT_WRITE,
+ MAP_SHARED, d_ptr->fd, 0);
+
+ if ((long)data == -1) {
+ if (QApplication::type() == QApplication::GuiServer) {
+ perror("QLinuxFbScreen::connect");
+ qWarning("Error: failed to map framebuffer device to memory.");
+ return false;
+ }
+ data = 0;
+ } else {
+ data += dataoffset;
+ }
+
+ canaccel = useOffscreen();
+ if(canaccel)
+ setupOffScreen();
+
+ // Now read in palette
+ if((vinfo.bits_per_pixel==8) || (vinfo.bits_per_pixel==4)) {
+ screencols= (vinfo.bits_per_pixel==8) ? 256 : 16;
+ int loopc;
+ ::fb_cmap startcmap;
+ startcmap.start=0;
+ startcmap.len=screencols;
+ startcmap.red=(unsigned short int *)
+ malloc(sizeof(unsigned short int)*screencols);
+ startcmap.green=(unsigned short int *)
+ malloc(sizeof(unsigned short int)*screencols);
+ startcmap.blue=(unsigned short int *)
+ malloc(sizeof(unsigned short int)*screencols);
+ startcmap.transp=(unsigned short int *)
+ malloc(sizeof(unsigned short int)*screencols);
+ if (d_ptr->fd == -1 || ioctl(d_ptr->fd, FBIOGETCMAP, &startcmap)) {
+ perror("QLinuxFbScreen::connect");
+ qWarning("Error reading palette from framebuffer, using default palette");
+ createPalette(startcmap, vinfo, finfo);
+ }
+ int bits_used = 0;
+ for(loopc=0;loopc<screencols;loopc++) {
+ screenclut[loopc]=qRgb(startcmap.red[loopc] >> 8,
+ startcmap.green[loopc] >> 8,
+ startcmap.blue[loopc] >> 8);
+ bits_used |= startcmap.red[loopc]
+ | startcmap.green[loopc]
+ | startcmap.blue[loopc];
+ }
+ // WORKAROUND: Some framebuffer drivers only return 8 bit
+ // color values, so we need to not bit shift them..
+ if ((bits_used & 0x00ff) && !(bits_used & 0xff00)) {
+ for(loopc=0;loopc<screencols;loopc++) {
+ screenclut[loopc] = qRgb(startcmap.red[loopc],
+ startcmap.green[loopc],
+ startcmap.blue[loopc]);
+ }
+ qWarning("8 bits cmap returned due to faulty FB driver, colors corrected");
+ }
+ free(startcmap.red);
+ free(startcmap.green);
+ free(startcmap.blue);
+ free(startcmap.transp);
+ } else {
+ screencols=0;
+ }
+
+ return true;
+}
+
+/*!
+ \reimp
+
+ This unmaps the framebuffer.
+
+ \sa connect()
+*/
+
+void QLinuxFbScreen::disconnect()
+{
+ data -= dataoffset;
+ if (data)
+ munmap((char*)data,mapsize);
+ close(d_ptr->fd);
+}
+
+// #define DEBUG_VINFO
+
+void QLinuxFbScreen::createPalette(fb_cmap &cmap, fb_var_screeninfo &vinfo, fb_fix_screeninfo &finfo)
+{
+ if((vinfo.bits_per_pixel==8) || (vinfo.bits_per_pixel==4)) {
+ screencols= (vinfo.bits_per_pixel==8) ? 256 : 16;
+ cmap.start=0;
+ cmap.len=screencols;
+ cmap.red=(unsigned short int *)
+ malloc(sizeof(unsigned short int)*screencols);
+ cmap.green=(unsigned short int *)
+ malloc(sizeof(unsigned short int)*screencols);
+ cmap.blue=(unsigned short int *)
+ malloc(sizeof(unsigned short int)*screencols);
+ cmap.transp=(unsigned short int *)
+ malloc(sizeof(unsigned short int)*screencols);
+
+ if (screencols==16) {
+ if (finfo.type == FB_TYPE_PACKED_PIXELS) {
+ // We'll setup a grayscale cmap for 4bpp linear
+ int val = 0;
+ for (int idx = 0; idx < 16; ++idx, val += 17) {
+ cmap.red[idx] = (val<<8)|val;
+ cmap.green[idx] = (val<<8)|val;
+ cmap.blue[idx] = (val<<8)|val;
+ screenclut[idx]=qRgb(val, val, val);
+ }
+ } else {
+ // Default 16 colour palette
+ // Green is now trolltech green so certain images look nicer
+ // black d_gray l_gray white red green blue cyan magenta yellow
+ unsigned char reds[16] = { 0x00, 0x7F, 0xBF, 0xFF, 0xFF, 0xA2, 0x00, 0xFF, 0xFF, 0x00, 0x7F, 0x7F, 0x00, 0x00, 0x00, 0x82 };
+ unsigned char greens[16] = { 0x00, 0x7F, 0xBF, 0xFF, 0x00, 0xC5, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x7F };
+ unsigned char blues[16] = { 0x00, 0x7F, 0xBF, 0xFF, 0x00, 0x11, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x7F, 0x7F, 0x7F, 0x00, 0x00 };
+
+ for (int idx = 0; idx < 16; ++idx) {
+ cmap.red[idx] = ((reds[idx]) << 8)|reds[idx];
+ cmap.green[idx] = ((greens[idx]) << 8)|greens[idx];
+ cmap.blue[idx] = ((blues[idx]) << 8)|blues[idx];
+ cmap.transp[idx] = 0;
+ screenclut[idx]=qRgb(reds[idx], greens[idx], blues[idx]);
+ }
+ }
+ } else {
+ if (grayscale) {
+ // Build grayscale palette
+ int i;
+ for(i=0;i<screencols;++i) {
+ int bval = screencols == 256 ? i : (i << 4);
+ ushort val = (bval << 8) | bval;
+ cmap.red[i] = val;
+ cmap.green[i] = val;
+ cmap.blue[i] = val;
+ cmap.transp[i] = 0;
+ screenclut[i] = qRgb(bval,bval,bval);
+ }
+ } else {
+ // 6x6x6 216 color cube
+ int idx = 0;
+ for(int ir = 0x0; ir <= 0xff; ir+=0x33) {
+ for(int ig = 0x0; ig <= 0xff; ig+=0x33) {
+ for(int ib = 0x0; ib <= 0xff; ib+=0x33) {
+ cmap.red[idx] = (ir << 8)|ir;
+ cmap.green[idx] = (ig << 8)|ig;
+ cmap.blue[idx] = (ib << 8)|ib;
+ cmap.transp[idx] = 0;
+ screenclut[idx]=qRgb(ir, ig, ib);
+ ++idx;
+ }
+ }
+ }
+ // Fill in rest with 0
+ for (int loopc=0; loopc<40; ++loopc) {
+ screenclut[idx]=0;
+ ++idx;
+ }
+ screencols=idx;
+ }
+ }
+ } else if(finfo.visual==FB_VISUAL_DIRECTCOLOR) {
+ cmap.start=0;
+ int rbits=0,gbits=0,bbits=0;
+ switch (vinfo.bits_per_pixel) {
+ case 8:
+ rbits=vinfo.red.length;
+ gbits=vinfo.green.length;
+ bbits=vinfo.blue.length;
+ if(rbits==0 && gbits==0 && bbits==0) {
+ // cyber2000 driver bug hack
+ rbits=3;
+ gbits=3;
+ bbits=2;
+ }
+ break;
+ case 15:
+ rbits=5;
+ gbits=5;
+ bbits=5;
+ break;
+ case 16:
+ rbits=5;
+ gbits=6;
+ bbits=5;
+ break;
+ case 18:
+ case 19:
+ rbits=6;
+ gbits=6;
+ bbits=6;
+ break;
+ case 24: case 32:
+ rbits=gbits=bbits=8;
+ break;
+ }
+ screencols=cmap.len=1<<qMax(rbits,qMax(gbits,bbits));
+ cmap.red=(unsigned short int *)
+ malloc(sizeof(unsigned short int)*256);
+ cmap.green=(unsigned short int *)
+ malloc(sizeof(unsigned short int)*256);
+ cmap.blue=(unsigned short int *)
+ malloc(sizeof(unsigned short int)*256);
+ cmap.transp=(unsigned short int *)
+ malloc(sizeof(unsigned short int)*256);
+ for(unsigned int i = 0x0; i < cmap.len; i++) {
+ cmap.red[i] = i*65535/((1<<rbits)-1);
+ cmap.green[i] = i*65535/((1<<gbits)-1);
+ cmap.blue[i] = i*65535/((1<<bbits)-1);
+ cmap.transp[i] = 0;
+ }
+ }
+}
+
+/*!
+ \reimp
+
+ This is called by the \l{Qt for Embedded Linux} server at startup time.
+ It turns off console blinking, sets up the color palette, enables write
+ combining on the framebuffer and initialises the off-screen memory
+ manager.
+*/
+
+bool QLinuxFbScreen::initDevice()
+{
+ d_ptr->openTty();
+
+ // Grab current mode so we can reset it
+ fb_var_screeninfo vinfo;
+ fb_fix_screeninfo finfo;
+ //#######################
+ // Shut up Valgrind
+ memset(&vinfo, 0, sizeof(vinfo));
+ memset(&finfo, 0, sizeof(finfo));
+ //#######################
+
+ if (ioctl(d_ptr->fd, FBIOGET_VSCREENINFO, &vinfo)) {
+ perror("QLinuxFbScreen::initDevice");
+ qFatal("Error reading variable information in card init");
+ return false;
+ }
+
+#ifdef DEBUG_VINFO
+ qDebug("Greyscale %d",vinfo.grayscale);
+ qDebug("Nonstd %d",vinfo.nonstd);
+ qDebug("Red %d %d %d",vinfo.red.offset,vinfo.red.length,
+ vinfo.red.msb_right);
+ qDebug("Green %d %d %d",vinfo.green.offset,vinfo.green.length,
+ vinfo.green.msb_right);
+ qDebug("Blue %d %d %d",vinfo.blue.offset,vinfo.blue.length,
+ vinfo.blue.msb_right);
+ qDebug("Transparent %d %d %d",vinfo.transp.offset,vinfo.transp.length,
+ vinfo.transp.msb_right);
+#endif
+
+ if (ioctl(d_ptr->fd, FBIOGET_FSCREENINFO, &finfo)) {
+ perror("QLinuxFbScreen::initDevice");
+ qCritical("Error reading fixed information in card init");
+ // It's not an /error/ as such, though definitely a bad sign
+ // so we return true
+ 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")) {
+ int mfd=QT_OPEN("/proc/mtrr",O_WRONLY,0);
+ // MTRR entry goes away when file is closed - i.e.
+ // hopefully when QWS is killed
+ if(mfd != -1) {
+ mtrr_sentry sentry;
+ sentry.base=(unsigned long int)finfo.smem_start;
+ //qDebug("Physical framebuffer address %p",(void*)finfo.smem_start);
+ // Size needs to be in 4k chunks, but that's not always
+ // what we get thanks to graphics card registers. Write combining
+ // these is Not Good, so we write combine what we can
+ // (which is not much - 4 megs on an 8 meg card, it seems)
+ unsigned int size=finfo.smem_len;
+ size=size >> 22;
+ size=size << 22;
+ sentry.size=size;
+ sentry.type=MTRR_TYPE_WRCOMB;
+ if(ioctl(mfd,MTRRIOC_ADD_ENTRY,&sentry)==-1) {
+ //printf("Couldn't add mtrr entry for %lx %lx, %s\n",
+ //sentry.base,sentry.size,strerror(errno));
+ }
+ }
+
+ // Should we close mfd here?
+ //QT_CLOSE(mfd);
+ }
+#endif
+ if ((vinfo.bits_per_pixel==8) || (vinfo.bits_per_pixel==4) || (finfo.visual==FB_VISUAL_DIRECTCOLOR))
+ {
+ fb_cmap cmap;
+ createPalette(cmap, vinfo, finfo);
+ if (ioctl(d_ptr->fd, FBIOPUTCMAP, &cmap)) {
+ perror("QLinuxFbScreen::initDevice");
+ qWarning("Error writing palette to framebuffer");
+ }
+ free(cmap.red);
+ free(cmap.green);
+ free(cmap.blue);
+ free(cmap.transp);
+ }
+
+ if (canaccel) {
+ *entryp=0;
+ *lowest = mapsize;
+ insert_entry(*entryp, *lowest, *lowest); // dummy entry to mark start
+ }
+
+ shared->fifocount = 0;
+ shared->buffer_offset = 0xffffffff; // 0 would be a sensible offset (screen)
+ shared->linestep = 0;
+ shared->cliptop = 0xffffffff;
+ shared->clipleft = 0xffffffff;
+ shared->clipright = 0xffffffff;
+ shared->clipbottom = 0xffffffff;
+ shared->rop = 0xffffffff;
+
+#ifdef QT_QWS_DEPTH_GENERIC
+ if (pixelFormat() == QImage::Format_Invalid && screencols == 0
+ && d_ptr->doGenericColors)
+ {
+ qt_set_generic_blit(this, vinfo.bits_per_pixel,
+ vinfo.red.length, vinfo.green.length,
+ vinfo.blue.length, vinfo.transp.length,
+ vinfo.red.offset, vinfo.green.offset,
+ vinfo.blue.offset, vinfo.transp.offset);
+ }
+#endif
+
+#ifndef QT_NO_QWS_CURSOR
+ QScreenCursor::initSoftwareCursor();
+#endif
+ blank(false);
+
+ return true;
+}
+
+/*
+ The offscreen memory manager's list of entries is stored at the bottom
+ of the offscreen memory area and consistes of a series of QPoolEntry's,
+ each of which keep track of a block of allocated memory. Unallocated memory
+ is implicitly indicated by the gap between blocks indicated by QPoolEntry's.
+ The memory manager looks through any unallocated memory before the end
+ of currently-allocated memory to see if a new block will fit in the gap;
+ if it doesn't it allocated it from the end of currently-allocated memory.
+ Memory is allocated from the top of the framebuffer downwards; if it hits
+ the list of entries then offscreen memory is full and further allocations
+ are made from main RAM (and hence unaccelerated). Allocated memory can
+ be seen as a sort of upside-down stack; lowest keeps track of the
+ bottom of the stack.
+*/
+
+void QLinuxFbScreen::delete_entry(int pos)
+{
+ if (pos > *entryp || pos < 0) {
+ qWarning("Attempt to delete odd pos! %d %d", pos, *entryp);
+ return;
+ }
+
+#ifdef DEBUG_CACHE
+ qDebug("Remove entry: %d", pos);
+#endif
+
+ QPoolEntry *qpe = &entries[pos];
+ if (qpe->start <= *lowest) {
+ // Lowest goes up again
+ *lowest = entries[pos-1].start;
+#ifdef DEBUG_CACHE
+ qDebug(" moved lowest to %d", *lowest);
+#endif
+ }
+
+ (*entryp)--;
+ if (pos == *entryp)
+ return;
+
+ int size = (*entryp)-pos;
+ memmove(&entries[pos], &entries[pos+1], size*sizeof(QPoolEntry));
+}
+
+void QLinuxFbScreen::insert_entry(int pos, int start, int end)
+{
+ if (pos > *entryp) {
+ qWarning("Attempt to insert odd pos! %d %d",pos,*entryp);
+ return;
+ }
+
+#ifdef DEBUG_CACHE
+ qDebug("Insert entry: %d, %d -> %d", pos, start, end);
+#endif
+
+ if (start < (int)*lowest) {
+ *lowest = start;
+#ifdef DEBUG_CACHE
+ qDebug(" moved lowest to %d", *lowest);
+#endif
+ }
+
+ if (pos == *entryp) {
+ entries[pos].start = start;
+ entries[pos].end = end;
+ entries[pos].clientId = qws_client_id;
+ (*entryp)++;
+ return;
+ }
+
+ int size=(*entryp)-pos;
+ memmove(&entries[pos+1],&entries[pos],size*sizeof(QPoolEntry));
+ entries[pos].start=start;
+ entries[pos].end=end;
+ entries[pos].clientId=qws_client_id;
+ (*entryp)++;
+}
+
+/*!
+ \fn uchar * QLinuxFbScreen::cache(int amount)
+
+ Requests the specified \a amount of offscreen graphics card memory
+ from the memory manager, and returns a pointer to the data within
+ the framebuffer (or 0 if there is no free memory).
+
+ Note that the display is locked while memory is allocated in order to
+ preserve the memory pool's integrity.
+
+ Use the QScreen::onCard() function to retrieve an offset (in
+ bytes) from the start of graphics card memory for the returned
+ pointer.
+
+ \sa uncache(), clearCache(), deleteEntry()
+*/
+
+uchar * QLinuxFbScreen::cache(int amount)
+{
+ if (!canaccel || entryp == 0)
+ return 0;
+
+ qt_fbdpy->grab();
+
+ int startp = cacheStart + (*entryp+1) * sizeof(QPoolEntry);
+ if (startp >= (int)*lowest) {
+ // We don't have room for another cache QPoolEntry.
+#ifdef DEBUG_CACHE
+ qDebug("No room for pool entry in VRAM");
+#endif
+ qt_fbdpy->ungrab();
+ return 0;
+ }
+
+ int align = pixmapOffsetAlignment();
+
+ if (*entryp > 1) {
+ // Try to find a gap in the allocated blocks.
+ for (int loopc = 0; loopc < *entryp-1; loopc++) {
+ int freestart = entries[loopc+1].end;
+ int freeend = entries[loopc].start;
+ if (freestart != freeend) {
+ while (freestart % align) {
+ freestart++;
+ }
+ int len=freeend-freestart;
+ if (len >= amount) {
+ insert_entry(loopc+1, freestart, freestart+amount);
+ qt_fbdpy->ungrab();
+ return data+freestart;
+ }
+ }
+ }
+ }
+
+ // No free blocks in already-taken memory; get some more
+ // if we can
+ int newlowest = (*lowest)-amount;
+ if (newlowest % align) {
+ newlowest -= align;
+ while (newlowest % align) {
+ newlowest++;
+ }
+ }
+ if (startp >= newlowest) {
+ qt_fbdpy->ungrab();
+#ifdef DEBUG_CACHE
+ qDebug("No VRAM available for %d bytes", amount);
+#endif
+ return 0;
+ }
+ insert_entry(*entryp, newlowest, *lowest);
+ qt_fbdpy->ungrab();
+
+ return data + newlowest;
+}
+
+/*!
+ \fn void QLinuxFbScreen::uncache(uchar * memoryBlock)
+
+ Deletes the specified \a memoryBlock allocated from the graphics
+ card memory.
+
+ Note that the display is locked while memory is unallocated in
+ order to preserve the memory pool's integrity.
+
+ This function will first sync the graphics card to ensure the
+ memory isn't still being used by a command in the graphics card
+ FIFO queue. It is possible to speed up a driver by overriding this
+ function to avoid syncing. For example, the driver might delay
+ deleting the memory until it detects that all commands dealing
+ with the memory are no longer in the queue. Note that it will then
+ be up to the driver to ensure that the specified \a memoryBlock no
+ longer is being used.
+
+ \sa cache(), deleteEntry(), clearCache()
+ */
+void QLinuxFbScreen::uncache(uchar * c)
+{
+ // need to sync graphics card
+
+ deleteEntry(c);
+}
+
+/*!
+ \fn void QLinuxFbScreen::deleteEntry(uchar * memoryBlock)
+
+ Deletes the specified \a memoryBlock allocated from the graphics
+ card memory.
+
+ \sa uncache(), cache(), clearCache()
+*/
+void QLinuxFbScreen::deleteEntry(uchar * c)
+{
+ qt_fbdpy->grab();
+ unsigned long pos=(unsigned long)c;
+ pos-=((unsigned long)data);
+ unsigned int hold=(*entryp);
+ for(unsigned int loopc=1;loopc<hold;loopc++) {
+ if (entries[loopc].start==pos) {
+ if (entries[loopc].clientId == qws_client_id)
+ delete_entry(loopc);
+ else
+ qWarning("Attempt to delete client id %d cache entry",
+ entries[loopc].clientId);
+ qt_fbdpy->ungrab();
+ return;
+ }
+ }
+ qt_fbdpy->ungrab();
+ qWarning("Attempt to delete unknown offset %ld",pos);
+}
+
+/*!
+ Removes all entries from the cache for the specified screen \a
+ instance and client identified by the given \a clientId.
+
+ Calling this function should only be necessary if a client exits
+ abnormally.
+
+ \sa cache(), uncache(), deleteEntry()
+*/
+void QLinuxFbScreen::clearCache(QScreen *instance, int clientId)
+{
+ QLinuxFbScreen *screen = (QLinuxFbScreen *)instance;
+ if (!screen->canaccel || !screen->entryp)
+ return;
+ qt_fbdpy->grab();
+ for (int loopc = 0; loopc < *(screen->entryp); loopc++) {
+ if (screen->entries[loopc].clientId == clientId) {
+ screen->delete_entry(loopc);
+ loopc--;
+ }
+ }
+ qt_fbdpy->ungrab();
+}
+
+
+void QLinuxFbScreen::setupOffScreen()
+{
+ // Figure out position of offscreen memory
+ // Set up pool entries pointer table and 64-bit align it
+ int psize = size;
+
+ // hw: this causes the limitation of cursors to 64x64
+ // the cursor should rather use the normal pixmap mechanism
+ psize += 4096; // cursor data
+ psize += 8; // for alignment
+ psize &= ~0x7; // align
+
+ unsigned long pos = (unsigned long)data;
+ pos += psize;
+ entryp = ((int *)pos);
+ lowest = ((unsigned int *)pos)+1;
+ pos += (sizeof(int))*4;
+ entries = (QPoolEntry *)pos;
+
+ // beginning of offscreen memory available for pixmaps.
+ cacheStart = psize + 4*sizeof(int) + sizeof(QPoolEntry);
+}
+
+/*!
+ \reimp
+
+ This is called by the \l{Qt for Embedded Linux} server when it shuts
+ down, and should be inherited if you need to do any card-specific cleanup.
+ The default version hides the screen cursor and reenables the blinking
+ cursor and screen blanking.
+*/
+
+void QLinuxFbScreen::shutdownDevice()
+{
+ // Causing crashes. Not needed.
+ //setMode(startupw,startuph,startupd);
+/*
+ if (startupd == 8) {
+ ioctl(fd,FBIOPUTCMAP,startcmap);
+ free(startcmap->red);
+ free(startcmap->green);
+ free(startcmap->blue);
+ free(startcmap->transp);
+ delete startcmap;
+ startcmap = 0;
+ }
+*/
+ d_ptr->closeTty();
+}
+
+/*!
+ \fn void QLinuxFbScreen::set(unsigned int index,unsigned int red,unsigned int green,unsigned int blue)
+
+ Sets the specified color \a index to the specified RGB value, (\a
+ red, \a green, \a blue), when in paletted graphics modes.
+*/
+
+void QLinuxFbScreen::set(unsigned int i,unsigned int r,unsigned int g,unsigned int b)
+{
+ if (d_ptr->fd != -1) {
+ fb_cmap cmap;
+ cmap.start=i;
+ cmap.len=1;
+ cmap.red=(unsigned short int *)
+ malloc(sizeof(unsigned short int)*256);
+ cmap.green=(unsigned short int *)
+ malloc(sizeof(unsigned short int)*256);
+ cmap.blue=(unsigned short int *)
+ malloc(sizeof(unsigned short int)*256);
+ cmap.transp=(unsigned short int *)
+ malloc(sizeof(unsigned short int)*256);
+ cmap.red[0]=r << 8;
+ cmap.green[0]=g << 8;
+ cmap.blue[0]=b << 8;
+ cmap.transp[0]=0;
+ ioctl(d_ptr->fd, FBIOPUTCMAP, &cmap);
+ free(cmap.red);
+ free(cmap.green);
+ free(cmap.blue);
+ free(cmap.transp);
+ }
+ screenclut[i] = qRgb(r, g, b);
+}
+
+/*!
+ \reimp
+
+ Sets the framebuffer to a new resolution and bit depth. The width is
+ in \a nw, the height is in \a nh, and the depth is in \a nd. After
+ doing this any currently-existing paint engines will be invalid and the
+ screen should be completely redrawn. In a multiple-process
+ Embedded Qt situation you must signal all other applications to
+ call setMode() to the same mode and redraw.
+*/
+
+void QLinuxFbScreen::setMode(int nw,int nh,int nd)
+{
+ if (d_ptr->fd == -1)
+ return;
+
+ fb_fix_screeninfo finfo;
+ fb_var_screeninfo vinfo;
+ //#######################
+ // Shut up Valgrind
+ memset(&vinfo, 0, sizeof(vinfo));
+ memset(&finfo, 0, sizeof(finfo));
+ //#######################
+
+ if (ioctl(d_ptr->fd, FBIOGET_VSCREENINFO, &vinfo)) {
+ perror("QLinuxFbScreen::setMode");
+ qFatal("Error reading variable information in mode change");
+ }
+
+ vinfo.xres=nw;
+ vinfo.yres=nh;
+ vinfo.bits_per_pixel=nd;
+
+ if (ioctl(d_ptr->fd, FBIOPUT_VSCREENINFO, &vinfo)) {
+ perror("QLinuxFbScreen::setMode");
+ qCritical("Error writing variable information in mode change");
+ }
+
+ if (ioctl(d_ptr->fd, FBIOGET_VSCREENINFO, &vinfo)) {
+ perror("QLinuxFbScreen::setMode");
+ qFatal("Error reading changed variable information in mode change");
+ }
+
+ if (ioctl(d_ptr->fd, FBIOGET_FSCREENINFO, &finfo)) {
+ perror("QLinuxFbScreen::setMode");
+ qFatal("Error reading fixed information");
+ }
+
+ fixupScreenInfo(finfo, vinfo);
+ disconnect();
+ connect(d_ptr->displaySpec);
+ exposeRegion(region(), 0);
+}
+
+// save the state of the graphics card
+// This is needed so that e.g. we can restore the palette when switching
+// between linux virtual consoles.
+
+/*!
+ \reimp
+
+ This doesn't do anything; accelerated drivers may wish to reimplement
+ it to save graphics cards registers. It's called by the
+ \l{Qt for Embedded Linux} server when the virtual console is switched.
+*/
+
+void QLinuxFbScreen::save()
+{
+ // nothing to do.
+}
+
+
+// restore the state of the graphics card.
+/*!
+ \reimp
+
+ This is called when the virtual console is switched back to
+ \l{Qt for Embedded Linux} and restores the palette.
+*/
+void QLinuxFbScreen::restore()
+{
+ if (d_ptr->fd == -1)
+ return;
+
+ if ((d == 8) || (d == 4)) {
+ fb_cmap cmap;
+ cmap.start=0;
+ cmap.len=screencols;
+ cmap.red=(unsigned short int *)
+ malloc(sizeof(unsigned short int)*256);
+ cmap.green=(unsigned short int *)
+ malloc(sizeof(unsigned short int)*256);
+ cmap.blue=(unsigned short int *)
+ malloc(sizeof(unsigned short int)*256);
+ cmap.transp=(unsigned short int *)
+ malloc(sizeof(unsigned short int)*256);
+ for (int loopc = 0; loopc < screencols; loopc++) {
+ cmap.red[loopc] = qRed(screenclut[loopc]) << 8;
+ cmap.green[loopc] = qGreen(screenclut[loopc]) << 8;
+ cmap.blue[loopc] = qBlue(screenclut[loopc]) << 8;
+ cmap.transp[loopc] = 0;
+ }
+ ioctl(d_ptr->fd, FBIOPUTCMAP, &cmap);
+ free(cmap.red);
+ free(cmap.green);
+ free(cmap.blue);
+ free(cmap.transp);
+ }
+}
+
+/*!
+ \fn int QLinuxFbScreen::sharedRamSize(void * end)
+ \internal
+*/
+
+// This works like the QScreenCursor code. end points to the end
+// of our shared structure, we return the amount of memory we reserved
+int QLinuxFbScreen::sharedRamSize(void * end)
+{
+ shared=(QLinuxFb_Shared *)end;
+ shared--;
+ return sizeof(QLinuxFb_Shared);
+}
+
+/*!
+ \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)
+ return;
+
+#if defined(QT_QWS_IPAQ)
+ if (on)
+ system("apm -suspend");
+#else
+ if (d_ptr->fd == -1)
+ return;
+// Some old kernel versions don't have this. These defines should go
+// away eventually
+#if defined(FBIOBLANK)
+#if defined(VESA_POWERDOWN) && defined(VESA_NO_BLANKING)
+ ioctl(d_ptr->fd, FBIOBLANK, on ? VESA_POWERDOWN : VESA_NO_BLANKING);
+#else
+ ioctl(d_ptr->fd, FBIOBLANK, on ? 1 : 0);
+#endif
+#endif
+#endif
+
+ d_ptr->blank = on;
+}
+
+void QLinuxFbScreen::setPixelFormat(struct fb_var_screeninfo info)
+{
+ const fb_bitfield rgba[4] = { info.red, info.green,
+ info.blue, info.transp };
+
+ QImage::Format format = QImage::Format_Invalid;
+
+ switch (d) {
+ case 32: {
+ const fb_bitfield argb8888[4] = {{16, 8, 0}, {8, 8, 0},
+ {0, 8, 0}, {24, 8, 0}};
+ const fb_bitfield abgr8888[4] = {{0, 8, 0}, {8, 8, 0},
+ {16, 8, 0}, {24, 8, 0}};
+ if (memcmp(rgba, argb8888, 4 * sizeof(fb_bitfield)) == 0) {
+ format = QImage::Format_ARGB32;
+ } else if (memcmp(rgba, argb8888, 3 * sizeof(fb_bitfield)) == 0) {
+ format = QImage::Format_RGB32;
+ } else if (memcmp(rgba, abgr8888, 3 * sizeof(fb_bitfield)) == 0) {
+ format = QImage::Format_RGB32;
+ pixeltype = QScreen::BGRPixel;
+ }
+ break;
+ }
+ case 24: {
+ const fb_bitfield rgb888[4] = {{16, 8, 0}, {8, 8, 0},
+ {0, 8, 0}, {0, 0, 0}};
+ const fb_bitfield bgr888[4] = {{0, 8, 0}, {8, 8, 0},
+ {16, 8, 0}, {0, 0, 0}};
+ if (memcmp(rgba, rgb888, 3 * sizeof(fb_bitfield)) == 0) {
+ format = QImage::Format_RGB888;
+ } else if (memcmp(rgba, bgr888, 3 * sizeof(fb_bitfield)) == 0) {
+ format = QImage::Format_RGB888;
+ pixeltype = QScreen::BGRPixel;
+ }
+ break;
+ }
+ case 18: {
+ const fb_bitfield rgb666[4] = {{12, 6, 0}, {6, 6, 0},
+ {0, 6, 0}, {0, 0, 0}};
+ if (memcmp(rgba, rgb666, 3 * sizeof(fb_bitfield)) == 0)
+ format = QImage::Format_RGB666;
+ break;
+ }
+ case 16: {
+ const fb_bitfield rgb565[4] = {{11, 5, 0}, {5, 6, 0},
+ {0, 5, 0}, {0, 0, 0}};
+ const fb_bitfield bgr565[4] = {{0, 5, 0}, {5, 6, 0},
+ {11, 5, 0}, {0, 0, 0}};
+ if (memcmp(rgba, rgb565, 3 * sizeof(fb_bitfield)) == 0) {
+ format = QImage::Format_RGB16;
+ } else if (memcmp(rgba, bgr565, 3 * sizeof(fb_bitfield)) == 0) {
+ format = QImage::Format_RGB16;
+ pixeltype = QScreen::BGRPixel;
+ }
+ break;
+ }
+ case 15: {
+ const fb_bitfield rgb1555[4] = {{10, 5, 0}, {5, 5, 0},
+ {0, 5, 0}, {15, 1, 0}};
+ const fb_bitfield bgr1555[4] = {{0, 5, 0}, {5, 5, 0},
+ {10, 5, 0}, {15, 1, 0}};
+ if (memcmp(rgba, rgb1555, 3 * sizeof(fb_bitfield)) == 0) {
+ format = QImage::Format_RGB555;
+ } else if (memcmp(rgba, bgr1555, 3 * sizeof(fb_bitfield)) == 0) {
+ format = QImage::Format_RGB555;
+ pixeltype = QScreen::BGRPixel;
+ }
+ break;
+ }
+ case 12: {
+ const fb_bitfield rgb444[4] = {{8, 4, 0}, {4, 4, 0},
+ {0, 4, 0}, {0, 0, 0}};
+ if (memcmp(rgba, rgb444, 3 * sizeof(fb_bitfield)) == 0)
+ format = QImage::Format_RGB444;
+ break;
+ }
+ case 8:
+ break;
+ case 1:
+ format = QImage::Format_Mono; //###: LSB???
+ break;
+ default:
+ break;
+ }
+
+ QScreen::setPixelFormat(format);
+}
+
+bool QLinuxFbScreen::useOffscreen()
+{
+ // 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;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_QWS_LINUXFB