1
/****************************************************************************
3
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4
** All rights reserved.
5
** Contact: Nokia Corporation (qt-info@nokia.com)
7
** This file is part of the QtGui module of the Qt Toolkit.
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
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.
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.
28
** If you have questions regarding the use of this file, please contact
29
** Nokia at qt-info@nokia.com.
40
****************************************************************************/
42
#include "qscreenlinuxfb_qws.h"
44
#ifndef QT_NO_QWS_LINUXFB
45
//#include "qmemorymanager_qws.h"
46
#include "qwsdisplay_qws.h"
48
#include <private/qwssignalhandler_p.h>
49
#include <private/qcore_unix_p.h> // overrides QT_OPEN
53
#include <sys/ioctl.h>
54
#include <sys/types.h>
64
#include "qwindowsystem_qws.h"
66
#if !defined(Q_OS_DARWIN) && !defined(Q_OS_FREEBSD)
76
extern int qws_client_id;
80
class QLinuxFbScreenPrivate : public QObject
83
QLinuxFbScreenPrivate();
84
~QLinuxFbScreenPrivate();
96
#ifdef QT_QWS_DEPTH_GENERIC
105
QLinuxFbScreenPrivate::QLinuxFbScreenPrivate()
106
: fd(-1), blank(true), doGraphicsMode(true),
107
#ifdef QT_QWS_DEPTH_GENERIC
108
doGenericColors(false),
110
ttyfd(-1), oldKdMode(KD_TEXT)
112
QWSSignalHandler::instance()->addObject(this);
115
QLinuxFbScreenPrivate::~QLinuxFbScreenPrivate()
120
void QLinuxFbScreenPrivate::openTty()
122
const char *const devs[] = {"/dev/tty0", "/dev/tty", "/dev/console", 0};
124
if (ttyDevice.isEmpty()) {
125
for (const char * const *dev = devs; *dev; ++dev) {
126
ttyfd = QT_OPEN(*dev, O_RDWR);
131
ttyfd = QT_OPEN(ttyDevice.toAscii().constData(), O_RDWR);
137
if (doGraphicsMode) {
138
ioctl(ttyfd, KDGETMODE, &oldKdMode);
139
if (oldKdMode != KD_GRAPHICS) {
140
int ret = ioctl(ttyfd, KDSETMODE, KD_GRAPHICS);
142
doGraphicsMode = false;
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));
151
void QLinuxFbScreenPrivate::closeTty()
157
ioctl(ttyfd, KDSETMODE, oldKdMode);
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));
170
\class QLinuxFbScreen
173
\brief The QLinuxFbScreen class implements a screen driver for the
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.
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.
192
In addition, when in paletted graphics modes, the set() function
193
provides the possibility of setting a specified color index to a
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.
201
\sa QScreen, QScreenDriverPlugin, {Running Applications}
205
\fn bool QLinuxFbScreen::useOffscreen()
209
// Unaccelerated screen/driver setup. Can be overridden by accelerated
213
\fn QLinuxFbScreen::QLinuxFbScreen(int displayId)
215
Constructs a QLinuxFbScreen object. The \a displayId argument
216
identifies the Qt for Embedded Linux server to connect to.
219
QLinuxFbScreen::QLinuxFbScreen(int display_id)
220
: QScreen(display_id, LinuxFBClass), d_ptr(new QLinuxFbScreenPrivate)
223
clearCacheFunc = &clearCache;
224
#ifdef QT_QWS_CLIENTBLIT
225
setSupportsBlitInClients(true);
230
Destroys this QLinuxFbScreen object.
233
QLinuxFbScreen::~QLinuxFbScreen()
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".
249
bool QLinuxFbScreen::connect(const QString &displaySpec)
251
d_ptr->displaySpec = displaySpec;
253
const QStringList args = displaySpec.split(QLatin1Char(':'));
255
if (args.contains(QLatin1String("nographicsmodeswitch")))
256
d_ptr->doGraphicsMode = false;
258
#ifdef QT_QWS_DEPTH_GENERIC
259
if (args.contains(QLatin1String("genericcolors")))
260
d_ptr->doGenericColors = true;
263
QRegExp ttyRegExp(QLatin1String("tty=(.*)"));
264
if (args.indexOf(ttyRegExp) != -1)
265
d_ptr->ttyDevice = ttyRegExp.cap(1);
267
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
268
#ifndef QT_QWS_FRAMEBUFFER_LITTLE_ENDIAN
269
if (args.contains(QLatin1String("littleendian")))
271
QScreen::setFrameBufferLittleEndian(true);
274
QString dev = QLatin1String("/dev/fb0");
275
foreach(QString d, args) {
276
if (d.startsWith(QLatin1Char('/'))) {
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));
290
if (access(dev.toLatin1().constData(), R_OK) == 0)
291
d_ptr->fd = QT_OPEN(dev.toLatin1().constData(), O_RDONLY);
294
::fb_fix_screeninfo finfo;
295
::fb_var_screeninfo vinfo;
296
//#######################
298
memset(&vinfo, 0, sizeof(vinfo));
299
memset(&finfo, 0, sizeof(finfo));
300
//#######################
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");
309
if (finfo.type == FB_TYPE_VGA_PLANES) {
310
qWarning("VGA16 video mode not supported");
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");
321
grayscale = vinfo.grayscale;
322
d = vinfo.bits_per_pixel;
324
d = vinfo.red.length + vinfo.green.length + vinfo.blue.length;
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;
332
lstep = finfo.line_length;
334
int xoff = vinfo.xoffset;
335
int yoff = vinfo.yoffset;
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;
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;
353
xoff += (vinfo.xres - w)/2;
354
yoff += (vinfo.yres - h)/2;
361
if (w == 0 || h == 0) {
362
qWarning("QScreenLinuxFb::connect(): Unable to find screen geometry, "
363
"will use 320x240.");
368
setPixelFormat(vinfo);
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);
377
mmWidthRx.exactMatch(displayArgs.at(dimIdxW));
378
physWidth = mmWidthRx.cap(1).toInt();
380
physHeight = dh*physWidth/dw;
383
mmHeightRx.exactMatch(displayArgs.at(dimIdxH));
384
physHeight = mmHeightRx.cap(1).toInt();
386
physWidth = dw*physHeight/dh;
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;
395
physWidth = qRound(dw * 25.4 / dpi);
396
physHeight = qRound(dh * 25.4 / dpi);
400
dataoffset = yoff * lstep + xoff * d / 8;
401
//qDebug("Using %dx%dx%d screen",w,h,d);
403
/* Figure out the size of the screen in bytes */
406
mapsize = finfo.smem_len;
408
data = (unsigned char *)-1;
410
data = (unsigned char *)mmap(0, mapsize, PROT_READ | PROT_WRITE,
411
MAP_SHARED, d_ptr->fd, 0);
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.");
424
canaccel = useOffscreen();
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;
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);
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];
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]);
465
qWarning("8 bits cmap returned due to faulty FB driver, colors corrected");
468
free(startcmap.green);
469
free(startcmap.blue);
470
free(startcmap.transp);
481
This unmaps the framebuffer.
486
void QLinuxFbScreen::disconnect()
490
munmap((char*)data,mapsize);
494
// #define DEBUG_VINFO
496
void QLinuxFbScreen::createPalette(fb_cmap &cmap, fb_var_screeninfo &vinfo, fb_fix_screeninfo &finfo)
498
if((vinfo.bits_per_pixel==8) || (vinfo.bits_per_pixel==4)) {
499
screencols= (vinfo.bits_per_pixel==8) ? 256 : 16;
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);
511
if (screencols==16) {
512
if (finfo.type == FB_TYPE_PACKED_PIXELS) {
513
// We'll setup a grayscale cmap for 4bpp linear
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);
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 };
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]);
539
// Build grayscale palette
541
for(i=0;i<screencols;++i) {
542
int bval = screencols == 256 ? i : (i << 4);
543
ushort val = (bval << 8) | bval;
548
screenclut[i] = qRgb(bval,bval,bval);
551
// 6x6x6 216 color cube
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);
565
// Fill in rest with 0
566
for (int loopc=0; loopc<40; ++loopc) {
573
} else if(finfo.visual==FB_VISUAL_DIRECTCOLOR) {
575
int rbits=0,gbits=0,bbits=0;
576
switch (vinfo.bits_per_pixel) {
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
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);
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
635
bool QLinuxFbScreen::initDevice()
639
// Grab current mode so we can reset it
640
fb_var_screeninfo vinfo;
641
fb_fix_screeninfo finfo;
642
//#######################
644
memset(&vinfo, 0, sizeof(vinfo));
645
memset(&finfo, 0, sizeof(finfo));
646
//#######################
648
if (ioctl(d_ptr->fd, FBIOGET_VSCREENINFO, &vinfo)) {
649
perror("QLinuxFbScreen::initDevice");
650
qFatal("Error reading variable information in card init");
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);
667
d_ptr->startupw=vinfo.xres;
668
d_ptr->startuph=vinfo.yres;
669
d_ptr->startupd=vinfo.bits_per_pixel;
670
grayscale = vinfo.grayscale;
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
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
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;
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));
705
// Should we close mfd here?
709
if ((vinfo.bits_per_pixel==8) || (vinfo.bits_per_pixel==4) || (finfo.visual==FB_VISUAL_DIRECTCOLOR))
712
createPalette(cmap, vinfo, finfo);
713
if (ioctl(d_ptr->fd, FBIOPUTCMAP, &cmap)) {
714
perror("QLinuxFbScreen::initDevice");
715
qWarning("Error writing palette to framebuffer");
726
insert_entry(*entryp, *lowest, *lowest); // dummy entry to mark start
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;
738
#ifdef QT_QWS_DEPTH_GENERIC
739
if (pixelFormat() == QImage::Format_Invalid && screencols == 0
740
&& d_ptr->doGenericColors)
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);
750
#ifndef QT_NO_QWS_CURSOR
751
QScreenCursor::initSoftwareCursor();
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
773
void QLinuxFbScreen::delete_entry(int pos)
775
if (pos > *entryp || pos < 0) {
776
qWarning("Attempt to delete odd pos! %d %d", pos, *entryp);
781
qDebug("Remove entry: %d", pos);
784
QPoolEntry *qpe = &entries[pos];
785
if (qpe->start <= *lowest) {
786
// Lowest goes up again
787
*lowest = entries[pos-1].start;
789
qDebug(" moved lowest to %d", *lowest);
797
int size = (*entryp)-pos;
798
memmove(&entries[pos], &entries[pos+1], size*sizeof(QPoolEntry));
801
void QLinuxFbScreen::insert_entry(int pos, int start, int end)
804
qWarning("Attempt to insert odd pos! %d %d",pos,*entryp);
809
qDebug("Insert entry: %d, %d -> %d", pos, start, end);
812
if (start < (int)*lowest) {
815
qDebug(" moved lowest to %d", *lowest);
819
if (pos == *entryp) {
820
entries[pos].start = start;
821
entries[pos].end = end;
822
entries[pos].clientId = qws_client_id;
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;
836
\fn uchar * QLinuxFbScreen::cache(int amount)
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).
842
Note that the display is locked while memory is allocated in order to
843
preserve the memory pool's integrity.
845
Use the QScreen::onCard() function to retrieve an offset (in
846
bytes) from the start of graphics card memory for the returned
849
\sa uncache(), clearCache(), deleteEntry()
852
uchar * QLinuxFbScreen::cache(int amount)
854
if (!canaccel || entryp == 0)
859
int startp = cacheStart + (*entryp+1) * sizeof(QPoolEntry);
860
if (startp >= (int)*lowest) {
861
// We don't have room for another cache QPoolEntry.
863
qDebug("No room for pool entry in VRAM");
869
int align = pixmapOffsetAlignment();
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) {
880
int len=freeend-freestart;
882
insert_entry(loopc+1, freestart, freestart+amount);
884
return data+freestart;
890
// No free blocks in already-taken memory; get some more
892
int newlowest = (*lowest)-amount;
893
if (newlowest % align) {
895
while (newlowest % align) {
899
if (startp >= newlowest) {
902
qDebug("No VRAM available for %d bytes", amount);
906
insert_entry(*entryp, newlowest, *lowest);
909
return data + newlowest;
913
\fn void QLinuxFbScreen::uncache(uchar * memoryBlock)
915
Deletes the specified \a memoryBlock allocated from the graphics
918
Note that the display is locked while memory is unallocated in
919
order to preserve the memory pool's integrity.
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.
930
\sa cache(), deleteEntry(), clearCache()
932
void QLinuxFbScreen::uncache(uchar * c)
934
// need to sync graphics card
940
\fn void QLinuxFbScreen::deleteEntry(uchar * memoryBlock)
942
Deletes the specified \a memoryBlock allocated from the graphics
945
\sa uncache(), cache(), clearCache()
947
void QLinuxFbScreen::deleteEntry(uchar * c)
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)
958
qWarning("Attempt to delete client id %d cache entry",
959
entries[loopc].clientId);
965
qWarning("Attempt to delete unknown offset %ld",pos);
969
Removes all entries from the cache for the specified screen \a
970
instance and client identified by the given \a clientId.
972
Calling this function should only be necessary if a client exits
975
\sa cache(), uncache(), deleteEntry()
977
void QLinuxFbScreen::clearCache(QScreen *instance, int clientId)
979
QLinuxFbScreen *screen = (QLinuxFbScreen *)instance;
980
if (!screen->canaccel || !screen->entryp)
983
for (int loopc = 0; loopc < *(screen->entryp); loopc++) {
984
if (screen->entries[loopc].clientId == clientId) {
985
screen->delete_entry(loopc);
993
void QLinuxFbScreen::setupOffScreen()
995
// Figure out position of offscreen memory
996
// Set up pool entries pointer table and 64-bit align it
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
1005
unsigned long pos = (unsigned long)data;
1007
entryp = ((int *)pos);
1008
lowest = ((unsigned int *)pos)+1;
1009
pos += (sizeof(int))*4;
1010
entries = (QPoolEntry *)pos;
1012
// beginning of offscreen memory available for pixmaps.
1013
cacheStart = psize + 4*sizeof(int) + sizeof(QPoolEntry);
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.
1025
void QLinuxFbScreen::shutdownDevice()
1027
// Causing crashes. Not needed.
1028
//setMode(startupw,startuph,startupd);
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);
1044
\fn void QLinuxFbScreen::set(unsigned int index,unsigned int red,unsigned int green,unsigned int blue)
1046
Sets the specified color \a index to the specified RGB value, (\a
1047
red, \a green, \a blue), when in paletted graphics modes.
1050
void QLinuxFbScreen::set(unsigned int i,unsigned int r,unsigned int g,unsigned int b)
1052
if (d_ptr->fd != -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);
1065
cmap.green[0]=g << 8;
1066
cmap.blue[0]=b << 8;
1068
ioctl(d_ptr->fd, FBIOPUTCMAP, &cmap);
1074
screenclut[i] = qRgb(r, g, b);
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.
1088
void QLinuxFbScreen::setMode(int nw,int nh,int nd)
1090
if (d_ptr->fd == -1)
1093
fb_fix_screeninfo finfo;
1094
fb_var_screeninfo vinfo;
1095
//#######################
1097
memset(&vinfo, 0, sizeof(vinfo));
1098
memset(&finfo, 0, sizeof(finfo));
1099
//#######################
1101
if (ioctl(d_ptr->fd, FBIOGET_VSCREENINFO, &vinfo)) {
1102
perror("QLinuxFbScreen::setMode");
1103
qFatal("Error reading variable information in mode change");
1108
vinfo.bits_per_pixel=nd;
1110
if (ioctl(d_ptr->fd, FBIOPUT_VSCREENINFO, &vinfo)) {
1111
perror("QLinuxFbScreen::setMode");
1112
qCritical("Error writing variable information in mode change");
1115
if (ioctl(d_ptr->fd, FBIOGET_VSCREENINFO, &vinfo)) {
1116
perror("QLinuxFbScreen::setMode");
1117
qFatal("Error reading changed variable information in mode change");
1120
if (ioctl(d_ptr->fd, FBIOGET_FSCREENINFO, &finfo)) {
1121
perror("QLinuxFbScreen::setMode");
1122
qFatal("Error reading fixed information");
1126
connect(d_ptr->displaySpec);
1127
exposeRegion(region(), 0);
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.
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.
1142
void QLinuxFbScreen::save()
1148
// restore the state of the graphics card.
1152
This is called when the virtual console is switched back to
1153
\l{Qt for Embedded Linux} and restores the palette.
1155
void QLinuxFbScreen::restore()
1157
if (d_ptr->fd == -1)
1160
if ((d == 8) || (d == 4)) {
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;
1178
ioctl(d_ptr->fd, FBIOPUTCMAP, &cmap);
1187
\fn int QLinuxFbScreen::sharedRamSize(void * end)
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)
1195
shared=(QLinuxFb_Shared *)end;
1197
return sizeof(QLinuxFb_Shared);
1203
void QLinuxFbScreen::blank(bool on)
1205
if (d_ptr->blank == on)
1208
#if defined(QT_QWS_IPAQ)
1210
system("apm -suspend");
1212
if (d_ptr->fd == -1)
1214
// Some old kernel versions don't have this. These defines should go
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);
1220
ioctl(d_ptr->fd, FBIOBLANK, on ? 1 : 0);
1228
void QLinuxFbScreen::setPixelFormat(struct fb_var_screeninfo info)
1230
const fb_bitfield rgba[4] = { info.red, info.green,
1231
info.blue, info.transp };
1233
QImage::Format format = QImage::Format_Invalid;
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;
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;
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;
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;
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;
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;
1307
format = QImage::Format_Mono; //###: LSB???
1313
QScreen::setPixelFormat(format);
1316
bool QLinuxFbScreen::useOffscreen()
1318
if ((mapsize - size) < 16*1024)
1326
#endif // QT_NO_QWS_LINUXFB