Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 934482 Details for
Bug 1078390
Rebase qxl driver in RHEL 6.6
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
compat revision 1
0001-Add-QXL-revision-1-compat-support.patch (text/plain), 110.04 KB, created by
Marc-Andre Lureau
on 2014-09-04 14:37:05 UTC
(
hide
)
Description:
compat revision 1
Filename:
MIME Type:
Creator:
Marc-Andre Lureau
Created:
2014-09-04 14:37:05 UTC
Size:
110.04 KB
patch
obsolete
>From da2e1170148781ca50d59689654959033075aac5 Mon Sep 17 00:00:00 2001 >From: Marc-Andre Lureau <marcandre.lureau@redhat.com> >Date: Thu, 4 Sep 2014 14:57:05 +0200 >Subject: [PATCH] Add QXL revision 1 compat support > >--- > configure.ac | 1 + > src/Makefile.am | 4 +- > src/compat/Makefile.am | 41 ++ > src/compat/compat-lookup3.c | 769 +++++++++++++++++++++ > src/compat/compat-lookup3.h | 26 + > src/compat/compat-qxl.h | 611 +++++++++++++++++ > src/compat/compat-qxl_cursor.c | 196 ++++++ > src/compat/compat-qxl_driver.c | 1460 ++++++++++++++++++++++++++++++++++++++++ > src/compat/compat-qxl_image.c | 255 +++++++ > src/compat/compat-qxl_mem.c | 321 +++++++++ > src/compat/compat-qxl_ring.c | 97 +++ > src/qxl_driver.c | 5 +- > 12 files changed, 3783 insertions(+), 3 deletions(-) > create mode 100644 src/compat/Makefile.am > create mode 100644 src/compat/compat-lookup3.c > create mode 100644 src/compat/compat-lookup3.h > create mode 100644 src/compat/compat-qxl.h > create mode 100644 src/compat/compat-qxl_cursor.c > create mode 100644 src/compat/compat-qxl_driver.c > create mode 100644 src/compat/compat-qxl_image.c > create mode 100644 src/compat/compat-qxl_mem.c > create mode 100644 src/compat/compat-qxl_ring.c > >diff --git a/configure.ac b/configure.ac >index 01377a4..2738f79 100644 >--- a/configure.ac >+++ b/configure.ac >@@ -166,6 +166,7 @@ fi > AC_CONFIG_FILES([ > Makefile > src/Makefile >+ src/compat/Makefile > src/uxa/Makefile > scripts/Makefile > examples/Makefile >diff --git a/src/Makefile.am b/src/Makefile.am >index bf50ae1..211ac9d 100644 >--- a/src/Makefile.am >+++ b/src/Makefile.am >@@ -25,7 +25,7 @@ > # _ladir passes a dummy rpath to libtool so the thing will actually link > # TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc. > >-SUBDIRS=uxa >+SUBDIRS = compat uxa > > AM_CFLAGS = $(SPICE_PROTOCOL_CFLAGS) $(XORG_CFLAGS) $(PCIACCESS_CFLAGS) $(CWARNFLAGS) $(DRM_CFLAGS) @LIBUDEV_CFLAGS@ > >@@ -34,7 +34,7 @@ qxl_drv_la_LTLIBRARIES = qxl_drv.la > qxl_drv_la_LDFLAGS = -module -avoid-version > qxl_drv_ladir = @moduledir@/drivers > >-qxl_drv_la_LIBADD = uxa/libuxa.la >+qxl_drv_la_LIBADD = compat/compatdriver.la uxa/libuxa.la > if LIBUDEV > qxl_drv_la_LIBADD += $(LIBUDEV_LIBS) > endif >diff --git a/src/compat/Makefile.am b/src/compat/Makefile.am >new file mode 100644 >index 0000000..64de89d >--- /dev/null >+++ b/src/compat/Makefile.am >@@ -0,0 +1,41 @@ >+# Copyright 2008 Red Hat, Inc. >+# >+# Permission is hereby granted, free of charge, to any person obtaining a >+# copy of this software and associated documentation files (the "Software"), >+# to deal in the Software without restriction, including without limitation >+# on the rights to use, copy, modify, merge, publish, distribute, sub >+# license, and/or sell copies of the Software, and to permit persons to whom >+# the Software is furnished to do so, subject to the following conditions: >+# >+# The above copyright notice and this permission notice (including the next >+# paragraph) shall be included in all copies or substantial portions of the >+# Software. >+# >+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR >+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, >+# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL >+# THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER >+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN >+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. >+ >+ >+# this is obnoxious: >+# -module lets us name the module exactly how we want >+# -avoid-version prevents gratuitous .0.0.0 version numbers on the end >+# _ladir passes a dummy rpath to libtool so the thing will actually link >+# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc. >+ >+noinst_LTLIBRARIES = compatdriver.la >+compatdriver_la_LDFLAGS = -module -avoid-version >+ >+AM_CFLAGS = $(XORG_CFLAGS) $(PCIACCESS_CFLAGS) $(CWARNFLAGS) >+ >+compatdriver_la_SOURCES = \ >+ compat-qxl.h \ >+ compat-qxl_driver.c \ >+ compat-qxl_image.c \ >+ compat-qxl_ring.c \ >+ compat-qxl_mem.c \ >+ compat-lookup3.c \ >+ compat-lookup3.h \ >+ compat-qxl_cursor.c >diff --git a/src/compat/compat-lookup3.c b/src/compat/compat-lookup3.c >new file mode 100644 >index 0000000..a0608a9 >--- /dev/null >+++ b/src/compat/compat-lookup3.c >@@ -0,0 +1,769 @@ >+/* >+------------------------------------------------------------------------------- >+lookup3.c, by Bob Jenkins, May 2006, Public Domain. >+ >+These are functions for producing 32-bit hashes for hash table lookup. >+compat_hashword(), compat_hashlittle(), compat_hashlittle2(), compat_hashbig(), mix(), and final() >+are externally useful functions. Routines to test the hash are included >+if SELF_TEST is defined. You can use this free for any purpose. It's in >+the public domain. It has no warranty. >+ >+You probably want to use compat_hashlittle(). compat_hashlittle() and compat_hashbig() >+hash byte arrays. compat_hashlittle() is is faster than compat_hashbig() on >+little-endian machines. Intel and AMD are little-endian machines. >+On second thought, you probably want compat_hashlittle2(), which is identical to >+compat_hashlittle() except it returns two 32-bit hashes for the price of one. >+You could implement compat_hashbig2() if you wanted but I haven't bothered here. >+ >+If you want to find a hash of, say, exactly 7 integers, do >+ a = i1; b = i2; c = i3; >+ mix(a,b,c); >+ a += i4; b += i5; c += i6; >+ mix(a,b,c); >+ a += i7; >+ final(a,b,c); >+then use c as the hash value. If you have a variable length array of >+4-byte integers to hash, use compat_hashword(). If you have a byte array (like >+a character string), use compat_hashlittle(). If you have several byte arrays, or >+a mix of things, see the comments above compat_hashlittle(). >+ >+Why is this so big? I read 12 bytes at a time into 3 4-byte integers, >+then mix those integers. This is fast (you can do a lot more thorough >+mixing with 12*3 instructions on 3 integers than you can with 3 instructions >+on 1 byte), but shoehorning those bytes into integers efficiently is messy. >+------------------------------------------------------------------------------- >+*/ >+ >+#include <stdio.h> /* defines printf for tests */ >+#include <time.h> /* defines time_t for timings in the test */ >+#include "compat-lookup3.h" >+#ifdef linux >+# include <endian.h> /* attempt to define endianness */ >+#endif >+ >+/* >+ * My best guess at if you are big-endian or little-endian. This may >+ * need adjustment. >+ */ >+#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ >+ __BYTE_ORDER == __LITTLE_ENDIAN) || \ >+ (defined(i386) || defined(__i386__) || defined(__i486__) || \ >+ defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL)) >+# define HASH_LITTLE_ENDIAN 1 >+# define HASH_BIG_ENDIAN 0 >+#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ >+ __BYTE_ORDER == __BIG_ENDIAN) || \ >+ (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel)) >+# define HASH_LITTLE_ENDIAN 0 >+# define HASH_BIG_ENDIAN 1 >+#else >+# define HASH_LITTLE_ENDIAN 0 >+# define HASH_BIG_ENDIAN 0 >+#endif >+ >+#define hashsize(n) ((uint32_t)1<<(n)) >+#define hashmask(n) (hashsize(n)-1) >+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) >+ >+/* >+------------------------------------------------------------------------------- >+mix -- mix 3 32-bit values reversibly. >+ >+This is reversible, so any information in (a,b,c) before mix() is >+still in (a,b,c) after mix(). >+ >+If four pairs of (a,b,c) inputs are run through mix(), or through >+mix() in reverse, there are at least 32 bits of the output that >+are sometimes the same for one pair and different for another pair. >+This was tested for: >+* pairs that differed by one bit, by two bits, in any combination >+ of top bits of (a,b,c), or in any combination of bottom bits of >+ (a,b,c). >+* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed >+ the output delta to a Gray code (a^(a>>1)) so a string of 1's (as >+ is commonly produced by subtraction) look like a single 1-bit >+ difference. >+* the base values were pseudorandom, all zero but one bit set, or >+ all zero plus a counter that starts at zero. >+ >+Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that >+satisfy this are >+ 4 6 8 16 19 4 >+ 9 15 3 18 27 15 >+ 14 9 3 7 17 3 >+Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing >+for "differ" defined as + with a one-bit base and a two-bit delta. I >+used http://burtleburtle.net/bob/hash/avalanche.html to choose >+the operations, constants, and arrangements of the variables. >+ >+This does not achieve avalanche. There are input bits of (a,b,c) >+that fail to affect some output bits of (a,b,c), especially of a. The >+most thoroughly mixed value is c, but it doesn't really even achieve >+avalanche in c. >+ >+This allows some parallelism. Read-after-writes are good at doubling >+the number of bits affected, so the goal of mixing pulls in the opposite >+direction as the goal of parallelism. I did what I could. Rotates >+seem to cost as much as shifts on every machine I could lay my hands >+on, and rotates are much kinder to the top and bottom bits, so I used >+rotates. >+------------------------------------------------------------------------------- >+*/ >+#define mix(a,b,c) \ >+{ \ >+ a -= c; a ^= rot(c, 4); c += b; \ >+ b -= a; b ^= rot(a, 6); a += c; \ >+ c -= b; c ^= rot(b, 8); b += a; \ >+ a -= c; a ^= rot(c,16); c += b; \ >+ b -= a; b ^= rot(a,19); a += c; \ >+ c -= b; c ^= rot(b, 4); b += a; \ >+} >+ >+/* >+------------------------------------------------------------------------------- >+final -- final mixing of 3 32-bit values (a,b,c) into c >+ >+Pairs of (a,b,c) values differing in only a few bits will usually >+produce values of c that look totally different. This was tested for >+* pairs that differed by one bit, by two bits, in any combination >+ of top bits of (a,b,c), or in any combination of bottom bits of >+ (a,b,c). >+* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed >+ the output delta to a Gray code (a^(a>>1)) so a string of 1's (as >+ is commonly produced by subtraction) look like a single 1-bit >+ difference. >+* the base values were pseudorandom, all zero but one bit set, or >+ all zero plus a counter that starts at zero. >+ >+These constants passed: >+ 14 11 25 16 4 14 24 >+ 12 14 25 16 4 14 24 >+and these came close: >+ 4 8 15 26 3 22 24 >+ 10 8 15 26 3 22 24 >+ 11 8 15 26 3 22 24 >+------------------------------------------------------------------------------- >+*/ >+#define final(a,b,c) \ >+{ \ >+ c ^= b; c -= rot(b,14); \ >+ a ^= c; a -= rot(c,11); \ >+ b ^= a; b -= rot(a,25); \ >+ c ^= b; c -= rot(b,16); \ >+ a ^= c; a -= rot(c,4); \ >+ b ^= a; b -= rot(a,14); \ >+ c ^= b; c -= rot(b,24); \ >+} >+ >+/* >+-------------------------------------------------------------------- >+ This works on all machines. To be useful, it requires >+ -- that the key be an array of uint32_t's, and >+ -- that the length be the number of uint32_t's in the key >+ >+ The function compat_hashword() is identical to compat_hashlittle() on little-endian >+ machines, and identical to compat_hashbig() on big-endian machines, >+ except that the length has to be measured in uint32_ts rather than in >+ bytes. compat_hashlittle() is more complicated than compat_hashword() only because >+ compat_hashlittle() has to dance around fitting the key bytes into registers. >+-------------------------------------------------------------------- >+*/ >+uint32_t compat_hashword( >+ const uint32_t *k, /* the key, an array of uint32_t values */ >+ size_t length, /* the length of the key, in uint32_ts */ >+ uint32_t initval) /* the previous hash, or an arbitrary value */ >+{ >+ uint32_t a,b,c; >+ >+ /* Set up the internal state */ >+ a = b = c = 0xdeadbeef + (((uint32_t)length)<<2) + initval; >+ >+ /*------------------------------------------------- handle most of the key */ >+ while (length > 3) >+ { >+ a += k[0]; >+ b += k[1]; >+ c += k[2]; >+ mix(a,b,c); >+ length -= 3; >+ k += 3; >+ } >+ >+ /*------------------------------------------- handle the last 3 uint32_t's */ >+ switch(length) /* all the case statements fall through */ >+ { >+ case 3 : c+=k[2]; >+ case 2 : b+=k[1]; >+ case 1 : a+=k[0]; >+ final(a,b,c); >+ case 0: /* case 0: nothing left to add */ >+ break; >+ } >+ /*------------------------------------------------------ report the result */ >+ return c; >+} >+ >+ >+/* >+-------------------------------------------------------------------- >+compat_hashword2() -- same as compat_hashword(), but take two seeds and return two >+32-bit values. pc and pb must both be nonnull, and *pc and *pb must >+both be initialized with seeds. If you pass in (*pb)==0, the output >+(*pc) will be the same as the return value from compat_hashword(). >+-------------------------------------------------------------------- >+*/ >+void compat_hashword2 ( >+const uint32_t *k, /* the key, an array of uint32_t values */ >+size_t length, /* the length of the key, in uint32_ts */ >+uint32_t *pc, /* IN: seed OUT: primary hash value */ >+uint32_t *pb) /* IN: more seed OUT: secondary hash value */ >+{ >+ uint32_t a,b,c; >+ >+ /* Set up the internal state */ >+ a = b = c = 0xdeadbeef + ((uint32_t)(length<<2)) + *pc; >+ c += *pb; >+ >+ /*------------------------------------------------- handle most of the key */ >+ while (length > 3) >+ { >+ a += k[0]; >+ b += k[1]; >+ c += k[2]; >+ mix(a,b,c); >+ length -= 3; >+ k += 3; >+ } >+ >+ /*------------------------------------------- handle the last 3 uint32_t's */ >+ switch(length) /* all the case statements fall through */ >+ { >+ case 3 : c+=k[2]; >+ case 2 : b+=k[1]; >+ case 1 : a+=k[0]; >+ final(a,b,c); >+ case 0: /* case 0: nothing left to add */ >+ break; >+ } >+ /*------------------------------------------------------ report the result */ >+ *pc=c; *pb=b; >+} >+ >+ >+/* >+------------------------------------------------------------------------------- >+compat_hashlittle() -- hash a variable-length key into a 32-bit value >+ k : the key (the unaligned variable-length array of bytes) >+ length : the length of the key, counting by bytes >+ initval : can be any 4-byte value >+Returns a 32-bit value. Every bit of the key affects every bit of >+the return value. Two keys differing by one or two bits will have >+totally different hash values. >+ >+The best hash table sizes are powers of 2. There is no need to do >+mod a prime (mod is sooo slow!). If you need less than 32 bits, >+use a bitmask. For example, if you need only 10 bits, do >+ h = (h & hashmask(10)); >+In which case, the hash table should have hashsize(10) elements. >+ >+If you are hashing n strings (uint8_t **)k, do it like this: >+ for (i=0, h=0; i<n; ++i) h = compat_hashlittle( k[i], len[i], h); >+ >+By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this >+code any way you wish, private, educational, or commercial. It's free. >+ >+Use for hash table lookup, or anything where one collision in 2^^32 is >+acceptable. Do NOT use for cryptographic purposes. >+------------------------------------------------------------------------------- >+*/ >+ >+uint32_t compat_hashlittle( const void *key, size_t length, uint32_t initval) >+{ >+ uint32_t a,b,c; /* internal state */ >+ union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */ >+ >+ /* Set up the internal state */ >+ a = b = c = 0xdeadbeef + ((uint32_t)length) + initval; >+ >+ u.ptr = key; >+ if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) { >+ const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ >+#ifdef VALGRIND >+ const uint8_t *k8; >+#endif >+ >+ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ >+ while (length > 12) >+ { >+ a += k[0]; >+ b += k[1]; >+ c += k[2]; >+ mix(a,b,c); >+ length -= 12; >+ k += 3; >+ } >+ >+ /*----------------------------- handle the last (probably partial) block */ >+ /* >+ * "k[2]&0xffffff" actually reads beyond the end of the string, but >+ * then masks off the part it's not allowed to read. Because the >+ * string is aligned, the masked-off tail is in the same word as the >+ * rest of the string. Every machine with memory protection I've seen >+ * does it on word boundaries, so is OK with this. But VALGRIND will >+ * still catch it and complain. The masking trick does make the hash >+ * noticably faster for short strings (like English words). >+ */ >+#ifndef VALGRIND >+ >+ switch(length) >+ { >+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; >+ case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; >+ case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; >+ case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; >+ case 8 : b+=k[1]; a+=k[0]; break; >+ case 7 : b+=k[1]&0xffffff; a+=k[0]; break; >+ case 6 : b+=k[1]&0xffff; a+=k[0]; break; >+ case 5 : b+=k[1]&0xff; a+=k[0]; break; >+ case 4 : a+=k[0]; break; >+ case 3 : a+=k[0]&0xffffff; break; >+ case 2 : a+=k[0]&0xffff; break; >+ case 1 : a+=k[0]&0xff; break; >+ case 0 : return c; /* zero length strings require no mixing */ >+ } >+ >+#else /* make valgrind happy */ >+ >+ k8 = (const uint8_t *)k; >+ switch(length) >+ { >+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; >+ case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ >+ case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ >+ case 9 : c+=k8[8]; /* fall through */ >+ case 8 : b+=k[1]; a+=k[0]; break; >+ case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ >+ case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ >+ case 5 : b+=k8[4]; /* fall through */ >+ case 4 : a+=k[0]; break; >+ case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ >+ case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ >+ case 1 : a+=k8[0]; break; >+ case 0 : return c; >+ } >+ >+#endif /* !valgrind */ >+ >+ } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { >+ const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ >+ const uint8_t *k8; >+ >+ /*--------------- all but last block: aligned reads and different mixing */ >+ while (length > 12) >+ { >+ a += k[0] + (((uint32_t)k[1])<<16); >+ b += k[2] + (((uint32_t)k[3])<<16); >+ c += k[4] + (((uint32_t)k[5])<<16); >+ mix(a,b,c); >+ length -= 12; >+ k += 6; >+ } >+ >+ /*----------------------------- handle the last (probably partial) block */ >+ k8 = (const uint8_t *)k; >+ switch(length) >+ { >+ case 12: c+=k[4]+(((uint32_t)k[5])<<16); >+ b+=k[2]+(((uint32_t)k[3])<<16); >+ a+=k[0]+(((uint32_t)k[1])<<16); >+ break; >+ case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ >+ case 10: c+=k[4]; >+ b+=k[2]+(((uint32_t)k[3])<<16); >+ a+=k[0]+(((uint32_t)k[1])<<16); >+ break; >+ case 9 : c+=k8[8]; /* fall through */ >+ case 8 : b+=k[2]+(((uint32_t)k[3])<<16); >+ a+=k[0]+(((uint32_t)k[1])<<16); >+ break; >+ case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ >+ case 6 : b+=k[2]; >+ a+=k[0]+(((uint32_t)k[1])<<16); >+ break; >+ case 5 : b+=k8[4]; /* fall through */ >+ case 4 : a+=k[0]+(((uint32_t)k[1])<<16); >+ break; >+ case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ >+ case 2 : a+=k[0]; >+ break; >+ case 1 : a+=k8[0]; >+ break; >+ case 0 : return c; /* zero length requires no mixing */ >+ } >+ >+ } else { /* need to read the key one byte at a time */ >+ const uint8_t *k = (const uint8_t *)key; >+ >+ /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ >+ while (length > 12) >+ { >+ a += k[0]; >+ a += ((uint32_t)k[1])<<8; >+ a += ((uint32_t)k[2])<<16; >+ a += ((uint32_t)k[3])<<24; >+ b += k[4]; >+ b += ((uint32_t)k[5])<<8; >+ b += ((uint32_t)k[6])<<16; >+ b += ((uint32_t)k[7])<<24; >+ c += k[8]; >+ c += ((uint32_t)k[9])<<8; >+ c += ((uint32_t)k[10])<<16; >+ c += ((uint32_t)k[11])<<24; >+ mix(a,b,c); >+ length -= 12; >+ k += 12; >+ } >+ >+ /*-------------------------------- last block: affect all 32 bits of (c) */ >+ switch(length) /* all the case statements fall through */ >+ { >+ case 12: c+=((uint32_t)k[11])<<24; >+ case 11: c+=((uint32_t)k[10])<<16; >+ case 10: c+=((uint32_t)k[9])<<8; >+ case 9 : c+=k[8]; >+ case 8 : b+=((uint32_t)k[7])<<24; >+ case 7 : b+=((uint32_t)k[6])<<16; >+ case 6 : b+=((uint32_t)k[5])<<8; >+ case 5 : b+=k[4]; >+ case 4 : a+=((uint32_t)k[3])<<24; >+ case 3 : a+=((uint32_t)k[2])<<16; >+ case 2 : a+=((uint32_t)k[1])<<8; >+ case 1 : a+=k[0]; >+ break; >+ case 0 : return c; >+ } >+ } >+ >+ final(a,b,c); >+ return c; >+} >+ >+ >+/* >+ * compat_hashlittle2: return 2 32-bit hash values >+ * >+ * This is identical to compat_hashlittle(), except it returns two 32-bit hash >+ * values instead of just one. This is good enough for hash table >+ * lookup with 2^^64 buckets, or if you want a second hash if you're not >+ * happy with the first, or if you want a probably-unique 64-bit ID for >+ * the key. *pc is better mixed than *pb, so use *pc first. If you want >+ * a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)". >+ */ >+void compat_hashlittle2( >+ const void *key, /* the key to hash */ >+ size_t length, /* length of the key */ >+ uint32_t *pc, /* IN: primary initval, OUT: primary hash */ >+ uint32_t *pb) /* IN: secondary initval, OUT: secondary hash */ >+{ >+ uint32_t a,b,c; /* internal state */ >+ union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */ >+ >+ /* Set up the internal state */ >+ a = b = c = 0xdeadbeef + ((uint32_t)length) + *pc; >+ c += *pb; >+ >+ u.ptr = key; >+ if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) { >+ const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ >+#ifdef VALGRIND >+ const uint8_t *k8; >+#endif >+ >+ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ >+ while (length > 12) >+ { >+ a += k[0]; >+ b += k[1]; >+ c += k[2]; >+ mix(a,b,c); >+ length -= 12; >+ k += 3; >+ } >+ >+ /*----------------------------- handle the last (probably partial) block */ >+ /* >+ * "k[2]&0xffffff" actually reads beyond the end of the string, but >+ * then masks off the part it's not allowed to read. Because the >+ * string is aligned, the masked-off tail is in the same word as the >+ * rest of the string. Every machine with memory protection I've seen >+ * does it on word boundaries, so is OK with this. But VALGRIND will >+ * still catch it and complain. The masking trick does make the hash >+ * noticably faster for short strings (like English words). >+ */ >+#ifndef VALGRIND >+ >+ switch(length) >+ { >+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; >+ case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; >+ case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; >+ case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; >+ case 8 : b+=k[1]; a+=k[0]; break; >+ case 7 : b+=k[1]&0xffffff; a+=k[0]; break; >+ case 6 : b+=k[1]&0xffff; a+=k[0]; break; >+ case 5 : b+=k[1]&0xff; a+=k[0]; break; >+ case 4 : a+=k[0]; break; >+ case 3 : a+=k[0]&0xffffff; break; >+ case 2 : a+=k[0]&0xffff; break; >+ case 1 : a+=k[0]&0xff; break; >+ case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ >+ } >+ >+#else /* make valgrind happy */ >+ >+ k8 = (const uint8_t *)k; >+ switch(length) >+ { >+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; >+ case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ >+ case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ >+ case 9 : c+=k8[8]; /* fall through */ >+ case 8 : b+=k[1]; a+=k[0]; break; >+ case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ >+ case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ >+ case 5 : b+=k8[4]; /* fall through */ >+ case 4 : a+=k[0]; break; >+ case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ >+ case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ >+ case 1 : a+=k8[0]; break; >+ case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ >+ } >+ >+#endif /* !valgrind */ >+ >+ } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { >+ const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ >+ const uint8_t *k8; >+ >+ /*--------------- all but last block: aligned reads and different mixing */ >+ while (length > 12) >+ { >+ a += k[0] + (((uint32_t)k[1])<<16); >+ b += k[2] + (((uint32_t)k[3])<<16); >+ c += k[4] + (((uint32_t)k[5])<<16); >+ mix(a,b,c); >+ length -= 12; >+ k += 6; >+ } >+ >+ /*----------------------------- handle the last (probably partial) block */ >+ k8 = (const uint8_t *)k; >+ switch(length) >+ { >+ case 12: c+=k[4]+(((uint32_t)k[5])<<16); >+ b+=k[2]+(((uint32_t)k[3])<<16); >+ a+=k[0]+(((uint32_t)k[1])<<16); >+ break; >+ case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ >+ case 10: c+=k[4]; >+ b+=k[2]+(((uint32_t)k[3])<<16); >+ a+=k[0]+(((uint32_t)k[1])<<16); >+ break; >+ case 9 : c+=k8[8]; /* fall through */ >+ case 8 : b+=k[2]+(((uint32_t)k[3])<<16); >+ a+=k[0]+(((uint32_t)k[1])<<16); >+ break; >+ case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ >+ case 6 : b+=k[2]; >+ a+=k[0]+(((uint32_t)k[1])<<16); >+ break; >+ case 5 : b+=k8[4]; /* fall through */ >+ case 4 : a+=k[0]+(((uint32_t)k[1])<<16); >+ break; >+ case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ >+ case 2 : a+=k[0]; >+ break; >+ case 1 : a+=k8[0]; >+ break; >+ case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ >+ } >+ >+ } else { /* need to read the key one byte at a time */ >+ const uint8_t *k = (const uint8_t *)key; >+ >+ /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ >+ while (length > 12) >+ { >+ a += k[0]; >+ a += ((uint32_t)k[1])<<8; >+ a += ((uint32_t)k[2])<<16; >+ a += ((uint32_t)k[3])<<24; >+ b += k[4]; >+ b += ((uint32_t)k[5])<<8; >+ b += ((uint32_t)k[6])<<16; >+ b += ((uint32_t)k[7])<<24; >+ c += k[8]; >+ c += ((uint32_t)k[9])<<8; >+ c += ((uint32_t)k[10])<<16; >+ c += ((uint32_t)k[11])<<24; >+ mix(a,b,c); >+ length -= 12; >+ k += 12; >+ } >+ >+ /*-------------------------------- last block: affect all 32 bits of (c) */ >+ switch(length) /* all the case statements fall through */ >+ { >+ case 12: c+=((uint32_t)k[11])<<24; >+ case 11: c+=((uint32_t)k[10])<<16; >+ case 10: c+=((uint32_t)k[9])<<8; >+ case 9 : c+=k[8]; >+ case 8 : b+=((uint32_t)k[7])<<24; >+ case 7 : b+=((uint32_t)k[6])<<16; >+ case 6 : b+=((uint32_t)k[5])<<8; >+ case 5 : b+=k[4]; >+ case 4 : a+=((uint32_t)k[3])<<24; >+ case 3 : a+=((uint32_t)k[2])<<16; >+ case 2 : a+=((uint32_t)k[1])<<8; >+ case 1 : a+=k[0]; >+ break; >+ case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ >+ } >+ } >+ >+ final(a,b,c); >+ *pc=c; *pb=b; >+} >+ >+ >+ >+/* >+ * compat_hashbig(): >+ * This is the same as compat_hashword() on big-endian machines. It is different >+ * from compat_hashlittle() on all machines. compat_hashbig() takes advantage of >+ * big-endian byte ordering. >+ */ >+uint32_t compat_hashbig( const void *key, size_t length, uint32_t initval) >+{ >+ uint32_t a,b,c; >+ union { const void *ptr; size_t i; } u; /* to cast key to (size_t) happily */ >+ >+ /* Set up the internal state */ >+ a = b = c = 0xdeadbeef + ((uint32_t)length) + initval; >+ >+ u.ptr = key; >+ if (HASH_BIG_ENDIAN && ((u.i & 0x3) == 0)) { >+ const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ >+#ifdef VALGRIND >+ const uint8_t *k8; >+#endif >+ >+ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ >+ while (length > 12) >+ { >+ a += k[0]; >+ b += k[1]; >+ c += k[2]; >+ mix(a,b,c); >+ length -= 12; >+ k += 3; >+ } >+ >+ /*----------------------------- handle the last (probably partial) block */ >+ /* >+ * "k[2]<<8" actually reads beyond the end of the string, but >+ * then shifts out the part it's not allowed to read. Because the >+ * string is aligned, the illegal read is in the same word as the >+ * rest of the string. Every machine with memory protection I've seen >+ * does it on word boundaries, so is OK with this. But VALGRIND will >+ * still catch it and complain. The masking trick does make the hash >+ * noticably faster for short strings (like English words). >+ */ >+#ifndef VALGRIND >+ >+ switch(length) >+ { >+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; >+ case 11: c+=k[2]&0xffffff00; b+=k[1]; a+=k[0]; break; >+ case 10: c+=k[2]&0xffff0000; b+=k[1]; a+=k[0]; break; >+ case 9 : c+=k[2]&0xff000000; b+=k[1]; a+=k[0]; break; >+ case 8 : b+=k[1]; a+=k[0]; break; >+ case 7 : b+=k[1]&0xffffff00; a+=k[0]; break; >+ case 6 : b+=k[1]&0xffff0000; a+=k[0]; break; >+ case 5 : b+=k[1]&0xff000000; a+=k[0]; break; >+ case 4 : a+=k[0]; break; >+ case 3 : a+=k[0]&0xffffff00; break; >+ case 2 : a+=k[0]&0xffff0000; break; >+ case 1 : a+=k[0]&0xff000000; break; >+ case 0 : return c; /* zero length strings require no mixing */ >+ } >+ >+#else /* make valgrind happy */ >+ >+ k8 = (const uint8_t *)k; >+ switch(length) /* all the case statements fall through */ >+ { >+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; >+ case 11: c+=((uint32_t)k8[10])<<8; /* fall through */ >+ case 10: c+=((uint32_t)k8[9])<<16; /* fall through */ >+ case 9 : c+=((uint32_t)k8[8])<<24; /* fall through */ >+ case 8 : b+=k[1]; a+=k[0]; break; >+ case 7 : b+=((uint32_t)k8[6])<<8; /* fall through */ >+ case 6 : b+=((uint32_t)k8[5])<<16; /* fall through */ >+ case 5 : b+=((uint32_t)k8[4])<<24; /* fall through */ >+ case 4 : a+=k[0]; break; >+ case 3 : a+=((uint32_t)k8[2])<<8; /* fall through */ >+ case 2 : a+=((uint32_t)k8[1])<<16; /* fall through */ >+ case 1 : a+=((uint32_t)k8[0])<<24; break; >+ case 0 : return c; >+ } >+ >+#endif /* !VALGRIND */ >+ >+ } else { /* need to read the key one byte at a time */ >+ const uint8_t *k = (const uint8_t *)key; >+ >+ /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ >+ while (length > 12) >+ { >+ a += ((uint32_t)k[0])<<24; >+ a += ((uint32_t)k[1])<<16; >+ a += ((uint32_t)k[2])<<8; >+ a += ((uint32_t)k[3]); >+ b += ((uint32_t)k[4])<<24; >+ b += ((uint32_t)k[5])<<16; >+ b += ((uint32_t)k[6])<<8; >+ b += ((uint32_t)k[7]); >+ c += ((uint32_t)k[8])<<24; >+ c += ((uint32_t)k[9])<<16; >+ c += ((uint32_t)k[10])<<8; >+ c += ((uint32_t)k[11]); >+ mix(a,b,c); >+ length -= 12; >+ k += 12; >+ } >+ >+ /*-------------------------------- last block: affect all 32 bits of (c) */ >+ switch(length) /* all the case statements fall through */ >+ { >+ case 12: c+=k[11]; >+ case 11: c+=((uint32_t)k[10])<<8; >+ case 10: c+=((uint32_t)k[9])<<16; >+ case 9 : c+=((uint32_t)k[8])<<24; >+ case 8 : b+=k[7]; >+ case 7 : b+=((uint32_t)k[6])<<8; >+ case 6 : b+=((uint32_t)k[5])<<16; >+ case 5 : b+=((uint32_t)k[4])<<24; >+ case 4 : a+=k[3]; >+ case 3 : a+=((uint32_t)k[2])<<8; >+ case 2 : a+=((uint32_t)k[1])<<16; >+ case 1 : a+=((uint32_t)k[0])<<24; >+ break; >+ case 0 : return c; >+ } >+ } >+ >+ final(a,b,c); >+ return c; >+} >+ >diff --git a/src/compat/compat-lookup3.h b/src/compat/compat-lookup3.h >new file mode 100644 >index 0000000..67658ad >--- /dev/null >+++ b/src/compat/compat-lookup3.h >@@ -0,0 +1,26 @@ >+#ifndef __LOOKUP3_H >+#define __LOOKUP3_H >+ >+#if defined(__GNUC__) || defined(__sun) >+ >+#include <stdint.h> >+ >+#else >+ >+#ifdef QXLDD >+#include <windef.h> >+#include "os_dep.h" >+#else >+#include <stddef.h> >+#include <basetsd.h> >+#endif >+ >+typedef UINT32 uint32_t; >+typedef UINT16 uint16_t; >+typedef UINT8 uint8_t; >+ >+#endif >+ >+uint32_t compat_hashlittle( const void *key, size_t length, uint32_t initval); >+ >+#endif >diff --git a/src/compat/compat-qxl.h b/src/compat/compat-qxl.h >new file mode 100644 >index 0000000..eed3a2f >--- /dev/null >+++ b/src/compat/compat-qxl.h >@@ -0,0 +1,611 @@ >+/* >+ * Copyright 2008 Red Hat, Inc. >+ * >+ * Permission is hereby granted, free of charge, to any person obtaining a >+ * copy of this software and associated documentation files (the "Software"), >+ * to deal in the Software without restriction, including without limitation >+ * on the rights to use, copy, modify, merge, publish, distribute, sub >+ * license, and/or sell copies of the Software, and to permit persons to whom >+ * the Software is furnished to do so, subject to the following conditions: >+ * >+ * The above copyright notice and this permission notice (including the next >+ * paragraph) shall be included in all copies or substantial portions of the >+ * Software. >+ * >+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR >+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, >+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL >+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER >+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN >+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. >+ */ >+ >+#include "config.h" >+ >+#include <stdint.h> >+ >+#include "compiler.h" >+#include "xf86.h" >+#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6 >+#include "xf86Resources.h" >+#endif >+#include "xf86PciInfo.h" >+#include "xf86Cursor.h" >+#include "xf86_OSproc.h" >+#include "xf86xv.h" >+#include "shadow.h" >+#include "micmap.h" >+#ifdef XSERVER_PCIACCESS >+#include "pciaccess.h" >+#endif >+#include "fb.h" >+#include "vgaHW.h" >+ >+#include "../compat-api.h" >+#define hidden _X_HIDDEN >+ >+#define QXL_NAME "compat_qxl" >+#define QXL_DRIVER_NAME "compat_qxl" >+#define PCI_VENDOR_RED_HAT 0x1b36 >+ >+#define PCI_CHIP_QXL_0100 0x0100 >+ >+#pragma pack(push,1) >+ >+/* I/O port definitions */ >+enum { >+ QXL_IO_NOTIFY_CMD, >+ QXL_IO_NOTIFY_CURSOR, >+ QXL_IO_UPDATE_AREA, >+ QXL_IO_UPDATE_IRQ, >+ QXL_IO_NOTIFY_OOM, >+ QXL_IO_RESET, >+ QXL_IO_SET_MODE, >+ QXL_IO_LOG, >+}; >+ >+struct compat_qxl_mode { >+ uint32_t id; >+ uint32_t x_res; >+ uint32_t y_res; >+ uint32_t bits; >+ uint32_t stride; >+ uint32_t x_mili; >+ uint32_t y_mili; >+ uint32_t orientation; >+}; >+ >+typedef enum >+{ >+ QXL_CMD_NOP, >+ QXL_CMD_DRAW, >+ QXL_CMD_UPDATE, >+ QXL_CMD_CURSOR, >+ QXL_CMD_MESSAGE >+} compat_qxl_command_type; >+ >+struct compat_qxl_command { >+ uint64_t data; >+ uint32_t type; >+ uint32_t pad; >+}; >+ >+struct compat_qxl_rect { >+ uint32_t top; >+ uint32_t left; >+ uint32_t bottom; >+ uint32_t right; >+}; >+ >+union compat_qxl_release_info { >+ uint64_t id; >+ uint64_t next; >+}; >+ >+struct compat_qxl_clip { >+ uint32_t type; >+ uint64_t address; >+}; >+ >+struct compat_qxl_point { >+ int x; >+ int y; >+}; >+ >+struct compat_qxl_pattern { >+ uint64_t pat; >+ struct compat_qxl_point pos; >+}; >+ >+typedef enum >+{ >+ QXL_BRUSH_TYPE_NONE, >+ QXL_BRUSH_TYPE_SOLID, >+ QXL_BRUSH_TYPE_PATTERN >+} compat_qxl_brush_type; >+ >+struct compat_qxl_brush { >+ uint32_t type; >+ union { >+ uint32_t color; >+ struct compat_qxl_pattern pattern; >+ } u; >+}; >+ >+struct compat_qxl_mask { >+ unsigned char flags; >+ struct compat_qxl_point pos; >+ uint64_t bitmap; >+}; >+ >+typedef enum { >+ QXL_IMAGE_TYPE_BITMAP, >+ QXL_IMAGE_TYPE_QUIC, >+ QXL_IMAGE_TYPE_PNG, >+ QXL_IMAGE_TYPE_LZ_PLT = 100, >+ QXL_IMAGE_TYPE_LZ_RGB, >+ QXL_IMAGE_TYPE_GLZ_RGB, >+ QXL_IMAGE_TYPE_FROM_CACHE, >+} compat_qxl_image_type; >+ >+typedef enum { >+ QXL_IMAGE_CACHE = (1 << 0) >+} compat_qxl_image_flags; >+ >+struct compat_qxl_image_descriptor >+{ >+ uint64_t id; >+ uint8_t type; >+ uint8_t flags; >+ uint32_t width; >+ uint32_t height; >+}; >+ >+struct compat_qxl_data_chunk { >+ uint32_t data_size; >+ uint64_t prev_chunk; >+ uint64_t next_chunk; >+ uint8_t data[0]; >+}; >+ >+typedef enum >+{ >+ QXL_BITMAP_FMT_INVALID, >+ QXL_BITMAP_FMT_1BIT_LE, >+ QXL_BITMAP_FMT_1BIT_BE, >+ QXL_BITMAP_FMT_4BIT_LE, >+ QXL_BITMAP_FMT_4BIT_BE, >+ QXL_BITMAP_FMT_8BIT, >+ QXL_BITMAP_FMT_16BIT, >+ QXL_BITMAP_FMT_24BIT, >+ QXL_BITMAP_FMT_32BIT, >+ QXL_BITMAP_FMT_RGBA, >+} compat_qxl_bitmap_format; >+ >+typedef enum { >+ QXL_BITMAP_PAL_CACHE_ME = (1 << 0), >+ QXL_BITMAP_PAL_FROM_CACHE = (1 << 1), >+ QXL_BITMAP_TOP_DOWN = (1 << 2), >+} compat_qxl_bitmap_flags; >+ >+struct compat_qxl_bitmap { >+ uint8_t format; >+ uint8_t flags; >+ uint32_t x; /* actually width */ >+ uint32_t y; /* actually height */ >+ uint32_t stride; /* in bytes */ >+ uint64_t palette; /* Can be NULL */ >+ uint64_t data; /* A compat_qxl_data_chunk that actually contains the data */ >+}; >+ >+struct compat_qxl_image { >+ struct compat_qxl_image_descriptor descriptor; >+ union >+ { >+ struct compat_qxl_bitmap bitmap; >+ } u; >+}; >+ >+struct compat_qxl_fill { >+ struct compat_qxl_brush brush; >+ unsigned short rop_descriptor; >+ struct compat_qxl_mask mask; >+}; >+ >+struct compat_qxl_opaque { >+ uint64_t src_bitmap; >+ struct compat_qxl_rect src_area; >+ struct compat_qxl_brush brush; >+ unsigned short rop_descriptor; >+ unsigned char scale_mode; >+ struct compat_qxl_mask mask; >+}; >+ >+struct compat_qxl_copy { >+ uint64_t src_bitmap; >+ struct compat_qxl_rect src_area; >+ unsigned short rop_descriptor; >+ unsigned char scale_mode; >+ struct compat_qxl_mask mask; >+}; >+ >+struct compat_qxl_transparent { >+ uint64_t src_bitmap; >+ struct compat_qxl_rect src_area; >+ uint32_t src_color; >+ uint32_t true_color; >+}; >+ >+struct compat_qxl_alpha_blend { >+ unsigned char alpha; >+ uint64_t src_bitmap; >+ struct compat_qxl_rect src_area; >+}; >+ >+struct compat_qxl_copy_bits { >+ struct compat_qxl_point src_pos; >+}; >+ >+struct compat_qxl_blend { /* same as copy */ >+ uint64_t src_bitmap; >+ struct compat_qxl_rect src_area; >+ unsigned short rop_descriptor; >+ unsigned char scale_mode; >+ struct compat_qxl_mask mask; >+}; >+ >+struct compat_qxl_rop3 { >+ uint64_t src_bitmap; >+ struct compat_qxl_rect src_area; >+ struct compat_qxl_brush brush; >+ unsigned char rop3; >+ unsigned char scale_mode; >+ struct compat_qxl_mask mask; >+}; >+ >+struct compat_qxl_line_attr { >+ unsigned char flags; >+ unsigned char join_style; >+ unsigned char end_style; >+ unsigned char style_nseg; >+ int width; >+ int miter_limit; >+ uint64_t style; >+}; >+ >+struct compat_qxl_stroke { >+ uint64_t path; >+ struct compat_qxl_line_attr attr; >+ struct compat_qxl_brush brush; >+ unsigned short fore_mode; >+ unsigned short back_mode; >+}; >+ >+struct compat_qxl_text { >+ uint64_t str; >+ struct compat_qxl_rect back_area; >+ struct compat_qxl_brush fore_brush; >+ struct compat_qxl_brush back_brush; >+ unsigned short fore_mode; >+ unsigned short back_mode; >+}; >+ >+struct compat_qxl_blackness { >+ struct compat_qxl_mask mask; >+}; >+ >+struct compat_qxl_inverse { >+ struct compat_qxl_mask mask; >+}; >+ >+struct compat_qxl_whiteness { >+ struct compat_qxl_mask mask; >+}; >+ >+/* Effects */ >+typedef enum >+{ >+ QXL_EFFECT_BLEND, >+ QXL_EFFECT_OPAQUE, >+ QXL_EFFECT_REVERT_ON_DUP, >+ QXL_EFFECT_BLACKNESS_ON_DUP, >+ QXL_EFFECT_WHITENESS_ON_DUP, >+ QXL_EFFECT_NOP_ON_DUP, >+ QXL_EFFECT_NOP, >+ QXL_EFFECT_OPAQUE_BRUSH >+} compat_qxl_effect_type; >+ >+typedef enum >+{ >+ QXL_CLIP_TYPE_NONE, >+ QXL_CLIP_TYPE_RECTS, >+ QXL_CLIP_TYPE_PATH, >+} compat_qxl_clip_type; >+ >+typedef enum { >+ QXL_DRAW_NOP, >+ QXL_DRAW_FILL, >+ QXL_DRAW_OPAQUE, >+ QXL_DRAW_COPY, >+ QXL_COPY_BITS, >+ QXL_DRAW_BLEND, >+ QXL_DRAW_BLACKNESS, >+ QXL_DRAW_WHITENESS, >+ QXL_DRAW_INVERS, >+ QXL_DRAW_ROP3, >+ QXL_DRAW_STROKE, >+ QXL_DRAW_TEXT, >+ QXL_DRAW_TRANSPARENT, >+ QXL_DRAW_ALPHA_BLEND, >+} compat_qxl_draw_type; >+ >+struct compat_qxl_drawable { >+ union compat_qxl_release_info release_info; >+ unsigned char effect; >+ unsigned char type; >+ unsigned short bitmap_offset; >+ struct compat_qxl_rect bitmap_area; >+ struct compat_qxl_rect bbox; >+ struct compat_qxl_clip clip; >+ uint32_t mm_time; >+ union { >+ struct compat_qxl_fill fill; >+ struct compat_qxl_opaque opaque; >+ struct compat_qxl_copy copy; >+ struct compat_qxl_transparent transparent; >+ struct compat_qxl_alpha_blend alpha_blend; >+ struct compat_qxl_copy_bits copy_bits; >+ struct compat_qxl_blend blend; >+ struct compat_qxl_rop3 rop3; >+ struct compat_qxl_stroke stroke; >+ struct compat_qxl_text text; >+ struct compat_qxl_blackness blackness; >+ struct compat_qxl_inverse inverse; >+ struct compat_qxl_whiteness whiteness; >+ } u; >+}; >+ >+struct compat_qxl_update_cmd { >+ union compat_qxl_release_info release_info; >+ struct compat_qxl_rect area; >+ uint32_t update_id; >+}; >+ >+struct compat_qxl_point16 { >+ int16_t x; >+ int16_t y; >+}; >+ >+enum { >+ QXL_CURSOR_SET, >+ QXL_CURSOR_MOVE, >+ QXL_CURSOR_HIDE, >+ QXL_CURSOR_TRAIL, >+}; >+ >+#define QXL_CURSOR_DEVICE_DATA_SIZE 128 >+ >+enum { >+ CURSOR_TYPE_ALPHA, >+ CURSOR_TYPE_MONO, >+ CURSOR_TYPE_COLOR4, >+ CURSOR_TYPE_COLOR8, >+ CURSOR_TYPE_COLOR16, >+ CURSOR_TYPE_COLOR24, >+ CURSOR_TYPE_COLOR32, >+}; >+ >+struct compat_qxl_cursor_header { >+ uint64_t unique; >+ uint16_t type; >+ uint16_t width; >+ uint16_t height; >+ uint16_t hot_spot_x; >+ uint16_t hot_spot_y; >+}; >+ >+struct compat_qxl_cursor >+{ >+ struct compat_qxl_cursor_header header; >+ uint32_t data_size; >+ struct compat_qxl_data_chunk chunk; >+}; >+ >+struct compat_qxl_cursor_cmd { >+ union compat_qxl_release_info release_info; >+ uint8_t type; >+ union { >+ struct { >+ struct compat_qxl_point16 position; >+ unsigned char visible; >+ uint64_t shape; >+ } set; >+ struct { >+ uint16_t length; >+ uint16_t frequency; >+ } trail; >+ struct compat_qxl_point16 position; >+ } u; >+ uint8_t device_data[QXL_CURSOR_DEVICE_DATA_SIZE]; >+}; >+ >+struct compat_qxl_rom { >+ uint32_t magic; >+ uint32_t id; >+ uint32_t update_id; >+ uint32_t compression_level; >+ uint32_t log_level; >+ uint32_t mode; >+ uint32_t modes_offset; >+ uint32_t num_io_pages; >+ uint32_t pages_offset; >+ uint32_t draw_area_offset; >+ uint32_t draw_area_size; >+ uint32_t ram_header_offset; >+ uint32_t mm_clock; >+}; >+ >+struct compat_qxl_ring_header { >+ uint32_t num_items; >+ uint32_t prod; >+ uint32_t notify_on_prod; >+ uint32_t cons; >+ uint32_t notify_on_cons; >+}; >+ >+#define QXL_LOG_BUF_SIZE 4096 >+ >+struct compat_qxl_ram_header { >+ uint32_t magic; >+ uint32_t int_pending; >+ uint32_t int_mask; >+ unsigned char log_buf[QXL_LOG_BUF_SIZE]; >+ struct compat_qxl_ring_header cmd_ring_hdr; >+ struct compat_qxl_command cmd_ring[32]; >+ struct compat_qxl_ring_header cursor_ring_hdr; >+ struct compat_qxl_command cursor_ring[32]; >+ struct compat_qxl_ring_header release_ring_hdr; >+ uint64_t release_ring[8]; >+ struct compat_qxl_rect update_area; >+}; >+ >+#pragma pack(pop) >+ >+typedef struct _compat_qxl_screen_t compat_qxl_screen_t; >+ >+struct _compat_qxl_screen_t >+{ >+ /* These are the names QXL uses */ >+ void * ram; /* Video RAM */ >+ void * ram_physical; >+ void * vram; /* Command RAM */ >+ struct compat_qxl_rom * rom; /* Parameter RAM */ >+ >+ struct compat_qxl_ring * command_ring; >+ struct compat_qxl_ring * cursor_ring; >+ struct compat_qxl_ring * release_ring; >+ >+ int num_modes; >+ struct compat_qxl_mode * modes; >+ int io_base; >+ int draw_area_offset; >+ int draw_area_size; >+ >+ void * fb; >+ int bytes_per_pixel; >+ >+ struct compat_qxl_mem * mem; /* Context for compat_qxl_alloc/free */ >+ >+ EntityInfoPtr entity; >+ >+ void * io_pages; >+ void * io_pages_physical; >+ >+#ifdef XSERVER_LIBPCIACCESS >+ struct pci_device * pci; >+#else >+ pciVideoPtr pci; >+ PCITAG pci_tag; >+#endif >+ vgaRegRec vgaRegs; >+ >+ CreateScreenResourcesProcPtr create_screen_resources; >+ CloseScreenProcPtr close_screen; >+ CreateGCProcPtr create_gc; >+#if 0 >+ PaintWindowProcPtr paint_window_background; >+ PaintWindowProcPtr paint_window_border; >+#endif >+ CopyWindowProcPtr copy_window; >+ >+ DamagePtr damage; >+ RegionRec pending_copy; >+ RegionRec to_be_sent; >+ >+ int16_t cur_x; >+ int16_t cur_y; >+ int16_t hot_x; >+ int16_t hot_y; >+ >+ ScrnInfoPtr pScrn; >+}; >+ >+static inline uint64_t >+physical_address (compat_qxl_screen_t *compat_qxl, void *virtual) >+{ >+ return (uint64_t) ((unsigned long)virtual + (((unsigned long)compat_qxl->ram_physical - (unsigned long)compat_qxl->ram))); >+} >+ >+static inline void * >+virtual_address (compat_qxl_screen_t *compat_qxl, void *physical) >+{ >+ return (void *) ((unsigned long)physical + ((unsigned long)compat_qxl->ram - (unsigned long)compat_qxl->ram_physical)); >+} >+ >+static inline void * >+u64_to_pointer (uint64_t u) >+{ >+ return (void *)(unsigned long)u; >+} >+ >+static inline uint64_t >+pointer_to_u64 (void *p) >+{ >+ return (uint64_t)(unsigned long)p; >+} >+ >+struct compat_qxl_ring; >+ >+/* >+ * HW cursor >+ */ >+void compat_qxl_cursor_init (ScreenPtr pScreen); >+ >+ >+ >+/* >+ * Rings >+ */ >+struct compat_qxl_ring * compat_qxl_ring_create (struct compat_qxl_ring_header *header, >+ int element_size, >+ int n_elements, >+ int prod_notify); >+void compat_qxl_ring_push (struct compat_qxl_ring *ring, >+ const void *element); >+Bool compat_qxl_ring_pop (struct compat_qxl_ring *ring, >+ void *element); >+void compat_qxl_ring_wait_idle (struct compat_qxl_ring *ring); >+ >+ >+ >+/* >+ * Images >+ */ >+struct compat_qxl_image *compat_qxl_image_create (compat_qxl_screen_t *compat_qxl, >+ const uint8_t *data, >+ int x, >+ int y, >+ int width, >+ int height, >+ int stride); >+void compat_qxl_image_destroy (compat_qxl_screen_t *compat_qxl, >+ struct compat_qxl_image *image); >+void compat_qxl_drop_image_cache (compat_qxl_screen_t *compat_qxl); >+ >+ >+/* >+ * Malloc >+ */ >+struct compat_qxl_mem * compat_qxl_mem_create (void *base, >+ unsigned long n_bytes); >+void compat_qxl_mem_dump_stats (struct compat_qxl_mem *mem, >+ const char *header); >+void * compat_qxl_alloc (struct compat_qxl_mem *mem, >+ unsigned long n_bytes); >+void compat_qxl_free (struct compat_qxl_mem *mem, >+ void *d); >+void compat_qxl_mem_free_all (struct compat_qxl_mem *mem); >+void * compat_qxl_allocnf (compat_qxl_screen_t *compat_qxl, >+ unsigned long size); >+ >+ >diff --git a/src/compat/compat-qxl_cursor.c b/src/compat/compat-qxl_cursor.c >new file mode 100644 >index 0000000..e94eb6a >--- /dev/null >+++ b/src/compat/compat-qxl_cursor.c >@@ -0,0 +1,196 @@ >+/* >+ * Copyright 2009 Red Hat, Inc. >+ * >+ * Permission is hereby granted, free of charge, to any person obtaining a >+ * copy of this software and associated documentation files (the "Software"), >+ * to deal in the Software without restriction, including without limitation >+ * on the rights to use, copy, modify, merge, publish, distribute, sub >+ * license, and/or sell copies of the Software, and to permit persons to whom >+ * the Software is furnished to do so, subject to the following conditions: >+ * >+ * The above copyright notice and this permission notice (including the next >+ * paragraph) shall be included in all copies or substantial portions of the >+ * Software. >+ * >+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR >+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, >+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL >+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER >+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN >+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. >+ */ >+ >+#include <string.h> >+#include "compat-qxl.h" >+#include <cursorstr.h> >+ >+static void >+push_cursor (compat_qxl_screen_t *compat_qxl, struct compat_qxl_cursor_cmd *cursor) >+{ >+ struct compat_qxl_command cmd; >+ >+ /* See comment on push_command() in compat_qxl_driver.c */ >+ if (compat_qxl->rom->mode != ~0) >+ { >+ cmd.type = QXL_CMD_CURSOR; >+ cmd.data = physical_address (compat_qxl, cursor); >+ >+ compat_qxl_ring_push (compat_qxl->cursor_ring, &cmd); >+ } >+} >+ >+static struct compat_qxl_cursor_cmd * >+compat_qxl_alloc_cursor_cmd(compat_qxl_screen_t *compat_qxl) >+{ >+ struct compat_qxl_cursor_cmd *cmd = >+ compat_qxl_allocnf (compat_qxl, sizeof(struct compat_qxl_cursor_cmd)); >+ >+ cmd->release_info.id = pointer_to_u64 (cmd) | 1; >+ >+ return cmd; >+} >+ >+static void >+compat_qxl_set_cursor_position(ScrnInfoPtr pScrn, int x, int y) >+{ >+ compat_qxl_screen_t *compat_qxl = pScrn->driverPrivate; >+ struct compat_qxl_cursor_cmd *cmd = compat_qxl_alloc_cursor_cmd(compat_qxl); >+ >+ compat_qxl->cur_x = x; >+ compat_qxl->cur_y = y; >+ >+ cmd->type = QXL_CURSOR_MOVE; >+ cmd->u.position.x = compat_qxl->cur_x + compat_qxl->hot_x; >+ cmd->u.position.y = compat_qxl->cur_y + compat_qxl->hot_y; >+ >+ push_cursor(compat_qxl, cmd); >+} >+ >+static void >+compat_qxl_load_cursor_image(ScrnInfoPtr pScrn, unsigned char *bits) >+{ >+} >+ >+static void >+compat_qxl_set_cursor_colors(ScrnInfoPtr pScrn, int bg, int fg) >+{ >+ /* Should not be called since UseHWCursor returned FALSE */ >+} >+ >+static void >+compat_qxl_load_cursor_argb (ScrnInfoPtr pScrn, CursorPtr pCurs) >+{ >+ compat_qxl_screen_t *compat_qxl = pScrn->driverPrivate; >+ int w = pCurs->bits->width; >+ int h = pCurs->bits->height; >+ int size = w * h * sizeof (CARD32); >+ >+ struct compat_qxl_cursor_cmd *cmd = compat_qxl_alloc_cursor_cmd (compat_qxl); >+ struct compat_qxl_cursor *cursor = >+ compat_qxl_allocnf(compat_qxl, sizeof(struct compat_qxl_cursor) + size); >+ >+ cursor->header.unique = 0; >+ cursor->header.type = CURSOR_TYPE_ALPHA; >+ cursor->header.width = w; >+ cursor->header.height = h; >+ /* I wonder if we can just tell the client that the hotspot is 0, 0 >+ * always? The coordinates we are getting from X are for 0, 0 anyway, >+ * so the question is if the client uses the hotspot for anything else? >+ */ >+ cursor->header.hot_spot_x = pCurs->bits->xhot; >+ cursor->header.hot_spot_y = pCurs->bits->yhot; >+ >+ cursor->data_size = size; >+ >+ cursor->chunk.next_chunk = 0; >+ cursor->chunk.prev_chunk = 0; >+ cursor->chunk.data_size = size; >+ >+ memcpy (cursor->chunk.data, pCurs->bits->argb, size); >+ >+#if 0 >+ int i, j; >+ for (j = 0; j < h; ++j) >+ { >+ for (i = 0; i < w; ++i) >+ { >+ ErrorF ("%c", (pCurs->bits->argb[j * w + i] & 0xff000000) == 0xff000000? '#' : '.'); >+ } >+ >+ ErrorF ("\n"); >+ } >+#endif >+ >+ compat_qxl->hot_x = pCurs->bits->xhot; >+ compat_qxl->hot_y = pCurs->bits->yhot; >+ >+ cmd->type = QXL_CURSOR_SET; >+ cmd->u.set.position.x = compat_qxl->cur_x + compat_qxl->hot_x; >+ cmd->u.set.position.y = compat_qxl->cur_y + compat_qxl->hot_y; >+ cmd->u.set.shape = physical_address (compat_qxl, cursor); >+ cmd->u.set.visible = TRUE; >+ >+ push_cursor(compat_qxl, cmd); >+} >+ >+static Bool >+compat_qxl_use_hw_cursor (ScreenPtr pScrn, CursorPtr pCurs) >+{ >+ /* Old-school bitmap cursors are not >+ * hardware accelerated for now. >+ */ >+ return FALSE; >+} >+ >+static Bool >+compat_qxl_use_hw_cursorARGB (ScreenPtr pScrn, CursorPtr pCurs) >+{ >+ return TRUE; >+} >+ >+static void >+compat_qxl_hide_cursor(ScrnInfoPtr pScrn) >+{ >+ compat_qxl_screen_t *compat_qxl = pScrn->driverPrivate; >+ struct compat_qxl_cursor_cmd *cursor = compat_qxl_alloc_cursor_cmd(compat_qxl); >+ >+ cursor->type = QXL_CURSOR_HIDE; >+ >+ push_cursor(compat_qxl, cursor); >+} >+ >+static void >+compat_qxl_show_cursor(ScrnInfoPtr pScrn) >+{ >+ /* >+ * slightly hacky, but there's no QXL_CURSOR_SHOW. Could maybe do >+ * QXL_CURSOR_SET? >+ */ >+ compat_qxl_screen_t *compat_qxl = pScrn->driverPrivate; >+ >+ compat_qxl_set_cursor_position(pScrn, compat_qxl->cur_x, compat_qxl->cur_y); >+} >+ >+hidden void >+compat_qxl_cursor_init(ScreenPtr pScreen) >+{ >+ xf86CursorInfoPtr cursor; >+ >+ cursor = xcalloc(1, sizeof(xf86CursorInfoRec)); >+ if (!cursor) >+ return; >+ >+ cursor->MaxWidth = cursor->MaxHeight = 64; >+ /* cursor->Flags; */ >+ cursor->SetCursorPosition = compat_qxl_set_cursor_position; >+ cursor->LoadCursorARGB = compat_qxl_load_cursor_argb; >+ cursor->UseHWCursor = compat_qxl_use_hw_cursor; >+ cursor->UseHWCursorARGB = compat_qxl_use_hw_cursorARGB; >+ cursor->LoadCursorImage = compat_qxl_load_cursor_image; >+ cursor->SetCursorColors = compat_qxl_set_cursor_colors; >+ cursor->HideCursor = compat_qxl_hide_cursor; >+ cursor->ShowCursor = compat_qxl_show_cursor; >+ >+ if (!xf86InitCursor(pScreen, cursor)) >+ xfree(cursor); >+} >diff --git a/src/compat/compat-qxl_driver.c b/src/compat/compat-qxl_driver.c >new file mode 100644 >index 0000000..3470068 >--- /dev/null >+++ b/src/compat/compat-qxl_driver.c >@@ -0,0 +1,1460 @@ >+/* >+ * Copyright 2008 Red Hat, Inc. >+ * >+ * Permission is hereby granted, free of charge, to any person obtaining a >+ * copy of this software and associated documentation files (the "Software"), >+ * to deal in the Software without restriction, including without limitation >+ * on the rights to use, copy, modify, merge, publish, distribute, sub >+ * license, and/or sell copies of the Software, and to permit persons to whom >+ * the Software is furnished to do so, subject to the following conditions: >+ * >+ * The above copyright notice and this permission notice (including the next >+ * paragraph) shall be included in all copies or substantial portions of the >+ * Software. >+ * >+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR >+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, >+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL >+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER >+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN >+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. >+ */ >+ >+/** \file compat_qxl_driver.c >+ * \author Adam Jackson <ajax@redhat.com> >+ * >+ * This is compat_qxl, a driver for the Qumranet paravirtualized graphics device >+ * in qemu. >+ */ >+ >+#include <unistd.h> >+#include <string.h> >+#include <stdio.h> >+#include <errno.h> >+#include <time.h> >+#include <stdlib.h> >+#include "compat-qxl.h" >+#include "assert.h" >+#include "xf86Crtc.h" >+ >+#define CHECK_POINT() >+ >+static int >+garbage_collect (compat_qxl_screen_t *compat_qxl) >+{ >+ uint64_t id; >+ int i = 0; >+ >+ while (compat_qxl_ring_pop (compat_qxl->release_ring, &id)) >+ { >+ while (id) >+ { >+ /* We assume that there the two low bits of a pointer are >+ * available. If the low one is set, then the command in >+ * question is a cursor command >+ */ >+#define POINTER_MASK ((1 << 2) - 1) >+ >+ union compat_qxl_release_info *info = u64_to_pointer (id & ~POINTER_MASK); >+ struct compat_qxl_cursor_cmd *cmd = (struct compat_qxl_cursor_cmd *)info; >+ struct compat_qxl_drawable *drawable = (struct compat_qxl_drawable *)info; >+ int is_cursor = FALSE; >+ >+ if ((id & POINTER_MASK) == 1) >+ is_cursor = TRUE; >+ >+ if (is_cursor && cmd->type == QXL_CURSOR_SET) >+ { >+ struct compat_qxl_cursor *cursor = (void *)virtual_address ( >+ compat_qxl, u64_to_pointer (cmd->u.set.shape)); >+ >+ compat_qxl_free (compat_qxl->mem, cursor); >+ } >+ else if (!is_cursor && drawable->type == QXL_DRAW_COPY) >+ { >+ struct compat_qxl_image *image = virtual_address ( >+ compat_qxl, u64_to_pointer (drawable->u.copy.src_bitmap)); >+ >+ compat_qxl_image_destroy (compat_qxl, image); >+ } >+ >+ id = info->next; >+ >+ compat_qxl_free (compat_qxl->mem, info); >+ } >+ } >+ >+ return i > 0; >+} >+ >+static void >+compat_qxl_usleep (int useconds) >+{ >+ struct timespec t; >+ >+ t.tv_sec = useconds / 1000000; >+ t.tv_nsec = (useconds - (t.tv_sec * 1000000)) * 1000; >+ >+ errno = 0; >+ while (nanosleep (&t, &t) == -1 && errno == EINTR) >+ ; >+ >+} >+ >+#if 0 >+static void >+push_update_area (compat_qxl_screen_t *compat_qxl, const struct compat_qxl_rect *area) >+{ >+ struct compat_qxl_update_cmd *update = compat_qxl_allocnf (compat_qxl, sizeof *update); >+ struct compat_qxl_command cmd; >+ >+ update->release_info.id = (uint64_t)update; >+ update->area = *area; >+ update->update_id = 0; >+ >+ cmd.type = QXL_CMD_UDPATE; >+ cmd.data = physical_address (compat_qxl, update); >+ >+ compat_qxl_ring_push (compat_qxl->command_ring, &cmd); >+} >+#endif >+ >+void * >+compat_qxl_allocnf (compat_qxl_screen_t *compat_qxl, unsigned long size) >+{ >+ void *result; >+ int n_attempts = 0; >+ static int nth_oom = 1; >+ >+ garbage_collect (compat_qxl); >+ >+ while (!(result = compat_qxl_alloc (compat_qxl->mem, size))) >+ { >+ struct compat_qxl_ram_header *ram_header = (void *)((unsigned long)compat_qxl->ram + >+ compat_qxl->rom->ram_header_offset); >+ >+ /* Rather than go out of memory, we simply tell the >+ * device to dump everything >+ */ >+ ram_header->update_area.top = 0; >+ ram_header->update_area.bottom = 1280; >+ ram_header->update_area.left = 0; >+ ram_header->update_area.right = 800; >+ >+ outb (compat_qxl->io_base + QXL_IO_UPDATE_AREA, 0); >+ >+ ErrorF ("eliminated memory (%d)\n", nth_oom++); >+ >+ outb (compat_qxl->io_base + QXL_IO_NOTIFY_OOM, 0); >+ >+ compat_qxl_usleep (10000); >+ >+ if (garbage_collect (compat_qxl)) >+ { >+ n_attempts = 0; >+ } >+ else if (++n_attempts == 1000) >+ { >+ compat_qxl_mem_dump_stats (compat_qxl->mem, "Out of mem - stats\n"); >+ >+ fprintf (stderr, "Out of memory\n"); >+ exit (1); >+ } >+ } >+ >+ return result; >+} >+ >+static Bool >+compat_qxl_blank_screen(ScreenPtr pScreen, int mode) >+{ >+ return TRUE; >+} >+ >+static void >+compat_qxl_unmap_memory(compat_qxl_screen_t *compat_qxl, int scrnIndex) >+{ >+#ifdef XSERVER_LIBPCIACCESS >+ if (compat_qxl->ram) >+ pci_device_unmap_range(compat_qxl->pci, compat_qxl->ram, compat_qxl->pci->regions[0].size); >+ if (compat_qxl->vram) >+ pci_device_unmap_range(compat_qxl->pci, compat_qxl->vram, compat_qxl->pci->regions[1].size); >+ if (compat_qxl->rom) >+ pci_device_unmap_range(compat_qxl->pci, compat_qxl->rom, compat_qxl->pci->regions[2].size); >+#else >+ if (compat_qxl->ram) >+ xf86UnMapVidMem(scrnIndex, compat_qxl->ram, (1 << compat_qxl->pci->size[0])); >+ if (compat_qxl->vram) >+ xf86UnMapVidMem(scrnIndex, compat_qxl->vram, (1 << compat_qxl->pci->size[1])); >+ if (compat_qxl->rom) >+ xf86UnMapVidMem(scrnIndex, compat_qxl->rom, (1 << compat_qxl->pci->size[2])); >+#endif >+ >+ compat_qxl->ram = compat_qxl->ram_physical = compat_qxl->vram = compat_qxl->rom = NULL; >+ >+ compat_qxl->num_modes = 0; >+ compat_qxl->modes = NULL; >+} >+ >+static Bool >+compat_qxl_map_memory(compat_qxl_screen_t *compat_qxl, int scrnIndex) >+{ >+#ifdef XSERVER_LIBPCIACCESS >+ pci_device_map_range(compat_qxl->pci, compat_qxl->pci->regions[0].base_addr, >+ compat_qxl->pci->regions[0].size, >+ PCI_DEV_MAP_FLAG_WRITABLE | PCI_DEV_MAP_FLAG_WRITE_COMBINE, >+ &compat_qxl->ram); >+ compat_qxl->ram_physical = u64_to_pointer (compat_qxl->pci->regions[0].base_addr); >+ >+ pci_device_map_range(compat_qxl->pci, compat_qxl->pci->regions[1].base_addr, >+ compat_qxl->pci->regions[1].size, >+ PCI_DEV_MAP_FLAG_WRITABLE, >+ &compat_qxl->vram); >+ >+ pci_device_map_range(compat_qxl->pci, compat_qxl->pci->regions[2].base_addr, >+ compat_qxl->pci->regions[2].size, 0, >+ (void **)&compat_qxl->rom); >+ >+ compat_qxl->io_base = compat_qxl->pci->regions[3].base_addr; >+#else >+ compat_qxl->ram = xf86MapPciMem(scrnIndex, VIDMEM_FRAMEBUFFER, >+ compat_qxl->pci_tag, compat_qxl->pci->memBase[0], >+ (1 << compat_qxl->pci->size[0])); >+ compat_qxl->ram_physical = (void *)compat_qxl->pci->memBase[0]; >+ >+ compat_qxl->vram = xf86MapPciMem(scrnIndex, VIDMEM_MMIO | VIDMEM_MMIO_32BIT, >+ compat_qxl->pci_tag, compat_qxl->pci->memBase[1], >+ (1 << compat_qxl->pci->size[1])); >+ >+ compat_qxl->rom = xf86MapPciMem(scrnIndex, VIDMEM_MMIO | VIDMEM_MMIO_32BIT, >+ compat_qxl->pci_tag, compat_qxl->pci->memBase[2], >+ (1 << compat_qxl->pci->size[2])); >+ >+ compat_qxl->io_base = compat_qxl->pci->ioBase[3]; >+#endif >+ if (!compat_qxl->ram || !compat_qxl->vram || !compat_qxl->rom) >+ return FALSE; >+ >+ xf86DrvMsg(scrnIndex, X_INFO, "ram at %p; vram at %p; rom at %p\n", >+ compat_qxl->ram, compat_qxl->vram, compat_qxl->rom); >+ >+ compat_qxl->num_modes = *(uint32_t *)((uint8_t *)compat_qxl->rom + compat_qxl->rom->modes_offset); >+ compat_qxl->modes = (struct compat_qxl_mode *)(((uint8_t *)compat_qxl->rom) + compat_qxl->rom->modes_offset + 4); >+ >+ return TRUE; >+} >+ >+static void >+compat_qxl_save_state(ScrnInfoPtr pScrn) >+{ >+ compat_qxl_screen_t *compat_qxl = pScrn->driverPrivate; >+ >+ vgaHWSaveFonts(pScrn, &compat_qxl->vgaRegs); >+} >+ >+static void >+compat_qxl_restore_state(ScrnInfoPtr pScrn) >+{ >+ compat_qxl_screen_t *compat_qxl = pScrn->driverPrivate; >+ >+ vgaHWRestoreFonts(pScrn, &compat_qxl->vgaRegs); >+} >+ >+static Bool >+compat_qxl_close_screen(CLOSE_SCREEN_ARGS_DECL) >+{ >+ ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); >+ compat_qxl_screen_t *compat_qxl = pScrn->driverPrivate; >+ >+ if (pScrn->vtSema) { >+ compat_qxl_restore_state(pScrn); >+ compat_qxl_unmap_memory(compat_qxl, pScrn->scrnIndex); >+ } >+ pScrn->vtSema = FALSE; >+ >+ xfree(compat_qxl->fb); >+ >+ pScreen->CreateScreenResources = compat_qxl->create_screen_resources; >+ pScreen->CloseScreen = compat_qxl->close_screen; >+ >+ return pScreen->CloseScreen(CLOSE_SCREEN_ARGS); >+} >+ >+static Bool >+compat_qxl_switch_mode(SWITCH_MODE_ARGS_DECL) >+{ >+ SCRN_INFO_PTR(arg); >+ compat_qxl_screen_t *compat_qxl = pScrn->driverPrivate; >+ int mode_index = (int)(unsigned long)mode->Private; >+ struct compat_qxl_mode *m = compat_qxl->modes + mode_index; >+ ScreenPtr pScreen = compat_qxl->pScrn->pScreen; >+ >+ if (!m) >+ return FALSE; >+ >+ /* if (debug) */ >+ xf86DrvMsg (pScrn->scrnIndex, X_INFO, "Setting mode %d (%d x %d) (%d x %d) %p\n", >+ m->id, m->x_res, m->y_res, mode->HDisplay, mode->VDisplay, mode); >+ >+ outb(compat_qxl->io_base + QXL_IO_RESET, 0); >+ >+ outb(compat_qxl->io_base + QXL_IO_SET_MODE, m->id); >+ >+ compat_qxl->bytes_per_pixel = (compat_qxl->pScrn->bitsPerPixel + 7) / 8; >+ >+ /* If this happens out of ScreenInit, we won't have a screen yet. In that >+ * case createScreenResources will make things right. >+ */ >+ if (pScreen) >+ { >+ PixmapPtr pPixmap = pScreen->GetScreenPixmap(pScreen); >+ >+ if (pPixmap) >+ { >+ pScreen->ModifyPixmapHeader( >+ pPixmap, >+ m->x_res, m->y_res, >+ -1, -1, >+ compat_qxl->pScrn->displayWidth * compat_qxl->bytes_per_pixel, >+ NULL); >+ } >+ } >+ >+ if (compat_qxl->mem) >+ { >+ compat_qxl_mem_free_all (compat_qxl->mem); >+ compat_qxl_drop_image_cache (compat_qxl); >+ } >+ >+ >+ return TRUE; >+} >+ >+static void >+push_drawable (compat_qxl_screen_t *compat_qxl, struct compat_qxl_drawable *drawable) >+{ >+ struct compat_qxl_command cmd; >+ >+ /* When someone runs "init 3", the device will be >+ * switched into VGA mode and there is nothing we >+ * can do about it. We get no notification. >+ * >+ * However, if commands are submitted when the device >+ * is in VGA mode, they will be queued up, and then >+ * the next time a mode set set, an assertion in the >+ * device will take down the entire virtual machine. >+ * >+ * The author of the QXL device is opposed to this >+ * for reasons I don't understand. >+ */ >+ if (compat_qxl->rom->mode != ~0) >+ { >+ cmd.type = QXL_CMD_DRAW; >+ cmd.data = physical_address (compat_qxl, drawable); >+ >+ compat_qxl_ring_push (compat_qxl->command_ring, &cmd); >+ } >+} >+ >+static struct compat_qxl_drawable * >+make_drawable (compat_qxl_screen_t *compat_qxl, uint8_t type, >+ const struct compat_qxl_rect *rect >+ /* , pRegion clip */) >+{ >+ struct compat_qxl_drawable *drawable; >+ >+ CHECK_POINT(); >+ >+ drawable = compat_qxl_allocnf (compat_qxl, sizeof *drawable); >+ >+ CHECK_POINT(); >+ >+ drawable->release_info.id = pointer_to_u64 (drawable); >+ >+ drawable->type = type; >+ >+ drawable->effect = QXL_EFFECT_OPAQUE; >+ drawable->bitmap_offset = 0; >+ drawable->bitmap_area.top = 0; >+ drawable->bitmap_area.left = 0; >+ drawable->bitmap_area.bottom = 0; >+ drawable->bitmap_area.right = 0; >+ /* FIXME: add clipping */ >+ drawable->clip.type = QXL_CLIP_TYPE_NONE; >+ >+ if (rect) { >+ if (rect->top < 0) >+ __asm__ __volatile__ ("int $03"); >+ drawable->bbox = *rect; >+} >+ >+ drawable->mm_time = compat_qxl->rom->mm_clock; >+ >+ CHECK_POINT(); >+ >+ return drawable; >+} >+ >+enum ROPDescriptor { >+ ROPD_INVERS_SRC = (1 << 0), >+ ROPD_INVERS_BRUSH = (1 << 1), >+ ROPD_INVERS_DEST = (1 << 2), >+ ROPD_OP_PUT = (1 << 3), >+ ROPD_OP_OR = (1 << 4), >+ ROPD_OP_AND = (1 << 5), >+ ROPD_OP_XOR = (1 << 6), >+ ROPD_OP_BLACKNESS = (1 << 7), >+ ROPD_OP_WHITENESS = (1 << 8), >+ ROPD_OP_INVERS = (1 << 9), >+ ROPD_INVERS_RES = (1 <<10), >+}; >+ >+static void >+undamage_box (compat_qxl_screen_t *compat_qxl, const struct compat_qxl_rect *rect) >+{ >+ RegionRec region; >+ BoxRec box; >+ >+ box.x1 = rect->left; >+ box.y1 = rect->top; >+ box.x2 = rect->right; >+ box.y2 = rect->bottom; >+ >+ REGION_INIT (compat_qxl->pScrn->pScreen, ®ion, &box, 0); >+ >+ REGION_SUBTRACT (compat_qxl->pScrn->pScreen, &(compat_qxl->pending_copy), &(compat_qxl->pending_copy), ®ion); >+ >+ REGION_EMPTY (compat_qxl->pScrn->pScreen, &(compat_qxl->pending_copy)); >+} >+ >+static void >+clear_pending_damage (compat_qxl_screen_t *compat_qxl) >+{ >+ REGION_EMPTY (compat_qxl->pScrn->pScreen, &(compat_qxl->pending_copy)); >+} >+ >+static void >+submit_fill (compat_qxl_screen_t *compat_qxl, const struct compat_qxl_rect *rect, uint32_t color) >+{ >+ struct compat_qxl_drawable *drawable; >+ >+ CHECK_POINT(); >+ >+ drawable = make_drawable (compat_qxl, QXL_DRAW_FILL, rect); >+ >+ CHECK_POINT(); >+ >+ drawable->u.fill.brush.type = QXL_BRUSH_TYPE_SOLID; >+ drawable->u.fill.brush.u.color = color; >+ drawable->u.fill.rop_descriptor = ROPD_OP_PUT; >+ drawable->u.fill.mask.flags = 0; >+ drawable->u.fill.mask.pos.x = 0; >+ drawable->u.fill.mask.pos.y = 0; >+ drawable->u.fill.mask.bitmap = 0; >+ >+ push_drawable (compat_qxl, drawable); >+ >+ undamage_box (compat_qxl, rect); >+} >+ >+static void >+translate_rect (struct compat_qxl_rect *rect) >+{ >+ rect->right -= rect->left; >+ rect->bottom -= rect->top; >+ rect->left = rect->top = 0; >+} >+ >+static void >+submit_copy (compat_qxl_screen_t *compat_qxl, const struct compat_qxl_rect *rect) >+{ >+ struct compat_qxl_drawable *drawable; >+ ScrnInfoPtr pScrn = compat_qxl->pScrn; >+ >+ if (rect->left == rect->right || >+ rect->top == rect->bottom) >+ { >+ /* Empty rectangle */ >+ return ; >+ } >+ >+ drawable = make_drawable (compat_qxl, QXL_DRAW_COPY, rect); >+ >+ drawable->u.copy.src_bitmap = physical_address ( >+ compat_qxl, compat_qxl_image_create (compat_qxl, compat_qxl->fb, rect->left, rect->top, >+ rect->right - rect->left, >+ rect->bottom - rect->top, >+ pScrn->displayWidth * compat_qxl->bytes_per_pixel)); >+ drawable->u.copy.src_area = *rect; >+ translate_rect (&drawable->u.copy.src_area); >+ drawable->u.copy.rop_descriptor = ROPD_OP_PUT; >+ drawable->u.copy.scale_mode = 0; >+ drawable->u.copy.mask.flags = 0; >+ drawable->u.copy.mask.pos.x = 0; >+ drawable->u.copy.mask.pos.y = 0; >+ drawable->u.copy.mask.bitmap = 0; >+ >+ push_drawable (compat_qxl, drawable); >+} >+ >+static void >+print_region (const char *header, RegionPtr pRegion) >+{ >+ int nbox = REGION_NUM_RECTS (pRegion); >+ BoxPtr pbox = REGION_RECTS (pRegion); >+ >+ ErrorF ("%s \n", header); >+ >+ while (nbox--) >+ { >+ ErrorF (" %d %d %d %d (size: %d %d)\n", >+ pbox->x1, pbox->y1, pbox->x2, pbox->y2, >+ pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); >+ >+ pbox++; >+ } >+} >+ >+static void >+accept_damage (compat_qxl_screen_t *compat_qxl) >+{ >+ REGION_UNION (compat_qxl->pScrn->pScreen, &(compat_qxl->to_be_sent), &(compat_qxl->to_be_sent), >+ &(compat_qxl->pending_copy)); >+ >+ REGION_EMPTY (compat_qxl->pScrn->pScreen, &(compat_qxl->pending_copy)); >+} >+ >+static void >+compat_qxl_send_copies (compat_qxl_screen_t *compat_qxl) >+{ >+ BoxPtr pBox; >+ int nbox; >+ >+ nbox = REGION_NUM_RECTS (&compat_qxl->to_be_sent); >+ pBox = REGION_RECTS (&compat_qxl->to_be_sent); >+ >+/* if (REGION_NUM_RECTS (&compat_qxl->to_be_sent) > 0) */ >+/* print_region ("send bits", &compat_qxl->to_be_sent); */ >+ >+ while (nbox--) >+ { >+ struct compat_qxl_rect qrect; >+ >+ qrect.top = pBox->y1; >+ qrect.left = pBox->x1; >+ qrect.bottom = pBox->y2; >+ qrect.right = pBox->x2; >+ >+ submit_copy (compat_qxl, &qrect); >+ >+ pBox++; >+ } >+ >+ REGION_EMPTY(compat_qxl->pScrn->pScreen, &compat_qxl->to_be_sent); >+} >+ >+static void >+paint_shadow (compat_qxl_screen_t *compat_qxl) >+{ >+ struct compat_qxl_rect qrect; >+ >+ qrect.top = 0; >+ qrect.bottom = 1200; >+ qrect.left = 0; >+ qrect.right = 1600; >+ >+ submit_copy (compat_qxl, &qrect); >+} >+ >+static void >+compat_qxl_sanity_check (compat_qxl_screen_t *compat_qxl) >+{ >+ /* read the mode back from the rom */ >+ if (!compat_qxl->rom || !compat_qxl->pScrn) >+ return; >+ >+ if (compat_qxl->rom->mode == ~0) >+ { >+ ErrorF("QXL device jumped back to VGA mode - resetting mode\n"); >+ compat_qxl_switch_mode(SWITCH_MODE_ARGS(compat_qxl->pScrn, compat_qxl->pScrn->currentMode)); >+ } >+} >+ >+static void >+compat_qxl_block_handler (pointer data, OSTimePtr pTimeout, pointer pRead) >+{ >+ compat_qxl_screen_t *compat_qxl = (compat_qxl_screen_t *) data; >+ >+ if (!compat_qxl->pScrn->vtSema) >+ return; >+ >+ compat_qxl_sanity_check(compat_qxl); >+ >+ accept_damage (compat_qxl); >+ >+ compat_qxl_send_copies (compat_qxl); >+} >+ >+static void >+compat_qxl_wakeup_handler (pointer data, int i, pointer LastSelectMask) >+{ >+} >+ >+/* Damage Handling >+ * >+ * When something is drawn, X first generates a damage callback, then >+ * it calls the GC function to actually draw it. In most cases, we want >+ * to simply draw into the shadow framebuffer, then submit a copy to the >+ * device, but when the operation is hardware accelerated, we don't want >+ * to submit the copy. So, damage is first accumulated into 'pending_copy', >+ * then if we accelerated the operation, that damage is deleted. >+ * >+ * If we _didn't_ accelerate, we need to union the pending_copy damage >+ * onto the to_be_sent damage, and then submit a copy command in the block >+ * handler. >+ * >+ * This means that when new damage happens, if there is already pending >+ * damage, that must first be unioned onto to_be_sent, and then the new >+ * damage must be stored in pending_copy. >+ * >+ * The compat_qxl_screen_t struct contains two regions, "pending_copy" and >+ * "to_be_sent". >+ * >+ * Pending copy is >+ * >+ */ >+static void >+compat_qxl_on_damage (DamagePtr pDamage, RegionPtr pRegion, pointer closure) >+{ >+ compat_qxl_screen_t *compat_qxl = closure; >+ >+/* print_region ("damage", pRegion); */ >+ >+/* print_region ("on_damage ", pRegion); */ >+ >+ accept_damage (compat_qxl); >+ >+/* print_region ("accepting, compat_qxl->to_be_sent is now", &compat_qxl->to_be_sent); */ >+ >+ REGION_COPY (compat_qxl->pScrn->pScreen, &(compat_qxl->pending_copy), pRegion); >+} >+ >+ >+static Bool >+compat_qxl_create_screen_resources(ScreenPtr pScreen) >+{ >+ ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); >+ compat_qxl_screen_t *compat_qxl = pScrn->driverPrivate; >+ Bool ret; >+ PixmapPtr pPixmap; >+ >+ pScreen->CreateScreenResources = compat_qxl->create_screen_resources; >+ ret = pScreen->CreateScreenResources (pScreen); >+ pScreen->CreateScreenResources = compat_qxl_create_screen_resources; >+ >+ if (!ret) >+ return FALSE; >+ >+ compat_qxl->damage = DamageCreate (compat_qxl_on_damage, NULL, >+ DamageReportRawRegion, >+ TRUE, pScreen, compat_qxl); >+ >+ >+ pPixmap = pScreen->GetScreenPixmap(pScreen); >+ >+ if (!RegisterBlockAndWakeupHandlers(compat_qxl_block_handler, compat_qxl_wakeup_handler, compat_qxl)) >+ return FALSE; >+ >+ REGION_INIT (pScreen, &(compat_qxl->pending_copy), NullBox, 0); >+ >+ REGION_INIT (pScreen, &(compat_qxl->to_be_sent), NullBox, 0); >+ >+ DamageRegister (&pPixmap->drawable, compat_qxl->damage); >+ return TRUE; >+} >+ >+static PixmapPtr >+get_window_pixmap (DrawablePtr pDrawable, int *xoff, int *yoff) >+{ >+ ScreenPtr pScreen = pDrawable->pScreen; >+ PixmapPtr result; >+ >+ if (pDrawable->type != DRAWABLE_WINDOW) >+ return NULL; >+ >+ result = pScreen->GetWindowPixmap ((WindowPtr)pDrawable); >+ >+ *xoff = pDrawable->x; >+ *yoff = pDrawable->y; >+ >+ return result; >+} >+ >+static void >+compat_qxl_poly_fill_rect (DrawablePtr pDrawable, >+ GCPtr pGC, >+ int nrect, >+ xRectangle *prect) >+{ >+ ScrnInfoPtr pScrn = xf86ScreenToScrn(pDrawable->pScreen); >+ compat_qxl_screen_t *compat_qxl = pScrn->driverPrivate; >+ PixmapPtr pPixmap; >+ int xoff, yoff; >+ >+ if ((pPixmap = get_window_pixmap (pDrawable, &xoff, &yoff)) && >+ pGC->fillStyle == FillSolid && >+ pGC->alu == GXcopy && >+ (unsigned int)pGC->planemask == FB_ALLONES) >+ { >+ RegionPtr pReg = RECTS_TO_REGION (pScreen, nrect, prect, CT_UNSORTED); >+ RegionPtr pClip = fbGetCompositeClip (pGC); >+ BoxPtr pBox; >+ int nbox; >+ >+ REGION_TRANSLATE(pScreen, pReg, xoff, yoff); >+ REGION_INTERSECT(pScreen, pReg, pClip, pReg); >+ >+ pBox = REGION_RECTS (pReg); >+ nbox = REGION_NUM_RECTS (pReg); >+ >+ while (nbox--) >+ { >+ struct compat_qxl_rect qrect; >+ >+ qrect.left = pBox->x1; >+ qrect.right = pBox->x2; >+ qrect.top = pBox->y1; >+ qrect.bottom = pBox->y2; >+ >+ submit_fill (compat_qxl, &qrect, pGC->fgPixel); >+ >+ pBox++; >+ } >+ >+ REGION_DESTROY (pScreen, pReg); >+ } >+ >+ fbPolyFillRect (pDrawable, pGC, nrect, prect); >+} >+ >+static void >+compat_qxl_copy_n_to_n (DrawablePtr pSrcDrawable, >+ DrawablePtr pDstDrawable, >+ GCPtr pGC, >+ BoxPtr pbox, >+ int nbox, >+ int dx, >+ int dy, >+ Bool reverse, >+ Bool upsidedown, >+ Pixel bitplane, >+ void *closure) >+{ >+ ScreenPtr pScreen = pSrcDrawable->pScreen; >+ ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); >+ compat_qxl_screen_t *compat_qxl = pScrn->driverPrivate; >+ int src_xoff, src_yoff; >+ int dst_xoff, dst_yoff; >+ PixmapPtr pSrcPixmap, pDstPixmap; >+ >+ if ((pSrcPixmap = get_window_pixmap (pSrcDrawable, &src_xoff, &src_yoff)) && >+ (pDstPixmap = get_window_pixmap (pDstDrawable, &dst_xoff, &dst_yoff))) >+ { >+ int n = nbox; >+ BoxPtr b = pbox; >+ >+ assert (pSrcPixmap == pDstPixmap); >+ >+/* ErrorF ("Accelerated copy: %d boxes\n", n); */ >+ >+ /* At this point we know that any pending damage must >+ * have been caused by whatever copy operation triggered us. >+ * >+ * Therefore we can clear it. >+ * >+ * We couldn't clear it at the toplevel function because >+ * the copy might end up being empty, in which case no >+ * damage would have been generated. Which means the >+ * pending damage would have been caused by some >+ * earlier operation. >+ */ >+ if (n) >+ { >+/* ErrorF ("Clearing pending damage\n"); */ >+ clear_pending_damage (compat_qxl); >+ >+ /* We have to do this because the copy will cause the damage >+ * to be sent to move. >+ * >+ * Instead of just sending the bits, we could also move >+ * the existing damage around; however that's a bit more >+ * complex, and the performance win is unlikely to be >+ * very big. >+ */ >+ compat_qxl_send_copies (compat_qxl); >+ } >+ >+ while (n--) >+ { >+ struct compat_qxl_drawable *drawable; >+ struct compat_qxl_rect qrect; >+ >+ qrect.top = b->y1; >+ qrect.bottom = b->y2; >+ qrect.left = b->x1; >+ qrect.right = b->x2; >+ >+/* ErrorF (" Translate %d %d %d %d by %d %d (offsets %d %d)\n", */ >+/* b->x1, b->y1, b->x2, b->y2, */ >+/* dx, dy, dst_xoff, dst_yoff); */ >+ >+ drawable = make_drawable (compat_qxl, QXL_COPY_BITS, &qrect); >+ drawable->u.copy_bits.src_pos.x = b->x1 + dx; >+ drawable->u.copy_bits.src_pos.y = b->y1 + dy; >+ >+ push_drawable (compat_qxl, drawable); >+ >+#if 0 >+ if (closure) >+ compat_qxl_usleep (1000000); >+#endif >+ >+#if 0 >+ submit_fill (compat_qxl, &qrect, rand()); >+#endif >+ >+ b++; >+ } >+ } >+/* else */ >+/* ErrorF ("Unaccelerated copy\n"); */ >+ >+ fbCopyNtoN (pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, upsidedown, bitplane, closure); >+} >+ >+static RegionPtr >+compat_qxl_copy_area(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, >+ int srcx, int srcy, int width, int height, int dstx, int dsty) >+{ >+ if (pSrcDrawable->type == DRAWABLE_WINDOW && >+ pDstDrawable->type == DRAWABLE_WINDOW) >+ { >+ RegionPtr res; >+ >+/* ErrorF ("accelerated copy %d %d %d %d %d %d\n", */ >+/* srcx, srcy, width, height, dstx, dsty); */ >+ >+ res = miDoCopy (pSrcDrawable, pDstDrawable, pGC, >+ srcx, srcy, width, height, dstx, dsty, >+ compat_qxl_copy_n_to_n, 0, NULL); >+ >+ return res; >+ } >+ else >+ { >+/* ErrorF ("Falling back %d %d %d %d %d %d\n", */ >+/* srcx, srcy, width, height, dstx, dsty); */ >+ >+ return fbCopyArea (pSrcDrawable, pDstDrawable, pGC, >+ srcx, srcy, width, height, dstx, dsty); >+ } >+} >+ >+static void >+compat_qxl_fill_region_solid (DrawablePtr pDrawable, RegionPtr pRegion, Pixel pixel) >+{ >+ ScreenPtr pScreen = pDrawable->pScreen; >+ ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); >+ compat_qxl_screen_t *compat_qxl = pScrn->driverPrivate; >+ PixmapPtr pPixmap; >+ int xoff, yoff; >+ >+ if ((pPixmap = get_window_pixmap (pDrawable, &xoff, &yoff))) >+ { >+ int nbox = REGION_NUM_RECTS (pRegion); >+ BoxPtr pBox = REGION_RECTS (pRegion); >+ >+ while (nbox--) >+ { >+ struct compat_qxl_rect qrect; >+ >+ qrect.left = pBox->x1; >+ qrect.right = pBox->x2; >+ qrect.top = pBox->y1; >+ qrect.bottom = pBox->y2; >+ >+ submit_fill (compat_qxl, &qrect, pixel); >+ >+ pBox++; >+ } >+ } >+ >+ fbFillRegionSolid (pDrawable, pRegion, 0, >+ fbReplicatePixel (pixel, pDrawable->bitsPerPixel)); >+} >+ >+static void >+compat_qxl_copy_window (WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) >+{ >+ RegionRec rgnDst; >+ int dx, dy; >+ >+ dx = ptOldOrg.x - pWin->drawable.x; >+ dy = ptOldOrg.y - pWin->drawable.y; >+ >+ REGION_TRANSLATE (pScreen, prgnSrc, -dx, -dy); >+ >+ REGION_INIT (pScreen, &rgnDst, NullBox, 0); >+ >+ REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, prgnSrc); >+ >+ miCopyRegion (&pWin->drawable, &pWin->drawable, >+ NULL, >+ &rgnDst, dx, dy, compat_qxl_copy_n_to_n, 0, NULL); >+ >+ REGION_UNINIT (pScreen, &rgnDst); >+ >+/* REGION_TRANSLATE (pScreen, prgnSrc, dx, dy); */ >+ >+/* fbCopyWindow (pWin, ptOldOrg, prgnSrc); */ >+} >+ >+static int >+compat_qxl_create_gc (GCPtr pGC) >+{ >+ static GCOps ops; >+ static int initialized; >+ >+ if (!fbCreateGC (pGC)) >+ return FALSE; >+ >+ if (!initialized) >+ { >+ ops = *pGC->ops; >+ ops.PolyFillRect = compat_qxl_poly_fill_rect; >+ ops.CopyArea = compat_qxl_copy_area; >+ >+ initialized = TRUE; >+ } >+ >+ pGC->ops = &ops; >+ return TRUE; >+} >+ >+static Bool >+compat_qxl_screen_init(SCREEN_INIT_ARGS_DECL) >+{ >+ ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); >+ compat_qxl_screen_t *compat_qxl = pScrn->driverPrivate; >+ struct compat_qxl_rom *rom; >+ struct compat_qxl_ram_header *ram_header; >+ VisualPtr visual; >+ >+ CHECK_POINT(); >+ >+ compat_qxl->pScrn = pScrn; >+ >+ if (!compat_qxl_map_memory(compat_qxl, pScrn->scrnIndex)) >+ return FALSE; >+ >+ rom = compat_qxl->rom; >+ ram_header = (void *)((unsigned long)compat_qxl->ram + (unsigned long)compat_qxl->rom->ram_header_offset); >+ >+ compat_qxl_save_state(pScrn); >+ compat_qxl_blank_screen(pScreen, SCREEN_SAVER_ON); >+ >+ miClearVisualTypes(); >+ if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth), >+ pScrn->rgbBits, pScrn->defaultVisual)) >+ goto out; >+ if (!miSetPixmapDepths()) >+ goto out; >+ >+ /* Note we do this before setting pScrn->virtualY to match our current >+ mode, so as to allocate a buffer large enough for the largest mode. >+ FIXME: add support for resizing the framebuffer on modeset. */ >+ compat_qxl->fb = xcalloc(pScrn->virtualY * pScrn->displayWidth, 4); >+ if (!compat_qxl->fb) >+ goto out; >+ >+ pScrn->virtualX = pScrn->currentMode->HDisplay; >+ pScrn->virtualY = pScrn->currentMode->VDisplay; >+ >+ if (!fbScreenInit(pScreen, compat_qxl->fb, >+ pScrn->currentMode->HDisplay, >+ pScrn->currentMode->VDisplay, >+ pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth, >+ pScrn->bitsPerPixel)) >+ { >+ goto out; >+ } >+ >+ visual = pScreen->visuals + pScreen->numVisuals; >+ while (--visual >= pScreen->visuals) >+ { >+ if ((visual->class | DynamicClass) == DirectColor) >+ { >+ visual->offsetRed = pScrn->offset.red; >+ visual->offsetGreen = pScrn->offset.green; >+ visual->offsetBlue = pScrn->offset.blue; >+ visual->redMask = pScrn->mask.red; >+ visual->greenMask = pScrn->mask.green; >+ visual->blueMask = pScrn->mask.blue; >+ } >+ } >+ >+ >+ fbPictureInit(pScreen, 0, 0); >+ >+ compat_qxl->create_screen_resources = pScreen->CreateScreenResources; >+ pScreen->CreateScreenResources = compat_qxl_create_screen_resources; >+ >+ /* Set up resources */ >+ compat_qxl->mem = compat_qxl_mem_create ((void *)((unsigned long)compat_qxl->ram + (unsigned long)rom->pages_offset), >+ rom->num_io_pages * getpagesize()); >+ compat_qxl->io_pages = (void *)((unsigned long)compat_qxl->ram + (unsigned long)rom->pages_offset); >+ compat_qxl->io_pages_physical = (void *)((unsigned long)compat_qxl->ram_physical + (unsigned long)rom->pages_offset); >+ >+ compat_qxl->command_ring = compat_qxl_ring_create (&(ram_header->cmd_ring_hdr), >+ sizeof (struct compat_qxl_command), >+ 32, compat_qxl->io_base + QXL_IO_NOTIFY_CMD); >+ compat_qxl->cursor_ring = compat_qxl_ring_create (&(ram_header->cursor_ring_hdr), >+ sizeof (struct compat_qxl_command), >+ 32, compat_qxl->io_base + QXL_IO_NOTIFY_CURSOR); >+ compat_qxl->release_ring = compat_qxl_ring_create (&(ram_header->release_ring_hdr), >+ sizeof (uint64_t), >+ 8, 0); >+ >+ /* xf86DPMSInit(pScreen, xf86DPMSSet, 0); */ >+ >+#if 0 /* XV accel */ >+ compat_qxlInitVideo(pScreen); >+#endif >+ >+ pScreen->SaveScreen = compat_qxl_blank_screen; >+ compat_qxl->close_screen = pScreen->CloseScreen; >+ pScreen->CloseScreen = compat_qxl_close_screen; >+ >+ compat_qxl->create_gc = pScreen->CreateGC; >+ pScreen->CreateGC = compat_qxl_create_gc; >+ >+#if 0 >+ compat_qxl->paint_window_background = pScreen->PaintWindowBackground; >+ compat_qxl->paint_window_border = pScreen->PaintWindowBorder; >+#endif >+ compat_qxl->copy_window = pScreen->CopyWindow; >+#if 0 >+ pScreen->PaintWindowBackground = compat_qxl_paint_window; >+ pScreen->PaintWindowBorder = compat_qxl_paint_window; >+#endif >+ pScreen->CopyWindow = compat_qxl_copy_window; >+ >+ miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); >+ >+ if (!miCreateDefColormap(pScreen)) >+ goto out; >+ >+ compat_qxl_cursor_init (pScreen); >+ >+ CHECK_POINT(); >+ >+ compat_qxl_switch_mode(SWITCH_MODE_ARGS(pScrn, pScrn->currentMode)); >+ >+ CHECK_POINT(); >+ >+ return TRUE; >+ >+out: >+ return FALSE; >+} >+ >+static Bool >+compat_qxl_enter_vt(VT_FUNC_ARGS_DECL) >+{ >+ SCRN_INFO_PTR(arg); >+ >+ compat_qxl_save_state(pScrn); >+ compat_qxl_switch_mode(SWITCH_MODE_ARGS(pScrn, pScrn->currentMode)); >+ >+ return TRUE; >+} >+ >+static void >+compat_qxl_leave_vt(VT_FUNC_ARGS_DECL) >+{ >+ SCRN_INFO_PTR(arg); >+ >+ compat_qxl_restore_state(pScrn); >+} >+ >+static Bool >+compat_qxl_color_setup(ScrnInfoPtr pScrn) >+{ >+ int scrnIndex = pScrn->scrnIndex; >+ Gamma gzeros = { 0.0, 0.0, 0.0 }; >+ rgb rzeros = { 0, 0, 0 }; >+ >+ if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support32bppFb)) >+ return FALSE; >+ >+ if (pScrn->depth != 15 && pScrn->depth != 24) >+ { >+ xf86DrvMsg(scrnIndex, X_ERROR, "Depth %d is not supported\n", >+ pScrn->depth); >+ return FALSE; >+ } >+ xf86PrintDepthBpp(pScrn); >+ >+ if (!xf86SetWeight(pScrn, rzeros, rzeros)) >+ return FALSE; >+ >+ if (!xf86SetDefaultVisual(pScrn, -1)) >+ return FALSE; >+ >+ if (!xf86SetGamma(pScrn, gzeros)) >+ return FALSE; >+ >+ return TRUE; >+} >+ >+static void >+print_modes (compat_qxl_screen_t *compat_qxl, int scrnIndex) >+{ >+ int i; >+ >+ for (i = 0; i < compat_qxl->num_modes; ++i) >+ { >+ struct compat_qxl_mode *m = compat_qxl->modes + i; >+ >+ xf86DrvMsg (scrnIndex, X_INFO, >+ "%d: %dx%d, %d bits, stride %d, %dmm x %dmm, orientation %d\n", >+ m->id, m->x_res, m->y_res, m->bits, m->stride, m->x_mili, >+ m->y_mili, m->orientation); >+ } >+} >+ >+static Bool >+compat_qxl_check_device(ScrnInfoPtr pScrn, compat_qxl_screen_t *compat_qxl) >+{ >+ int scrnIndex = pScrn->scrnIndex; >+ struct compat_qxl_rom *rom = compat_qxl->rom; >+ struct compat_qxl_ram_header *ram_header = (void *)((unsigned long)compat_qxl->ram + rom->ram_header_offset); >+ >+ CHECK_POINT(); >+ >+ if (rom->magic != 0x4f525851) { /* "QXRO" little-endian */ >+ xf86DrvMsg(scrnIndex, X_ERROR, "Bad ROM signature %x\n", rom->magic); >+ return FALSE; >+ } >+ >+ xf86DrvMsg(scrnIndex, X_INFO, "Device version %d.%d\n", >+ rom->id, rom->update_id); >+ >+ xf86DrvMsg(scrnIndex, X_INFO, "Compression level %d, log level %d\n", >+ rom->compression_level, >+ rom->log_level); >+ >+ xf86DrvMsg(scrnIndex, X_INFO, "Currently using mode #%d, list at 0x%x\n", >+ rom->mode, rom->modes_offset); >+ >+ xf86DrvMsg(scrnIndex, X_INFO, "%d io pages at 0x%x\n", >+ rom->num_io_pages, rom->pages_offset); >+ >+ xf86DrvMsg(scrnIndex, X_INFO, "%d byte draw area at 0x%x\n", >+ rom->draw_area_size, rom->draw_area_offset); >+ >+ xf86DrvMsg(scrnIndex, X_INFO, "RAM header offset: 0x%x\n", rom->ram_header_offset); >+ >+ if (ram_header->magic != 0x41525851) { /* "QXRA" little-endian */ >+ xf86DrvMsg(scrnIndex, X_ERROR, "Bad RAM signature %x at %p\n", >+ ram_header->magic, >+ &ram_header->magic); >+ return FALSE; >+ } >+ >+ xf86DrvMsg(scrnIndex, X_INFO, "Correct RAM signature %x\n", >+ ram_header->magic); >+ >+ compat_qxl->draw_area_offset = rom->draw_area_offset; >+ compat_qxl->draw_area_size = rom->draw_area_size; >+ pScrn->videoRam = rom->draw_area_size / 1024; >+ >+ return TRUE; >+} >+ >+static int >+compat_qxl_find_native_mode(ScrnInfoPtr pScrn, DisplayModePtr p) >+{ >+ int i; >+ compat_qxl_screen_t *compat_qxl = pScrn->driverPrivate; >+ >+ CHECK_POINT(); >+ >+ for (i = 0; i < compat_qxl->num_modes; i++) >+ { >+ struct compat_qxl_mode *m = compat_qxl->modes + i; >+ >+ if (m->x_res == p->HDisplay && >+ m->y_res == p->VDisplay && >+ m->bits == pScrn->bitsPerPixel) >+ { >+ if (m->bits == 16) >+ { >+ /* What QXL calls 16 bit is actually x1r5g5b515 */ >+ if (pScrn->depth == 15) >+ return i; >+ } >+ else if (m->bits == 32) >+ { >+ /* What QXL calls 32 bit is actually x8r8g8b8 */ >+ if (pScrn->depth == 24) >+ return i; >+ } >+ } >+ } >+ >+ return -1; >+} >+ >+static ModeStatus >+compat_qxl_valid_mode(SCRN_ARG_TYPE arg, DisplayModePtr p, Bool flag, int pass) >+{ >+ SCRN_INFO_PTR(arg); >+ compat_qxl_screen_t *compat_qxl = pScrn->driverPrivate; >+ int bpp = pScrn->bitsPerPixel; >+ int mode_idx; >+ >+ /* FIXME: I don't think this is necessary now that we report the >+ * correct amount of video ram? >+ */ >+ if (p->HDisplay * p->VDisplay * (bpp/8) > compat_qxl->draw_area_size) >+ return MODE_MEM; >+ >+ mode_idx = compat_qxl_find_native_mode (pScrn, p); >+ if (mode_idx == -1) >+ return MODE_NOMODE; >+ >+ p->Private = (void *)(unsigned long)mode_idx; >+ >+ return MODE_OK; >+} >+ >+static void compat_qxl_add_mode(ScrnInfoPtr pScrn, int width, int height, int type) >+{ >+ DisplayModePtr mode; >+ >+ /* Skip already present modes */ >+ for (mode = pScrn->monitor->Modes; mode; mode = mode->next) >+ if (mode->HDisplay == width && mode->VDisplay == height) >+ return; >+ >+ mode = xnfcalloc(1, sizeof(DisplayModeRec)); >+ >+ mode->status = MODE_OK; >+ mode->type = type; >+ mode->HDisplay = width; >+ mode->HSyncStart = (width * 105 / 100 + 7) & ~7; >+ mode->HSyncEnd = (width * 115 / 100 + 7) & ~7; >+ mode->HTotal = (width * 130 / 100 + 7) & ~7; >+ mode->VDisplay = height; >+ mode->VSyncStart = height + 1; >+ mode->VSyncEnd = height + 4; >+ mode->VTotal = height * 1035 / 1000; >+ mode->Clock = mode->HTotal * mode->VTotal * 60 / 1000; >+ mode->Flags = V_NHSYNC | V_PVSYNC; >+ >+ xf86SetModeDefaultName(mode); >+ xf86ModesAdd(pScrn->monitor->Modes, mode); >+} >+ >+static Bool >+compat_qxl_pre_init(ScrnInfoPtr pScrn, int flags) >+{ >+ int i, scrnIndex = pScrn->scrnIndex; >+ compat_qxl_screen_t *compat_qxl = NULL; >+ ClockRangePtr clockRanges = NULL; >+ int *linePitches = NULL; >+ DisplayModePtr mode; >+ unsigned int max_x = 0, max_y = 0; >+ >+ CHECK_POINT(); >+ >+ /* zaphod mode is for suckers and i choose not to implement it */ >+ if (xf86IsEntityShared(pScrn->entityList[0])) { >+ xf86DrvMsg(scrnIndex, X_ERROR, "No Zaphod mode for you\n"); >+ return FALSE; >+ } >+ >+ if (!pScrn->driverPrivate) >+ pScrn->driverPrivate = xnfcalloc(sizeof(compat_qxl_screen_t), 1); >+ compat_qxl = pScrn->driverPrivate; >+ >+ compat_qxl->entity = xf86GetEntityInfo(pScrn->entityList[0]); >+ compat_qxl->pci = xf86GetPciInfoForEntity(compat_qxl->entity->index); >+#ifndef XSERVER_LIBPCIACCESS >+ compat_qxl->pci_tag = pciTag(compat_qxl->pci->bus, compat_qxl->pci->device, compat_qxl->pci->func); >+#endif >+ >+ pScrn->monitor = pScrn->confScreen->monitor; >+ >+ if (!compat_qxl_color_setup(pScrn)) >+ goto out; >+ >+ /* option parsing and card differentiation */ >+ xf86CollectOptions(pScrn, NULL); >+ >+ if (!compat_qxl_map_memory(compat_qxl, scrnIndex)) >+ goto out; >+ >+ if (!compat_qxl_check_device(pScrn, compat_qxl)) >+ goto out; >+ >+ /* ddc stuff here */ >+ >+ clockRanges = xnfcalloc(sizeof(ClockRange), 1); >+ clockRanges->next = NULL; >+ clockRanges->minClock = 10000; >+ clockRanges->maxClock = 400000; >+ clockRanges->clockIndex = -1; >+ clockRanges->interlaceAllowed = clockRanges->doubleScanAllowed = 0; >+ clockRanges->ClockMulFactor = clockRanges->ClockDivFactor = 1; >+ pScrn->progClock = TRUE; >+ >+ /* override QXL monitor stuff */ >+ if (pScrn->monitor->nHsync <= 0) { >+ pScrn->monitor->hsync[0].lo = 29.0; >+ pScrn->monitor->hsync[0].hi = 160.0; >+ pScrn->monitor->nHsync = 1; >+ } >+ if (pScrn->monitor->nVrefresh <= 0) { >+ pScrn->monitor->vrefresh[0].lo = 50; >+ pScrn->monitor->vrefresh[0].hi = 75; >+ pScrn->monitor->nVrefresh = 1; >+ } >+ >+ /* Add any modes not in xorg's default mode list */ >+ for (i = 0; i < compat_qxl->num_modes; i++) >+ if (compat_qxl->modes[i].orientation == 0) { >+ compat_qxl_add_mode(pScrn, compat_qxl->modes[i].x_res, compat_qxl->modes[i].y_res, >+ M_T_DRIVER); >+ if (compat_qxl->modes[i].x_res > max_x) >+ max_x = compat_qxl->modes[i].x_res; >+ if (compat_qxl->modes[i].y_res > max_y) >+ max_y = compat_qxl->modes[i].y_res; >+ } >+ >+ if (pScrn->display->virtualX == 0 && pScrn->display->virtualY == 0) { >+ /* It is possible for the largest x + largest y size combined leading >+ to a virtual size which will not fit into the framebuffer when this >+ happens we prefer max width and make height as large as possible */ >+ if (max_x * max_y * (pScrn->bitsPerPixel / 8) > compat_qxl->draw_area_size) >+ pScrn->display->virtualY = compat_qxl->draw_area_size / >+ (max_x * (pScrn->bitsPerPixel / 8)); >+ else >+ pScrn->display->virtualY = max_y; >+ >+ pScrn->display->virtualX = max_x; >+ } >+ >+ if (0 >= xf86ValidateModes(pScrn, pScrn->monitor->Modes, >+ pScrn->display->modes, clockRanges, linePitches, >+ 128, max_x, 128 * 4, 128, max_y, >+ pScrn->display->virtualX, >+ pScrn->display->virtualY, >+ 128 * 1024 * 1024, LOOKUP_BEST_REFRESH)) >+ goto out; >+ >+ CHECK_POINT(); >+ >+ xf86PruneDriverModes(pScrn); >+ pScrn->currentMode = pScrn->modes; >+ /* If no modes are specified in xorg.conf, default to 1024x768 */ >+ if (pScrn->display->modes == NULL || pScrn->display->modes[0] == NULL) >+ for (mode = pScrn->modes; mode; mode = mode->next) >+ if (mode->HDisplay == 1024 && mode->VDisplay == 768) { >+ pScrn->currentMode = mode; >+ break; >+ } >+ >+ xf86PrintModes(pScrn); >+ xf86SetDpi(pScrn, 0, 0); >+ >+ if (!xf86LoadSubModule(pScrn, "fb") || >+ !xf86LoadSubModule(pScrn, "ramdac") || >+ !xf86LoadSubModule(pScrn, "vgahw")) >+ { >+ goto out; >+ } >+ >+ print_modes (compat_qxl, scrnIndex); >+ >+ /* VGA hardware initialisation */ >+ if (!vgaHWGetHWRec(pScrn)) >+ return FALSE; >+ vgaHWSetStdFuncs (VGAHWPTR (pScrn)); >+ >+ /* hate */ >+ compat_qxl_unmap_memory(compat_qxl, scrnIndex); >+ >+ CHECK_POINT(); >+ >+ xf86DrvMsg(scrnIndex, X_INFO, "PreInit complete\n"); >+ return TRUE; >+ >+out: >+ if (clockRanges) >+ xfree(clockRanges); >+ if (compat_qxl) >+ xfree(compat_qxl); >+ >+ return FALSE; >+} >+ >+#ifdef XSERVER_LIBPCIACCESS >+enum compat_qxl_class >+{ >+ CHIP_QXL_1, >+}; >+ >+static const struct pci_id_match compat_qxl_device_match[] = { >+ { >+ PCI_VENDOR_RED_HAT, PCI_CHIP_QXL_0100, PCI_MATCH_ANY, PCI_MATCH_ANY, >+ 0x00030000, 0x00ffffff, CHIP_QXL_1 >+ }, >+ >+ { 0 }, >+}; >+#endif >+ >+static SymTabRec compat_qxlChips[] = >+{ >+ { PCI_CHIP_QXL_0100, "QXL 1", }, >+ { -1, NULL } >+}; >+ >+#ifndef XSERVER_LIBPCIACCESS >+static PciChipsets compat_qxlPciChips[] = >+{ >+ { PCI_CHIP_QXL_0100, PCI_CHIP_QXL_0100, RES_SHARED_VGA }, >+ { -1, -1, RES_UNDEFINED } >+}; >+#endif >+ >+static void >+compat_qxl_identify(int flags) >+{ >+ xf86PrintChipsets("compat_qxl", "Driver for QXL virtual graphics", compat_qxlChips); >+} >+ >+void >+compat_init_scrn(ScrnInfoPtr pScrn) >+{ >+ pScrn->driverVersion = 0; >+ pScrn->driverName = pScrn->name = "compat_qxl"; >+ pScrn->PreInit = compat_qxl_pre_init; >+ pScrn->ScreenInit = compat_qxl_screen_init; >+ pScrn->SwitchMode = compat_qxl_switch_mode; >+ pScrn->ValidMode = compat_qxl_valid_mode; >+ pScrn->EnterVT = compat_qxl_enter_vt; >+ pScrn->LeaveVT = compat_qxl_leave_vt; >+} >diff --git a/src/compat/compat-qxl_image.c b/src/compat/compat-qxl_image.c >new file mode 100644 >index 0000000..2307138 >--- /dev/null >+++ b/src/compat/compat-qxl_image.c >@@ -0,0 +1,255 @@ >+#include <string.h> >+#include <assert.h> >+#include <stdlib.h> >+#include "compat-qxl.h" >+#include "compat-lookup3.h" >+ >+typedef struct image_info_t image_info_t; >+ >+struct image_info_t >+{ >+ struct compat_qxl_image *image; >+ int ref_count; >+ image_info_t *next; >+}; >+ >+#define HASH_SIZE 4096 >+static image_info_t *image_table[HASH_SIZE]; >+ >+static unsigned int >+hash_and_copy (const uint8_t *src, int src_stride, >+ uint8_t *dest, int dest_stride, >+ int bytes_per_pixel, int width, int height) >+{ >+ unsigned int hash = 0; >+ int i; >+ >+ for (i = 0; i < height; ++i) >+ { >+ const uint8_t *src_line = src + i * src_stride; >+ uint8_t *dest_line = dest + i * dest_stride; >+ int n_bytes = width * bytes_per_pixel; >+ >+ if (dest) >+ memcpy (dest_line, src_line, n_bytes); >+ >+ hash = compat_hashlittle (src_line, n_bytes, hash); >+ } >+ >+ return hash; >+} >+ >+static image_info_t * >+lookup_image_info (unsigned int hash, >+ int width, >+ int height) >+{ >+ struct image_info_t *info = image_table[hash % HASH_SIZE]; >+ >+ while (info) >+ { >+ struct compat_qxl_image *image = info->image; >+ >+ if (image->descriptor.id == hash && >+ image->descriptor.width == width && >+ image->descriptor.height == height) >+ { >+ return info; >+ } >+ >+ info = info->next; >+ } >+ >+#if 0 >+ ErrorF ("lookup of %u failed\n", hash); >+#endif >+ >+ return NULL; >+} >+ >+static image_info_t * >+insert_image_info (unsigned int hash) >+{ >+ struct image_info_t *info = malloc (sizeof (image_info_t)); >+ >+ if (!info) >+ return NULL; >+ >+ info->next = image_table[hash % HASH_SIZE]; >+ image_table[hash % HASH_SIZE] = info; >+ >+ return info; >+} >+ >+static void >+remove_image_info (image_info_t *info) >+{ >+ struct image_info_t **location = &image_table[info->image->descriptor.id % HASH_SIZE]; >+ >+ while (*location && (*location) != info) >+ location = &((*location)->next); >+ >+ if (*location) >+ *location = info->next; >+ >+ free (info); >+} >+ >+struct compat_qxl_image * >+compat_qxl_image_create (compat_qxl_screen_t *compat_qxl, const uint8_t *data, >+ int x, int y, int width, int height, >+ int stride) >+{ >+ unsigned int hash; >+ image_info_t *info; >+ >+ data += y * stride + x * compat_qxl->bytes_per_pixel; >+ >+ hash = hash_and_copy (data, stride, NULL, -1, compat_qxl->bytes_per_pixel, width, height); >+ >+ info = lookup_image_info (hash, width, height); >+ if (info) >+ { >+ int i, j; >+ >+#if 0 >+ ErrorF ("reusing image %p with hash %u (%d x %d)\n", info->image, hash, width, height); >+#endif >+ >+ info->ref_count++; >+ >+ for (i = 0; i < height; ++i) >+ { >+ struct compat_qxl_data_chunk *chunk; >+ const uint8_t *src_line = data + i * stride; >+ uint32_t *dest_line; >+ >+ chunk = virtual_address (compat_qxl, u64_to_pointer (info->image->u.bitmap.data)); >+ >+ dest_line = (uint32_t *)chunk->data + width * i; >+ >+ for (j = 0; j < width; ++j) >+ { >+ uint32_t *s = (uint32_t *)src_line; >+ uint32_t *d = (uint32_t *)dest_line; >+ >+ if (d[j] != s[j]) >+ { >+#if 0 >+ ErrorF ("bad collision at (%d, %d)! %d != %d\n", j, i, s[j], d[j]); >+#endif >+ goto out; >+ } >+ } >+ } >+ out: >+ return info->image; >+ } >+ else >+ { >+ struct compat_qxl_image *image; >+ struct compat_qxl_data_chunk *chunk; >+ int dest_stride = width * compat_qxl->bytes_per_pixel; >+ image_info_t *info; >+ >+#if 0 >+ ErrorF ("Must create new image of size %d %d\n", width, height); >+#endif >+ >+ /* Chunk */ >+ >+ /* FIXME: Check integer overflow */ >+ chunk = compat_qxl_allocnf (compat_qxl, sizeof *chunk + height * dest_stride); >+ >+ chunk->data_size = height * dest_stride; >+ chunk->prev_chunk = 0; >+ chunk->next_chunk = 0; >+ >+ hash_and_copy (data, stride, >+ chunk->data, dest_stride, >+ compat_qxl->bytes_per_pixel, width, height); >+ >+ /* Image */ >+ image = compat_qxl_allocnf (compat_qxl, sizeof *image); >+ >+ image->descriptor.id = 0; >+ image->descriptor.type = QXL_IMAGE_TYPE_BITMAP; >+ >+ image->descriptor.flags = 0; >+ image->descriptor.width = width; >+ image->descriptor.height = height; >+ >+ if (compat_qxl->bytes_per_pixel == 2) >+ { >+ image->u.bitmap.format = QXL_BITMAP_FMT_16BIT; >+ } >+ else >+ { >+ image->u.bitmap.format = QXL_BITMAP_FMT_32BIT; >+ } >+ >+ image->u.bitmap.flags = QXL_BITMAP_TOP_DOWN; >+ image->u.bitmap.x = width; >+ image->u.bitmap.y = height; >+ image->u.bitmap.stride = width * compat_qxl->bytes_per_pixel; >+ image->u.bitmap.palette = 0; >+ image->u.bitmap.data = physical_address (compat_qxl, chunk); >+ >+#if 0 >+ ErrorF ("%p has size %d %d\n", image, width, height); >+#endif >+ >+ /* Add to hash table */ >+ if ((info = insert_image_info (hash))) >+ { >+ info->image = image; >+ info->ref_count = 1; >+ >+ image->descriptor.id = hash; >+ image->descriptor.flags = QXL_IMAGE_CACHE; >+ >+#if 0 >+ ErrorF ("added with hash %u\n", hash); >+#endif >+ } >+ >+ return image; >+ } >+} >+ >+void >+compat_qxl_image_destroy (compat_qxl_screen_t *compat_qxl, >+ struct compat_qxl_image *image) >+{ >+ struct compat_qxl_data_chunk *chunk; >+ image_info_t *info; >+ >+ chunk = virtual_address (compat_qxl, u64_to_pointer (image->u.bitmap.data)); >+ >+ info = lookup_image_info (image->descriptor.id, >+ image->descriptor.width, >+ image->descriptor.height); >+ >+ if (info && info->image == image) >+ { >+ --info->ref_count; >+ >+ if (info->ref_count != 0) >+ return; >+ >+#if 0 >+ ErrorF ("removed %p from hash table\n", info->image); >+#endif >+ >+ remove_image_info (info); >+ } >+ >+ compat_qxl_free (compat_qxl->mem, chunk); >+ compat_qxl_free (compat_qxl->mem, image); >+} >+ >+void >+compat_qxl_drop_image_cache (compat_qxl_screen_t *compat_qxl) >+{ >+ memset (image_table, 0, HASH_SIZE * sizeof (image_info_t *)); >+} >diff --git a/src/compat/compat-qxl_mem.c b/src/compat/compat-qxl_mem.c >new file mode 100644 >index 0000000..26e85f9 >--- /dev/null >+++ b/src/compat/compat-qxl_mem.c >@@ -0,0 +1,321 @@ >+#include <assert.h> >+#include <stdio.h> >+#include <stdlib.h> >+ >+#include "compat-qxl.h" >+ >+struct block >+{ >+ unsigned long n_bytes; >+ >+ union >+ { >+ struct >+ { >+ struct block *next; >+ } unused; >+ >+ struct >+ { >+ uint8_t data[0]; >+ } used; >+ } u; >+}; >+ >+struct compat_qxl_mem >+{ >+ void * base; >+ unsigned long n_bytes; >+ >+ struct block *unused; >+ unsigned long total_allocated; >+ unsigned long total_freed; >+ unsigned long n_allocated_blocks; >+ unsigned long n_freed_blocks; >+}; >+ >+static void >+initialize (struct compat_qxl_mem *mem) >+{ >+ mem->unused = (struct block *)mem->base; >+ mem->unused->n_bytes = mem->n_bytes; >+ mem->unused->u.unused.next = NULL; >+ >+ mem->total_allocated = 0; >+ mem->total_freed = 0; >+ mem->n_allocated_blocks = 0; >+ mem->n_freed_blocks = 0; >+} >+ >+struct compat_qxl_mem * >+compat_qxl_mem_create (void *base, unsigned long n_bytes) >+{ >+ struct compat_qxl_mem *mem = NULL; >+ >+ mem = calloc (sizeof (*mem), 1); >+ if (!mem) >+ goto out; >+ >+ mem->base = base; >+ mem->n_bytes = n_bytes; >+ >+ initialize (mem); >+ >+out: >+ return mem; >+} >+ >+void >+compat_qxl_mem_free_all (struct compat_qxl_mem *mem) >+{ >+ initialize (mem); >+} >+ >+void >+compat_qxl_mem_dump_stats (struct compat_qxl_mem *mem, const char *header) >+{ >+ struct block *b; >+ int n_blocks; >+ unsigned long max_block = 0; >+ unsigned long min_block = 0xffffffffffffffffUL; >+ >+ fprintf (stderr, "%s\n", header); >+ >+ n_blocks = 0; >+ for (b = mem->unused; b != NULL; b = b->u.unused.next) >+ { >+ fprintf (stderr, "block: %p (%lu bytes)\n", b, b->n_bytes); >+ >+ if (b->u.unused.next && b >= b->u.unused.next) >+ { >+ fprintf (stderr, "b: %p b->next: %p\n", >+ b, b->u.unused.next); >+ assert (0); >+ } >+ >+ if (b->u.unused.next && (void *)b + b->n_bytes >= b->u.unused.next) >+ { >+ fprintf (stderr, "OVERLAPPING BLOCKS b: %p b->next: %p\n", >+ b, b->u.unused.next); >+ assert (0); >+ } >+ >+ if (b->n_bytes > max_block) >+ max_block = b->n_bytes; >+ >+ if (b->n_bytes < min_block) >+ min_block = b->n_bytes; >+ >+ ++n_blocks; >+ } >+ >+ fprintf (stderr, "=========\n"); >+ >+ fprintf (stderr, "%d blocks\n", n_blocks); >+ fprintf (stderr, "min block: %lu bytes\n", min_block); >+ fprintf (stderr, "max block: %lu bytes\n", max_block); >+ fprintf (stderr, "total freed: %lu bytres\n", mem->total_freed); >+ fprintf (stderr, "total allocated: %lu bytes\n", >+ mem->total_allocated - mem->total_freed); >+ fprintf (stderr, "total free: %lu bytes\n", >+ mem->n_bytes - (mem->total_allocated - mem->total_freed)); >+} >+ >+void * >+compat_qxl_alloc (struct compat_qxl_mem *mem, unsigned long n_bytes) >+{ >+ struct block *b, *prev; >+ >+ mem->n_allocated_blocks++; >+ >+ /* Simply pretend the user asked to allocate the header as well. Then >+ * we can mostly ignore the difference between blocks and allocations >+ */ >+ n_bytes += sizeof (unsigned long); >+ >+ n_bytes = (n_bytes + 7) & ~((1 << 3) - 1); >+ >+ if (n_bytes < sizeof (struct block)) >+ n_bytes = sizeof (struct block); >+ >+ assert (mem->unused); >+ >+ prev = NULL; >+ for (b = mem->unused; b != NULL; prev = b, b = b->u.unused.next) >+ { >+ if (b->n_bytes >= n_bytes) >+ { >+ struct block *new_block; >+ >+ if (b->n_bytes - n_bytes >= sizeof (struct block)) >+ { >+ new_block = (void *)b + n_bytes; >+ >+ new_block->n_bytes = b->n_bytes - n_bytes; >+ >+ if (prev) >+ { >+ assert (prev < b); >+ assert (prev->u.unused.next == NULL || prev < prev->u.unused.next); >+ >+ new_block->u.unused.next = b->u.unused.next; >+ prev->u.unused.next = new_block; >+ } >+ else >+ { >+ assert (mem->unused == b); >+ >+ new_block->u.unused.next = mem->unused->u.unused.next; >+ mem->unused = new_block; >+ } >+ >+ b->n_bytes = n_bytes; >+ } >+ else >+ { >+#if 0 >+ printf ("Exact match\n"); >+#endif >+ >+ if (prev) >+ { >+ prev->u.unused.next = b->u.unused.next; >+ } >+ else >+ { >+ mem->unused = b->u.unused.next; >+ } >+ } >+ >+ mem->total_allocated += n_bytes; >+ >+ return (void *)b->u.used.data; >+ } >+ else >+ { >+#if 0 >+ printf ("Skipping small block %d\n", b->n_bytes); >+#endif >+ } >+ } >+ >+ /* If we get here, we are out of memory, so print some stats */ >+#if 0 >+ fprintf (stderr, "Failing to allocate %lu bytes\n", n_bytes); >+ compat_qxl_mem_dump_stats (mem, "out of memory"); >+#endif >+ >+ return NULL; >+} >+ >+/* Finds the unused block before and the unused block after @data. Both >+ * before and after can be NULL if data is before the first or after the >+ * last unused block. >+ */ >+static void >+find_neighbours (struct compat_qxl_mem *mem, void *data, >+ struct block **before, struct block **after) >+{ >+ struct block *b; >+ *before = NULL; >+ *after = NULL; >+ >+ for (b = mem->unused; b != NULL; b = b->u.unused.next) >+ { >+ if ((void *)b < data) >+ *before = b; >+ >+ if ((void *)b > data) >+ { >+ *after = b; >+ break; >+ } >+ } >+ >+ if (*before) >+ assert ((*before)->u.unused.next == *after); >+} >+ >+void >+compat_qxl_free (struct compat_qxl_mem *mem, void *d) >+{ >+ struct block *b = d - sizeof (unsigned long); >+ struct block *before, *after; >+ >+ mem->total_freed += b->n_bytes; >+ mem->n_freed_blocks++; >+ >+#if 0 >+ printf ("freeing %p (%d bytes)\n", b, b->n_bytes); >+ >+ compat_qxl_mem_dump_stats (mem, "before free"); >+#endif >+ >+ find_neighbours (mem, (void *)b, &before, &after); >+ >+ if (before) >+ { >+#if 0 >+ printf (" free: merge before: %p\n", before->u.used.data); >+#endif >+ >+ if ((void *)before + before->n_bytes == b) >+ { >+#if 0 >+ printf (" free: merge with before (adding %d bytes)\n", b->n_bytes); >+#endif >+ >+ /* Merge before and b */ >+ before->n_bytes += b->n_bytes; >+ b = before; >+ } >+ else >+ { >+#if 0 >+ printf (" free: no merge with before\n"); >+#endif >+ >+ before->u.unused.next = b; >+ } >+ } >+ else >+ { >+#if 0 >+ printf (" free: no before\n"); >+#endif >+ mem->unused = b; >+ } >+ >+ if (after) >+ { >+#if 0 >+ printf (" free: after: %p\n", after->u.used.data); >+#endif >+ if ((void *)b + b->n_bytes == after) >+ { >+#if 0 >+ printf (" merge with after\n"); >+#endif >+ b->n_bytes += after->n_bytes; >+ b->u.unused.next = after->u.unused.next; >+ } >+ else >+ { >+#if 0 >+ printf (" no merge with after\n"); >+#endif >+ b->u.unused.next = after; >+ } >+ } >+ else >+ { >+#if 0 >+ printf (" free: no after\n"); >+#endif >+ b->u.unused.next = NULL; >+ } >+ >+#if 0 >+ compat_qxl_mem_dump_stats (mem, "after free"); >+#endif >+} >diff --git a/src/compat/compat-qxl_ring.c b/src/compat/compat-qxl_ring.c >new file mode 100644 >index 0000000..d875357 >--- /dev/null >+++ b/src/compat/compat-qxl_ring.c >@@ -0,0 +1,97 @@ >+#include <string.h> >+#include <unistd.h> >+#include <stdlib.h> >+#include "compat-qxl.h" >+ >+struct ring >+{ >+ struct compat_qxl_ring_header header; >+ uint8_t elements[0]; >+}; >+ >+struct compat_qxl_ring >+{ >+ volatile struct ring *ring; >+ int element_size; >+ int n_elements; >+ int prod_notify; >+}; >+ >+struct compat_qxl_ring * >+compat_qxl_ring_create (struct compat_qxl_ring_header *header, >+ int element_size, >+ int n_elements, >+ int prod_notify) >+{ >+ struct compat_qxl_ring *ring; >+ >+ ring = malloc (sizeof *ring); >+ if (!ring) >+ return NULL; >+ >+ ring->ring = (volatile struct ring *)header; >+ ring->element_size = element_size; >+ ring->n_elements = n_elements; >+ ring->prod_notify = prod_notify; >+ >+ return ring; >+} >+ >+void >+compat_qxl_ring_push (struct compat_qxl_ring *ring, >+ const void *new_elt) >+{ >+ volatile struct compat_qxl_ring_header *header = &(ring->ring->header); >+ volatile uint8_t *elt; >+ int idx; >+ >+ while (header->prod - header->cons == header->num_items) >+ { >+ header->notify_on_cons = header->cons + 1; >+ >+ mem_barrier(); >+ } >+ >+ idx = header->prod & (ring->n_elements - 1); >+ elt = ring->ring->elements + idx * ring->element_size; >+ >+ memcpy((void *)elt, new_elt, ring->element_size); >+ >+ header->prod++; >+ >+ mem_barrier(); >+ >+ if (header->prod == header->notify_on_prod) >+ outb (ring->prod_notify, 0); >+} >+ >+Bool >+compat_qxl_ring_pop (struct compat_qxl_ring *ring, >+ void *element) >+{ >+ volatile struct compat_qxl_ring_header *header = &(ring->ring->header); >+ volatile uint8_t *ring_elt; >+ int idx; >+ >+ if (header->cons == header->prod) >+ return FALSE; >+ >+ idx = header->cons & (ring->n_elements - 1); >+ ring_elt = ring->ring->elements + idx * ring->element_size; >+ >+ memcpy (element, (void *)ring_elt, ring->element_size); >+ >+ header->cons++; >+ >+ return TRUE; >+} >+ >+void >+compat_qxl_ring_wait_idle (struct compat_qxl_ring *ring) >+{ >+ while (ring->ring->header.cons != ring->ring->header.prod) >+ { >+ usleep (1000); >+ mem_barrier(); >+ } >+} >diff --git a/src/qxl_driver.c b/src/qxl_driver.c >index 4b7c64d..b308746 100644 >--- a/src/qxl_driver.c >+++ b/src/qxl_driver.c >@@ -1381,7 +1381,10 @@ qxl_pci_probe (DriverPtr drv, int entity, struct pci_device *dev, intptr_t match > qxl = pScrn->driverPrivate; > qxl->pci = dev; > >- qxl_init_scrn (pScrn, kms); >+ if (qxl->pci->revision == 0x01) >+ compat_init_scrn (pScrn); >+ else >+ qxl_init_scrn (pScrn, kms); > > return TRUE; > } >-- >1.7.1 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 1078390
: 934482