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