xf86-video-nv: 2 commits - configure.ac COPYING man/Makefile.am man/nv.man src/g80_cursor.c src/g80_cursor.h src/g80_ddc.c src/g80_ddc.h src/g80_display.c src/g80_display.h src/g80_dma.c src/g80_dma.h src/g80_driver.c src/g80_type.h src/g80_xaa.c src/g80_xaa.h src/Makefile.am src/nv_driver.c src/nv_include.h

Aaron Plattner aplattner at kemper.freedesktop.org
Fri Mar 9 04:13:13 EET 2007


 COPYING           |   26 +
 configure.ac      |   13 
 man/Makefile.am   |    9 
 man/nv.man        |   80 ++--
 src/Makefile.am   |   24 +
 src/g80_cursor.c  |  185 ++++++++++
 src/g80_cursor.h  |    3 
 src/g80_ddc.c     |  232 +++++++++++++
 src/g80_ddc.h     |    1 
 src/g80_display.c |  515 ++++++++++++++++++++++++++++++
 src/g80_display.h |    9 
 src/g80_dma.c     |   65 +++
 src/g80_dma.h     |   14 
 src/g80_driver.c  |  916 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/g80_type.h    |   75 ++++
 src/g80_xaa.c     |  554 ++++++++++++++++++++++++++++++++
 src/g80_xaa.h     |    1 
 src/nv_driver.c   |   42 ++
 src/nv_include.h  |    2 
 19 files changed, 2719 insertions(+), 47 deletions(-)

New commits:
diff-tree 06b168ced3cc4aa47cdad21a2351cca674fa26e0 (from 23383c2c2e1aa590f69197b1860053d5cb710cf7)
Author: Aaron Plattner <aplattner at nvidia.com>
Date:   Thu Mar 8 18:12:43 2007 -0800

    Enable G80 support by default.

diff --git a/configure.ac b/configure.ac
index acebecf..6b1f98e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -64,10 +64,10 @@ PKG_CHECK_MODULES(XORG, [xorg-server xpr
 sdkdir=$(pkg-config --variable=sdkdir xorg-server)
 
 # Check for optional compile-time support
-AC_ARG_ENABLE(g80, AC_HELP_STRING([--enable-g80],
-                                  [Enable G80 support [[default=no]]]),
+AC_ARG_ENABLE(g80, AC_HELP_STRING([--disable-g80],
+                                  [Disable G80 support [[default=no]]]),
               [SUPPORT_G80="$enableval"],
-              [SUPPORT_G80=no])
+              [SUPPORT_G80=yes])
 AM_CONDITIONAL(SUPPORT_G80, test x$SUPPORT_G80 = xyes)
 if test "$SUPPORT_G80" = yes; then
         AC_DEFINE(SUPPORT_G80,1,[Enable G80 support])
diff-tree 23383c2c2e1aa590f69197b1860053d5cb710cf7 (from dd305c3f64f9267d54324d734f1028bfc00e474f)
Author: Aaron Plattner <aplattner at nvidia.com>
Date:   Fri Feb 16 16:11:13 2007 -0800

    Initial G80 support.  Bump to 1.99.1.

diff --git a/COPYING b/COPYING
index 7f33cbf..cad7191 100644
--- a/COPYING
+++ b/COPYING
@@ -1,12 +1,20 @@
-This is a stub file.  This package has not yet had its complete licensing
-information compiled.  Please see the individual source files for details on
-your rights to use and modify this software.
+Copyright (c) 2007 NVIDIA, Corporation
 
-Please submit updated COPYING files to the Xorg bugzilla:
+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 the rights to use, copy, modify, merge, publish,
+distribute, sublicense, 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:
 
-https://bugs.freedesktop.org/enter_bug.cgi?product=xorg
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
 
-All licensing questions regarding this software should be directed at the
-Xorg mailing list:
-
-http://lists.freedesktop.org/mailman/listinfo/xorg
+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 NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 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.
diff --git a/configure.ac b/configure.ac
index 571d3f3..acebecf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -22,7 +22,7 @@
 
 AC_PREREQ(2.57)
 AC_INIT([xf86-video-nv],
-        1.2.2.1,
+        1.99.1,
         [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg],
         xf86-video-nv)
 
@@ -63,6 +63,17 @@ PKG_CHECK_EXISTS([xorg-server >= 1.0.99.
 PKG_CHECK_MODULES(XORG, [xorg-server xproto fontsproto $REQUIRED_MODULES])
 sdkdir=$(pkg-config --variable=sdkdir xorg-server)
 
+# Check for optional compile-time support
+AC_ARG_ENABLE(g80, AC_HELP_STRING([--enable-g80],
+                                  [Enable G80 support [[default=no]]]),
+              [SUPPORT_G80="$enableval"],
+              [SUPPORT_G80=no])
+AM_CONDITIONAL(SUPPORT_G80, test x$SUPPORT_G80 = xyes)
+if test "$SUPPORT_G80" = yes; then
+        AC_DEFINE(SUPPORT_G80,1,[Enable G80 support])
+        echo "Enabling G80 support"
+fi
+
 # Checks for libraries.
 
 # Checks for header files.
diff --git a/man/Makefile.am b/man/Makefile.am
index bf7ec17..036545c 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -41,6 +41,12 @@ SED = sed
 XORGRELSTRING = @PACKAGE_STRING@
   XORGMANNAME = X Version 11
 
+if SUPPORT_G80
+MAN_SUPPORT_G80 := 1
+else
+MAN_SUPPORT_G80 := 0
+endif
+
 MAN_SUBSTS = \
 	-e 's|__vendorversion__|"$(XORGRELSTRING)" "$(XORGMANNAME)"|' \
 	-e 's|__xorgversion__|"$(XORGRELSTRING)" "$(XORGMANNAME)"|' \
@@ -51,7 +57,8 @@ MAN_SUBSTS = \
 	-e 's|__drivermansuffix__|$(DRIVER_MAN_SUFFIX)|g' \
 	-e 's|__adminmansuffix__|$(ADMIN_MAN_SUFFIX)|g' \
 	-e 's|__miscmansuffix__|$(MISC_MAN_SUFFIX)|g' \
-	-e 's|__filemansuffix__|$(FILE_MAN_SUFFIX)|g'
+	-e 's|__filemansuffix__|$(FILE_MAN_SUFFIX)|g' \
+	-e 's|__support_g80__|$(MAN_SUPPORT_G80)|g'
 
 SUFFIXES = .$(DRIVER_MAN_SUFFIX) .man
 
diff --git a/man/nv.man b/man/nv.man
index 83d20ae..243b406 100644
--- a/man/nv.man
+++ b/man/nv.man
@@ -58,6 +58,12 @@ NV40, NV41, NV43, NV44, NV45, C51
 .TP 22
 .B GeForce 7XXX
 G70, G71, G72, G73
+.de G8
+.TP 22
+.B GeForce 8XXX
+G80
+..
+.if __support_g80__ .G8
 
 .SH CONFIGURATION DETAILS
 Please refer to __xconfigfile__(__filemansuffix__) for general configuration
@@ -69,7 +75,7 @@ present for all chips.
 .PP
 The following driver
 .B Options
-are supported:
+are supported for pre-G80 hardware:
 .TP
 .BI "Option \*qHWCursor\*q \*q" boolean \*q
 Enable or disable the HW cursor.  Default: on.
@@ -128,42 +134,54 @@ Default: no rotation support.
 .TP
 .BI "Option \*qShadowFB\*q \*q" boolean \*q
 Enable or disable use of the shadow framebuffer layer.  Default: off.
+.
+.\" ******************** begin G80 section ********************
+.de G8
+.PP
+The following driver
+.B Options
+are available for G80:
+.TP
+.BI "Option \*qHWCursor\*q \*q" boolean \*q
+Enable or disable the hardware cursor.  Default: on.
+.TP
+.BI "Option \*qNoAccel\*q \*q" boolean \*q
+Disable or enable acceleration.  Default: acceleration is enabled.
+.TP
+.BI "Option \*qBackendMode\*q \*q" mode \*q
+Designate a mode to be used as the physical mode driving the display.
+The screen will be scaled to fit the requested mode.
+For example, if
+.B Option \*qBackendMode\*q \*q1280x1024\*q
+is specified, the monitor will always display the 1280x1024 mode and the screen will be scaled to match.
+..
+.if __support_g80__ .G8
+.\" ******************** end G80 section ********************
+.
 .SH "SEE ALSO"
 __xservername__(__appmansuffix__), __xconfigfile__(__filemansuffix__), xorgconfig(__appmansuffix__), Xserver(__appmansuffix__), X(__miscmansuffix__)
 .SH AUTHORS
 Authors include: David McKay, Jarno Paananen, Chas Inman, Dave Schmenk, 
-Mark Vojkovich
+Mark Vojkovich, Aaron Plattner
 .SH COPYRIGHT
 .LP
-NOTICE TO USER:   The source code  is copyrighted under  U.S. and
-international laws.  Users and possessors of this source code are
-hereby granted a nonexclusive,  royalty-free copyright license to
-use this code in individual and commercial software.
-.LP
-Any use of this source code must include,  in the user documentation and
-internal comments to the code,  notices to the end user as follows:
+Copyright (c) 2003 - 2007 NVIDIA, Corporation
 .LP
-Copyright 1993-2003 NVIDIA, Corporation.  All rights reserved.
+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 the rights to use, copy, modify, merge, publish,
+distribute, sublicense, 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:
 .LP
-NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY
-OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"
-WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPORATION 
-DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,
-INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT,  
-AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL
-NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCIDENTAL, 
-OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RESULTING FROM 
-LOSS OF USE,  DATA OR PROFITS,  WHETHER IN AN ACTION
-OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,  ARISING OUT OF
-OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
 .LP
-U.S. Government  End  Users.   This source code  is a "commercial
-item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),
-consisting  of "commercial  computer  software"  and  "commercial
-computer  software  documentation,"  as such  terms  are  used in
-48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Government 
-only as  a commercial end item.   Consistent with  48 C.F.R.
-12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),
-all U.S. Government End Users  acquire the source code  with only
-those rights set forth herein.                                   
-
+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 NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 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.
diff --git a/src/Makefile.am b/src/Makefile.am
index ecc8597..b7c1128 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -28,7 +28,9 @@ nv_drv_la_LTLIBRARIES = nv_drv.la
 nv_drv_la_LDFLAGS = -module -avoid-version
 nv_drv_ladir = @moduledir@/drivers
 
-nv_drv_la_SOURCES = \
+nv_drv_la_SOURCES = $(nv_sources) $(riva_sources) $(g80_sources)
+
+nv_sources = \
          nv_const.h \
          nv_cursor.c \
          nv_dac.c \
@@ -45,7 +47,9 @@ nv_drv_la_SOURCES = \
          nv_type.h \
          nvvga.h \
          nv_video.c \
-         nv_xaa.c \
+         nv_xaa.c
+
+riva_sources = \
          riva_const.h \
          riva_cursor.c \
          riva_dac.c \
@@ -61,3 +65,19 @@ nv_drv_la_SOURCES = \
          riva_tbl.h \
          riva_type.h \
          riva_xaa.c
+
+if SUPPORT_G80
+g80_sources = \
+         g80_cursor.c \
+         g80_cursor.h \
+         g80_ddc.c \
+         g80_ddc.h \
+         g80_display.c \
+         g80_display.h \
+         g80_dma.c \
+         g80_dma.h \
+         g80_driver.c \
+         g80_type.h \
+         g80_xaa.c \
+         g80_xaa.h
+endif
diff --git a/src/g80_cursor.c b/src/g80_cursor.c
new file mode 100644
index 0000000..07422e5
--- /dev/null
+++ b/src/g80_cursor.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2007 NVIDIA, Corporation
+ *
+ * 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 the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, 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 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 NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include <cursorstr.h>
+
+#include "g80_type.h"
+#include "g80_cursor.h"
+#include "g80_display.h"
+
+#define CURSOR_PTR ((CARD32*)pNv->mem + pNv->videoRam * 256 - 0x1000)
+
+static void G80SetCursorColors(ScrnInfoPtr pScrn, int bg, int fg)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+    CARD32 *dst = CURSOR_PTR;
+    CARD32 *src = pNv->tmpCursor;
+    int i, j;
+
+    fg |= 0xff000000;
+    bg |= 0xff000000;
+
+    for(i = 0; i < 128; i++) {
+        CARD32 b = *src++;
+        CARD32 m = *src++;
+
+        for(j = 0; j < 32; j++) {
+            if(m & 1)
+                *dst = (b & 1) ? fg : bg;
+            else
+                *dst = 0;
+            b >>= 1;
+            m >>= 1;
+            dst++;
+        }
+    }
+}
+
+static void G80SetCursorPosition(ScrnInfoPtr pScrn, int x, int y)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+    const int headOff = 0x1000*pNv->head;
+
+    x &= 0xffff;
+    y &= 0xffff;
+    pNv->reg[(0x00647084 + headOff)/4] = y << 16 | x;
+    pNv->reg[(0x00647080 + headOff)/4] = 0;
+}
+
+static void G80LoadCursorImage(ScrnInfoPtr pScrn, unsigned char *bits)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+    memcpy(pNv->tmpCursor, bits, sizeof(pNv->tmpCursor));
+}
+
+static void G80HideCursor(ScrnInfoPtr pScrn)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+
+    pNv->cursorVisible = FALSE;
+    G80DispHideCursor(G80PTR(pScrn), TRUE);
+}
+
+static void G80ShowCursor(ScrnInfoPtr pScrn)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+
+    pNv->cursorVisible = TRUE;
+    G80DispShowCursor(G80PTR(pScrn), TRUE);
+}
+
+static Bool G80UseHWCursor(ScreenPtr pScreen, CursorPtr pCurs)
+{
+    return TRUE;
+}
+
+#ifdef ARGB_CURSOR
+static Bool G80UseHWCursorARGB(ScreenPtr pScreen, CursorPtr pCurs)
+{
+    if((pCurs->bits->width <= 64) && (pCurs->bits->height <= 64))
+        return TRUE;
+
+    return FALSE;
+}
+
+static void G80LoadCursorARGB(ScrnInfoPtr pScrn, CursorPtr pCurs)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+    CARD32 *dst = CURSOR_PTR, *src = pCurs->bits->argb;
+    int y;
+
+    for(y = 0; y < pCurs->bits->height; y++) {
+        memcpy(dst, src, pCurs->bits->width * 4);
+        memset(dst + pCurs->bits->width, 0, (64 - pCurs->bits->width) * 4);
+        src += pCurs->bits->width;
+        dst += 64;
+    }
+
+    memset(dst, 0, (64 - y) * 64 * 4);
+}
+#endif
+
+Bool G80CursorAcquire(G80Ptr pNv)
+{
+    const int headOff = 0x10 * pNv->head;
+
+    if(!pNv->HWCursor) return TRUE;
+
+    pNv->reg[(0x00610270+headOff)/4] = 0x2000;
+    while(pNv->reg[(0x00610270+headOff)/4] & 0x30000);
+
+    pNv->reg[(0x00610270+headOff)/4] = 1;
+    while((pNv->reg[(0x00610270+headOff)/4] & 0x30000) != 0x10000);
+
+    return TRUE;
+}
+
+void G80CursorRelease(G80Ptr pNv)
+{
+    const int headOff = 0x10 * pNv->head;
+
+    if(!pNv->HWCursor) return;
+
+    pNv->reg[(0x00610270+headOff)/4] = 0;
+    while(pNv->reg[(0x00610270+headOff)/4] & 0x30000);
+}
+
+Bool G80CursorInit(ScreenPtr pScreen)
+{
+    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+    G80Ptr pNv = G80PTR(pScrn);
+    xf86CursorInfoPtr infoPtr;
+
+    if(!pNv->HWCursor)
+        return TRUE;
+
+    infoPtr = xf86CreateCursorInfoRec();
+    if(!infoPtr) return FALSE;
+
+    pNv->CursorInfo = infoPtr;
+    pNv->cursorVisible = FALSE;
+
+    infoPtr->MaxWidth = infoPtr->MaxHeight = 64;
+    infoPtr->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
+                     HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32;
+    infoPtr->SetCursorColors = G80SetCursorColors;
+    infoPtr->SetCursorPosition = G80SetCursorPosition;
+    infoPtr->LoadCursorImage = G80LoadCursorImage;
+    infoPtr->HideCursor = G80HideCursor;
+    infoPtr->ShowCursor = G80ShowCursor;
+    infoPtr->UseHWCursor = G80UseHWCursor;
+
+#ifdef ARGB_CURSOR
+    infoPtr->UseHWCursorARGB = G80UseHWCursorARGB;
+    infoPtr->LoadCursorARGB = G80LoadCursorARGB;
+#endif
+
+    return xf86InitCursor(pScreen, infoPtr);
+}
diff --git a/src/g80_cursor.h b/src/g80_cursor.h
new file mode 100644
index 0000000..9cd56ee
--- /dev/null
+++ b/src/g80_cursor.h
@@ -0,0 +1,3 @@
+Bool G80CursorInit(ScreenPtr);
+Bool G80CursorAcquire(G80Ptr);
+void G80CursorRelease(G80Ptr);
diff --git a/src/g80_ddc.c b/src/g80_ddc.c
new file mode 100644
index 0000000..3713028
--- /dev/null
+++ b/src/g80_ddc.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2007 NVIDIA, Corporation
+ *
+ * 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 the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, 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 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 NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <strings.h>
+#include <xf86DDC.h>
+
+#include "g80_type.h"
+#include "g80_ddc.h"
+
+static Bool G80ReadPortMapping(int scrnIndex, G80Ptr pNv)
+{
+    unsigned char *table2;
+    unsigned char headerSize, entries;
+    int i;
+    CARD16 a;
+    CARD32 b;
+
+    /* Clear the i2c map to invalid */
+    for(i = 0; i < 4; i++)
+        pNv->i2cMap[i].dac = pNv->i2cMap[i].sor = -1;
+
+    if(*(CARD16*)pNv->table1 != 0xaa55) goto fail;
+
+    a = *(CARD16*)(pNv->table1 + 0x36);
+    table2 = (unsigned char*)pNv->table1 + a;
+
+    if(table2[0] != 0x40) goto fail;
+
+    b = *(CARD32*)(table2 + 6);
+    if(b != 0x4edcbdcb) goto fail;
+
+    headerSize = table2[1];
+    entries = table2[2];
+
+    for(i = 0; i < entries; i++) {
+        CARD32 type, port;
+        ORNum or;
+
+        b = *(CARD32*)&table2[headerSize + 8*i];
+        type = b & 0xf;
+        port = (b >> 4) & 0xf;
+        or = ffs((b >> 24) & 0xf) - 1;
+
+        if(type < 4 && port != 0xf) {
+            switch(type) {
+                case 0: /* CRT */
+                case 1: /* TV */
+                    if(pNv->i2cMap[port].dac != -1) {
+                        xf86DrvMsg(scrnIndex, X_WARNING,
+                                   "DDC routing table corrupt!  DAC %i -> %i "
+                                   "for port %i\n",
+                                   or, pNv->i2cMap[port].dac, port);
+                    }
+                    pNv->i2cMap[port].dac = or;
+                    break;
+                case 2: /* TMDS */
+                case 3: /* LVDS */
+                    if(pNv->i2cMap[port].sor != -1)
+                        xf86DrvMsg(scrnIndex, X_WARNING,
+                                   "DDC routing table corrupt!  SOR %i -> %i "
+                                   "for port %i\n",
+                                   or, pNv->i2cMap[port].sor, port);
+                    pNv->i2cMap[port].sor = or;
+                    break;
+            }
+        }
+    }
+
+    xf86DrvMsg(scrnIndex, X_PROBED, "I2C map:\n");
+    for(i = 0; i < 4; i++) {
+        if(pNv->i2cMap[i].dac != -1)
+            xf86DrvMsg(scrnIndex, X_PROBED, "  Bus %i -> DAC%i\n", i, pNv->i2cMap[i].dac);
+        if(pNv->i2cMap[i].sor != -1)
+            xf86DrvMsg(scrnIndex, X_PROBED, "  Bus %i -> SOR%i\n", i, pNv->i2cMap[i].sor);
+    }
+
+    return TRUE;
+
+fail:
+    xf86DrvMsg(scrnIndex, X_ERROR, "Couldn't find the DDC routing table.  "
+               "Mode setting will probably fail!\n");
+    return FALSE;
+}
+
+static void G80_I2CPutBits(I2CBusPtr b, int clock, int data)
+{
+    G80Ptr pNv = G80PTR(xf86Screens[b->scrnIndex]);
+    const int off = b->DriverPrivate.val;
+
+    pNv->reg[(0x0000E138+off)/4] = 4 | clock | data << 1;
+}
+
+static void G80_I2CGetBits(I2CBusPtr b, int *clock, int *data)
+{
+    G80Ptr pNv = G80PTR(xf86Screens[b->scrnIndex]);
+    const int off = b->DriverPrivate.val;
+    unsigned char val;
+
+    val = pNv->reg[(0x0000E138+off)/4];
+    *clock = !!(val & 1);
+    *data = !!(val & 2);
+}
+
+static xf86MonPtr G80ProbeDDCBus(ScrnInfoPtr pScrn, int bus)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+    I2CBusPtr i2c;
+    xf86MonPtr monInfo = NULL;
+    const int off = bus * 0x18;
+
+    /* Allocate the I2C bus structure */
+    i2c = xf86CreateI2CBusRec();
+    if(!i2c) return NULL;
+
+    i2c->BusName = "DDC";
+    i2c->scrnIndex = pScrn->scrnIndex;
+    i2c->I2CPutBits = G80_I2CPutBits;
+    i2c->I2CGetBits = G80_I2CGetBits;
+    i2c->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */
+    i2c->StartTimeout = 550;
+    i2c->BitTimeout = 40;
+    i2c->ByteTimeout = 40;
+    i2c->AcknTimeout = 40;
+    i2c->DriverPrivate.val = off;
+
+    if(!xf86I2CBusInit(i2c)) goto done;
+
+    pNv->reg[(0x0000E138+off)/4] = 7;
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+            "Probing for EDID on I2C bus %i...\n", bus);
+    monInfo = xf86DoEDID_DDC2(pScrn->scrnIndex, i2c);
+
+    pNv->reg[(0x0000E138+off)/4] = 3;
+
+    if(monInfo) {
+        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+                "DDC detected a %s:\n", monInfo->features.input_type ?
+                "DFP" : "CRT");
+        xf86PrintEDID(monInfo);
+    } else {
+        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "  ... none found\n");
+    }
+
+done:
+    xf86DestroyI2CBusRec(i2c, TRUE, TRUE);
+
+    return monInfo;
+}
+
+/*
+ * Try DDC on each bus until we find one that works.
+ */
+Bool G80ProbeDDC(ScrnInfoPtr pScrn)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+    xf86MonPtr monInfo;
+    int port;
+    Bool flatPanel;
+
+    if(!G80ReadPortMapping(pScrn->scrnIndex, pNv))
+        return FALSE;
+
+    for(port = 0; port < 4; port++) {
+        if(pNv->i2cMap[port].dac == -1 && pNv->i2cMap[port].sor == -1)
+            /* No outputs on this port.  Skip it. */
+            continue;
+
+        monInfo = G80ProbeDDCBus(pScrn, port);
+        if(!monInfo)
+            /* No EDID on this port. */
+            continue;
+
+        flatPanel = (monInfo->features.input_type == 1);
+
+        if(flatPanel) {
+            if(pNv->i2cMap[port].sor == -1) {
+                xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Saw a flat panel EDID "
+                    "on I2C port %i but no SOR outputs were registered for "
+                    "that port.\n", port);
+                continue;
+            }
+            pNv->orType = SOR;
+            pNv->or = pNv->i2cMap[port].sor;
+        } else {
+            if(pNv->i2cMap[port].dac == -1) {
+                xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Saw a flat panel EDID "
+                    "on I2C port %i but no DAC outputs were registered for "
+                    "that port.\n", port);
+                continue;
+            }
+            pNv->orType = DAC;
+            pNv->or = pNv->i2cMap[port].dac;
+        }
+
+        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+                   "Found a %s on I2C port %i, assigning %s%i\n",
+                   flatPanel ? "flat panel" : "CRT",
+                   port, flatPanel ? "SOR" : "DAC", pNv->or);
+
+        pScrn->monitor->DDC = monInfo;
+        xf86SetDDCproperties(pScrn, monInfo);
+
+        return TRUE;
+    }
+
+    return FALSE;
+}
diff --git a/src/g80_ddc.h b/src/g80_ddc.h
new file mode 100644
index 0000000..d209d62
--- /dev/null
+++ b/src/g80_ddc.h
@@ -0,0 +1 @@
+Bool G80ProbeDDC(ScrnInfoPtr pScrn);
diff --git a/src/g80_display.c b/src/g80_display.c
new file mode 100644
index 0000000..5ff3514
--- /dev/null
+++ b/src/g80_display.c
@@ -0,0 +1,515 @@
+/*
+ * Copyright (c) 2007 NVIDIA, Corporation
+ *
+ * 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 the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, 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 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 NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <float.h>
+#include <math.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include "g80_type.h"
+#include "g80_display.h"
+
+#define DPMS_SERVER
+#include <X11/extensions/dpms.h>
+
+/*
+ * PLL calculation.  pclk is in kHz.
+ */
+static void
+G80CalcPLL(float pclk, int *pNA, int *pMA, int *pNB, int *pMB, int *pP)
+{
+    const float refclk = 27000.0f;
+    const float minVcoA = 100000;
+    const float maxVcoA = 400000;
+    const float minVcoB = 600000;
+    float maxVcoB = 1400000;
+    const float minUA = 2000;
+    const float maxUA = 400000;
+    const float minUB = 50000;
+    const float maxUB = 200000;
+    const int minNA = 1, maxNA = 255;
+    const int minNB = 1, maxNB = 31;
+    const int minMA = 1, maxMA = 255;
+    const int minMB = 1, maxMB = 31;
+    const int minP = 0, maxP = 6;
+    int lowP, highP;
+    float vcoB;
+
+    int na, ma, nb, mb, p;
+    float bestError = FLT_MAX;
+
+    *pNA = *pMA = *pNB = *pMB = *pP = 0;
+
+    if(maxVcoB < pclk + pclk / 200)
+        maxVcoB = pclk + pclk / 200;
+    if(minVcoB / (1 << maxP) > pclk)
+        pclk = minVcoB / (1 << maxP);
+
+    vcoB = maxVcoB - maxVcoB / 200;
+    lowP = minP;
+    vcoB /= 1 << (lowP + 1);
+
+    while(pclk <= vcoB && lowP < maxP)
+    {
+        vcoB /= 2;
+        lowP++;
+    }
+
+    vcoB = maxVcoB + maxVcoB / 200;
+    highP = lowP;
+    vcoB /= 1 << (highP + 1);
+
+    while(pclk <= vcoB && highP < maxP)
+    {
+        vcoB /= 2;
+        highP++;
+    }
+
+    for(p = lowP; p <= highP; p++)
+    {
+        for(ma = minMA; ma <= maxMA; ma++)
+        {
+            if(refclk / ma < minUA)
+                break;
+            else if(refclk / ma > maxUA)
+                continue;
+
+            for(na = minNA; na <= maxNA; na++)
+            {
+                if(refclk * na / ma < minVcoA || refclk * na / ma > maxVcoA)
+                    continue;
+
+                for(mb = minMB; mb <= maxMB; mb++)
+                {
+                    if(refclk * na / ma / mb < minUB)
+                        break;
+                    else if(refclk * na / ma / mb > maxUB)
+                        continue;
+
+                    nb = rint(pclk * (1 << p) * (ma / (float)na) * mb / refclk);
+
+                    if(nb > maxNB)
+                        break;
+                    else if(nb < minNB)
+                        continue;
+                    else
+                    {
+                        float freq = refclk * (na / (float)ma) * (nb / (float)mb) / (1 << p);
+                        float error = fabsf(pclk - freq);
+                        if(error < bestError) {
+                            *pNA = na;
+                            *pMA = ma;
+                            *pNB = nb;
+                            *pMB = mb;
+                            *pP = p;
+                            bestError = error;
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+static void
+G80DispCommand(G80Ptr pNv, CARD32 addr, CARD32 data)
+{
+    pNv->reg[0x00610304/4] = data;
+    pNv->reg[0x00610300/4] = addr | 0x80010001;
+
+    while(pNv->reg[0x00610300/4] & 0x80000000) {
+        const int super = ffs((pNv->reg[0x00610024/4] >> 4) & 7);
+
+        if(super) {
+            if(super == 2) {
+                const int headOff = 0x800 * pNv->head;
+                const int orOff = 0x800 * pNv->or;
+
+                if(pNv->reg[0x00610030/4] & 0x600) {
+                    int lo_n, lo_m, hi_n, hi_m, p;
+                    CARD32 lo = pNv->reg[(0x00614104+headOff)/4];
+                    CARD32 hi = pNv->reg[(0x00614108+headOff)/4];
+
+                    pNv->reg[(0x00614100+headOff)/4] = 0x10000610;
+                    lo &= 0xff00ff00;
+                    hi &= 0x8000ff00;
+
+                    G80CalcPLL(pNv->pclk, &lo_n, &lo_m, &hi_n, &hi_m, &p);
+
+                    lo |= (lo_m << 16) | lo_n;
+                    hi |= (p << 28) | (hi_m << 16) | hi_n;
+                    pNv->reg[(0x00614104+headOff)/4] = lo;
+                    pNv->reg[(0x00614108+headOff)/4] = hi;
+                }
+
+                pNv->reg[(0x00614200+headOff)/4] = 0;
+                switch(pNv->orType) {
+                case DAC:
+                    pNv->reg[(0x00614280+orOff)/4] = 0;
+                    break;
+                case SOR:
+                    pNv->reg[(0x00614300+orOff)/4] =
+                        (pNv->pclk > 165000) ? 0x101 : 0;
+                    break;
+                }
+            }
+
+            pNv->reg[0x00610024/4] = 8 << super;
+            pNv->reg[0x00610030/4] = 0x80000000;
+        }
+    }
+}
+#define C(mthd, data) G80DispCommand(pNv, (mthd), (data))
+
+/*
+ * Performs load detection on the DACs.  Sets pNv->orType and pNv->or
+ * accordingly.
+ */
+Bool G80LoadDetect(ScrnInfoPtr pScrn)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+    const int scrnIndex = pScrn->scrnIndex;
+    ORNum or;
+
+    pNv->orType = DAC;
+
+    for(or = DAC0; or <= DAC2; or++) {
+        const int dacOff = 2048 * or;
+        CARD32 load, tmp;
+
+        xf86DrvMsg(scrnIndex, X_PROBED, "Trying load detection on DAC%i ... ", or);
+
+        pNv->reg[(0x0061A010+dacOff)/4] = 0x00000001;
+        pNv->reg[(0x0061A004+dacOff)/4] = 0x80150000;
+        while(pNv->reg[(0x0061A004+dacOff)/4] & 0x80000000);
+        tmp = pNv->architecture == 0x50 ? 420 : 340;
+        pNv->reg[(0x0061A00C+dacOff)/4] = tmp | 0x100000;
+        usleep(4500);
+        load = pNv->reg[(0x0061A00C+dacOff)/4];
+        pNv->reg[(0x0061A00C+dacOff)/4] = 0;
+        pNv->reg[(0x0061A004+dacOff)/4] = 0x80550000;
+        if((load & 0x38000000) == 0x38000000) {
+            xf86ErrorF("found one!\n");
+            pNv->or = or;
+            return TRUE;
+        }
+
+        xf86ErrorF("nothing.\n");
+    }
+
+    return FALSE;
+}
+
+Bool
+G80DispInit(ScrnInfoPtr pScrn)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+
+    pNv->reg[0x00610184/4] = pNv->reg[0x00614004/4];
+    pNv->reg[0x00610190/4] = pNv->reg[0x00616100/4];
+    pNv->reg[0x006101a0/4] = pNv->reg[0x00616900/4];
+    pNv->reg[0x00610194/4] = pNv->reg[0x00616104/4];
+    pNv->reg[0x006101a4/4] = pNv->reg[0x00616904/4];
+    pNv->reg[0x00610198/4] = pNv->reg[0x00616108/4];
+    pNv->reg[0x006101a8/4] = pNv->reg[0x00616908/4];
+    pNv->reg[0x0061019C/4] = pNv->reg[0x0061610C/4];
+    pNv->reg[0x006101ac/4] = pNv->reg[0x0061690c/4];
+    pNv->reg[0x006101D0/4] = pNv->reg[0x0061A000/4];
+    pNv->reg[0x006101D4/4] = pNv->reg[0x0061A800/4];
+    pNv->reg[0x006101D8/4] = pNv->reg[0x0061B000/4];
+    pNv->reg[0x006101E0/4] = pNv->reg[0x0061C000/4];
+    pNv->reg[0x006101E4/4] = pNv->reg[0x0061C800/4];
+    pNv->reg[0x0061c00c/4] = 0x03010700;
+    pNv->reg[0x0061c010/4] = 0x0000152f;
+    pNv->reg[0x0061c014/4] = 0x00000000;
+    pNv->reg[0x0061c018/4] = 0x00245af8;
+    pNv->reg[0x0061c80c/4] = 0x03010700;
+    pNv->reg[0x0061c810/4] = 0x0000152f;
+    pNv->reg[0x0061c814/4] = 0x00000000;
+    pNv->reg[0x0061c818/4] = 0x00245af8;
+    pNv->reg[0x0061A004/4] = 0x80550000;
+    pNv->reg[0x0061A010/4] = 0x00000001;
+    pNv->reg[0x0061A804/4] = 0x80550000;
+    pNv->reg[0x0061A810/4] = 0x00000001;
+    pNv->reg[0x0061B004/4] = 0x80550000;
+    pNv->reg[0x0061B010/4] = 0x00000001;
+
+    if(pNv->reg[0x00610024/4] & 0x100) {
+        pNv->reg[0x00610024/4] = 0x100;
+        pNv->reg[0x006194E8/4] &= ~1;
+        while(pNv->reg[0x006194E8/4] & 2);
+    }
+
+    pNv->reg[0x00610200/4] = 0x2b00;
+    while((pNv->reg[0x00610200/4] & 0x1e0000) != 0);
+    pNv->reg[0x00610300/4] = 1;
+    pNv->reg[0x00610200/4] = 0x1000b03;
+    while(!(pNv->reg[0x00610200/4] & 0x40000000));
+
+    C(0x00000084, 0);
+    C(0x00000088, 0);
+    C(0x00000874, 0);
+    C(0x00000800, 0);
+    C(0x00000810, 0);
+    C(0x0000082C, 0);
+
+    return TRUE;
+}
+
+void
+G80DispShutdown(ScrnInfoPtr pScrn)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+    CARD32 mask;
+
+    G80DispBlankScreen(pScrn, TRUE);
+
+    mask = 4 << pNv->head;
+    pNv->reg[0x00610024/4] = mask;
+    while(!(pNv->reg[0x00610024/4] & mask));
+    pNv->reg[0x00610200/4] = 0;
+    pNv->reg[0x00610300/4] = 0;
+    while((pNv->reg[0x00610200/4] & 0x1e0000) != 0);
+}
+
+static void
+setupDAC(G80Ptr pNv, Head head, ORNum or, DisplayModePtr mode)
+{
+    const int dacOff = 0x80 * pNv->or;
+
+    C(0x00000400 + dacOff, (head == HEAD0 ? 1 : 2) | 0x40);
+    C(0x00000404 + dacOff,
+        (mode->Flags & V_NHSYNC) ? 1 : 0 |
+        (mode->Flags & V_NVSYNC) ? 2 : 0);
+}
+
+static void
+setupSOR(G80Ptr pNv, Head head, ORNum or, DisplayModePtr mode)
+{
+    const int sorOff = 0x40 * pNv->or;
+
+    C(0x00000600 + sorOff,
+        (head == HEAD0 ? 1 : 2) |
+        (mode->SynthClock > 165000 ? 0x500 : 0x100) |
+        ((mode->Flags & V_NHSYNC) ? 0x1000 : 0) |
+        ((mode->Flags & V_NVSYNC) ? 0x2000 : 0));
+}
+
+Bool
+G80DispSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+    const int HDisplay = mode->HDisplay, VDisplay = mode->VDisplay;
+    const int headOff = 0x400 * pNv->head;
+    int interlaceDiv, fudge;
+
+    if(pNv->BackendMode)
+        mode = pNv->BackendMode;
+
+    pNv->pclk = mode->SynthClock;
+
+    /* Magic mode timing fudge factor */
+    fudge = ((mode->Flags & V_INTERLACE) && (mode->Flags & V_DBLSCAN)) ? 2 : 1;
+    interlaceDiv = (mode->Flags & V_INTERLACE) ? 2 : 1;
+
+    switch(pNv->orType) {
+    case DAC:
+        setupDAC(pNv, pNv->head, pNv->or, mode);
+        break;
+    case SOR:
+        setupSOR(pNv, pNv->head, pNv->or, mode);
+        break;
+    }
+
+    C(0x00000804 + headOff, mode->SynthClock | 0x800000);
+    C(0x00000808 + headOff, (mode->Flags & V_INTERLACE) ? 2 : 0);
+    C(0x00000810 + headOff, 0);
+    C(0x0000082C + headOff, 0);
+    C(0x00000814 + headOff, mode->CrtcVTotal << 16 | mode->CrtcHTotal);
+    C(0x00000818 + headOff,
+        ((mode->CrtcVSyncEnd - mode->CrtcVSyncStart) / interlaceDiv - 1) << 16 |
+        (mode->CrtcHSyncEnd - mode->CrtcHSyncStart - 1));
+    C(0x0000081C + headOff,
+        ((mode->CrtcVBlankEnd - mode->CrtcVSyncStart) / interlaceDiv - fudge) << 16 |
+        (mode->CrtcHBlankEnd - mode->CrtcHSyncStart - 1));
+    C(0x00000820 + headOff,
+        ((mode->CrtcVTotal - mode->CrtcVSyncStart + mode->CrtcVBlankStart) / interlaceDiv - fudge) << 16 |
+        (mode->CrtcHTotal - mode->CrtcHSyncStart + mode->CrtcHBlankStart - 1));
+    if(mode->Flags & V_INTERLACE) {
+        C(0x00000824 + headOff,
+            ((mode->CrtcVTotal + mode->CrtcVBlankEnd - mode->CrtcVSyncStart) / 2 - 2) << 16 |
+            ((2*mode->CrtcVTotal - mode->CrtcVSyncStart + mode->CrtcVBlankStart) / 2 - 2));
+    }
+    C(0x00000868 + headOff, pScrn->virtualY << 16 | pScrn->virtualX);
+    C(0x0000086C + headOff, pScrn->displayWidth * (pScrn->bitsPerPixel / 8) | 0x100000);
+    switch(pScrn->depth) {
+        case  8: C(0x00000870 + headOff, 0x1E00); break;
+        case 15: C(0x00000870 + headOff, 0xE900); break;
+        case 16: C(0x00000870 + headOff, 0xE800); break;
+        case 24: C(0x00000870 + headOff, 0xCF00); break;
+    }
+    C(0x000008A0 + headOff, 0);
+    if((mode->Flags & V_DBLSCAN) || (mode->Flags & V_INTERLACE) ||
+       mode->CrtcHDisplay != HDisplay || mode->CrtcVDisplay != VDisplay) {
+        C(0x000008A4 + headOff, 9);
+    } else {
+        C(0x000008A4 + headOff, 0);
+    }
+    C(0x000008A8 + headOff, 0x40000);
+    /* Use the screen's panning, but not if it's bogus */
+    if(pScrn->frameX0 >= 0 && pScrn->frameY0 >= 0 &&
+       pScrn->frameX0 + HDisplay <= pScrn->virtualX &&
+       pScrn->frameY0 + VDisplay <= pScrn->virtualY) {
+        C(0x000008C0 + headOff, pScrn->frameY0 << 16 | pScrn->frameX0);
+    } else {
+        C(0x000008C0 + headOff, 0);
+    }
+    C(0x000008C8 + headOff, VDisplay << 16 | HDisplay);
+    C(0x000008D4 + headOff, 0);
+    C(0x000008D8 + headOff, mode->CrtcVDisplay << 16 | mode->CrtcHDisplay);
+    C(0x000008DC + headOff, mode->CrtcVDisplay << 16 | mode->CrtcHDisplay);
+
+    G80DispBlankScreen(pScrn, FALSE);
+
+    return TRUE;
+}
+
+void
+G80DispAdjustFrame(G80Ptr pNv, int x, int y)
+{
+    const int headOff = 0x400 * pNv->head;
+
+    C(0x000008C0 + headOff, y << 16 | x);
+    C(0x00000080, 0);
+}
+
+void
+G80DispBlankScreen(ScrnInfoPtr pScrn, Bool blank)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+    const int headOff = 0x400 * pNv->head;
+
+    if(blank) {
+        G80DispHideCursor(pNv, FALSE);
+
+        C(0x00000840 + headOff, 0);
+        C(0x00000844 + headOff, 0);
+        if(pNv->architecture != 0x50)
+            C(0x0000085C + headOff, 0);
+        C(0x00000874 + headOff, 0);
+        if(pNv->architecture != 0x50)
+            C(0x0000089C + headOff, 0);
+    } else {
+        C(0x00000860 + headOff, 0);
+        C(0x00000864 + headOff, 0);
+        pNv->reg[0x00610380/4] = 0;
+        pNv->reg[0x00610384/4] = pNv->RamAmountKBytes * 1024 - 1;
+        pNv->reg[0x00610388/4] = 0x150000;
+        pNv->reg[0x0061038C/4] = 0;
+        C(0x00000884 + headOff, (pNv->videoRam << 2) - 0x40);
+        if(pNv->architecture != 0x50)
+            C(0x0000089C + headOff, 1);
+        if(pNv->cursorVisible)
+            G80DispShowCursor(pNv, FALSE);
+        C(0x00000840 + headOff, pScrn->depth == 8 ? 0x80000000 : 0xc0000000);
+        C(0x00000844 + headOff, (pNv->videoRam * 1024 - 0x5000) >> 8);
+        if(pNv->architecture != 0x50)
+            C(0x0000085C + headOff, 1);
+        C(0x00000874 + headOff, 1);
+    }
+
+    C(0x00000080, 0);
+}
+
+void
+G80DispDPMSSet(ScrnInfoPtr pScrn, int mode, int flags)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+    const int off = 0x800 * pNv->or;
+    CARD32 tmp;
+
+    /*
+     * DPMSModeOn       everything on
+     * DPMSModeStandby  hsync disabled, vsync enabled
+     * DPMSModeSuspend  hsync enabled, vsync disabled
+     * DPMSModeOff      sync disabled
+     */
+    switch(pNv->orType) {
+    case DAC:
+        while(pNv->reg[(0x0061A004+off)/4] & 0x80000000);
+
+        tmp = pNv->reg[(0x0061A004+off)/4];
+        tmp &= ~0x7f;
+        tmp |= 0x80000000;
+
+        if(mode == DPMSModeStandby || mode == DPMSModeOff)
+            tmp |= 1;
+        if(mode == DPMSModeSuspend || mode == DPMSModeOff)
+            tmp |= 4;
+        if(mode != DPMSModeOn)
+            tmp |= 0x10;
+        if(mode == DPMSModeOff)
+            tmp |= 0x40;
+
+        pNv->reg[(0x0061A004+off)/4] = tmp;
+
+        break;
+
+    case SOR:
+        while(pNv->reg[(0x0061C004+off)/4] & 0x80000000);
+
+        tmp = pNv->reg[(0x0061C004+off)/4];
+        tmp |= 0x80000000;
+
+        if(mode == DPMSModeOn)
+            tmp |= 1;
+        else
+            tmp &= ~1;
+
+        pNv->reg[(0x0061C004+off)/4] = tmp;
+
+        break;
+    }
+}
+
+/******************************** Cursor stuff ********************************/
+void G80DispShowCursor(G80Ptr pNv, Bool update)
+{
+    const int headOff = 0x400 * pNv->head;
+
+    C(0x00000880 + headOff, 0x85000000);
+    if(update) C(0x00000080, 0);
+}
+
+void G80DispHideCursor(G80Ptr pNv, Bool update)
+{
+    const int headOff = 0x400 * pNv->head;
+
+    C(0x00000880 + headOff, 0x5000000);
+    if(update) C(0x00000080, 0);
+}
diff --git a/src/g80_display.h b/src/g80_display.h
new file mode 100644
index 0000000..aec6314
--- /dev/null
+++ b/src/g80_display.h
@@ -0,0 +1,9 @@
+Bool G80LoadDetect(ScrnInfoPtr);
+Bool G80DispInit(ScrnInfoPtr);
+Bool G80DispSetMode(ScrnInfoPtr, DisplayModePtr);
+void G80DispShutdown(ScrnInfoPtr);
+void G80DispAdjustFrame(G80Ptr pNv, int x, int y);
+void G80DispBlankScreen(ScrnInfoPtr, Bool blank);
+void G80DispDPMSSet(ScrnInfoPtr, int mode, int flags);
+void G80DispShowCursor(G80Ptr, Bool update);
+void G80DispHideCursor(G80Ptr, Bool update);
diff --git a/src/g80_dma.c b/src/g80_dma.c
new file mode 100644
index 0000000..63fdbe5
--- /dev/null
+++ b/src/g80_dma.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2007 NVIDIA, Corporation
+ *
+ * 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 the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, 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 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 NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "g80_type.h"
+#include "g80_dma.h"
+
+void G80DmaKickoff(G80Ptr pNv)
+{
+    if(pNv->dmaCurrent != pNv->dmaPut) {
+        pNv->dmaPut = pNv->dmaCurrent;
+        pNv->reg[0x00c02040/4] = pNv->dmaPut << 2;
+    }
+}
+
+void G80DmaWait(G80Ptr pNv, int size)
+{
+    CARD32 dmaGet;
+
+    size++;
+
+    while(pNv->dmaFree < size) {
+        dmaGet = pNv->reg[0x00c02044/4] >> 2;
+
+        if(pNv->dmaPut >= dmaGet) {
+            pNv->dmaFree = pNv->dmaMax - pNv->dmaCurrent;
+            if(pNv->dmaFree < size) {
+                G80DmaNext(pNv, 0x20000000);
+                if(dmaGet <= SKIPS) {
+                    if(pNv->dmaPut <= SKIPS) /* corner case - will be idle */
+                        pNv->reg[0x00c02040/4] = (SKIPS + 1) << 2;
+                    do { dmaGet = pNv->reg[0x00c02044/4] >> 2; }
+                    while(dmaGet <= SKIPS);
+                }
+                pNv->reg[0x00c02040/4] = SKIPS << 2;
+                pNv->dmaCurrent = pNv->dmaPut = SKIPS;
+                pNv->dmaFree = dmaGet - (SKIPS + 1);
+            }
+        } else
+            pNv->dmaFree = dmaGet - pNv->dmaCurrent - 1;
+    }
+}
diff --git a/src/g80_dma.h b/src/g80_dma.h
new file mode 100644
index 0000000..52031da
--- /dev/null
+++ b/src/g80_dma.h
@@ -0,0 +1,14 @@
+#define SKIPS 8
+
+#define G80DmaNext(pNv, data) \
+     (pNv)->dmaBase[(pNv)->dmaCurrent++] = (data)
+
+#define G80DmaStart(pNv, tag, size) {         \
+     if((pNv)->dmaFree <= (size))             \
+        G80DmaWait(pNv, size);                \
+     G80DmaNext(pNv, ((size) << 18) | (tag)); \
+     (pNv)->dmaFree -= ((size) + 1);          \
+}
+
+void G80DmaKickoff(G80Ptr pNv);
+void G80DmaWait(G80Ptr pNv, int size);
diff --git a/src/g80_driver.c b/src/g80_driver.c
new file mode 100644
index 0000000..2a3120f
--- /dev/null
+++ b/src/g80_driver.c
@@ -0,0 +1,916 @@
+/*
+ * Copyright (c) 2007 NVIDIA, Corporation
+ *
+ * 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 the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, 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 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 NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include <xf86_OSproc.h>
+#include <xf86Resources.h>
+#include <mipointer.h>
+#include <mibstore.h>
+#include <micmap.h>
+#include <xf86cmap.h>
+#include <fb.h>
+#define DPMS_SERVER
+#include <X11/extensions/dpms.h>
+
+#include "nv_const.h"
+#include "g80_type.h"
+#include "g80_cursor.h"
+#include "g80_display.h"
+#include "g80_ddc.h"
+#include "g80_dma.h"
+#include "g80_xaa.h"
+
+#define G80_REG_SIZE (1024 * 1024 * 16)
+#define G80_RESERVED_VIDMEM 0xd000
+
+static const char *fbSymbols[] = {
+    "fbPictureInit",
+    "fbScreenInit",
+    NULL
+};
+
+static const char *xaaSymbols[] = {
+    "XAACopyROP",
+    "XAACreateInfoRec",
+    "XAADestroyInfoRec",
+    "XAAFallbackOps",
+    "XAAInit",
+    "XAAPatternROP",
+    NULL
+};
+
+static const char *i2cSymbols[] = {
+    "xf86CreateI2CBusRec",
+    "xf86I2CBusInit",
+    NULL
+};
+
+static const char *ramdacSymbols[] = {
+    "xf86CreateCursorInfoRec",
+    "xf86DestroyCursorInfoRec",
+    "xf86InitCursor",
+    NULL
+};
+
+static const char *ddcSymbols[] = {
+    "xf86PrintEDID",
+    "xf86DoEDID_DDC2",
+    "xf86SetDDCproperties",
+    NULL
+};
+
+static const char *int10Symbols[] = {
+    "xf86FreeInt10",
+    "xf86InitInt10",
+    "xf86ExecX86int10",
+    NULL
+};
+
+typedef enum {
+    OPTION_HW_CURSOR,
+    OPTION_NOACCEL,
+    OPTION_BACKEND_MODE,
+} G80Opts;
+
+static const OptionInfoRec G80Options[] = {
+    { OPTION_HW_CURSOR,         "HWCursor",     OPTV_BOOLEAN,   {0}, FALSE },
+    { OPTION_NOACCEL,           "NoAccel",      OPTV_BOOLEAN,   {0}, FALSE },
+    { OPTION_BACKEND_MODE,      "BackendMode",  OPTV_ANYSTR,    {0}, FALSE },
+    { -1,                       NULL,           OPTV_NONE,      {0}, FALSE }
+};
+
+static Bool
+G80GetRec(ScrnInfoPtr pScrn)
+{
+    if(pScrn->driverPrivate == NULL)
+        pScrn->driverPrivate = xcalloc(sizeof(G80Rec), 1);
+
+    return (pScrn->driverPrivate != NULL);
+}
+
+static void
+G80FreeRec(ScrnInfoPtr pScrn)
+{
+    xfree(pScrn->driverPrivate);
+    pScrn->driverPrivate = NULL;
+}
+
+static Bool
+G80PreInit(ScrnInfoPtr pScrn, int flags)
+{
+    G80Ptr pNv;
+    EntityInfoPtr pEnt;
+    pciVideoPtr pPci;
+    PCITAG pcitag;
+    ClockRangePtr clockRanges;
+    MessageType from;
+    Bool primary;
+    int i;
+    char *s;
+    const rgb zeros = {0, 0, 0};
+    const Gamma gzeros = {0.0, 0.0, 0.0};
+    CARD32 tmp;
+
+    if(flags & PROBE_DETECT) {
+        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+                "G80 PROBE_DETECT unimplemented\n");
+        return FALSE;
+    }
+
+    /* Check the number of entities, and fail if it isn't one. */
+    if(pScrn->numEntities != 1)
+        return FALSE;
+
+    /* Allocate the NVRec driverPrivate */
+    if(!G80GetRec(pScrn)) {
+        return FALSE;
+    }
+    pNv = G80PTR(pScrn);
+
+    /* Get the entity, and make sure it is PCI. */
+    pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
+    if(pEnt->location.type != BUS_PCI) goto fail;
+    pPci = xf86GetPciInfoForEntity(pEnt->index);
+    pcitag = pciTag(pPci->bus, pPci->device, pPci->func);
+    primary = xf86IsPrimaryPci(pPci);
+
+    /* The ROM size sometimes isn't read correctly, so fix it up here. */
+    if(pPci->biosSize == 0)
+        /* The BIOS is 64k */
+        pPci->biosSize = 16;
+
+    pNv->int10 = NULL;
+    pNv->int10Mode = 0;
+    if(xf86LoadSubModule(pScrn, "int10")) {
+        xf86LoaderReqSymLists(int10Symbols, NULL);
+        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Initializing int10\n");
+        pNv->int10 = xf86InitInt10(pEnt->index);
+    }
+
+    if(!pNv->int10) {
+        if(primary) {
+            xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+                       "Failed to initialize the int10 module; the console "
+                       "will not be restored.\n");
+        } else {
+            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+                       "Failed to initialize the int10 module; this screen "
+                       "will not be initialized.\n");
+            goto fail;
+        }
+    }
+
+    if(primary && pNv->int10) {
+        const xf86Int10InfoPtr int10 = pNv->int10;
+
+        /* Get the current video mode */
+        int10->num = 0x10;
+        int10->ax = 0x4f03;
+        int10->bx = int10->cx = int10->dx = 0;
+        xf86ExecX86int10(int10);
+        pNv->int10Mode = int10->bx & 0x3fff;
+        xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Console is VGA mode 0x%x\n",
+                   pNv->int10Mode);
+    }
+
+    /* Disable VGA access */
+    xf86SetOperatingState(resVgaIo, pEnt->index, ResUnusedOpr);
+    xf86SetOperatingState(resVgaMem, pEnt->index, ResDisableOpr);
+
+    pScrn->monitor = pScrn->confScreen->monitor;
+
+    if(!xf86SetDepthBpp(pScrn, 0, 0, 0, Support32bppFb)) goto fail;
+    switch (pScrn->depth) {
+        case 8:
+        case 15:
+        case 16:
+        case 24:
+            /* OK */
+            break;
+        default:
+            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+                    "Given depth (%d) is not supported by this driver\n",
+                    pScrn->depth);
+            goto fail;
+    }
+    xf86PrintDepthBpp(pScrn);
+
+    if(!xf86SetWeight(pScrn, zeros, zeros)) goto fail;
+    if(!xf86SetDefaultVisual(pScrn, -1)) goto fail;
+
+    /* We use a programmable clock */
+    pScrn->progClock = TRUE;
+
+    /* Process options */
+    xf86CollectOptions(pScrn, NULL);
+    if(!(pNv->Options = xalloc(sizeof(G80Options)))) goto fail;
+    memcpy(pNv->Options, G80Options, sizeof(G80Options));
+    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pNv->Options);
+
+    from = X_DEFAULT;
+    pNv->HWCursor = TRUE;
+    if(xf86GetOptValBool(pNv->Options, OPTION_HW_CURSOR, &pNv->HWCursor))
+        from = X_CONFIG;
+    xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n",
+               pNv->HWCursor ? "hardware" : "software");
+    if(xf86ReturnOptValBool(pNv->Options, OPTION_NOACCEL, FALSE)) {
+        pNv->NoAccel = TRUE;
+        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Acceleration disabled\n");
+    }
+
+    /* Set the bits per RGB for 8bpp mode */
+    if(pScrn->depth == 8)
+        pScrn->rgbBits = 8;
+
+    if(!xf86SetGamma(pScrn, gzeros)) goto fail;
+
+    /*
+     * Setup the ClockRanges, which describe what clock ranges are available,
+     * and what sort of modes they can be used for.
+     */
+    clockRanges = xnfcalloc(sizeof(ClockRange), 1);
+    clockRanges->next = NULL;
+    clockRanges->minClock = 0;
+    clockRanges->maxClock = 400000;
+    clockRanges->clockIndex = -1;       /* programmable */
+    clockRanges->doubleScanAllowed = TRUE;
+    clockRanges->interlaceAllowed = TRUE;
+
+    /* Map memory */
+    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "MMIO registers at 0x%lx\n",
+               pPci->memBase[0]);
+    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Linear framebuffer at 0x%lx\n",
+               pPci->memBase[1]);
+    pScrn->memPhysBase = pPci->memBase[1];
+    pScrn->fbOffset = 0;
+
+    pNv->reg = xf86MapPciMem(pScrn->scrnIndex,
+                             VIDMEM_MMIO | VIDMEM_READSIDEEFFECT,
+                             pcitag, pPci->memBase[0], G80_REG_SIZE);
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "MMIO registers mapped at %p\n",
+               (void*)pNv->reg);
+
+    if(xf86RegisterResources(pEnt->index, NULL, ResExclusive)) {
+        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "xf86RegisterResources() found "
+                   "resource conflicts\n");
+        goto fail;
+    }
+
+    pNv->architecture = pNv->reg[0] >> 20 & 0x1ff;
+    pNv->RamAmountKBytes = pNv->RamAmountKBytes = (pNv->reg[0x0010020C/4] & 0xFFF00000) >> 10;
+    pNv->videoRam = pNv->RamAmountKBytes;
+    /* Limit videoRam to the max BAR1 size of 256MB */
+    if(pNv->videoRam <= 1024) {
+        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to determine the amount of "
+                   "available video memory\n");
+        goto fail;
+    }
+    pNv->videoRam -= 1024;
+    if(pNv->videoRam > 256 * 1024)
+        pNv->videoRam = 256 * 1024;
+    pScrn->videoRam = pNv->videoRam;
+    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Mapping %.1f of %.1f MB of video RAM\n",
+               pScrn->videoRam / 1024.0, pNv->RamAmountKBytes / 1024.0);
+    pNv->mem = xf86MapPciMem(pScrn->scrnIndex,
+                             VIDMEM_MMIO | VIDMEM_READSIDEEFFECT,
+                             pcitag, pPci->memBase[1], pScrn->videoRam * 1024);
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Linear framebuffer mapped at %p\n",
+               (void*)pNv->mem);
+
+    pNv->table1 = (unsigned const char*)&pNv->reg[0x00800000/4];
+    tmp = pNv->reg[0x00619F04/4] >> 8;
+    if(tmp)
+        pNv->table1 -= ((pNv->RamAmountKBytes << 10) - (tmp << 16));
+    else
+        pNv->table1 -= 0x10000;
+
+    /* Probe DDC */
+    /* If no DDC info found, try DAC load detection */
+    if(!xf86LoadSubModule(pScrn, "i2c")) goto fail;
+    if(!xf86LoadSubModule(pScrn, "ddc")) goto fail;
+    xf86LoaderReqSymLists(i2cSymbols, ddcSymbols, NULL);
+    if(!G80ProbeDDC(pScrn) && !G80LoadDetect(pScrn)) {
+        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No display devices found\n");
+        goto fail;
+    }
+    /* Hardcode HEAD0 for now.  RandR 1.2 will move this into a Crtc struct. */
+    pNv->head = 0;
+
+    i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
+                          pScrn->display->modes, clockRanges,
+                          NULL, 256, 8192,
+                          512, 128, 8192,
+                          pScrn->display->virtualX,
+                          pScrn->display->virtualY,
+                          pNv->videoRam * 1024 - G80_RESERVED_VIDMEM,
+                          LOOKUP_BEST_REFRESH);
+    if(i == -1) goto fail;
+    xf86PruneDriverModes(pScrn);
+    if(i == 0 || !pScrn->modes) {
+        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
+        goto fail;
+    }
+    xf86SetCrtcForModes(pScrn, 0);
+
+    pScrn->currentMode = pScrn->modes;
+    xf86PrintModes(pScrn);
+    xf86SetDpi(pScrn, 0, 0);
+
+    /* Custom backend timings */
+    pNv->BackendMode = NULL;
+    if((s = xf86GetOptValString(pNv->Options, OPTION_BACKEND_MODE))) {
+        DisplayModePtr mode;
+
+        for(mode = pScrn->modes; ; mode = mode->next) {
+            if(!strcmp(mode->name, s))
+                break;
+            if(mode->next == pScrn->modes) {
+                mode = NULL;
+                break;
+            }
+        }
+
+        pNv->BackendMode = mode;
+
+        if(mode)
+            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "BackendMode: Using mode "
+                       "\"%s\" for display timings\n", mode->name);
+        else
+            xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Cannot honor "
+                       "\"BackendMode\" option: no mode named \"%s\" "
+                       "found.\n", s);
+    }
+
+    /* Load fb */
+    if(!xf86LoadSubModule(pScrn, "fb")) goto fail;
+    xf86LoaderReqSymLists(fbSymbols, NULL);
+
+    if(!pNv->NoAccel) {
+        if(!xf86LoadSubModule(pScrn, "xaa")) goto fail;
+        xf86LoaderReqSymLists(xaaSymbols, NULL);
+    }
+
+    /* Load ramdac if needed */
+    if(pNv->HWCursor) {
+        if(!xf86LoadSubModule(pScrn, "ramdac")) {
+            xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to load ramdac. "
+                       "Falling back to software cursor.\n");
+            pNv->HWCursor = FALSE;
+        } else {
+            xf86LoaderReqSymLists(ramdacSymbols, NULL);
+        }
+    }
+
+    return TRUE;
+
+fail:
+    if(pNv->int10) xf86FreeInt10(pNv->int10);
+    G80FreeRec(pScrn);
+    return FALSE;
+}
+
+/*
+ * Initialize the display and set the current mode.
+ */
+static Bool
+AcquireDisplay(ScrnInfoPtr pScrn)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+
+    if(!G80DispInit(pScrn))
+        return FALSE;
+    if(!G80CursorAcquire(pNv))
+        return FALSE;
+    if(!G80DispSetMode(pScrn, pScrn->currentMode))
+        return FALSE;
+    G80DispDPMSSet(pScrn, DPMSModeOn, 0);
+
+    return TRUE;
+}
+
+/*
+ * Tear down the display and restore the console mode.
+ */
+static Bool
+ReleaseDisplay(ScrnInfoPtr pScrn)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+
+    G80CursorRelease(pNv);
+    G80DispShutdown(pScrn);
+
+    if(pNv->int10 && pNv->int10Mode) {
+        xf86Int10InfoPtr int10 = pNv->int10;
+
+        /* Use int10 to restore the console mode */
+        int10->num = 0x10;
+        int10->ax = 0x4f02;
+        int10->bx = pNv->int10Mode | 0x8000;
+        int10->cx = int10->dx = 0;
+        xf86ExecX86int10(int10);
+    }
+
+    return TRUE;
+}
+
+static Bool
+G80CloseScreen(int scrnIndex, ScreenPtr pScreen)
+{
+    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+    G80Ptr pNv = G80PTR(pScrn);
+
+    if(pScrn->vtSema)
+        ReleaseDisplay(pScrn);
+
+    if(pNv->xaa)
+        XAADestroyInfoRec(pNv->xaa);
+    if(pNv->HWCursor)
+        xf86DestroyCursorInfoRec(pNv->CursorInfo);
+
+    if(xf86ServerIsExiting()) {
+        if(pNv->int10) xf86FreeInt10(pNv->int10);
+        xf86UnMapVidMem(pScrn->scrnIndex, pNv->mem, pNv->videoRam * 1024);
+        xf86UnMapVidMem(pScrn->scrnIndex, (void*)pNv->reg, G80_REG_SIZE);
+        pNv->reg = NULL;
+        pNv->mem = NULL;
+    }
+
+    pScrn->vtSema = FALSE;
+    pScreen->CloseScreen = pNv->CloseScreen;
+    pScreen->BlockHandler = pNv->BlockHandler;
+    return (*pScreen->CloseScreen)(scrnIndex, pScreen);
+}
+
+static void
+G80BlockHandler(int i, pointer blockData, pointer pTimeout, pointer pReadmask)
+{
+    ScreenPtr pScreen = screenInfo.screens[i];
+    ScrnInfoPtr pScrnInfo = xf86Screens[i];
+    G80Ptr pNv = G80PTR(pScrnInfo);
+
+    if(pNv->DMAKickoffCallback)
+        (*pNv->DMAKickoffCallback)(pScrnInfo);
+
+    pScreen->BlockHandler = pNv->BlockHandler;
+    (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
+    pScreen->BlockHandler = G80BlockHandler;
+}
+
+static Bool
+G80SaveScreen(ScreenPtr pScreen, int mode)
+{
+    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+
+    if(!pScrn->vtSema) return FALSE;
+
+    G80DispBlankScreen(pScrn, !xf86IsUnblank(mode));
+
+    return TRUE;
+}
+
+static void
+G80InitHW(ScrnInfoPtr pScrn)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+    CARD32 bar0_pramin = 0;
+    const int pitch = pScrn->displayWidth * (pScrn->bitsPerPixel / 8);
+    volatile CARD32 *p;
+
+    /* Clear registers */
+    for(p = &pNv->reg[0x00700000/4]; p < (const CARD32*)pNv->table1; p++)
+        *p = 0;
+
+    bar0_pramin = pNv->reg[0x00001700/4] << 16;
+
+    pNv->reg[0x00000200/4] = 0xffff00ff;
+    pNv->reg[0x00000200/4] = 0xffffffff;
+    pNv->reg[0x00002100/4] = 0xffffffff;
+    pNv->reg[0x0000250c/4] = 0x6f3cfc34;
+    pNv->reg[0x00400804/4] = 0xc0000000;
+    pNv->reg[0x00406800/4] = 0xc0000000;
+    pNv->reg[0x00400c04/4] = 0xc0000000;
+    pNv->reg[0x00401800/4] = 0xc0000000;
+    pNv->reg[0x00405018/4] = 0xc0000000;
+    pNv->reg[0x00402000/4] = 0xc0000000;
+    pNv->reg[0x00400108/4] = 0xffffffff;
+    pNv->reg[0x00400100/4] = 0xffffffff;
+
+    if(pNv->architecture != 0x50) {
+        pNv->reg[0x00700000/4] = 0x00000001;
+        pNv->reg[0x00700004/4] = bar0_pramin + 0x00200;
+        pNv->reg[0x00700020/4] = 0x00190002;
+        pNv->reg[0x00700024/4] = bar0_pramin + 0x7ffff;
+        pNv->reg[0x00700028/4] = bar0_pramin + 0x20000;
+        pNv->reg[0x00700034/4] = 0x00010000;
+    } else {
+        pNv->reg[0x00700200/4] = 0x00190002;
+        pNv->reg[0x00700204/4] = bar0_pramin + 0x7ffff;
+        pNv->reg[0x00700208/4] = bar0_pramin + 0x20000;
+        pNv->reg[0x00700214/4] = 0x00010000;
+    }
+
+    pNv->reg[0x00710004/4] = 0x00100642;
+    pNv->reg[0x00710008/4] = 0x80000011;
+    pNv->reg[0x0071000c/4] = 0x00000644;
+    pNv->reg[0x00710010/4] = 0x80000012;
+    pNv->reg[0x00710014/4] = 0x00100646;
+    pNv->reg[0x00710018/4] = 0x80000013;
+    pNv->reg[0x0071001c/4] = 0x00100648;
+    pNv->reg[0x00710020/4] = 0x80000014;
+    pNv->reg[0x00710024/4] = 0x0000064a;
+    pNv->reg[0x00706420/4] = 0x00190030;
+    pNv->reg[0x00706434/4] = 0x00010000;
+    pNv->reg[0x00706440/4] = 0x0019003d;
+    pNv->reg[0x00706444/4] = (pNv->videoRam << 10) - 0x4001;
+    pNv->reg[0x00706448/4] = (pNv->videoRam << 10) - G80_RESERVED_VIDMEM;
+    pNv->reg[0x00706454/4] = 0x00010000;
+    pNv->reg[0x00706460/4] = 0x0000502d;
+    pNv->reg[0x00706474/4] = 0x00010000;
+    pNv->reg[0x00706480/4] = 0x0019003d;
+    pNv->reg[0x00706484/4] = (pNv->videoRam << 10) - G80_RESERVED_VIDMEM;
+    pNv->reg[0x00706494/4] = 0x00010000;
+    pNv->reg[0x007064a0/4] = 0x0019003d;
+    pNv->reg[0x007064a4/4] = bar0_pramin + 0x1100f;
+    pNv->reg[0x007064a8/4] = bar0_pramin + 0x11000;
+    pNv->reg[0x007064b4/4] = 0x00010000;
+
+    if(pNv->architecture != 0x50) {
+        pNv->reg[0x00002604/4] = 0x80000002 | (bar0_pramin >> 8);
+    } else {
+        pNv->reg[0x00002604/4] = 0x80000000 | (bar0_pramin >> 12);
+    }
+
+    pNv->reg[0x00003224/4] = 0x000f0078;
+    pNv->reg[0x0000322c/4] = 0x00000644;
+    pNv->reg[0x00003234/4] = G80_RESERVED_VIDMEM - 0x5001;
+    pNv->reg[0x00003254/4] = 0x00000001;
+    pNv->reg[0x00002210/4] = 0x1c001000;
+
+    if(pNv->architecture != 0x50) {
+        pNv->reg[0x0000340c/4] = (bar0_pramin + 0x1000) >> 10;
+        pNv->reg[0x00003410/4] = (bar0_pramin >> 12);
+    }
+
+    pNv->reg[0x00400824/4] = 0x00004000;
+    pNv->reg[0x00400784/4] = 0x80000000 | (bar0_pramin >> 12);
+    pNv->reg[0x00400320/4] = 0x00000004;
+    pNv->reg[0x0040032C/4] = 0x80000000 | (bar0_pramin >> 12);
+    pNv->reg[0x00400500/4] = 0x00010001;
+    pNv->reg[0x00003250/4] = 0x00000001;
+    pNv->reg[0x00003200/4] = 0x00000001;
+    pNv->reg[0x00003220/4] = 0x00001001;
+    pNv->reg[0x00003204/4] = 0x00010001;
+
+    pNv->dmaBase = (CARD32*)(pNv->mem + (pNv->videoRam << 10) -
+        G80_RESERVED_VIDMEM);
+    memset(pNv->dmaBase, 0, SKIPS*4);
+
+    pNv->dmaPut = 0;
+    pNv->dmaCurrent = SKIPS;
+    pNv->dmaMax = (G80_RESERVED_VIDMEM - 0x5000) / 4 - 2;
+    pNv->dmaFree = pNv->dmaMax - pNv->dmaCurrent;
+
+    G80DmaStart(pNv, 0, 1);
+    G80DmaNext (pNv, 0x80000012);
+    G80DmaStart(pNv, 0x180, 3);
+    G80DmaNext (pNv, 0x80000014);
+    G80DmaNext (pNv, 0x80000013);
+    G80DmaNext (pNv, 0x80000013);
+    G80DmaStart(pNv, 0x200, 2);
+    switch(pScrn->depth) {
+        case  8: G80DmaNext (pNv, 0x000000f3); break;
+        case 15: G80DmaNext (pNv, 0x000000f8); break;
+        case 16: G80DmaNext (pNv, 0x000000e8); break;
+        case 24: G80DmaNext (pNv, 0x000000e6); break;
+    }
+    G80DmaNext (pNv, 0x00000001);
+    G80DmaStart(pNv, 0x214, 5);
+    G80DmaNext (pNv, pitch);
+    G80DmaNext (pNv, pitch);
+    G80DmaNext (pNv, pNv->offscreenHeight);
+    G80DmaNext (pNv, 0x00000000);
+    G80DmaNext (pNv, 0x00000000);
+    G80DmaStart(pNv, 0x230, 2);
+    switch(pScrn->depth) {
+        case  8: G80DmaNext (pNv, 0x000000f3); break;
+        case 15: G80DmaNext (pNv, 0x000000f8); break;
+        case 16: G80DmaNext (pNv, 0x000000e8); break;
+        case 24: G80DmaNext (pNv, 0x000000e6); break;
+    }
+    G80DmaNext (pNv, 0x00000001);
+    G80DmaStart(pNv, 0x244, 5);
+    G80DmaNext (pNv, pitch);
+    G80DmaNext (pNv, pitch);
+    G80DmaNext (pNv, pNv->offscreenHeight);
+    G80DmaNext (pNv, 0x00000000);
+    G80DmaNext (pNv, 0x00000000);
+    G80DmaStart(pNv, 0x260, 1);
+    G80DmaNext (pNv, 0x00000001);
+    G80DmaStart(pNv, 0x290, 1);
+    G80DmaNext (pNv, 1);
+    G80DmaStart(pNv, 0x29c, 1);
+    G80DmaNext (pNv, 0);
+    G80DmaStart(pNv, 0x2e8, 2);
+    switch(pScrn->depth) {
+        case  8: G80DmaNext (pNv, 3); break;
+        case 15: G80DmaNext (pNv, 1); break;
+        case 16: G80DmaNext (pNv, 0); break;
+        case 24: G80DmaNext (pNv, 2); break;
+    }
+    G80DmaNext (pNv, 1);
+    G80DmaStart(pNv, 0x584, 1);
+    switch(pScrn->depth) {
+        case  8: G80DmaNext (pNv, 0xf3); break;
+        case 15: G80DmaNext (pNv, 0xf8); break;
+        case 16: G80DmaNext (pNv, 0xe8); break;
+        case 24: G80DmaNext (pNv, 0xe6); break;
+    }
+    G80DmaStart(pNv, 0x58c, 1);
+    G80DmaNext (pNv, 0x111);
+    G80DmaStart(pNv, 0x804, 1);
+    switch(pScrn->depth) {
+        case  8: G80DmaNext (pNv, 0xf3); break;
+        case 15: G80DmaNext (pNv, 0xf8); break;
+        case 16: G80DmaNext (pNv, 0xe8); break;
+        case 24: G80DmaNext (pNv, 0xe6); break;
+    }
+
+    pNv->currentRop = ~0; /* Set to something invalid */
+}
+
+#define DEPTH_SHIFT(val, w) ((val << (8 - w)) | (val >> ((w << 1) - 8)))
+#define COLOR(c) (unsigned int)(0x3fff * ((c)/255.0))
+static void
+G80LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors,
+               VisualPtr pVisual)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+    int i, index;
+    volatile struct {
+        unsigned short red, green, blue, unused;
+    } *lut = (void*)&pNv->mem[pNv->videoRam * 1024 - 0x5000];
+
+    switch(pScrn->depth) {
+        case 15:
+            for(i = 0; i < numColors; i++) {
+                index = indices[i];
+                lut[DEPTH_SHIFT(index, 5)].red = COLOR(colors[index].red);
+                lut[DEPTH_SHIFT(index, 5)].green = COLOR(colors[index].green);
+                lut[DEPTH_SHIFT(index, 5)].blue = COLOR(colors[index].blue);
+            }
+            break;
+        case 16:
+            for(i = 0; i < numColors; i++) {
+                index = indices[i];
+                lut[DEPTH_SHIFT(index, 6)].green = COLOR(colors[index].green);
+                if(index < 32) {
+                    lut[DEPTH_SHIFT(index, 5)].red = COLOR(colors[index].red);
+                    lut[DEPTH_SHIFT(index, 5)].blue = COLOR(colors[index].blue);
+                }
+            }
+            break;
+        default:
+            for(i = 0; i < numColors; i++) {
+                index = indices[i];
+                lut[index].red = COLOR(colors[index].red);
+                lut[index].green = COLOR(colors[index].green);
+                lut[index].blue = COLOR(colors[index].blue);
+            }
+            break;
+    }
+}
+
+static Bool
+G80ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
+{
+    ScrnInfoPtr pScrn;
+    G80Ptr pNv;
+    CARD32 pitch;
+    int visualMask;
+    BoxRec AvailFBArea;
+
+    /* First get the ScrnInfoRec */
+    pScrn = xf86Screens[pScreen->myNum];
+    pNv = G80PTR(pScrn);
+
+    pScrn->vtSema = TRUE;
+
+    /* DIX visual init */
+    miClearVisualTypes();
+    visualMask = miGetDefaultVisualMask(pScrn->depth);
+    if(!miSetVisualTypes(pScrn->depth, visualMask, 8, pScrn->defaultVisual))
+        return FALSE;
+    if(!miSetPixmapDepths())
+        return FALSE;
+
+    /* pad the screen pitch to 256 bytes */
+    pitch = pScrn->displayWidth * (pScrn->bitsPerPixel / 8);
+    pitch = (pitch + 0xff) & ~0xff;
+    pScrn->displayWidth = pitch / (pScrn->bitsPerPixel / 8);
+
+    /* fb init */
+    if(!fbScreenInit(pScreen, pNv->mem,
+                     pScrn->virtualX, pScrn->virtualY,
+                     pScrn->xDpi, pScrn->yDpi,
+                     pScrn->displayWidth, pScrn->bitsPerPixel))
+        return FALSE;
+
+    if(pScrn->bitsPerPixel > 8) {
+        VisualPtr visual;
+
+        /* Fixup RGB ordering */
+        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);
+
+    xf86SetBlackWhitePixels(pScreen);
+
+    pNv->offscreenHeight = ((pNv->videoRam << 10) - G80_RESERVED_VIDMEM) / pitch;
+    if(pNv->offscreenHeight > 32767) pNv->offscreenHeight = 32767;
+    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+        "%.2f MB available for offscreen pixmaps\n",
+        (pNv->offscreenHeight - pScrn->virtualY) * pitch / 1024.0 / 1024.0);
+
+    AvailFBArea.x1 = 0;
+    AvailFBArea.y1 = 0;
+    AvailFBArea.x2 = pScrn->displayWidth;
+    AvailFBArea.y2 = pNv->offscreenHeight;
+    xf86InitFBManager(pScreen, &AvailFBArea);
+
+    if(!pNv->NoAccel) {
+        G80InitHW(pScrn);
+        if(!G80XAAInit(pScreen)) {
+            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+                       "Hardware acceleration initialization failed\n");
+            pNv->NoAccel = FALSE;
+        }
+    }
+
+    miInitializeBackingStore(pScreen);
+    xf86SetBackingStore(pScreen);
+    xf86SetSilkenMouse(pScreen);
+
+    /* Initialize software cursor.
+       Must precede creation of the default colormap */
+    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
+
+    /* Initialize hardware cursor.  Must follow software cursor initialization. */
+    if(pNv->HWCursor && !G80CursorInit(pScreen)) {
+        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+                   "Hardware cursor initialization failed\n");
+        pNv->HWCursor = FALSE;
+    }
+
+    /* Initialize default colormap */
+    if(!miCreateDefColormap(pScreen))
+        return FALSE;
+
+    /* Initialize colormap layer.
+       Must follow initialization of the default colormap */
+    if(!xf86HandleColormaps(pScreen, 256, 8, G80LoadPalette, NULL,
+                            CMAP_PALETTED_TRUECOLOR))
+        return FALSE;
+
+    xf86DPMSInit(pScreen, G80DispDPMSSet, 0);
+
+    /* Clear the screen */
+    if(pNv->xaa) {
+        /* Use the acceleration engine */
+        pNv->xaa->SetupForSolidFill(pScrn, 0, GXcopy, ~0);
+        pNv->xaa->SubsequentSolidFillRect(pScrn,
+            0, 0, pScrn->displayWidth, pNv->offscreenHeight);
+        G80DmaKickoff(pNv);
+    } else {
+        /* Use a slow software clear path */
+        memset(pNv->mem, 0, pitch * pNv->offscreenHeight);
+    }
+
+    /* Initialize the display */
+    if(!AcquireDisplay(pScrn))
+        return FALSE;
+
+    pScreen->SaveScreen = G80SaveScreen;
+
+    pNv->CloseScreen = pScreen->CloseScreen;
+    pScreen->CloseScreen = G80CloseScreen;
+
+    pNv->BlockHandler = pScreen->BlockHandler;
+    pScreen->BlockHandler = G80BlockHandler;
+
+    return TRUE;
+}
+
+static void
+G80FreeScreen(int scrnIndex, int flags)
+{
+    G80FreeRec(xf86Screens[scrnIndex]);
+}
+
+static Bool
+G80SwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
+{
+    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+
+    return G80DispSetMode(pScrn, mode);
+}
+
+static void
+G80AdjustFrame(int scrnIndex, int x, int y, int flags)
+{
+    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+    G80Ptr pNv = G80PTR(pScrn);
+
+    if(x + pScrn->currentMode->HDisplay > pScrn->virtualX ||
+       y + pScrn->currentMode->VDisplay > pScrn->virtualY ||
+       x < 0 || y < 0)
+        /* Ignore bogus panning */
+        return;
+    G80DispAdjustFrame(pNv, x, y);
+}
+
+static Bool
+G80EnterVT(int scrnIndex, int flags)
+{
+    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+    G80Ptr pNv = G80PTR(pScrn);
+
+    /* Reinit the hardware */
+    if(pNv->xaa)
+        G80InitHW(pScrn);
+
+    if(!AcquireDisplay(pScrn))
+        return FALSE;
+
+    return TRUE;
+}
+
+static void
+G80LeaveVT(int scrnIndex, int flags)
+{
+    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+
+    ReleaseDisplay(pScrn);
+}
+
+Bool G80GetScrnInfoRec(PciChipsets *chips, int chip)
+{
+    ScrnInfoPtr pScrn;
+
+    pScrn = xf86ConfigPciEntity(NULL, 0, chip,
+                                chips, NULL, NULL, NULL,
+                                NULL, NULL);
+
+    if(!pScrn) return FALSE;
+
+    pScrn->driverVersion    = NV_VERSION;
+    pScrn->driverName       = NV_DRIVER_NAME;
+    pScrn->name             = NV_NAME;
+
+    pScrn->PreInit          = G80PreInit;
+    pScrn->ScreenInit       = G80ScreenInit;
+    pScrn->SwitchMode       = G80SwitchMode;
+    pScrn->AdjustFrame      = G80AdjustFrame;
+    pScrn->EnterVT          = G80EnterVT;
+    pScrn->LeaveVT          = G80LeaveVT;
+    pScrn->FreeScreen       = G80FreeScreen;
+    // pScrn->ValidMode        = G80ValidMode;
+
+    return TRUE;
+}
diff --git a/src/g80_type.h b/src/g80_type.h
new file mode 100644
index 0000000..39d737c
--- /dev/null
+++ b/src/g80_type.h
@@ -0,0 +1,75 @@
+#include <xaa.h>
+#include <xf86.h>
+#include <xf86int10.h>
+#include <xf86Cursor.h>
+
+typedef enum Head {
+    HEAD0 = 0,
+    HEAD1
+} Head;
+
+typedef enum ORType {
+   DAC,
+   SOR
+} ORType;
+
+typedef enum ORNum {
+   DAC0 = 0,
+   DAC1 = 1,
+   DAC2 = 2,
+   SOR0 = 0,
+   SOR1 = 1
+} ORNum;
+
+typedef struct G80Rec {
+    volatile CARD32 *   reg;
+    unsigned char *     mem;
+
+    /* Probed data */
+    CARD32              architecture;
+    CARD32              RamAmountKBytes; /* Total vidmem */
+    CARD32              videoRam;        /* Mapped vidmem */
+    const unsigned char*table1;
+    int                 offscreenHeight;
+    struct {
+        ORNum dac;
+        ORNum sor;
+    } i2cMap[4];
+
+    float               pclk; /* Current mode pclk in kHz */
+
+    Head                head;
+    ORType              orType;
+    ORNum               or;
+
+    xf86Int10InfoPtr    int10;
+    int                 int10Mode; /* Console mode to restore */
+
+    /* Options */
+    OptionInfoPtr       Options;
+    Bool                HWCursor;
+    Bool                NoAccel;
+    DisplayModePtr      BackendMode;
+
+    /* Cursor */
+    xf86CursorInfoPtr   CursorInfo;
+    Bool                cursorVisible;
+    CARD32              tmpCursor[256]; /* Temporary 1bpp cursor image */
+
+    /* XAA */
+    XAAInfoRecPtr       xaa;
+    CARD32              currentRop;
+
+    /* DMA command buffer */
+    CARD32              dmaPut;
+    CARD32              dmaCurrent;
+    CARD32              dmaFree;
+    CARD32              dmaMax;
+    CARD32 *            dmaBase;
+    void              (*DMAKickoffCallback)(ScrnInfoPtr);
+
+    CloseScreenProcPtr  CloseScreen;
+    ScreenBlockHandlerProcPtr BlockHandler;
+} G80Rec, *G80Ptr;
+
+#define G80PTR(p) ((G80Ptr)((p)->driverPrivate))
diff --git a/src/g80_xaa.c b/src/g80_xaa.c
new file mode 100644
index 0000000..1f07444
--- /dev/null
+++ b/src/g80_xaa.c
@@ -0,0 +1,554 @@
+/*
+ * Copyright (c) 2007 NVIDIA, Corporation
+ *
+ * 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 the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, 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 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 NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <miline.h>
+
+#include "g80_type.h"
+#include "g80_dma.h"
+#include "g80_xaa.h"
+
+static void
+G80Sync(ScrnInfoPtr pScrn)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+    volatile CARD16 *pSync = (volatile CARD16*)&pNv->reg[0x00711008/4] + 1;
+
+    G80DmaStart(pNv, 0x104, 1);
+    G80DmaNext (pNv, 0);
+    G80DmaStart(pNv, 0x100, 1);
+    G80DmaNext (pNv, 0);
+
+    *pSync = 0x8000;
+    G80DmaKickoff(pNv);
+    while(*pSync);
+}
+
+static void
+G80DMAKickoffCallback(ScrnInfoPtr pScrn)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+
+    G80DmaKickoff(pNv);
+    pNv->DMAKickoffCallback = NULL;
+}
+
+static void
+G80SetPattern(G80Ptr pNv, int bg, int fg, int pat0, int pat1)
+{
+    G80DmaStart(pNv, 0x2f0, 4);
+    G80DmaNext (pNv, bg);
+    G80DmaNext (pNv, fg);
+    G80DmaNext (pNv, pat0);
+    G80DmaNext (pNv, pat1);
+}
+
+static void
+G80SetRopSolid(G80Ptr pNv, CARD32 rop, CARD32 planemask)
+{
+    static const int rops[] = {
+        0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0,
+        0x30, 0xB0, 0x70, 0xF0
+    };
+
+    if(planemask != ~0) {
+        G80SetPattern(pNv, 0, planemask, ~0, ~0);
+        if(pNv->currentRop != (rop + 32)) {
+            pNv->currentRop = rop + 32;
+
+            rop = rops[rop] | 0xA;
+            G80DmaStart(pNv, 0x2a0, 1);
+            G80DmaNext (pNv, rop);
+        }
+    } else if(pNv->currentRop != rop) {
+        if(pNv->currentRop >= 16)
+            G80SetPattern(pNv, ~0, ~0, ~0, ~0);
+        pNv->currentRop = rop;
+
+        rop = rops[rop];
+        rop |= rop >> 4;
+        G80DmaStart(pNv, 0x2a0, 1);
+        G80DmaNext (pNv, rop);
+    }
+}
+
+static void inline
+G80SetClip(G80Ptr pNv, int x, int y, int w, int h)
+{
+    G80DmaStart(pNv, 0x280, 4);
+    G80DmaNext (pNv, x);
+    G80DmaNext (pNv, y);
+    G80DmaNext (pNv, w);
+    G80DmaNext (pNv, h);
+}
+
+/* Screen to screen copies */
+
+static void
+G80SetupForScreenToScreenCopy(
+    ScrnInfoPtr pScrn,
+    int xdir, int ydir,
+    int rop,
+    unsigned planemask,
+    int transparency_color
+)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+
+    planemask |= ~0 << pScrn->depth;
+
+    G80SetClip(pNv, 0, 0, 0x7fff, 0x7fff);
+    G80DmaStart(pNv, 0x2ac, 1);
+    if(rop == GXcopy && planemask == ~0) {
+        G80DmaNext (pNv, 3);
+    } else {
+        G80DmaNext (pNv, 1);
+        G80SetRopSolid(pNv, rop, planemask);
+    }
+    pNv->DMAKickoffCallback = G80DMAKickoffCallback;
+}
+
+static void
+G80SubsequentScreenToScreenCopy(
+    ScrnInfoPtr pScrn,
+    int x1, int y1,
+    int x2, int y2,
+    int w, int h
+)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+
+    G80DmaStart(pNv, 0x110, 1);
+    G80DmaNext (pNv, 0);
+    G80DmaStart(pNv, 0x8b0, 12);
+    G80DmaNext (pNv, x2);
+    G80DmaNext (pNv, y2);
+    G80DmaNext (pNv, w);
+    G80DmaNext (pNv, h);
+    G80DmaNext (pNv, 0);
+    G80DmaNext (pNv, 1);
+    G80DmaNext (pNv, 0);
+    G80DmaNext (pNv, 1);
+    G80DmaNext (pNv, 0);
+    G80DmaNext (pNv, x1);
+    G80DmaNext (pNv, 0);
+    G80DmaNext (pNv, y1);
+
+    if(w * h >= 512)
+        G80DmaKickoff(pNv);
+}
+
+/* Solid fills */
+
+static void
+G80SetupForSolidFill(
+    ScrnInfoPtr pScrn,
+    int color,
+    int rop,
+    unsigned planemask
+)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+
+    planemask |= ~0 << pScrn->depth;
+
+    G80SetClip(pNv, 0, 0, 0x7fff, 0x7fff);
+    G80DmaStart(pNv, 0x2ac, 1);
+    G80DmaNext (pNv, 1);
+    G80SetRopSolid(pNv, rop, planemask);
+    G80DmaStart(pNv, 0x580, 1);
+    G80DmaNext (pNv, 4);
+    G80DmaStart(pNv, 0x588, 1);
+    G80DmaNext (pNv, color);
+
+    pNv->DMAKickoffCallback = G80DMAKickoffCallback;
+}
+
+static void
+G80SubsequentFillRect(ScrnInfoPtr pScrn, int x, int y, int w, int h)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+
+    G80DmaStart(pNv, 0x600, 4);
+    G80DmaNext (pNv, x);
+    G80DmaNext (pNv, y);
+    G80DmaNext (pNv, x + w);
+    G80DmaNext (pNv, y + h);
+
+    if(w * h >= 512)
+        G80DmaKickoff(pNv);
+}
+
+/* 8x8 pattern fills */
+
+static void
+G80SetupForMono8x8PatternFill(
+    ScrnInfoPtr pScrn,
+    int patternx, int patterny,
+    int fg, int bg,
+    int rop,
+    unsigned planemask
+)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+    static const int rops[] = {
+        0x00, 0xA0, 0x50, 0xF0, 0x0A, 0xAA, 0x5A, 0xFA, 0x05, 0xA5, 0x55, 0xF5,
+        0x0F, 0xAF, 0x5F, 0xFF
+    };
+
+    planemask = ~0 << pScrn->depth;
+
+    fg |= planemask;
+    if(bg == -1) bg = 0;
+    else bg |= planemask;
+
+    if(pNv->currentRop != (rop + 16)) {
+        G80DmaStart(pNv, 0x2a0, 1);
+        G80DmaNext (pNv, rops[rop]);
+        pNv->currentRop = rop + 16;
+    }
+
+    G80SetClip(pNv, 0, 0, 0x7fff, 0x7fff);
+    G80SetPattern(pNv, bg, fg, patternx, patterny);
+
+    G80DmaStart(pNv, 0x2ac, 1);
+    G80DmaNext (pNv, 1);
+    G80DmaStart(pNv, 0x580, 1);
+    G80DmaNext (pNv, 4);
+    G80DmaStart(pNv, 0x588, 1);
+    G80DmaNext (pNv, fg);
+
+    pNv->DMAKickoffCallback = G80DMAKickoffCallback;
+}
+
+static void
+G80SubsequentMono8x8PatternFillRect(
+    ScrnInfoPtr pScrn,
+    int patternx, int patterny,
+    int x, int y,
+    int w, int h
+)
+{
+    G80SubsequentFillRect(pScrn, x, y, w, h);
+}
+
+/* Color expansion fills */
+
+static CARD32 _color_expand_dwords;
+static int _remaining;
+static unsigned char *_storage_buffer[1];
+
+static void
+G80SetupForScanlineCPUToScreenColorExpandFill(
+    ScrnInfoPtr pScrn,
+    int fg, int bg,
+    int rop,
+    unsigned int planemask
+)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+    CARD32 mask = ~0 << pScrn->depth;
+
+    planemask |= mask;
+
+    G80DmaStart(pNv, 0x2ac, 1);
+    G80DmaNext (pNv, 1);
+    G80SetRopSolid(pNv, rop, planemask);
+    G80DmaStart(pNv, 0x800, 1);
+    G80DmaNext (pNv, 1);
+    G80DmaStart(pNv, 0x808, 6);
+    G80DmaNext (pNv, 0);
+    G80DmaNext (pNv, 1);
+    G80DmaNext (pNv, 0);
+    G80DmaNext (pNv, bg | mask);
+    G80DmaNext (pNv, fg | mask);
+    G80DmaNext (pNv, (bg == -1) ? 0 : 1);
+}
+
+static void
+G80SubsequentScanlineCPUToScreenColorExpandFill(
+    ScrnInfoPtr pScrn,
+    int x, int y,
+    int w, int h,
+    int skipleft
+)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+    int bw = (w + 31) & ~31;
+
+    _color_expand_dwords = bw >> 5;
+    _remaining = h;
+
+    G80SetClip(pNv, x + skipleft, y, w - skipleft, h);
+
+    G80DmaStart(pNv, 0x838, 10);
+    G80DmaNext (pNv, bw);
+    G80DmaNext (pNv, h);
+    G80DmaNext (pNv, 0);
+    G80DmaNext (pNv, 1);
+    G80DmaNext (pNv, 0);
+    G80DmaNext (pNv, 1);
+    G80DmaNext (pNv, 0);
+    G80DmaNext (pNv, x);
+    G80DmaNext (pNv, 0);
+    G80DmaNext (pNv, y);
+
+    G80DmaStart(pNv, 0x40000860, _color_expand_dwords);
+    _storage_buffer[0] = (unsigned char*)&pNv->dmaBase[pNv->dmaCurrent];
+}
+
+static void
+G80SubsequentColorExpandScanline(ScrnInfoPtr pScrn, int bufno)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+
+    pNv->dmaCurrent += _color_expand_dwords;
+
+    if(--_remaining) {
+        G80DmaStart(pNv, 0x40000860, _color_expand_dwords);
+        _storage_buffer[0] = (unsigned char*)&pNv->dmaBase[pNv->dmaCurrent];
+    } else {
+        G80DmaKickoff(pNv);
+    }
+}
+
+/* Scaline image write */
+
+static void
+G80SetupForScanlineImageWrite(
+    ScrnInfoPtr pScrn, int rop,
+    unsigned int planemask,
+    int trans_color,
+    int bpp, int depth
+)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+
+    planemask |= ~0 << pScrn->depth;
+
+    G80DmaStart(pNv, 0x2ac, 1);
+    if(rop == GXcopy && planemask == ~0) {
+        G80DmaNext (pNv, 3);
+    } else {
+        G80DmaNext (pNv, 1);
+        G80SetRopSolid(pNv, rop, planemask);
+    }
+
+    G80DmaStart(pNv, 0x800, 1);
+    G80DmaNext (pNv, 0);
+}
+
+static CARD32 _image_dwords;
+
+static void
+G80SubsequentScanlineImageWriteRect(
+    ScrnInfoPtr pScrn,
+    int x, int y,
+    int w, int h,
+    int skipleft
+)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+    int Bpp = pScrn->bitsPerPixel >> 3;
+
+    _remaining = h;
+    _image_dwords = (w * Bpp + 3) / 4;
+
+    G80SetClip(pNv, x + skipleft, y, w - skipleft, h);
+
+    G80DmaStart(pNv, 0x838, 10);
+    G80DmaNext (pNv, w);
+    G80DmaNext (pNv, h);
+    G80DmaNext (pNv, 0);
+    G80DmaNext (pNv, 1);
+    G80DmaNext (pNv, 0);
+    G80DmaNext (pNv, 1);
+    G80DmaNext (pNv, 0);
+    G80DmaNext (pNv, x);
+    G80DmaNext (pNv, 0);
+    G80DmaNext (pNv, y);
+
+    G80DmaStart(pNv, 0x40000860, _image_dwords);
+    _storage_buffer[0] = (unsigned char*)&pNv->dmaBase[pNv->dmaCurrent];
+}
+
+static void G80SubsequentImageWriteScanline(ScrnInfoPtr pScrn, int bufno)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+
+    pNv->dmaCurrent += _image_dwords;
+
+    if(--_remaining) {
+        G80DmaStart(pNv, 0x40000860, _image_dwords);
+        _storage_buffer[0] = (unsigned char*)&pNv->dmaBase[pNv->dmaCurrent];
+    } else {
+        G80DmaKickoff(pNv);
+    }
+}
+
+/* Solid lines */
+
+static void
+G80SetupForSolidLine(ScrnInfoPtr pScrn, int color, int rop, unsigned planemask)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+
+    planemask |= ~0 << pScrn->depth;
+
+    G80SetClip(pNv, 0, 0, 0x7fff, 0x7fff);
+    G80DmaStart(pNv, 0x2ac, 1);
+    G80DmaNext (pNv, 1);
+    G80SetRopSolid(pNv, rop, planemask);
+    G80DmaStart(pNv, 0x580, 1);
+    G80DmaNext (pNv, 1);
+    G80DmaStart(pNv, 0x588, 1);
+    G80DmaNext (pNv, color);
+
+    pNv->DMAKickoffCallback = G80DMAKickoffCallback;
+}
+
+static void
+G80SubsequentSolidHorVertLine(ScrnInfoPtr pScrn, int x, int y, int len, int dir)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+
+    G80DmaStart(pNv, 0x400005e0, 2);
+    G80DmaNext (pNv, (y << 16) | (x & 0xffff));
+    if(dir == DEGREES_0) {
+       G80DmaNext (pNv, (y << 16) | ((x + len) & 0xffff));
+    } else {
+       G80DmaNext (pNv, ((y + len) << 16) | (x & 0xffff));
+    }
+}
+
+static void
+G80SubsequentSolidTwoPointLine(
+    ScrnInfoPtr pScrn,
+    int x1, int y1,
+    int x2, int y2,
+    int flags
+)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+    Bool drawLast = !(flags & OMIT_LAST);
+
+    G80DmaStart(pNv, 0x400005e0, drawLast ? 4 : 2);
+    G80DmaNext (pNv, (y1 << 16) | (x1 & 0xffff));
+    G80DmaNext (pNv, (y2 << 16) | (x2 & 0xffff));
+    if(drawLast) {
+        G80DmaNext (pNv, (y2 << 16) | (x2 & 0xffff));
+        G80DmaNext (pNv, ((y2 + 1) << 16) | (x2 & 0xffff));
+    }
+}
+
+static void
+G80SetClippingRectangle(ScrnInfoPtr pScrn, int x1, int y1, int x2, int y2)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+    int h = y2 - y1 + 1;
+    int w = x2 - x1 + 1;
+
+    G80SetClip(pNv, x1, y1, w, h);
+}
+
+static void
+G80DisableClipping(ScrnInfoPtr pScrn)
+{
+    G80Ptr pNv = G80PTR(pScrn);
+
+    G80SetClip(pNv, 0, 0, 0x7fff, 0x7fff);
+}
+
+
+Bool
+G80XAAInit(ScreenPtr pScreen)
+{
+    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+    G80Ptr pNv = G80PTR(pScrn);
+    XAAInfoRecPtr xaa;
+
+    xaa = pNv->xaa = XAACreateInfoRec();
+    if(!xaa) return FALSE;
+
+    xaa->Flags = LINEAR_FRAMEBUFFER | PIXMAP_CACHE | OFFSCREEN_PIXMAPS;
+    xaa->Sync = G80Sync;
+
+    /* Screen to screen copies */
+    xaa->ScreenToScreenCopyFlags = NO_TRANSPARENCY;
+    xaa->SetupForScreenToScreenCopy = G80SetupForScreenToScreenCopy;
+    xaa->SubsequentScreenToScreenCopy = G80SubsequentScreenToScreenCopy;
+
+    /* Solid fills */
+    xaa->SolidFillFlags = 0;
+    xaa->SetupForSolidFill = G80SetupForSolidFill;
+    xaa->SubsequentSolidFillRect = G80SubsequentFillRect;
+
+    /* 8x8 pattern fills */
+    xaa->Mono8x8PatternFillFlags = HARDWARE_PATTERN_SCREEN_ORIGIN |
+                                   HARDWARE_PATTERN_PROGRAMMED_BITS |
+                                   NO_PLANEMASK;
+    xaa->SetupForMono8x8PatternFill = G80SetupForMono8x8PatternFill;
+    xaa->SubsequentMono8x8PatternFillRect = G80SubsequentMono8x8PatternFillRect;
+
+    /* Color expansion fills */
+    xaa->ScanlineCPUToScreenColorExpandFillFlags =
+        BIT_ORDER_IN_BYTE_LSBFIRST |
+        CPU_TRANSFER_PAD_DWORD |
+        LEFT_EDGE_CLIPPING |
+        LEFT_EDGE_CLIPPING_NEGATIVE_X;
+    xaa->NumScanlineColorExpandBuffers = 1;
+    xaa->SetupForScanlineCPUToScreenColorExpandFill =
+        G80SetupForScanlineCPUToScreenColorExpandFill;
+    xaa->SubsequentScanlineCPUToScreenColorExpandFill =
+        G80SubsequentScanlineCPUToScreenColorExpandFill;
+    xaa->SubsequentColorExpandScanline =
+        G80SubsequentColorExpandScanline;
+    xaa->ScanlineColorExpandBuffers = _storage_buffer;
+
+    /* Scaline image write */
+    xaa->ScanlineImageWriteFlags = NO_GXCOPY |
+                                   NO_TRANSPARENCY |
+                                   LEFT_EDGE_CLIPPING |
+                                   LEFT_EDGE_CLIPPING_NEGATIVE_X;
+    xaa->NumScanlineImageWriteBuffers = 1;
+    xaa->SetupForScanlineImageWrite = G80SetupForScanlineImageWrite;
+    xaa->SubsequentScanlineImageWriteRect = G80SubsequentScanlineImageWriteRect;
+    xaa->SubsequentImageWriteScanline = G80SubsequentImageWriteScanline;
+    xaa->ScanlineImageWriteBuffers = _storage_buffer;
+
+    /* Solid lines */
+    xaa->SolidLineFlags = 0;
+    xaa->SetupForSolidLine = G80SetupForSolidLine;
+    xaa->SubsequentSolidHorVertLine = G80SubsequentSolidHorVertLine;
+    xaa->SubsequentSolidTwoPointLine = G80SubsequentSolidTwoPointLine;
+    xaa->SetClippingRectangle = G80SetClippingRectangle;
+    xaa->DisableClipping = G80DisableClipping;
+    xaa->ClippingFlags = HARDWARE_CLIP_SOLID_LINE;
+
+    miSetZeroLineBias(pScreen, OCTANT1 | OCTANT3 | OCTANT4 | OCTANT6);
+
+    return XAAInit(pScreen, xaa);
+}
diff --git a/src/g80_xaa.h b/src/g80_xaa.h
new file mode 100644
index 0000000..e2f1f63
--- /dev/null
+++ b/src/g80_xaa.h
@@ -0,0 +1 @@
+Bool G80XAAInit(ScreenPtr);
diff --git a/src/nv_driver.c b/src/nv_driver.c
index 8f40cfa..64d45c5 100644
--- a/src/nv_driver.c
+++ b/src/nv_driver.c
@@ -37,6 +37,7 @@
 
 const   OptionInfoRec * RivaAvailableOptions(int chipid, int busid);
 Bool    RivaGetScrnInfoRec(PciChipsets *chips, int chip);
+Bool    G80GetScrnInfoRec(PciChipsets *chips, int chip);
 
 /*
  * Forward definitions for the functions that make up the driver.
@@ -332,6 +333,13 @@ static SymTabRec NVKnownChipsets[] =
   { 0x10DE0244, "GeForce Go 6150" },
   { 0x10DE0247, "GeForce Go 6100" },
 
+#if SUPPORT_G80
+  { 0x10DE0191, "GeForce 8800 GTX" },
+  { 0x10DE0193, "GeForce 8800 GTS" },
+  { 0x10DE019D, "Quadro FX 5600" },
+  { 0x10DE019E, "Quadro FX 4600" },
+#endif
+
   {-1, NULL}
 };
 
@@ -647,6 +655,20 @@ NVGetPCIXpressChip (pciVideoPtr pVideo)
     return pciid;
 }
 
+#if SUPPORT_G80
+static Bool
+NVIsG80(int chipType)
+{
+    switch(chipType & 0xfff0) {
+        case 0x0190:
+        case 0x0400:
+        case 0x0420:
+            return TRUE;
+    }
+
+    return FALSE;
+}
+#endif
 
 /* Mandatory */
 static Bool
@@ -700,6 +722,8 @@ NVProbe(DriverPtr drv, int flags)
                NVPciChipsets[numUsed].resList = RES_SHARED_VGA;
                numUsed++;
             } else if ((*ppPci)->vendor == PCI_VENDOR_NVIDIA) {
+               Bool canHandle = FALSE;
+
                /* look for a compatible devices which may be newer than 
                   the NVKnownChipsets list above.  */
                switch(token & 0xfff0) {
@@ -725,14 +749,23 @@ NVProbe(DriverPtr drv, int flags)
                case 0x0290:
                case 0x0390:
                case 0x03D0:
+                   canHandle = TRUE;
+                   break;
+               default:  break;  /* we don't recognize it */
+               }
+
+#if SUPPORT_G80
+               if(NVIsG80((*ppPci)->chipType))
+                   canHandle = TRUE;
+#endif
+
+               if(canHandle) {
                    NVChipsets[numUsed].token = pciid;
                    NVChipsets[numUsed].name = "Unknown NVIDIA chip";
                    NVPciChipsets[numUsed].numChipset = pciid;
                    NVPciChipsets[numUsed].PCIid = pciid;
                    NVPciChipsets[numUsed].resList = RES_SHARED_VGA;
                    numUsed++;
-                   break;
-               default:  break;  /* we don't recognize it */
                }
             }
         }
@@ -762,6 +795,11 @@ NVProbe(DriverPtr drv, int flags)
         if(pPci->vendor == PCI_VENDOR_NVIDIA_SGS) {
             if(RivaGetScrnInfoRec(NVPciChipsets, usedChips[i]))
                 foundScreen = TRUE;
+#if SUPPORT_G80
+        } else if (NVIsG80(pPci->chipType)) {
+            if(G80GetScrnInfoRec(NVPciChipsets, usedChips[i]))
+                foundScreen = TRUE;
+#endif
         } else {
             if(NVGetScrnInfoRec(NVPciChipsets, usedChips[i])) 
 	        foundScreen = TRUE;
diff --git a/src/nv_include.h b/src/nv_include.h
index 071a4a0..03f2997 100644
--- a/src/nv_include.h
+++ b/src/nv_include.h
@@ -6,6 +6,7 @@
 #if !USE_LIBC_WRAPPER
 #include <string.h>
 #include <math.h>
+#include <unistd.h>
 #endif
 
 /* All drivers should typically include these */
@@ -55,7 +56,6 @@
 #include "vgaHW.h"
 
 #include "xf86Cursor.h"
-#include "xf86DDC.h"
 
 #include "region.h"
 



More information about the xorg-commit mailing list