src/gui/embedded/qscreenlinuxfb_qws.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qscreenlinuxfb_qws.h"
       
    43 
       
    44 #ifndef QT_NO_QWS_LINUXFB
       
    45 //#include "qmemorymanager_qws.h"
       
    46 #include "qwsdisplay_qws.h"
       
    47 #include "qpixmap.h"
       
    48 #include <private/qwssignalhandler_p.h>
       
    49 #include <private/qcore_unix_p.h> // overrides QT_OPEN
       
    50 
       
    51 #include <unistd.h>
       
    52 #include <stdlib.h>
       
    53 #include <sys/ioctl.h>
       
    54 #include <sys/types.h>
       
    55 #include <sys/stat.h>
       
    56 #include <sys/mman.h>
       
    57 #include <sys/kd.h>
       
    58 #include <fcntl.h>
       
    59 #include <errno.h>
       
    60 #include <stdio.h>
       
    61 #include <limits.h>
       
    62 #include <signal.h>
       
    63 
       
    64 #include "qwindowsystem_qws.h"
       
    65 
       
    66 #if !defined(Q_OS_DARWIN) && !defined(Q_OS_FREEBSD)
       
    67 #include <linux/fb.h>
       
    68 
       
    69 #ifdef __i386__
       
    70 #include <asm/mtrr.h>
       
    71 #endif
       
    72 #endif
       
    73 
       
    74 QT_BEGIN_NAMESPACE
       
    75 
       
    76 extern int qws_client_id;
       
    77 
       
    78 //#define DEBUG_CACHE
       
    79 
       
    80 class QLinuxFbScreenPrivate : public QObject
       
    81 {
       
    82 public:
       
    83     QLinuxFbScreenPrivate();
       
    84     ~QLinuxFbScreenPrivate();
       
    85 
       
    86     void openTty();
       
    87     void closeTty();
       
    88 
       
    89     int fd;
       
    90     int startupw;
       
    91     int startuph;
       
    92     int startupd;
       
    93     bool blank;
       
    94 
       
    95     bool doGraphicsMode;
       
    96 #ifdef QT_QWS_DEPTH_GENERIC
       
    97     bool doGenericColors;
       
    98 #endif
       
    99     int ttyfd;
       
   100     long oldKdMode;
       
   101     QString ttyDevice;
       
   102     QString displaySpec;
       
   103 };
       
   104 
       
   105 QLinuxFbScreenPrivate::QLinuxFbScreenPrivate()
       
   106     : fd(-1), blank(true), doGraphicsMode(true),
       
   107 #ifdef QT_QWS_DEPTH_GENERIC
       
   108       doGenericColors(false),
       
   109 #endif
       
   110       ttyfd(-1), oldKdMode(KD_TEXT)
       
   111 {
       
   112     QWSSignalHandler::instance()->addObject(this);
       
   113 }
       
   114 
       
   115 QLinuxFbScreenPrivate::~QLinuxFbScreenPrivate()
       
   116 {
       
   117     closeTty();
       
   118 }
       
   119 
       
   120 void QLinuxFbScreenPrivate::openTty()
       
   121 {
       
   122     const char *const devs[] = {"/dev/tty0", "/dev/tty", "/dev/console", 0};
       
   123 
       
   124     if (ttyDevice.isEmpty()) {
       
   125         for (const char * const *dev = devs; *dev; ++dev) {
       
   126             ttyfd = QT_OPEN(*dev, O_RDWR);
       
   127             if (ttyfd != -1)
       
   128                 break;
       
   129         }
       
   130     } else {
       
   131         ttyfd = QT_OPEN(ttyDevice.toAscii().constData(), O_RDWR);
       
   132     }
       
   133 
       
   134     if (ttyfd == -1)
       
   135         return;
       
   136 
       
   137     if (doGraphicsMode) {
       
   138         ioctl(ttyfd, KDGETMODE, &oldKdMode);
       
   139         if (oldKdMode != KD_GRAPHICS) {
       
   140             int ret = ioctl(ttyfd, KDSETMODE, KD_GRAPHICS);
       
   141             if (ret == -1)
       
   142                 doGraphicsMode = false;
       
   143         }
       
   144     }
       
   145 
       
   146     // No blankin' screen, no blinkin' cursor!, no cursor!
       
   147     const char termctl[] = "\033[9;0]\033[?33l\033[?25l\033[?1c";
       
   148     QT_WRITE(ttyfd, termctl, sizeof(termctl));
       
   149 }
       
   150 
       
   151 void QLinuxFbScreenPrivate::closeTty()
       
   152 {
       
   153     if (ttyfd == -1)
       
   154         return;
       
   155 
       
   156     if (doGraphicsMode)
       
   157         ioctl(ttyfd, KDSETMODE, oldKdMode);
       
   158 
       
   159     // Blankin' screen, blinkin' cursor!
       
   160     const char termctl[] = "\033[9;15]\033[?33h\033[?25h\033[?0c";
       
   161     QT_WRITE(ttyfd, termctl, sizeof(termctl));
       
   162 
       
   163     QT_CLOSE(ttyfd);
       
   164     ttyfd = -1;
       
   165 }
       
   166 
       
   167 /*!
       
   168     \internal
       
   169 
       
   170     \class QLinuxFbScreen
       
   171     \ingroup qws
       
   172 
       
   173     \brief The QLinuxFbScreen class implements a screen driver for the
       
   174     Linux framebuffer.
       
   175 
       
   176     Note that this class is only available in \l{Qt for Embedded Linux}.
       
   177     Custom screen drivers can be added by subclassing the
       
   178     QScreenDriverPlugin class, using the QScreenDriverFactory class to
       
   179     dynamically load the driver into the application, but there should
       
   180     only be one screen object per application.
       
   181 
       
   182     The QLinuxFbScreen class provides the cache() function allocating
       
   183     off-screen graphics memory, and the complementary uncache()
       
   184     function releasing the allocated memory. The latter function will
       
   185     first sync the graphics card to ensure the memory isn't still
       
   186     being used by a command in the graphics card FIFO queue. The
       
   187     deleteEntry() function deletes the given memory block without such
       
   188     synchronization.  Given the screen instance and client id, the
       
   189     memory can also be released using the clearCache() function, but
       
   190     this should only be necessary if a client exits abnormally.
       
   191 
       
   192     In addition, when in paletted graphics modes, the set() function
       
   193     provides the possibility of setting a specified color index to a
       
   194     given RGB value.
       
   195 
       
   196     The QLinuxFbScreen class also acts as a factory for the
       
   197     unaccelerated screen cursor and the unaccelerated raster-based
       
   198     implementation of QPaintEngine (\c QRasterPaintEngine);
       
   199     accelerated drivers for Linux should derive from this class.
       
   200 
       
   201     \sa QScreen, QScreenDriverPlugin, {Running Applications}
       
   202 */
       
   203 
       
   204 /*!
       
   205     \fn bool QLinuxFbScreen::useOffscreen()
       
   206     \internal
       
   207 */
       
   208 
       
   209 // Unaccelerated screen/driver setup. Can be overridden by accelerated
       
   210 // drivers
       
   211 
       
   212 /*!
       
   213     \fn QLinuxFbScreen::QLinuxFbScreen(int displayId)
       
   214 
       
   215     Constructs a QLinuxFbScreen object. The \a displayId argument
       
   216     identifies the Qt for Embedded Linux server to connect to.
       
   217 */
       
   218 
       
   219 QLinuxFbScreen::QLinuxFbScreen(int display_id)
       
   220     : QScreen(display_id, LinuxFBClass), d_ptr(new QLinuxFbScreenPrivate)
       
   221 {
       
   222     canaccel=false;
       
   223     clearCacheFunc = &clearCache;
       
   224 #ifdef QT_QWS_CLIENTBLIT
       
   225     setSupportsBlitInClients(true);
       
   226 #endif
       
   227 }
       
   228 
       
   229 /*!
       
   230     Destroys this QLinuxFbScreen object.
       
   231 */
       
   232 
       
   233 QLinuxFbScreen::~QLinuxFbScreen()
       
   234 {
       
   235 }
       
   236 
       
   237 /*!
       
   238     \reimp
       
   239 
       
   240     This is called by \l{Qt for Embedded Linux} clients to map in the framebuffer.
       
   241     It should be reimplemented by accelerated drivers to map in
       
   242     graphics card registers; those drivers should then call this
       
   243     function in order to set up offscreen memory management. The
       
   244     device is specified in \a displaySpec; e.g. "/dev/fb".
       
   245 
       
   246     \sa disconnect()
       
   247 */
       
   248 
       
   249 bool QLinuxFbScreen::connect(const QString &displaySpec)
       
   250 {
       
   251     d_ptr->displaySpec = displaySpec;
       
   252 
       
   253     const QStringList args = displaySpec.split(QLatin1Char(':'));
       
   254 
       
   255     if (args.contains(QLatin1String("nographicsmodeswitch")))
       
   256         d_ptr->doGraphicsMode = false;
       
   257 
       
   258 #ifdef QT_QWS_DEPTH_GENERIC
       
   259     if (args.contains(QLatin1String("genericcolors")))
       
   260         d_ptr->doGenericColors = true;
       
   261 #endif
       
   262 
       
   263     QRegExp ttyRegExp(QLatin1String("tty=(.*)"));
       
   264     if (args.indexOf(ttyRegExp) != -1)
       
   265         d_ptr->ttyDevice = ttyRegExp.cap(1);
       
   266 
       
   267 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
       
   268 #ifndef QT_QWS_FRAMEBUFFER_LITTLE_ENDIAN
       
   269     if (args.contains(QLatin1String("littleendian")))
       
   270 #endif
       
   271         QScreen::setFrameBufferLittleEndian(true);
       
   272 #endif
       
   273 
       
   274     QString dev = QLatin1String("/dev/fb0");
       
   275     foreach(QString d, args) {
       
   276 	if (d.startsWith(QLatin1Char('/'))) {
       
   277 	    dev = d;
       
   278 	    break;
       
   279 	}
       
   280     }
       
   281 
       
   282     if (access(dev.toLatin1().constData(), R_OK|W_OK) == 0)
       
   283         d_ptr->fd = QT_OPEN(dev.toLatin1().constData(), O_RDWR);
       
   284     if (d_ptr->fd == -1) {
       
   285         if (QApplication::type() == QApplication::GuiServer) {
       
   286             perror("QScreenLinuxFb::connect");
       
   287             qCritical("Error opening framebuffer device %s", qPrintable(dev));
       
   288             return false;
       
   289         }
       
   290         if (access(dev.toLatin1().constData(), R_OK) == 0)
       
   291             d_ptr->fd = QT_OPEN(dev.toLatin1().constData(), O_RDONLY);
       
   292     }
       
   293 
       
   294     ::fb_fix_screeninfo finfo;
       
   295     ::fb_var_screeninfo vinfo;
       
   296     //#######################
       
   297     // Shut up Valgrind
       
   298     memset(&vinfo, 0, sizeof(vinfo));
       
   299     memset(&finfo, 0, sizeof(finfo));
       
   300     //#######################
       
   301 
       
   302     /* Get fixed screen information */
       
   303     if (d_ptr->fd != -1 && ioctl(d_ptr->fd, FBIOGET_FSCREENINFO, &finfo)) {
       
   304         perror("QLinuxFbScreen::connect");
       
   305         qWarning("Error reading fixed information");
       
   306         return false;
       
   307     }
       
   308 
       
   309     if (finfo.type == FB_TYPE_VGA_PLANES) {
       
   310         qWarning("VGA16 video mode not supported");
       
   311         return false;
       
   312     }
       
   313 
       
   314     /* Get variable screen information */
       
   315     if (d_ptr->fd != -1 && ioctl(d_ptr->fd, FBIOGET_VSCREENINFO, &vinfo)) {
       
   316         perror("QLinuxFbScreen::connect");
       
   317         qWarning("Error reading variable information");
       
   318         return false;
       
   319     }
       
   320 
       
   321     grayscale = vinfo.grayscale;
       
   322     d = vinfo.bits_per_pixel;
       
   323     if (d == 24) {
       
   324         d = vinfo.red.length + vinfo.green.length + vinfo.blue.length;
       
   325         if (d <= 0)
       
   326             d = 24; // reset if color component lengths are not reported
       
   327     } else if (d == 16) {
       
   328         d = vinfo.red.length + vinfo.green.length + vinfo.blue.length;
       
   329         if (d <= 0)
       
   330             d = 16;
       
   331     }
       
   332     lstep = finfo.line_length;
       
   333 
       
   334     int xoff = vinfo.xoffset;
       
   335     int yoff = vinfo.yoffset;
       
   336     const char* qwssize;
       
   337     if((qwssize=::getenv("QWS_SIZE")) && sscanf(qwssize,"%dx%d",&w,&h)==2) {
       
   338         if (d_ptr->fd != -1) {
       
   339             if ((uint)w > vinfo.xres) w = vinfo.xres;
       
   340             if ((uint)h > vinfo.yres) h = vinfo.yres;
       
   341         }
       
   342         dw=w;
       
   343         dh=h;
       
   344         int xxoff, yyoff;
       
   345         if (sscanf(qwssize, "%*dx%*d+%d+%d", &xxoff, &yyoff) == 2) {
       
   346             if (xxoff < 0 || xxoff + w > vinfo.xres)
       
   347                 xxoff = vinfo.xres - w;
       
   348             if (yyoff < 0 || yyoff + h > vinfo.yres)
       
   349                 yyoff = vinfo.yres - h;
       
   350             xoff += xxoff;
       
   351             yoff += yyoff;
       
   352         } else {
       
   353             xoff += (vinfo.xres - w)/2;
       
   354             yoff += (vinfo.yres - h)/2;
       
   355         }
       
   356     } else {
       
   357         dw=w=vinfo.xres;
       
   358         dh=h=vinfo.yres;
       
   359     }
       
   360 
       
   361     if (w == 0 || h == 0) {
       
   362         qWarning("QScreenLinuxFb::connect(): Unable to find screen geometry, "
       
   363                  "will use 320x240.");
       
   364         dw = w = 320;
       
   365         dh = h = 240;
       
   366     }
       
   367 
       
   368     setPixelFormat(vinfo);
       
   369 
       
   370     // Handle display physical size spec.
       
   371     QStringList displayArgs = displaySpec.split(QLatin1Char(':'));
       
   372     QRegExp mmWidthRx(QLatin1String("mmWidth=?(\\d+)"));
       
   373     int dimIdxW = displayArgs.indexOf(mmWidthRx);
       
   374     QRegExp mmHeightRx(QLatin1String("mmHeight=?(\\d+)"));
       
   375     int dimIdxH = displayArgs.indexOf(mmHeightRx);
       
   376     if (dimIdxW >= 0) {
       
   377         mmWidthRx.exactMatch(displayArgs.at(dimIdxW));
       
   378         physWidth = mmWidthRx.cap(1).toInt();
       
   379         if (dimIdxH < 0)
       
   380             physHeight = dh*physWidth/dw;
       
   381     }
       
   382     if (dimIdxH >= 0) {
       
   383         mmHeightRx.exactMatch(displayArgs.at(dimIdxH));
       
   384         physHeight = mmHeightRx.cap(1).toInt();
       
   385         if (dimIdxW < 0)
       
   386             physWidth = dw*physHeight/dh;
       
   387     }
       
   388     if (dimIdxW < 0 && dimIdxH < 0) {
       
   389         if (vinfo.width != 0 && vinfo.height != 0
       
   390             && vinfo.width != UINT_MAX && vinfo.height != UINT_MAX) {
       
   391             physWidth = vinfo.width;
       
   392             physHeight = vinfo.height;
       
   393         } else {
       
   394             const int dpi = 72;
       
   395             physWidth = qRound(dw * 25.4 / dpi);
       
   396             physHeight = qRound(dh * 25.4 / dpi);
       
   397         }
       
   398     }
       
   399 
       
   400     dataoffset = yoff * lstep + xoff * d / 8;
       
   401     //qDebug("Using %dx%dx%d screen",w,h,d);
       
   402 
       
   403     /* Figure out the size of the screen in bytes */
       
   404     size = h * lstep;
       
   405 
       
   406     mapsize = finfo.smem_len;
       
   407 
       
   408     data = (unsigned char *)-1;
       
   409     if (d_ptr->fd != -1)
       
   410         data = (unsigned char *)mmap(0, mapsize, PROT_READ | PROT_WRITE,
       
   411                                      MAP_SHARED, d_ptr->fd, 0);
       
   412 
       
   413     if ((long)data == -1) {
       
   414         if (QApplication::type() == QApplication::GuiServer) {
       
   415             perror("QLinuxFbScreen::connect");
       
   416             qWarning("Error: failed to map framebuffer device to memory.");
       
   417             return false;
       
   418         }
       
   419         data = 0;
       
   420     } else {
       
   421         data += dataoffset;
       
   422     }
       
   423 
       
   424     canaccel = useOffscreen();
       
   425     if(canaccel)
       
   426         setupOffScreen();
       
   427 
       
   428     // Now read in palette
       
   429     if((vinfo.bits_per_pixel==8) || (vinfo.bits_per_pixel==4)) {
       
   430         screencols= (vinfo.bits_per_pixel==8) ? 256 : 16;
       
   431         int loopc;
       
   432         ::fb_cmap startcmap;
       
   433         startcmap.start=0;
       
   434         startcmap.len=screencols;
       
   435         startcmap.red=(unsigned short int *)
       
   436                  malloc(sizeof(unsigned short int)*screencols);
       
   437         startcmap.green=(unsigned short int *)
       
   438                    malloc(sizeof(unsigned short int)*screencols);
       
   439         startcmap.blue=(unsigned short int *)
       
   440                   malloc(sizeof(unsigned short int)*screencols);
       
   441         startcmap.transp=(unsigned short int *)
       
   442                     malloc(sizeof(unsigned short int)*screencols);
       
   443         if (d_ptr->fd == -1 || ioctl(d_ptr->fd, FBIOGETCMAP, &startcmap)) {
       
   444             perror("QLinuxFbScreen::connect");
       
   445             qWarning("Error reading palette from framebuffer, using default palette");
       
   446             createPalette(startcmap, vinfo, finfo);
       
   447         }
       
   448         int bits_used = 0;
       
   449         for(loopc=0;loopc<screencols;loopc++) {
       
   450             screenclut[loopc]=qRgb(startcmap.red[loopc] >> 8,
       
   451                                    startcmap.green[loopc] >> 8,
       
   452                                    startcmap.blue[loopc] >> 8);
       
   453             bits_used |= startcmap.red[loopc]
       
   454                          | startcmap.green[loopc]
       
   455                          | startcmap.blue[loopc];
       
   456         }
       
   457         // WORKAROUND: Some framebuffer drivers only return 8 bit
       
   458         // color values, so we need to not bit shift them..
       
   459         if ((bits_used & 0x00ff) && !(bits_used & 0xff00)) {
       
   460             for(loopc=0;loopc<screencols;loopc++) {
       
   461                 screenclut[loopc] = qRgb(startcmap.red[loopc],
       
   462                                          startcmap.green[loopc],
       
   463                                          startcmap.blue[loopc]);
       
   464             }
       
   465             qWarning("8 bits cmap returned due to faulty FB driver, colors corrected");
       
   466         }
       
   467         free(startcmap.red);
       
   468         free(startcmap.green);
       
   469         free(startcmap.blue);
       
   470         free(startcmap.transp);
       
   471     } else {
       
   472         screencols=0;
       
   473     }
       
   474 
       
   475     return true;
       
   476 }
       
   477 
       
   478 /*!
       
   479     \reimp
       
   480 
       
   481     This unmaps the framebuffer.
       
   482 
       
   483     \sa connect()
       
   484 */
       
   485 
       
   486 void QLinuxFbScreen::disconnect()
       
   487 {
       
   488     data -= dataoffset;
       
   489     if (data)
       
   490         munmap((char*)data,mapsize);
       
   491     close(d_ptr->fd);
       
   492 }
       
   493 
       
   494 // #define DEBUG_VINFO
       
   495 
       
   496 void QLinuxFbScreen::createPalette(fb_cmap &cmap, fb_var_screeninfo &vinfo, fb_fix_screeninfo &finfo)
       
   497 {
       
   498     if((vinfo.bits_per_pixel==8) || (vinfo.bits_per_pixel==4)) {
       
   499         screencols= (vinfo.bits_per_pixel==8) ? 256 : 16;
       
   500         cmap.start=0;
       
   501         cmap.len=screencols;
       
   502         cmap.red=(unsigned short int *)
       
   503                  malloc(sizeof(unsigned short int)*screencols);
       
   504         cmap.green=(unsigned short int *)
       
   505                    malloc(sizeof(unsigned short int)*screencols);
       
   506         cmap.blue=(unsigned short int *)
       
   507                   malloc(sizeof(unsigned short int)*screencols);
       
   508         cmap.transp=(unsigned short int *)
       
   509                     malloc(sizeof(unsigned short int)*screencols);
       
   510 
       
   511         if (screencols==16) {
       
   512             if (finfo.type == FB_TYPE_PACKED_PIXELS) {
       
   513                 // We'll setup a grayscale cmap for 4bpp linear
       
   514                 int val = 0;
       
   515                 for (int idx = 0; idx < 16; ++idx, val += 17) {
       
   516                     cmap.red[idx] = (val<<8)|val;
       
   517                     cmap.green[idx] = (val<<8)|val;
       
   518                     cmap.blue[idx] = (val<<8)|val;
       
   519                     screenclut[idx]=qRgb(val, val, val);
       
   520                 }
       
   521             } else {
       
   522                 // Default 16 colour palette
       
   523                 // Green is now trolltech green so certain images look nicer
       
   524                 //                             black  d_gray l_gray white  red  green  blue cyan magenta yellow
       
   525                 unsigned char reds[16]   = { 0x00, 0x7F, 0xBF, 0xFF, 0xFF, 0xA2, 0x00, 0xFF, 0xFF, 0x00, 0x7F, 0x7F, 0x00, 0x00, 0x00, 0x82 };
       
   526                 unsigned char greens[16] = { 0x00, 0x7F, 0xBF, 0xFF, 0x00, 0xC5, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x7F };
       
   527                 unsigned char blues[16]  = { 0x00, 0x7F, 0xBF, 0xFF, 0x00, 0x11, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x7F, 0x7F, 0x7F, 0x00, 0x00 };
       
   528 
       
   529                 for (int idx = 0; idx < 16; ++idx) {
       
   530                     cmap.red[idx] = ((reds[idx]) << 8)|reds[idx];
       
   531                     cmap.green[idx] = ((greens[idx]) << 8)|greens[idx];
       
   532                     cmap.blue[idx] = ((blues[idx]) << 8)|blues[idx];
       
   533                     cmap.transp[idx] = 0;
       
   534                     screenclut[idx]=qRgb(reds[idx], greens[idx], blues[idx]);
       
   535                 }
       
   536             }
       
   537         } else {
       
   538             if (grayscale) {
       
   539                 // Build grayscale palette
       
   540                 int i;
       
   541                 for(i=0;i<screencols;++i) {
       
   542                     int bval = screencols == 256 ? i : (i << 4);
       
   543                     ushort val = (bval << 8) | bval;
       
   544                     cmap.red[i] = val;
       
   545                     cmap.green[i] = val;
       
   546                     cmap.blue[i] = val;
       
   547                     cmap.transp[i] = 0;
       
   548                     screenclut[i] = qRgb(bval,bval,bval);
       
   549                 }
       
   550             } else {
       
   551                 // 6x6x6 216 color cube
       
   552                 int idx = 0;
       
   553                 for(int ir = 0x0; ir <= 0xff; ir+=0x33) {
       
   554                     for(int ig = 0x0; ig <= 0xff; ig+=0x33) {
       
   555                         for(int ib = 0x0; ib <= 0xff; ib+=0x33) {
       
   556                             cmap.red[idx] = (ir << 8)|ir;
       
   557                             cmap.green[idx] = (ig << 8)|ig;
       
   558                             cmap.blue[idx] = (ib << 8)|ib;
       
   559                             cmap.transp[idx] = 0;
       
   560                             screenclut[idx]=qRgb(ir, ig, ib);
       
   561                             ++idx;
       
   562                         }
       
   563                     }
       
   564                 }
       
   565                 // Fill in rest with 0
       
   566                 for (int loopc=0; loopc<40; ++loopc) {
       
   567                     screenclut[idx]=0;
       
   568                     ++idx;
       
   569                 }
       
   570                 screencols=idx;
       
   571             }
       
   572         }
       
   573     } else if(finfo.visual==FB_VISUAL_DIRECTCOLOR) {
       
   574         cmap.start=0;
       
   575         int rbits=0,gbits=0,bbits=0;
       
   576         switch (vinfo.bits_per_pixel) {
       
   577         case 8:
       
   578             rbits=vinfo.red.length;
       
   579             gbits=vinfo.green.length;
       
   580             bbits=vinfo.blue.length;
       
   581             if(rbits==0 && gbits==0 && bbits==0) {
       
   582                 // cyber2000 driver bug hack
       
   583                 rbits=3;
       
   584                 gbits=3;
       
   585                 bbits=2;
       
   586             }
       
   587             break;
       
   588         case 15:
       
   589             rbits=5;
       
   590             gbits=5;
       
   591             bbits=5;
       
   592             break;
       
   593         case 16:
       
   594             rbits=5;
       
   595             gbits=6;
       
   596             bbits=5;
       
   597             break;
       
   598         case 18:
       
   599         case 19:
       
   600             rbits=6;
       
   601             gbits=6;
       
   602             bbits=6;
       
   603             break;
       
   604         case 24: case 32:
       
   605             rbits=gbits=bbits=8;
       
   606             break;
       
   607         }
       
   608         screencols=cmap.len=1<<qMax(rbits,qMax(gbits,bbits));
       
   609         cmap.red=(unsigned short int *)
       
   610                  malloc(sizeof(unsigned short int)*256);
       
   611         cmap.green=(unsigned short int *)
       
   612                    malloc(sizeof(unsigned short int)*256);
       
   613         cmap.blue=(unsigned short int *)
       
   614                   malloc(sizeof(unsigned short int)*256);
       
   615         cmap.transp=(unsigned short int *)
       
   616                     malloc(sizeof(unsigned short int)*256);
       
   617         for(unsigned int i = 0x0; i < cmap.len; i++) {
       
   618             cmap.red[i] = i*65535/((1<<rbits)-1);
       
   619             cmap.green[i] = i*65535/((1<<gbits)-1);
       
   620             cmap.blue[i] = i*65535/((1<<bbits)-1);
       
   621             cmap.transp[i] = 0;
       
   622         }
       
   623     }
       
   624 }
       
   625 
       
   626 /*!
       
   627     \reimp
       
   628 
       
   629     This is called by the \l{Qt for Embedded Linux} server at startup time.
       
   630     It turns off console blinking, sets up the color palette, enables write
       
   631     combining on the framebuffer and initialises the off-screen memory
       
   632     manager.
       
   633 */
       
   634 
       
   635 bool QLinuxFbScreen::initDevice()
       
   636 {
       
   637     d_ptr->openTty();
       
   638 
       
   639     // Grab current mode so we can reset it
       
   640     fb_var_screeninfo vinfo;
       
   641     fb_fix_screeninfo finfo;
       
   642     //#######################
       
   643     // Shut up Valgrind
       
   644     memset(&vinfo, 0, sizeof(vinfo));
       
   645     memset(&finfo, 0, sizeof(finfo));
       
   646     //#######################
       
   647 
       
   648     if (ioctl(d_ptr->fd, FBIOGET_VSCREENINFO, &vinfo)) {
       
   649         perror("QLinuxFbScreen::initDevice");
       
   650         qFatal("Error reading variable information in card init");
       
   651         return false;
       
   652     }
       
   653 
       
   654 #ifdef DEBUG_VINFO
       
   655     qDebug("Greyscale %d",vinfo.grayscale);
       
   656     qDebug("Nonstd %d",vinfo.nonstd);
       
   657     qDebug("Red %d %d %d",vinfo.red.offset,vinfo.red.length,
       
   658            vinfo.red.msb_right);
       
   659     qDebug("Green %d %d %d",vinfo.green.offset,vinfo.green.length,
       
   660            vinfo.green.msb_right);
       
   661     qDebug("Blue %d %d %d",vinfo.blue.offset,vinfo.blue.length,
       
   662            vinfo.blue.msb_right);
       
   663     qDebug("Transparent %d %d %d",vinfo.transp.offset,vinfo.transp.length,
       
   664            vinfo.transp.msb_right);
       
   665 #endif
       
   666 
       
   667     d_ptr->startupw=vinfo.xres;
       
   668     d_ptr->startuph=vinfo.yres;
       
   669     d_ptr->startupd=vinfo.bits_per_pixel;
       
   670     grayscale = vinfo.grayscale;
       
   671 
       
   672     if (ioctl(d_ptr->fd, FBIOGET_FSCREENINFO, &finfo)) {
       
   673         perror("QLinuxFbScreen::initDevice");
       
   674         qCritical("Error reading fixed information in card init");
       
   675         // It's not an /error/ as such, though definitely a bad sign
       
   676         // so we return true
       
   677         return true;
       
   678     }
       
   679 
       
   680 #ifdef __i386__
       
   681     // Now init mtrr
       
   682     if(!::getenv("QWS_NOMTRR")) {
       
   683         int mfd=QT_OPEN("/proc/mtrr",O_WRONLY,0);
       
   684         // MTRR entry goes away when file is closed - i.e.
       
   685         // hopefully when QWS is killed
       
   686         if(mfd != -1) {
       
   687             mtrr_sentry sentry;
       
   688             sentry.base=(unsigned long int)finfo.smem_start;
       
   689             //qDebug("Physical framebuffer address %p",(void*)finfo.smem_start);
       
   690             // Size needs to be in 4k chunks, but that's not always
       
   691             // what we get thanks to graphics card registers. Write combining
       
   692             // these is Not Good, so we write combine what we can
       
   693             // (which is not much - 4 megs on an 8 meg card, it seems)
       
   694             unsigned int size=finfo.smem_len;
       
   695             size=size >> 22;
       
   696             size=size << 22;
       
   697             sentry.size=size;
       
   698             sentry.type=MTRR_TYPE_WRCOMB;
       
   699             if(ioctl(mfd,MTRRIOC_ADD_ENTRY,&sentry)==-1) {
       
   700                 //printf("Couldn't add mtrr entry for %lx %lx, %s\n",
       
   701                 //sentry.base,sentry.size,strerror(errno));
       
   702             }
       
   703         }
       
   704 
       
   705         // Should we close mfd here?
       
   706         //QT_CLOSE(mfd);
       
   707     }
       
   708 #endif
       
   709     if ((vinfo.bits_per_pixel==8) || (vinfo.bits_per_pixel==4) || (finfo.visual==FB_VISUAL_DIRECTCOLOR))
       
   710     {
       
   711         fb_cmap cmap;
       
   712         createPalette(cmap, vinfo, finfo);
       
   713         if (ioctl(d_ptr->fd, FBIOPUTCMAP, &cmap)) {
       
   714             perror("QLinuxFbScreen::initDevice");
       
   715             qWarning("Error writing palette to framebuffer");
       
   716         }
       
   717         free(cmap.red);
       
   718         free(cmap.green);
       
   719         free(cmap.blue);
       
   720         free(cmap.transp);
       
   721     }
       
   722 
       
   723     if (canaccel) {
       
   724         *entryp=0;
       
   725         *lowest = mapsize;
       
   726         insert_entry(*entryp, *lowest, *lowest);  // dummy entry to mark start
       
   727     }
       
   728 
       
   729     shared->fifocount = 0;
       
   730     shared->buffer_offset = 0xffffffff;  // 0 would be a sensible offset (screen)
       
   731     shared->linestep = 0;
       
   732     shared->cliptop = 0xffffffff;
       
   733     shared->clipleft = 0xffffffff;
       
   734     shared->clipright = 0xffffffff;
       
   735     shared->clipbottom = 0xffffffff;
       
   736     shared->rop = 0xffffffff;
       
   737 
       
   738 #ifdef QT_QWS_DEPTH_GENERIC
       
   739     if (pixelFormat() == QImage::Format_Invalid && screencols == 0
       
   740         && d_ptr->doGenericColors)
       
   741     {
       
   742         qt_set_generic_blit(this, vinfo.bits_per_pixel,
       
   743                             vinfo.red.length, vinfo.green.length,
       
   744                             vinfo.blue.length, vinfo.transp.length,
       
   745                             vinfo.red.offset, vinfo.green.offset,
       
   746                             vinfo.blue.offset, vinfo.transp.offset);
       
   747     }
       
   748 #endif
       
   749 
       
   750 #ifndef QT_NO_QWS_CURSOR
       
   751     QScreenCursor::initSoftwareCursor();
       
   752 #endif
       
   753     blank(false);
       
   754 
       
   755     return true;
       
   756 }
       
   757 
       
   758 /*
       
   759   The offscreen memory manager's list of entries is stored at the bottom
       
   760   of the offscreen memory area and consistes of a series of QPoolEntry's,
       
   761   each of which keep track of a block of allocated memory. Unallocated memory
       
   762   is implicitly indicated by the gap between blocks indicated by QPoolEntry's.
       
   763   The memory manager looks through any unallocated memory before the end
       
   764   of currently-allocated memory to see if a new block will fit in the gap;
       
   765   if it doesn't it allocated it from the end of currently-allocated memory.
       
   766   Memory is allocated from the top of the framebuffer downwards; if it hits
       
   767   the list of entries then offscreen memory is full and further allocations
       
   768   are made from main RAM (and hence unaccelerated). Allocated memory can
       
   769   be seen as a sort of upside-down stack; lowest keeps track of the
       
   770   bottom of the stack.
       
   771 */
       
   772 
       
   773 void QLinuxFbScreen::delete_entry(int pos)
       
   774 {
       
   775     if (pos > *entryp || pos < 0) {
       
   776         qWarning("Attempt to delete odd pos! %d %d", pos, *entryp);
       
   777         return;
       
   778     }
       
   779 
       
   780 #ifdef DEBUG_CACHE
       
   781     qDebug("Remove entry: %d", pos);
       
   782 #endif
       
   783 
       
   784     QPoolEntry *qpe = &entries[pos];
       
   785     if (qpe->start <= *lowest) {
       
   786         // Lowest goes up again
       
   787         *lowest = entries[pos-1].start;
       
   788 #ifdef DEBUG_CACHE
       
   789         qDebug("   moved lowest to %d", *lowest);
       
   790 #endif
       
   791     }
       
   792 
       
   793     (*entryp)--;
       
   794     if (pos == *entryp)
       
   795         return;
       
   796 
       
   797     int size = (*entryp)-pos;
       
   798     memmove(&entries[pos], &entries[pos+1], size*sizeof(QPoolEntry));
       
   799 }
       
   800 
       
   801 void QLinuxFbScreen::insert_entry(int pos, int start, int end)
       
   802 {
       
   803     if (pos > *entryp) {
       
   804         qWarning("Attempt to insert odd pos! %d %d",pos,*entryp);
       
   805         return;
       
   806     }
       
   807 
       
   808 #ifdef DEBUG_CACHE
       
   809     qDebug("Insert entry: %d, %d -> %d", pos, start, end);
       
   810 #endif
       
   811 
       
   812     if (start < (int)*lowest) {
       
   813         *lowest = start;
       
   814 #ifdef DEBUG_CACHE
       
   815         qDebug("    moved lowest to %d", *lowest);
       
   816 #endif
       
   817     }
       
   818 
       
   819     if (pos == *entryp) {
       
   820         entries[pos].start = start;
       
   821         entries[pos].end = end;
       
   822         entries[pos].clientId = qws_client_id;
       
   823         (*entryp)++;
       
   824         return;
       
   825     }
       
   826 
       
   827     int size=(*entryp)-pos;
       
   828     memmove(&entries[pos+1],&entries[pos],size*sizeof(QPoolEntry));
       
   829     entries[pos].start=start;
       
   830     entries[pos].end=end;
       
   831     entries[pos].clientId=qws_client_id;
       
   832     (*entryp)++;
       
   833 }
       
   834 
       
   835 /*!
       
   836     \fn uchar * QLinuxFbScreen::cache(int amount)
       
   837 
       
   838     Requests the specified \a amount of offscreen graphics card memory
       
   839     from the memory manager, and returns a pointer to the data within
       
   840     the framebuffer (or 0 if there is no free memory).
       
   841 
       
   842     Note that the display is locked while memory is allocated in order to
       
   843     preserve the memory pool's integrity.
       
   844 
       
   845     Use the QScreen::onCard() function to retrieve an offset (in
       
   846     bytes) from the start of graphics card memory for the returned
       
   847     pointer.
       
   848 
       
   849     \sa uncache(), clearCache(), deleteEntry()
       
   850 */
       
   851 
       
   852 uchar * QLinuxFbScreen::cache(int amount)
       
   853 {
       
   854     if (!canaccel || entryp == 0)
       
   855         return 0;
       
   856 
       
   857     qt_fbdpy->grab();
       
   858 
       
   859     int startp = cacheStart + (*entryp+1) * sizeof(QPoolEntry);
       
   860     if (startp >= (int)*lowest) {
       
   861         // We don't have room for another cache QPoolEntry.
       
   862 #ifdef DEBUG_CACHE
       
   863         qDebug("No room for pool entry in VRAM");
       
   864 #endif
       
   865         qt_fbdpy->ungrab();
       
   866         return 0;
       
   867     }
       
   868 
       
   869     int align = pixmapOffsetAlignment();
       
   870 
       
   871     if (*entryp > 1) {
       
   872         // Try to find a gap in the allocated blocks.
       
   873         for (int loopc = 0; loopc < *entryp-1; loopc++) {
       
   874             int freestart = entries[loopc+1].end;
       
   875             int freeend = entries[loopc].start;
       
   876             if (freestart != freeend) {
       
   877                 while (freestart % align) {
       
   878                     freestart++;
       
   879                 }
       
   880                 int len=freeend-freestart;
       
   881                 if (len >= amount) {
       
   882                     insert_entry(loopc+1, freestart, freestart+amount);
       
   883                     qt_fbdpy->ungrab();
       
   884                     return data+freestart;
       
   885                 }
       
   886             }
       
   887         }
       
   888     }
       
   889 
       
   890     // No free blocks in already-taken memory; get some more
       
   891     // if we can
       
   892     int newlowest = (*lowest)-amount;
       
   893     if (newlowest % align) {
       
   894         newlowest -= align;
       
   895         while (newlowest % align) {
       
   896             newlowest++;
       
   897         }
       
   898     }
       
   899     if (startp >= newlowest) {
       
   900         qt_fbdpy->ungrab();
       
   901 #ifdef DEBUG_CACHE
       
   902         qDebug("No VRAM available for %d bytes", amount);
       
   903 #endif
       
   904         return 0;
       
   905     }
       
   906     insert_entry(*entryp, newlowest, *lowest);
       
   907     qt_fbdpy->ungrab();
       
   908 
       
   909     return data + newlowest;
       
   910 }
       
   911 
       
   912 /*!
       
   913     \fn void QLinuxFbScreen::uncache(uchar * memoryBlock)
       
   914 
       
   915     Deletes the specified \a memoryBlock allocated from the graphics
       
   916     card memory.
       
   917 
       
   918     Note that the display is locked while memory is unallocated in
       
   919     order to preserve the memory pool's integrity.
       
   920 
       
   921     This function will first sync the graphics card to ensure the
       
   922     memory isn't still being used by a command in the graphics card
       
   923     FIFO queue. It is possible to speed up a driver by overriding this
       
   924     function to avoid syncing. For example, the driver might delay
       
   925     deleting the memory until it detects that all commands dealing
       
   926     with the memory are no longer in the queue. Note that it will then
       
   927     be up to the driver to ensure that the specified \a memoryBlock no
       
   928     longer is being used.
       
   929 
       
   930     \sa cache(), deleteEntry(), clearCache()
       
   931  */
       
   932 void QLinuxFbScreen::uncache(uchar * c)
       
   933 {
       
   934     // need to sync graphics card
       
   935 
       
   936     deleteEntry(c);
       
   937 }
       
   938 
       
   939 /*!
       
   940     \fn void QLinuxFbScreen::deleteEntry(uchar * memoryBlock)
       
   941 
       
   942     Deletes the specified \a memoryBlock allocated from the graphics
       
   943     card memory.
       
   944 
       
   945     \sa uncache(), cache(), clearCache()
       
   946 */
       
   947 void QLinuxFbScreen::deleteEntry(uchar * c)
       
   948 {
       
   949     qt_fbdpy->grab();
       
   950     unsigned long pos=(unsigned long)c;
       
   951     pos-=((unsigned long)data);
       
   952     unsigned int hold=(*entryp);
       
   953     for(unsigned int loopc=1;loopc<hold;loopc++) {
       
   954         if (entries[loopc].start==pos) {
       
   955             if (entries[loopc].clientId == qws_client_id)
       
   956                 delete_entry(loopc);
       
   957             else
       
   958                 qWarning("Attempt to delete client id %d cache entry",
       
   959                          entries[loopc].clientId);
       
   960             qt_fbdpy->ungrab();
       
   961             return;
       
   962         }
       
   963     }
       
   964     qt_fbdpy->ungrab();
       
   965     qWarning("Attempt to delete unknown offset %ld",pos);
       
   966 }
       
   967 
       
   968 /*!
       
   969     Removes all entries from the cache for the specified screen \a
       
   970     instance and client identified by the given \a clientId.
       
   971 
       
   972     Calling this function should only be necessary if a client exits
       
   973     abnormally.
       
   974 
       
   975     \sa cache(), uncache(), deleteEntry()
       
   976 */
       
   977 void QLinuxFbScreen::clearCache(QScreen *instance, int clientId)
       
   978 {
       
   979     QLinuxFbScreen *screen = (QLinuxFbScreen *)instance;
       
   980     if (!screen->canaccel || !screen->entryp)
       
   981         return;
       
   982     qt_fbdpy->grab();
       
   983     for (int loopc = 0; loopc < *(screen->entryp); loopc++) {
       
   984         if (screen->entries[loopc].clientId == clientId) {
       
   985             screen->delete_entry(loopc);
       
   986             loopc--;
       
   987         }
       
   988     }
       
   989     qt_fbdpy->ungrab();
       
   990 }
       
   991 
       
   992 
       
   993 void QLinuxFbScreen::setupOffScreen()
       
   994 {
       
   995     // Figure out position of offscreen memory
       
   996     // Set up pool entries pointer table and 64-bit align it
       
   997     int psize = size;
       
   998 
       
   999     // hw: this causes the limitation of cursors to 64x64
       
  1000     // the cursor should rather use the normal pixmap mechanism
       
  1001     psize += 4096;  // cursor data
       
  1002     psize += 8;     // for alignment
       
  1003     psize &= ~0x7;  // align
       
  1004 
       
  1005     unsigned long pos = (unsigned long)data;
       
  1006     pos += psize;
       
  1007     entryp = ((int *)pos);
       
  1008     lowest = ((unsigned int *)pos)+1;
       
  1009     pos += (sizeof(int))*4;
       
  1010     entries = (QPoolEntry *)pos;
       
  1011 
       
  1012     // beginning of offscreen memory available for pixmaps.
       
  1013     cacheStart = psize + 4*sizeof(int) + sizeof(QPoolEntry);
       
  1014 }
       
  1015 
       
  1016 /*!
       
  1017     \reimp
       
  1018 
       
  1019     This is called by the \l{Qt for Embedded Linux} server when it shuts
       
  1020     down, and should be inherited if you need to do any card-specific cleanup.
       
  1021     The default version hides the screen cursor and reenables the blinking
       
  1022     cursor and screen blanking.
       
  1023 */
       
  1024 
       
  1025 void QLinuxFbScreen::shutdownDevice()
       
  1026 {
       
  1027     // Causing crashes. Not needed.
       
  1028     //setMode(startupw,startuph,startupd);
       
  1029 /*
       
  1030     if (startupd == 8) {
       
  1031         ioctl(fd,FBIOPUTCMAP,startcmap);
       
  1032         free(startcmap->red);
       
  1033         free(startcmap->green);
       
  1034         free(startcmap->blue);
       
  1035         free(startcmap->transp);
       
  1036         delete startcmap;
       
  1037         startcmap = 0;
       
  1038     }
       
  1039 */
       
  1040     d_ptr->closeTty();
       
  1041 }
       
  1042 
       
  1043 /*!
       
  1044     \fn void QLinuxFbScreen::set(unsigned int index,unsigned int red,unsigned int green,unsigned int blue)
       
  1045 
       
  1046     Sets the specified color \a index to the specified RGB value, (\a
       
  1047     red, \a green, \a blue), when in paletted graphics modes.
       
  1048 */
       
  1049 
       
  1050 void QLinuxFbScreen::set(unsigned int i,unsigned int r,unsigned int g,unsigned int b)
       
  1051 {
       
  1052     if (d_ptr->fd != -1) {
       
  1053         fb_cmap cmap;
       
  1054         cmap.start=i;
       
  1055         cmap.len=1;
       
  1056         cmap.red=(unsigned short int *)
       
  1057                  malloc(sizeof(unsigned short int)*256);
       
  1058         cmap.green=(unsigned short int *)
       
  1059                    malloc(sizeof(unsigned short int)*256);
       
  1060         cmap.blue=(unsigned short int *)
       
  1061                   malloc(sizeof(unsigned short int)*256);
       
  1062         cmap.transp=(unsigned short int *)
       
  1063                     malloc(sizeof(unsigned short int)*256);
       
  1064         cmap.red[0]=r << 8;
       
  1065         cmap.green[0]=g << 8;
       
  1066         cmap.blue[0]=b << 8;
       
  1067         cmap.transp[0]=0;
       
  1068         ioctl(d_ptr->fd, FBIOPUTCMAP, &cmap);
       
  1069         free(cmap.red);
       
  1070         free(cmap.green);
       
  1071         free(cmap.blue);
       
  1072         free(cmap.transp);
       
  1073     }
       
  1074     screenclut[i] = qRgb(r, g, b);
       
  1075 }
       
  1076 
       
  1077 /*!
       
  1078     \reimp
       
  1079 
       
  1080     Sets the framebuffer to a new resolution and bit depth. The width is
       
  1081     in \a nw, the height is in \a nh, and the depth is in \a nd. After
       
  1082     doing this any currently-existing paint engines will be invalid and the
       
  1083     screen should be completely redrawn. In a multiple-process
       
  1084     Embedded Qt situation you must signal all other applications to
       
  1085     call setMode() to the same mode and redraw.
       
  1086 */
       
  1087 
       
  1088 void QLinuxFbScreen::setMode(int nw,int nh,int nd)
       
  1089 {
       
  1090     if (d_ptr->fd == -1)
       
  1091         return;
       
  1092 
       
  1093     fb_fix_screeninfo finfo;
       
  1094     fb_var_screeninfo vinfo;
       
  1095     //#######################
       
  1096     // Shut up Valgrind
       
  1097     memset(&vinfo, 0, sizeof(vinfo));
       
  1098     memset(&finfo, 0, sizeof(finfo));
       
  1099     //#######################
       
  1100 
       
  1101     if (ioctl(d_ptr->fd, FBIOGET_VSCREENINFO, &vinfo)) {
       
  1102         perror("QLinuxFbScreen::setMode");
       
  1103         qFatal("Error reading variable information in mode change");
       
  1104     }
       
  1105 
       
  1106     vinfo.xres=nw;
       
  1107     vinfo.yres=nh;
       
  1108     vinfo.bits_per_pixel=nd;
       
  1109 
       
  1110     if (ioctl(d_ptr->fd, FBIOPUT_VSCREENINFO, &vinfo)) {
       
  1111         perror("QLinuxFbScreen::setMode");
       
  1112         qCritical("Error writing variable information in mode change");
       
  1113     }
       
  1114 
       
  1115     if (ioctl(d_ptr->fd, FBIOGET_VSCREENINFO, &vinfo)) {
       
  1116         perror("QLinuxFbScreen::setMode");
       
  1117         qFatal("Error reading changed variable information in mode change");
       
  1118     }
       
  1119 
       
  1120     if (ioctl(d_ptr->fd, FBIOGET_FSCREENINFO, &finfo)) {
       
  1121         perror("QLinuxFbScreen::setMode");
       
  1122         qFatal("Error reading fixed information");
       
  1123     }
       
  1124 
       
  1125     disconnect();
       
  1126     connect(d_ptr->displaySpec);
       
  1127     exposeRegion(region(), 0);
       
  1128 }
       
  1129 
       
  1130 // save the state of the graphics card
       
  1131 // This is needed so that e.g. we can restore the palette when switching
       
  1132 // between linux virtual consoles.
       
  1133 
       
  1134 /*!
       
  1135     \reimp
       
  1136 
       
  1137     This doesn't do anything; accelerated drivers may wish to reimplement
       
  1138     it to save graphics cards registers. It's called by the
       
  1139     \l{Qt for Embedded Linux} server when the virtual console is switched.
       
  1140 */
       
  1141 
       
  1142 void QLinuxFbScreen::save()
       
  1143 {
       
  1144     // nothing to do.
       
  1145 }
       
  1146 
       
  1147 
       
  1148 // restore the state of the graphics card.
       
  1149 /*!
       
  1150     \reimp
       
  1151 
       
  1152     This is called when the virtual console is switched back to
       
  1153     \l{Qt for Embedded Linux} and restores the palette.
       
  1154 */
       
  1155 void QLinuxFbScreen::restore()
       
  1156 {
       
  1157     if (d_ptr->fd == -1)
       
  1158         return;
       
  1159 
       
  1160     if ((d == 8) || (d == 4)) {
       
  1161         fb_cmap cmap;
       
  1162         cmap.start=0;
       
  1163         cmap.len=screencols;
       
  1164         cmap.red=(unsigned short int *)
       
  1165                  malloc(sizeof(unsigned short int)*256);
       
  1166         cmap.green=(unsigned short int *)
       
  1167                    malloc(sizeof(unsigned short int)*256);
       
  1168         cmap.blue=(unsigned short int *)
       
  1169                   malloc(sizeof(unsigned short int)*256);
       
  1170         cmap.transp=(unsigned short int *)
       
  1171                     malloc(sizeof(unsigned short int)*256);
       
  1172         for (int loopc = 0; loopc < screencols; loopc++) {
       
  1173             cmap.red[loopc] = qRed(screenclut[loopc]) << 8;
       
  1174             cmap.green[loopc] = qGreen(screenclut[loopc]) << 8;
       
  1175             cmap.blue[loopc] = qBlue(screenclut[loopc]) << 8;
       
  1176             cmap.transp[loopc] = 0;
       
  1177         }
       
  1178         ioctl(d_ptr->fd, FBIOPUTCMAP, &cmap);
       
  1179         free(cmap.red);
       
  1180         free(cmap.green);
       
  1181         free(cmap.blue);
       
  1182         free(cmap.transp);
       
  1183     }
       
  1184 }
       
  1185 
       
  1186 /*!
       
  1187     \fn int QLinuxFbScreen::sharedRamSize(void * end)
       
  1188     \internal
       
  1189 */
       
  1190 
       
  1191 // This works like the QScreenCursor code. end points to the end
       
  1192 // of our shared structure, we return the amount of memory we reserved
       
  1193 int QLinuxFbScreen::sharedRamSize(void * end)
       
  1194 {
       
  1195     shared=(QLinuxFb_Shared *)end;
       
  1196     shared--;
       
  1197     return sizeof(QLinuxFb_Shared);
       
  1198 }
       
  1199 
       
  1200 /*!
       
  1201     \reimp
       
  1202 */
       
  1203 void QLinuxFbScreen::blank(bool on)
       
  1204 {
       
  1205     if (d_ptr->blank == on)
       
  1206         return;
       
  1207 
       
  1208 #if defined(QT_QWS_IPAQ)
       
  1209     if (on)
       
  1210         system("apm -suspend");
       
  1211 #else
       
  1212     if (d_ptr->fd == -1)
       
  1213         return;
       
  1214 // Some old kernel versions don't have this.  These defines should go
       
  1215 // away eventually
       
  1216 #if defined(FBIOBLANK)
       
  1217 #if defined(VESA_POWERDOWN) && defined(VESA_NO_BLANKING)
       
  1218     ioctl(d_ptr->fd, FBIOBLANK, on ? VESA_POWERDOWN : VESA_NO_BLANKING);
       
  1219 #else
       
  1220     ioctl(d_ptr->fd, FBIOBLANK, on ? 1 : 0);
       
  1221 #endif
       
  1222 #endif
       
  1223 #endif
       
  1224 
       
  1225     d_ptr->blank = on;
       
  1226 }
       
  1227 
       
  1228 void QLinuxFbScreen::setPixelFormat(struct fb_var_screeninfo info)
       
  1229 {
       
  1230     const fb_bitfield rgba[4] = { info.red, info.green,
       
  1231                                   info.blue, info.transp };
       
  1232 
       
  1233     QImage::Format format = QImage::Format_Invalid;
       
  1234 
       
  1235     switch (d) {
       
  1236     case 32: {
       
  1237         const fb_bitfield argb8888[4] = {{16, 8, 0}, {8, 8, 0},
       
  1238                                          {0, 8, 0}, {24, 8, 0}};
       
  1239         const fb_bitfield abgr8888[4] = {{0, 8, 0}, {8, 8, 0},
       
  1240                                          {16, 8, 0}, {24, 8, 0}};
       
  1241         if (memcmp(rgba, argb8888, 4 * sizeof(fb_bitfield)) == 0) {
       
  1242             format = QImage::Format_ARGB32;
       
  1243         } else if (memcmp(rgba, argb8888, 3 * sizeof(fb_bitfield)) == 0) {
       
  1244             format = QImage::Format_RGB32;
       
  1245         } else if (memcmp(rgba, abgr8888, 3 * sizeof(fb_bitfield)) == 0) {
       
  1246             format = QImage::Format_RGB32;
       
  1247             pixeltype = QScreen::BGRPixel;
       
  1248         }
       
  1249         break;
       
  1250     }
       
  1251     case 24: {
       
  1252         const fb_bitfield rgb888[4] = {{16, 8, 0}, {8, 8, 0},
       
  1253                                        {0, 8, 0}, {0, 0, 0}};
       
  1254         const fb_bitfield bgr888[4] = {{0, 8, 0}, {8, 8, 0},
       
  1255                                        {16, 8, 0}, {0, 0, 0}};
       
  1256         if (memcmp(rgba, rgb888, 3 * sizeof(fb_bitfield)) == 0) {
       
  1257             format = QImage::Format_RGB888;
       
  1258         } else if (memcmp(rgba, bgr888, 3 * sizeof(fb_bitfield)) == 0) {
       
  1259             format = QImage::Format_RGB888;
       
  1260             pixeltype = QScreen::BGRPixel;
       
  1261         }
       
  1262         break;
       
  1263     }
       
  1264     case 18: {
       
  1265         const fb_bitfield rgb666[4] = {{12, 6, 0}, {6, 6, 0},
       
  1266                                        {0, 6, 0}, {0, 0, 0}};
       
  1267         if (memcmp(rgba, rgb666, 3 * sizeof(fb_bitfield)) == 0)
       
  1268             format = QImage::Format_RGB666;
       
  1269         break;
       
  1270     }
       
  1271     case 16: {
       
  1272         const fb_bitfield rgb565[4] = {{11, 5, 0}, {5, 6, 0},
       
  1273                                        {0, 5, 0}, {0, 0, 0}};
       
  1274         const fb_bitfield bgr565[4] = {{0, 5, 0}, {5, 6, 0},
       
  1275                                        {11, 5, 0}, {0, 0, 0}};
       
  1276         if (memcmp(rgba, rgb565, 3 * sizeof(fb_bitfield)) == 0) {
       
  1277             format = QImage::Format_RGB16;
       
  1278         } else if (memcmp(rgba, bgr565, 3 * sizeof(fb_bitfield)) == 0) {
       
  1279             format = QImage::Format_RGB16;
       
  1280             pixeltype = QScreen::BGRPixel;
       
  1281         }
       
  1282         break;
       
  1283     }
       
  1284     case 15: {
       
  1285         const fb_bitfield rgb1555[4] = {{10, 5, 0}, {5, 5, 0},
       
  1286                                         {0, 5, 0}, {15, 1, 0}};
       
  1287         const fb_bitfield bgr1555[4] = {{0, 5, 0}, {5, 5, 0},
       
  1288                                         {10, 5, 0}, {15, 1, 0}};
       
  1289         if (memcmp(rgba, rgb1555, 3 * sizeof(fb_bitfield)) == 0) {
       
  1290             format = QImage::Format_RGB555;
       
  1291         } else if (memcmp(rgba, bgr1555, 3 * sizeof(fb_bitfield)) == 0) {
       
  1292             format = QImage::Format_RGB555;
       
  1293             pixeltype = QScreen::BGRPixel;
       
  1294         }
       
  1295         break;
       
  1296     }
       
  1297     case 12: {
       
  1298         const fb_bitfield rgb444[4] = {{8, 4, 0}, {4, 4, 0},
       
  1299                                        {0, 4, 0}, {0, 0, 0}};
       
  1300         if (memcmp(rgba, rgb444, 3 * sizeof(fb_bitfield)) == 0)
       
  1301             format = QImage::Format_RGB444;
       
  1302         break;
       
  1303     }
       
  1304     case 8:
       
  1305         break;
       
  1306     case 1:
       
  1307         format = QImage::Format_Mono; //###: LSB???
       
  1308         break;
       
  1309     default:
       
  1310         break;
       
  1311     }
       
  1312 
       
  1313     QScreen::setPixelFormat(format);
       
  1314 }
       
  1315 
       
  1316 bool QLinuxFbScreen::useOffscreen()
       
  1317 {
       
  1318     if ((mapsize - size) < 16*1024)
       
  1319         return false;
       
  1320 
       
  1321     return true;
       
  1322 }
       
  1323 
       
  1324 QT_END_NAMESPACE
       
  1325 
       
  1326 #endif // QT_NO_QWS_LINUXFB