~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/gui/embedded/qscreenlinuxfb_qws.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghersi
  • Date: 2009-11-02 18:30:08 UTC
  • mfrom: (1.2.2 upstream)
  • mto: (15.2.5 experimental)
  • mto: This revision was merged to the branch mainline in revision 88.
  • Revision ID: james.westby@ubuntu.com-20091102183008-b6a4gcs128mvfb3m
Tags: upstream-4.6.0~beta1
ImportĀ upstreamĀ versionĀ 4.6.0~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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