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