http://drm.bkbits.net/drm-2.6
airlied@starflyer.(none)|ChangeSet|20040815085825|05193 airlied

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/08/15 18:58:25+10:00 airlied@starflyer.(none) 
#   make the gamma_old_dma.h looks like the gamma_dma.h
# 
# drivers/char/drm/gamma_old_dma.h
#   2004/08/15 18:58:19+10:00 airlied@starflyer.(none) +0 -27
#   make the gamma_old_dma.h looks like the gamma_dma.h
# 
# drivers/char/drm/drm_drv.h
#   2004/08/15 17:15:31+10:00 airlied@starflyer.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/02 22:18:06+10:00 airlied@starflyer.(none) 
#   Fix up multiple devices issues with creating /proc/dri/
#   
#   From: Jon Smirl
#   Approved-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/drm_stub.h
#   2004/08/02 22:18:00+10:00 airlied@starflyer.(none) +21 -12
#   Fix up multiple devices issues with creating /proc/dri/
#   
#   From: Jon Smirl
#   Approved-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/drm_proc.h
#   2004/08/02 22:18:00+10:00 airlied@starflyer.(none) +4 -13
#   Fix up multiple devices issues with creating /proc/dri/
#   
#   From: Jon Smirl
#   Approved-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/drm_drv.h
#   2004/08/02 22:18:00+10:00 airlied@starflyer.(none) +2 -1
#   Fix up multiple devices issues with creating /proc/dri/
#   
#   From: Jon Smirl
#   Approved-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/drmP.h
#   2004/08/02 22:18:00+10:00 airlied@starflyer.(none) +4 -4
#   Fix up multiple devices issues with creating /proc/dri/
#   
#   From: Jon Smirl
#   Approved-by: Dave Airlie <airlied@linux.ie>
# 
# ChangeSet
#   2004/08/02 22:08:26+10:00 airlied@starflyer.(none) 
#   add hotplug support function 
#   
#   From: Jon Smirl
#   Approved-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/drm_stub.h
#   2004/08/02 22:08:20+10:00 airlied@starflyer.(none) +69 -0
#   add hotplug support function 
#   
#   From: Jon Smirl
#   Approved-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/drmP.h
#   2004/08/02 22:08:20+10:00 airlied@starflyer.(none) +5 -3
#   add hotplug support function 
#   
#   From: Jon Smirl
#   Approved-by: Dave Airlie <airlied@linux.ie>
# 
# ChangeSet
#   2004/08/02 22:05:51+10:00 airlied@starflyer.(none) 
#   fixup prototype..
# 
# drivers/char/drm/i915_drv.h
#   2004/08/02 22:05:39+10:00 airlied@starflyer.(none) +1 -1
#   fixup prototype..
# 
# ChangeSet
#   2004/07/31 17:37:47+10:00 airlied@starflyer.(none) 
#   switch to using i915_dma_cleanup as this conflicts on BSD builds..
# 
# drivers/char/drm/i915_dma.c
#   2004/07/31 17:37:42+10:00 airlied@starflyer.(none) +6 -6
#   switch to using i915_dma_cleanup as this conflicts on BSD builds..
# 
# drivers/char/drm/i915.h
#   2004/07/31 17:37:42+10:00 airlied@starflyer.(none) +1 -1
#   switch to using i915_dma_cleanup as this conflicts on BSD builds..
# 
# ChangeSet
#   2004/07/31 17:21:52+10:00 airlied@starflyer.(none) 
#   sparse: use of user space pointer in kernel...
#   
#   Approved-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/i915_dma.c
#   2004/07/31 17:21:45+10:00 airlied@starflyer.(none) +1 -1
#   sparse: use of user space pointer in kernel...
#   
#   Approved-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/gamma_old_dma.h
#   2004/07/31 17:21:45+10:00 airlied@starflyer.(none) +46 -16
#   sparse: use of user space pointer in kernel...
#   
#   Approved-by: Dave Airlie <airlied@linux.ie>
# 
# ChangeSet
#   2004/07/31 17:06:34+10:00 airlied@starflyer.(none) 
#   sparse: 0->NULL conversions.
#   
#   From: Dave Airlie
# 
# drivers/char/drm/i915_mem.c
#   2004/07/31 17:05:06+10:00 airlied@starflyer.(none) +2 -2
#   sparse: 0->NULL conversions.
#   
#   From: Dave Airlie
# 
# ChangeSet
#   2004/07/31 16:43:41+10:00 airlied@starflyer.(none) 
#   the patch below optimises the drm code to not do put_user() on memory the
#   kernel allocated and then mmap-installed to userspace, but instead makes it
#   use the kernel virtual address directly instead.
#   
#   From: Arjan van de Ven <arjanv@redhat.com>
#   Approved-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/i830_dma.c
#   2004/07/31 16:43:12+10:00 airlied@starflyer.(none) +6 -6
#   the patch below optimises the drm code to not do put_user() on memory the
#   kernel allocated and then mmap-installed to userspace, but instead makes it
#   use the kernel virtual address directly instead.
#   
#   From: Arjan van de Ven <arjanv@redhat.com>
#   Approved-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/i810_dma.c
#   2004/07/31 16:43:12+10:00 airlied@starflyer.(none) +2 -5
#   the patch below optimises the drm code to not do put_user() on memory the
#   kernel allocated and then mmap-installed to userspace, but instead makes it
#   use the kernel virtual address directly instead.
#   
#   From: Arjan van de Ven <arjanv@redhat.com>
#   Approved-by: Dave Airlie <airlied@linux.ie>
# 
# ChangeSet
#   2004/07/26 21:32:41+10:00 airlied@starflyer.(none) 
#   ATI Rage 128 and Radeon DRM unconditionally depend on PCI
#    
#   Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
# 
# drivers/char/drm/Kconfig
#   2004/07/26 21:32:32+10:00 airlied@starflyer.(none) +2 -2
#   ATI Rage 128 and Radeon DRM unconditionally depend on PCI
#    
#   Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
# 
# ChangeSet
#   2004/07/26 21:29:53+10:00 airlied@starflyer.(none) 
#   Correct a couple of packet length calculations. - keithw
# 
# drivers/char/drm/i915_dma.c
#   2004/07/26 21:29:47+10:00 airlied@starflyer.(none) +8 -1
#   Correct a couple of packet length calculations. - keithw
# 
# ChangeSet
#   2004/07/25 18:55:44+10:00 airlied@starflyer.(none) 
#   define user if not already.. this isn't needed in kernel but for building against the kernel headers it is ...
# 
# drivers/char/drm/drm.h
#   2004/07/25 18:55:37+10:00 airlied@starflyer.(none) +4 -0
#   define user if not already.. this isn't needed in kernel but for building against the kernel headers it is ...
# 
# ChangeSet
#   2004/07/25 18:37:04+10:00 airlied@starflyer.(none) 
#   sync up device/driver tracking with CVS, 
#   
#   Approved-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/drm_stub.h
#   2004/07/25 18:36:57+10:00 airlied@starflyer.(none) +45 -30
#   sync up device/driver tracking with CVS, 
#   
#   Approved-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/drm_drv.h
#   2004/07/25 18:36:56+10:00 airlied@starflyer.(none) +1 -0
#   sync up device/driver tracking with CVS, 
#   
#   Approved-by: Dave Airlie <airlied@linux.ie>
# 
# ChangeSet
#   2004/07/25 18:35:57+10:00 airlied@starflyer.(none) 
#   fix whitespace on tabbing
# 
# drivers/char/drm/drm_os_linux.h
#   2004/07/25 18:35:51+10:00 airlied@starflyer.(none) +2 -2
#   fix whitespace on tabbing
# 
# ChangeSet
#   2004/07/25 18:35:16+10:00 airlied@starflyer.(none) 
#   add some annotations Als patch missed
#   add annotations for i915 driver
# 
# drivers/char/drm/sis_mm.c
#   2004/07/25 18:35:10+10:00 airlied@starflyer.(none) +4 -3
#   add some annotations Als patch missed
#   add annotations for i915 driver
# 
# drivers/char/drm/i915_mem.c
#   2004/07/25 18:35:10+10:00 airlied@starflyer.(none) +3 -3
#   add some annotations Als patch missed
#   add annotations for i915 driver
# 
# drivers/char/drm/i915_irq.c
#   2004/07/25 18:35:10+10:00 airlied@starflyer.(none) +2 -2
#   add some annotations Als patch missed
#   add annotations for i915 driver
# 
# drivers/char/drm/i915_drm.h
#   2004/07/25 18:35:10+10:00 airlied@starflyer.(none) +6 -6
#   add some annotations Als patch missed
#   add annotations for i915 driver
# 
# drivers/char/drm/i915_dma.c
#   2004/07/25 18:35:10+10:00 airlied@starflyer.(none) +8 -9
#   add some annotations Als patch missed
#   add annotations for i915 driver
# 
# ChangeSet
#   2004/07/25 18:32:42+10:00 airlied@starflyer.(none) 
#   add missing prototype
# 
# drivers/char/drm/drmP.h
#   2004/07/25 18:32:36+10:00 airlied@starflyer.(none) +1 -1
#   add missing prototype
# 
# ChangeSet
#   2004/07/25 16:03:47+10:00 airlied@starflyer.(none) 
#   fixup annotation 
# 
# drivers/char/drm/drm_ioctl.h
#   2004/07/25 16:03:39+10:00 airlied@starflyer.(none) +1 -1
#   fixup annotation 
# 
# ChangeSet
#   2004/07/25 15:49:46+10:00 airlied@starflyer.(none) 
#   patch from Tom Arbuckle for missing bus_address
#   
#   Approved-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/drm_bufs.h
#   2004/07/25 15:49:40+10:00 airlied@starflyer.(none) +1 -0
#   patch from Tom Arbuckle for missing bus_address
#   
#   Approved-by: Dave Airlie <airlied@linux.ie>
# 
# ChangeSet
#   2004/07/20 21:43:43+10:00 airlied@starflyer.(none) 
#   use NULLs instead of 0s
#   
#   Approved-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/i915_mem.c
#   2004/07/20 21:43:37+10:00 airlied@starflyer.(none) +9 -9
#   use NULLs instead of 0s
#   
#   Approved-by: Dave Airlie <airlied@linux.ie>
# 
# ChangeSet
#   2004/07/20 21:41:54+10:00 airlied@starflyer.(none) 
#   fixup drm_stub so it works with two-headed cards properly...
#   
#   Approved-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/drm_stub.h
#   2004/07/20 21:41:42+10:00 airlied@starflyer.(none) +16 -12
#   fixup drm_stub so it works with two-headed cards properly...
# 
# ChangeSet
#   2004/07/18 20:22:59-07:00 drm.adm@hostme.bitkeeper.com 
#   Merge http://linux.bkbits.net/linux-2.5
#   into hostme.bitkeeper.com:/repos/d/drm/drm-2.6
# 
# drivers/char/drm/drm_drv.h
#   2004/07/18 20:22:52-07:00 drm.adm@hostme.bitkeeper.com +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/07/15 05:53:22-07:00 drm.adm@hostme.bitkeeper.com 
#   Merge http://linux.bkbits.net/linux-2.5
#   into hostme.bitkeeper.com:/repos/d/drm/drm-2.6
# 
# drivers/char/drm/drm_drv.h
#   2004/07/15 05:53:14-07:00 drm.adm@hostme.bitkeeper.com +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/07/15 22:46:05+10:00 airlied@starflyer.(none) 
#   Add new i915 driver from Tungsten Graphics Inc. This driver covers the i830
#   chipsets also, a new X 2D + 3D driver are needed to use this but they have 
#   been integrated into at least the X.org tree at this point and I think the
#   XFree86 tree. There are probably a few cleanups necessary for this driver.
#   
#   From: Keith Whitwell <keith@tungstengraphics.com>
#   Approved-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/drm_pciids.h
#   2004/07/15 22:45:59+10:00 airlied@starflyer.(none) +8 -0
#   Add new i915 driver from Tungsten Graphics Inc. This driver covers the i830
#   chipsets also, a new X 2D + 3D driver are needed to use this but they have 
#   been integrated into at least the X.org tree at this point and I think the
#   XFree86 tree. There are probably a few cleanups necessary for this driver.
#   
#   From: Keith Whitwell <keith@tungstengraphics.com>
#   Approved-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/drm_os_linux.h
#   2004/07/15 22:45:59+10:00 airlied@starflyer.(none) +4 -0
#   Add new i915 driver from Tungsten Graphics Inc. This driver covers the i830
#   chipsets also, a new X 2D + 3D driver are needed to use this but they have 
#   been integrated into at least the X.org tree at this point and I think the
#   XFree86 tree. There are probably a few cleanups necessary for this driver.
#   
#   From: Keith Whitwell <keith@tungstengraphics.com>
#   Approved-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/Makefile
#   2004/07/15 22:45:59+10:00 airlied@starflyer.(none) +2 -0
#   Add new i915 driver from Tungsten Graphics Inc. This driver covers the i830
#   chipsets also, a new X 2D + 3D driver are needed to use this but they have 
#   been integrated into at least the X.org tree at this point and I think the
#   XFree86 tree. There are probably a few cleanups necessary for this driver.
#   
#   From: Keith Whitwell <keith@tungstengraphics.com>
#   Approved-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/Kconfig
#   2004/07/15 22:45:59+10:00 airlied@starflyer.(none) +12 -1
#   Add new i915 driver from Tungsten Graphics Inc. This driver covers the i830
#   chipsets also, a new X 2D + 3D driver are needed to use this but they have 
#   been integrated into at least the X.org tree at this point and I think the
#   XFree86 tree. There are probably a few cleanups necessary for this driver.
#   
#   From: Keith Whitwell <keith@tungstengraphics.com>
#   Approved-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/i915_mem.c
#   2004/07/15 22:40:16+10:00 airlied@starflyer.(none) +361 -0
# 
# drivers/char/drm/i915_irq.c
#   2004/07/15 22:40:16+10:00 airlied@starflyer.(none) +173 -0
# 
# drivers/char/drm/i915_drv.h
#   2004/07/15 22:40:16+10:00 airlied@starflyer.(none) +228 -0
# 
# drivers/char/drm/i915_drv.c
#   2004/07/15 22:40:16+10:00 airlied@starflyer.(none) +31 -0
# 
# drivers/char/drm/i915_drm.h
#   2004/07/15 22:40:16+10:00 airlied@starflyer.(none) +162 -0
# 
# drivers/char/drm/i915.h
#   2004/07/15 22:40:16+10:00 airlied@starflyer.(none) +95 -0
# 
# drivers/char/drm/i915_mem.c
#   2004/07/15 22:40:16+10:00 airlied@starflyer.(none) +0 -0
#   BitKeeper file /home/airlied/drm/drm-2.6/drivers/char/drm/i915_mem.c
# 
# drivers/char/drm/i915_irq.c
#   2004/07/15 22:40:16+10:00 airlied@starflyer.(none) +0 -0
#   BitKeeper file /home/airlied/drm/drm-2.6/drivers/char/drm/i915_irq.c
# 
# drivers/char/drm/i915_drv.h
#   2004/07/15 22:40:16+10:00 airlied@starflyer.(none) +0 -0
#   BitKeeper file /home/airlied/drm/drm-2.6/drivers/char/drm/i915_drv.h
# 
# drivers/char/drm/i915_drv.c
#   2004/07/15 22:40:16+10:00 airlied@starflyer.(none) +0 -0
#   BitKeeper file /home/airlied/drm/drm-2.6/drivers/char/drm/i915_drv.c
# 
# drivers/char/drm/i915_drm.h
#   2004/07/15 22:40:16+10:00 airlied@starflyer.(none) +0 -0
#   BitKeeper file /home/airlied/drm/drm-2.6/drivers/char/drm/i915_drm.h
# 
# drivers/char/drm/i915_dma.c
#   2004/07/15 22:40:15+10:00 airlied@starflyer.(none) +754 -0
# 
# drivers/char/drm/i915.h
#   2004/07/15 22:40:16+10:00 airlied@starflyer.(none) +0 -0
#   BitKeeper file /home/airlied/drm/drm-2.6/drivers/char/drm/i915.h
# 
# drivers/char/drm/i915_dma.c
#   2004/07/15 22:40:15+10:00 airlied@starflyer.(none) +0 -0
#   BitKeeper file /home/airlied/drm/drm-2.6/drivers/char/drm/i915_dma.c
# 
# ChangeSet
#   2004/07/15 11:45:43+10:00 airlied@starflyer.(none) 
#   Fix issue with keeping count of registered DRMs with new driver model
#   
#   Submitted-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/drm_stub.h
#   2004/07/15 11:45:37+10:00 airlied@starflyer.(none) +10 -2
#   Fix issue with keeping count of registered DRMs with new driver model
#   
#   Submitted-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/drm_drv.h
#   2004/07/15 11:45:37+10:00 airlied@starflyer.(none) +2 -0
#   Fix issue with keeping count of registered DRMs with new driver model
#   
#   Submitted-by: Dave Airlie <airlied@linux.ie>
# 
# ChangeSet
#   2004/07/06 21:20:25+10:00 airlied@starflyer.(none) 
#   changes for better hotplug and proper PCI device support from Jon Smirl and
#   Dave Airlie, along with a big fix from Paul Mackerras.
#   
#   Note: these are complex due to the need for the DRM to fallback if the 
#   framebuffer driver has already taken the device.
#   
#   These changes have been in the DRM CVS tree for about 3 months, style
#   comments are appreciated...
# 
# drivers/char/drm/drm_stub.h
#   2004/07/06 21:20:12+10:00 airlied@starflyer.(none) +19 -27
#   changes for better hotplug and proper PCI device support from Jon Smirl and
#   Dave Airlie, along with a big fix from Paul Mackerras.
#   
#   Note: these are complex due to the need for the DRM to fallback if the 
#   framebuffer driver has already taken the device.
#   
#   These changes have been in the DRM CVS tree for about 3 months, style
#   comments are appreciated...
# 
# drivers/char/drm/drm_drv.h
#   2004/07/06 21:20:12+10:00 airlied@starflyer.(none) +128 -56
#   changes for better hotplug and proper PCI device support from Jon Smirl and
#   Dave Airlie, along with a big fix from Paul Mackerras.
#   
#   Note: these are complex due to the need for the DRM to fallback if the 
#   framebuffer driver has already taken the device.
#   
#   These changes have been in the DRM CVS tree for about 3 months, style
#   comments are appreciated...
# 
diff -Nru a/drivers/char/drm/Kconfig b/drivers/char/drm/Kconfig
--- a/drivers/char/drm/Kconfig	2004-08-25 19:41:26 -07:00
+++ b/drivers/char/drm/Kconfig	2004-08-25 19:41:26 -07:00
@@ -31,7 +31,7 @@
 
 config DRM_R128
 	tristate "ATI Rage 128"
-	depends on DRM
+	depends on DRM && PCI
 	help
 	  Choose this option if you have an ATI Rage 128 graphics card.  If M
 	  is selected, the module will be called r128.  AGP support for
@@ -39,7 +39,7 @@
 
 config DRM_RADEON
 	tristate "ATI Radeon"
-	depends on DRM
+	depends on DRM && PCI
 	help
 	  Choose this option if you have an ATI Radeon graphics card.  There
 	  are both PCI and AGP versions.  You don't need to choose this to
@@ -62,7 +62,18 @@
 	  Choose this option if you have a system that has Intel 830M, 845G,
 	  852GM, 855GM or 865G integrated graphics.  If M is selected, the
 	  module will be called i830.  AGP support is required for this driver
-	  to work.
+	  to work. This driver will eventually be replaced by the i915 one.
+
+config DRM_I915
+	tristate "Intel 830M, 845G, 852GM, 855GM, 865G, 915G"
+	depends on DRM && AGP && AGP_INTEL
+	help
+	  Choose this option if you have a system that has Intel 830M, 845G,
+	  852GM, 855GM 865G or 915G integrated graphics.  If M is selected, the
+	  module will be called i915.  AGP support is required for this driver
+	  to work. This driver will eventually replace the I830 driver, when
+	  later release of X start to use the new DDX and DRI.
+	
 
 config DRM_MGA
 	tristate "Matrox g200/g400"
diff -Nru a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile
--- a/drivers/char/drm/Makefile	2004-08-25 19:41:26 -07:00
+++ b/drivers/char/drm/Makefile	2004-08-25 19:41:26 -07:00
@@ -8,6 +8,7 @@
 mga-objs    := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o
 i810-objs   := i810_drv.o i810_dma.o
 i830-objs   := i830_drv.o i830_dma.o i830_irq.o
+i915-objs   := i915_drv.o i915_dma.o i915_irq.o i915_mem.o
 radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o
 ffb-objs    := ffb_drv.o ffb_context.o
 sis-objs    := sis_drv.o sis_ds.o sis_mm.o
@@ -19,6 +20,7 @@
 obj-$(CONFIG_DRM_MGA)	+= mga.o
 obj-$(CONFIG_DRM_I810)	+= i810.o
 obj-$(CONFIG_DRM_I830)	+= i830.o
+obj-$(CONFIG_DRM_I915)  += i915.o
 obj-$(CONFIG_DRM_FFB)   += ffb.o
 obj-$(CONFIG_DRM_SIS)   += sis.o
 
diff -Nru a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h
--- a/drivers/char/drm/drm.h	2004-08-25 19:41:26 -07:00
+++ b/drivers/char/drm/drm.h	2004-08-25 19:41:26 -07:00
@@ -37,6 +37,10 @@
 #ifndef _DRM_H_
 #define _DRM_H_
 
+#ifndef __user
+#define __user
+#endif
+
 #if defined(__linux__)
 #include <linux/config.h>
 #include <asm/ioctl.h>		/* For _IO* macros */
diff -Nru a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
--- a/drivers/char/drm/drmP.h	2004-08-25 19:41:26 -07:00
+++ b/drivers/char/drm/drmP.h	2004-08-25 19:41:26 -07:00
@@ -733,11 +733,13 @@
 	struct pci_controller *hose;
 #endif
 #endif
-	drm_sg_mem_t      *sg;  /**< Scatter gather memory */
+	drm_sg_mem_t      *sg;		/**< Scatter gather memory */
 	unsigned long     *ctx_bitmap;	/**< context bitmap */
-	void		  *dev_private; /**< device private data */
-	drm_sigdata_t     sigdata; /**< For block_all_signals */
+	void		  *dev_private;	/**< device private data */
+	drm_sigdata_t     sigdata;	/**< For block_all_signals */
 	sigset_t          sigmask;
+	
+	int		  need_reset;	/**< secondary device needing reset */
 } drm_device_t;
 
 
@@ -761,7 +763,7 @@
 			       unsigned int cmd, unsigned long arg);
 extern int           DRM(unlock)(struct inode *inode, struct file *filp,
 				 unsigned int cmd, unsigned long arg);
-
+extern int           DRM(fb_loaded);
 				/* Device support (drm_fops.h) */
 extern int	     DRM(open_helper)(struct inode *inode, struct file *filp,
 				      drm_device_t *dev);
@@ -961,10 +963,10 @@
 int                   DRM(stub_unregister)(int minor);
 
 				/* Proc support (drm_proc.h) */
-extern struct proc_dir_entry *DRM(proc_init)(drm_device_t *dev,
-					     int minor,
-					     struct proc_dir_entry *root,
-					     struct proc_dir_entry **dev_root);
+extern int 	      DRM(proc_init)(drm_device_t *dev,
+					int minor,
+					struct proc_dir_entry *root,
+					struct proc_dir_entry **dev_root);
 extern int            DRM(proc_cleanup)(int minor,
 					struct proc_dir_entry *root,
 					struct proc_dir_entry *dev_root);
diff -Nru a/drivers/char/drm/drm_bufs.h b/drivers/char/drm/drm_bufs.h
--- a/drivers/char/drm/drm_bufs.h	2004-08-25 19:41:26 -07:00
+++ b/drivers/char/drm/drm_bufs.h	2004-08-25 19:41:26 -07:00
@@ -691,6 +691,7 @@
 			buf->used    = 0;
 			buf->offset  = (dma->byte_count + byte_count + offset);
 			buf->address = (void *)(page + offset);
+			buf->bus_address = virt_to_bus(buf->address);
 			buf->next    = NULL;
 			buf->waiting = 0;
 			buf->pending = 0;
diff -Nru a/drivers/char/drm/drm_drv.h b/drivers/char/drm/drm_drv.h
--- a/drivers/char/drm/drm_drv.h	2004-08-25 19:41:26 -07:00
+++ b/drivers/char/drm/drm_drv.h	2004-08-25 19:41:26 -07:00
@@ -103,10 +103,10 @@
 #endif
 
 #ifndef DRIVER_PREINIT
-#define DRIVER_PREINIT()
+#define DRIVER_PREINIT() 0
 #endif
 #ifndef DRIVER_POSTINIT
-#define DRIVER_POSTINIT()
+#define DRIVER_POSTINIT() 0
 #endif
 #ifndef DRIVER_PRERELEASE
 #define DRIVER_PRERELEASE()
@@ -144,6 +144,19 @@
 }
 #endif
 
+static void __exit drm_cleanup( drm_device_t *dev );
+
+/** Stub information */
+struct drm_stub_info {
+	int (*info_register)(const char *name, struct file_operations *fops,
+			     drm_device_t *dev);
+	int (*info_unregister)(int minor);
+	struct class_simple *drm_class;
+	int *info_count;
+	struct proc_dir_entry *proc_root;
+};
+extern struct drm_stub_info DRM(stub_info);
+
 #ifndef MODULE
 /** Use an additional macro to avoid preprocessor troubles */
 #define DRM_OPTIONS_FUNC DRM(options)
@@ -163,8 +176,9 @@
 #endif
 
 #define MAX_DEVICES 4
-static drm_device_t	DRM(device)[MAX_DEVICES];
-static int		DRM(numdevs) = 0;
+drm_device_t            DRM(device)[MAX_DEVICES];
+int DRM(numdevs) = 0;
+int DRM(fb_loaded) = 0;
 
 DRIVER_FOPS;
 
@@ -546,30 +560,19 @@
 	DRM(PCI_IDS)
 };
 
-static int DRM(probe)(struct pci_dev *pdev)
+static int drm_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	drm_device_t *dev;
-#if __HAVE_CTX_BITMAP
 	int retcode;
-#endif
-	int i;
-	int is_compat = 0;
 
 	DRM_DEBUG( "\n" );
 
-	for (i = 0; DRM(pciidlist)[i].vendor != 0; i++) {
-		if ((DRM(pciidlist)[i].vendor == pdev->vendor) &&
-		    (DRM(pciidlist)[i].device == pdev->device)) {
-			is_compat = 1;
-		}
-	}
-	if (is_compat == 0)
-		return -ENODEV;
-
 	if (DRM(numdevs) >= MAX_DEVICES)
 		return -ENODEV;
 
 	dev = &(DRM(device)[DRM(numdevs)]);
+	if (DRM(fb_loaded)==0)
+		pci_set_drvdata(pdev, dev);
 
 	memset( (void *)dev, 0, sizeof(*dev) );
 	dev->count_lock = SPIN_LOCK_UNLOCKED;
@@ -578,11 +581,16 @@
 	sema_init( &dev->ctxlist_sem, 1 );
 
 	if ((dev->minor = DRM(stub_register)(DRIVER_NAME, &DRM(fops),dev)) < 0)
-		return -EPERM;
+	{
+		retcode = -EPERM;
+		goto error_out;
+	}
+			
 	dev->device = MKDEV(DRM_MAJOR, dev->minor );
 	dev->name   = DRIVER_NAME;
 
 	dev->pdev   = pdev;
+	pci_enable_device(pdev);
 #ifdef __alpha__
 	dev->hose   = pdev->sysdata;
 	dev->pci_domain = dev->hose->bus->number;
@@ -594,16 +602,16 @@
 	dev->pci_func = PCI_FUNC(pdev->devfn);
 	dev->irq = pdev->irq;
 
-	DRIVER_PREINIT();
+	if ((retcode = DRIVER_PREINIT()))
+	  goto error_out_unreg;
 
 #if __REALLY_HAVE_AGP
 	dev->agp = DRM(agp_init)();
 #if __MUST_HAVE_AGP
 	if ( dev->agp == NULL ) {
 		DRM_ERROR( "Cannot initialize the agpgart module.\n" );
-		DRM(stub_unregister)(dev->minor);
-		DRM(takedown)( dev );
-		return -EINVAL;
+		retcode = -EINVAL;
+		goto error_out_unreg;
 	}
 #endif
 #if __REALLY_HAVE_MTRR
@@ -619,13 +627,11 @@
 	retcode = DRM(ctxbitmap_init)( dev );
 	if( retcode ) {
 		DRM_ERROR( "Cannot allocate memory for context bitmap.\n" );
-		DRM(stub_unregister)(dev->minor);
-		DRM(takedown)( dev );
-		return retcode;
+		goto error_out_unreg;
  	}
 #endif
 	DRM(numdevs)++; /* no errors, mark it reserved */
-	
+
 	DRM_INFO( "Initialized %s %d.%d.%d %s on minor %d: %s\n",
 		DRIVER_NAME,
 		DRIVER_MAJOR,
@@ -633,13 +639,43 @@
 		DRIVER_PATCHLEVEL,
 		DRIVER_DATE,
 		dev->minor,
-		pci_pretty_name(pdev));
+		pci_pretty_name(pdev)
+		);
 
-	DRIVER_POSTINIT();
+	if ((retcode = DRIVER_POSTINIT()))
+		goto error_out_unreg;
+
+
+	/*
+	 * don't move this earlier, for upcoming hotplugging support
+	 */
+	class_simple_device_add(DRM(stub_info).drm_class, 
+					MKDEV(DRM_MAJOR, dev->minor), &pdev->dev, "card%d", dev->minor);
 
 	return 0;
+
+ error_out_unreg:
+	DRM(stub_unregister)(dev->minor);
+	DRM(takedown)(dev);
+ error_out:
+	return retcode;
 }
 
+static void __exit drm_cleanup_pci(struct pci_dev *pdev)
+{
+	drm_device_t *dev = pci_get_drvdata(pdev);
+
+	pci_set_drvdata(pdev, NULL);
+	drm_cleanup(dev);
+}
+
+static struct pci_driver drm_driver = {
+	.name          = DRIVER_NAME,
+	.id_table      = DRM(pciidlist),
+	.probe         = drm_probe,
+	.remove        = __devexit_p(drm_cleanup_pci),
+};
+
 /**
  * Module initialization. Called via init_module at module load time, or via
  * linux/init/main.c (this is not currently supported).
@@ -656,7 +692,9 @@
 static int __init drm_init( void )
 {
 	struct pci_dev *pdev = NULL;
-
+	struct pci_driver *pdriver = NULL;
+	int i;
+	
 	DRM_DEBUG( "\n" );
 
 #ifdef MODULE
@@ -664,10 +702,26 @@
 #endif
 
 	DRM(mem_init)();
-
-	while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
-		DRM(probe)(pdev);
+	
+	for (i=0; DRM(pciidlist)[i].vendor != 0; i++) {
+		pdev = pci_get_subsys(DRM(pciidlist[i]).vendor, DRM(pciidlist[i]).device, DRM(pciidlist[i]).subvendor, DRM(pciidlist[i]).subdevice, NULL);
+		if (pdev)
+		{
+			pdriver = pci_dev_driver(pdev);
+			if (pdriver)
+			{
+				DRM(fb_loaded)=1;
+				drm_probe(pdev, &DRM(pciidlist[i]));
+			}
+			else
+				pci_dev_put(pdev);
+		}
 	}
+	
+	if (DRM(fb_loaded)==0)
+		pci_register_driver(&drm_driver);
+	else
+		DRM_INFO("Used old pci detect: framebuffer loaded\n");
 	return 0;
 }
 
@@ -678,23 +732,26 @@
  * 
  * \sa drm_init().
  */
-static void __exit drm_cleanup( void )
+static void __exit drm_cleanup( drm_device_t *dev )
 {
-	drm_device_t *dev;
-	int i;
-
 	DRM_DEBUG( "\n" );
+	if (!dev) {
+		DRM_ERROR("cleanup called no dev\n");
+		return;
+	}
 
-	for (i = DRM(numdevs) - 1; i >= 0; i--) {
-		dev = &(DRM(device)[i]);
-		if ( DRM(stub_unregister)(dev->minor) ) {
-			DRM_ERROR( "Cannot unload module\n" );
-		} else {
-			DRM_DEBUG("minor %d unregistered\n", dev->minor);
-			if (i == 0) {
-				DRM_INFO( "Module unloaded\n" );
-			}
-		}
+	DRM(takedown)(dev);
+
+	if (DRM(fb_loaded)==0)
+		pci_disable_device(dev->pdev);
+
+	DRM(numdevs)--;
+	if ( DRM(stub_unregister)(dev->minor) ) {
+		DRM_ERROR( "Cannot unload module\n" );
+	} else {
+		DRM_DEBUG( "minor %d unregistered\n", dev->minor);
+	}
+	
 #if __HAVE_CTX_BITMAP
 		DRM(ctxbitmap_cleanup)( dev );
 #endif
@@ -709,22 +766,41 @@
 		}
 #endif
 
-		DRM(takedown)( dev );
 
 #if __REALLY_HAVE_AGP
-		if ( dev->agp ) {
-			DRM(agp_uninit)();
-			DRM(free)( dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS );
-			dev->agp = NULL;
-		}
+	if ( dev->agp ) {
+		DRM(agp_uninit)();
+		DRM(free)( dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS );
+		dev->agp = NULL;
+	}
 #endif
+
+	class_simple_device_remove(MKDEV(DRM_MAJOR, dev->minor));
+}
+
+static void __exit drm_exit (void)
+{
+	DRM_DEBUG( "\n" );
+	if (DRM(fb_loaded)==1)
+	{
+		int i;
+		drm_device_t *dev;
+
+		for (i = DRM(numdevs) - 1; i >= 0; i--) {
+			dev = &(DRM(device)[i]);
+			/* release the pci driver */
+			if (dev->pdev)
+				pci_dev_put(dev->pdev);
+			drm_cleanup(dev);
+		}
 	}
-	DRIVER_POSTCLEANUP();
-	DRM(numdevs) = 0;
+	else
+		pci_unregister_driver(&drm_driver);
+	DRM_INFO( "Module unloaded\n" );
 }
 
 module_init( drm_init );
-module_exit( drm_cleanup );
+module_exit( drm_exit );
 
 
 /**
diff -Nru a/drivers/char/drm/drm_ioctl.h b/drivers/char/drm/drm_ioctl.h
--- a/drivers/char/drm/drm_ioctl.h	2004-08-25 19:41:26 -07:00
+++ b/drivers/char/drm/drm_ioctl.h	2004-08-25 19:41:26 -07:00
@@ -257,7 +257,7 @@
 	client.iocs  = pt->ioctl_count;
 	up(&dev->struct_sem);
 
-	if (copy_to_user((drm_client_t __user *)arg, &client, sizeof(client)))
+	if (copy_to_user(argp, &client, sizeof(client)))
 		return -EFAULT;
 	return 0;
 }
diff -Nru a/drivers/char/drm/drm_os_linux.h b/drivers/char/drm/drm_os_linux.h
--- a/drivers/char/drm/drm_os_linux.h	2004-08-25 19:41:26 -07:00
+++ b/drivers/char/drm/drm_os_linux.h	2004-08-25 19:41:26 -07:00
@@ -17,10 +17,14 @@
 #define DRM_UDELAY(d)			udelay(d)
 /** Read a byte from a MMIO region */
 #define DRM_READ8(map, offset)		readb(((unsigned long)(map)->handle) + (offset))
+/** Read a word from a MMIO region */
+#define DRM_READ16(map, offset)		readw(((unsigned long)(map)->handle) + (offset))
 /** Read a dword from a MMIO region */
 #define DRM_READ32(map, offset)		readl(((unsigned long)(map)->handle) + (offset))
 /** Write a byte into a MMIO region */
 #define DRM_WRITE8(map, offset, val)	writeb(val, ((unsigned long)(map)->handle) + (offset))
+/** Write a word into a MMIO region */
+#define DRM_WRITE16(map, offset, val)	writew(val, ((unsigned long)(map)->handle) + (offset))
 /** Write a dword into a MMIO region */
 #define DRM_WRITE32(map, offset, val)	writel(val, ((unsigned long)(map)->handle) + (offset))
 /** Read memory barrier */
diff -Nru a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h
--- a/drivers/char/drm/drm_pciids.h	2004-08-25 19:41:26 -07:00
+++ b/drivers/char/drm/drm_pciids.h	2004-08-25 19:41:26 -07:00
@@ -201,3 +201,11 @@
 #define ffb_PCI_IDS \
 	{0, 0, 0}
 
+#define i915_PCI_IDS \
+	{0x8086, 0x3577, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x8086, 0x2562, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x8086, 0x3582, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x8086, 0x2572, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x8086, 0x2582, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0, 0, 0}
+
diff -Nru a/drivers/char/drm/drm_proc.h b/drivers/char/drm/drm_proc.h
--- a/drivers/char/drm/drm_proc.h	2004-08-25 19:41:26 -07:00
+++ b/drivers/char/drm/drm_proc.h	2004-08-25 19:41:26 -07:00
@@ -86,7 +86,7 @@
  * "/proc/dri/%minor%/", and each entry in proc_list as
  * "/proc/dri/%minor%/%name%".
  */
-struct proc_dir_entry *DRM(proc_init)(drm_device_t *dev, int minor,
+int DRM(proc_init)(drm_device_t *dev, int minor,
 				      struct proc_dir_entry *root,
 				      struct proc_dir_entry **dev_root)
 {
@@ -94,17 +94,11 @@
 	int		      i, j;
 	char                  name[64];
 
-	if (!minor) root = create_proc_entry("dri", S_IFDIR, NULL);
-	if (!root) {
-		DRM_ERROR("Cannot create /proc/dri\n");
-		return NULL;
-	}
-
 	sprintf(name, "%d", minor);
 	*dev_root = create_proc_entry(name, S_IFDIR, root);
 	if (!*dev_root) {
 		DRM_ERROR("Cannot create /proc/dri/%s\n", name);
-		return NULL;
+		return -1;
 	}
 
 	for (i = 0; i < DRM_PROC_ENTRIES; i++) {
@@ -117,14 +111,12 @@
 				remove_proc_entry(DRM(proc_list)[i].name,
 						  *dev_root);
 			remove_proc_entry(name, root);
-			if (!minor) remove_proc_entry("dri", NULL);
-			return NULL;
+			return -1;
 		}
 		ent->read_proc = DRM(proc_list)[i].f;
 		ent->data      = dev;
 	}
-
-	return root;
+	return 0;
 }
 
 
@@ -150,7 +142,6 @@
 		remove_proc_entry(DRM(proc_list)[i].name, dev_root);
 	sprintf(name, "%d", minor);
 	remove_proc_entry(name, root);
-	if (!minor) remove_proc_entry("dri", NULL);
 
 	return 0;
 }
diff -Nru a/drivers/char/drm/drm_stub.h b/drivers/char/drm/drm_stub.h
--- a/drivers/char/drm/drm_stub.h	2004-08-25 19:41:26 -07:00
+++ b/drivers/char/drm/drm_stub.h	2004-08-25 19:41:26 -07:00
@@ -35,8 +35,6 @@
 
 #define DRM_STUB_MAXCARDS 16	/* Enough for one machine */
 
-static struct class_simple *drm_class;
-
 /** Stub list. One for each minor. */
 static struct drm_stub_list {
 	const char             *name;
@@ -44,15 +42,6 @@
 	struct proc_dir_entry  *dev_root;	/**< proc directory entry */
 } *DRM(stub_list);
 
-static struct proc_dir_entry *DRM(stub_root);
-
-/** Stub information */
-static struct drm_stub_info {
-	int (*info_register)(const char *name, struct file_operations *fops,
-			     drm_device_t *dev);
-	int (*info_unregister)(int minor);
-} DRM(stub_info);
-
 /**
  * File \c open operation.
  *
@@ -86,6 +75,73 @@
 	.open  = DRM(stub_open)
 };
 
+static int drm_hotplug (struct class_device *dev, char **envp, int num_envp,
+				char *buffer, int buffer_size)
+{
+	drm_device_t *ddev;
+	struct pci_dev *pdev;
+	char *scratch;
+	int i = 0;
+	int length = 0;
+	
+	DRM_DEBUG("\n");
+	if (!dev)
+		return -ENODEV;
+
+	pdev = to_pci_dev(dev->dev);
+	if (!pdev)
+		return -ENODEV;
+
+	scratch = buffer;
+
+	/* stuff we want to pass to /sbin/hotplug */
+	envp[i++] = scratch;
+	length += snprintf (scratch, buffer_size - length, "PCI_CLASS=%04X",
+							pdev->class);
+	if ((buffer_size - length <= 0) || (i >= num_envp))
+		return -ENOMEM;
+	++length;
+	scratch += length;
+
+	envp[i++] = scratch;
+	length += snprintf (scratch, buffer_size - length, "PCI_ID=%04X:%04X",
+							pdev->vendor, pdev->device);
+	if ((buffer_size - length <= 0) || (i >= num_envp))
+		return -ENOMEM;
+	++length;
+	scratch += length;
+	
+	envp[i++] = scratch;
+	length += snprintf (scratch, buffer_size - length,
+							"PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor,
+							pdev->subsystem_device);
+	if ((buffer_size - length <= 0) || (i >= num_envp))
+		return -ENOMEM;
+	++length;
+	scratch += length;
+
+	envp[i++] = scratch;
+	length += snprintf (scratch, buffer_size - length, "PCI_SLOT_NAME=%s",
+							pci_name(pdev));
+	if ((buffer_size - length <= 0) || (i >= num_envp))
+		return -ENOMEM;
+	++length;
+	scratch += length;
+	
+	ddev = pci_get_drvdata(pdev);
+	if (ddev) {
+		envp[i++] = scratch;
+		length += snprintf (scratch, buffer_size - length, 
+							"RESET=%s", (ddev->need_reset ? "true" : "false"));
+		if ((buffer_size - length <= 0) || (i >= num_envp))
+			return -ENOMEM;
+	}
+	envp[i] = 0;
+	DRM_DEBUG(" - ok\n");
+	
+	return 0;
+}
+
 /**
  * Get a device minor number.
  *
@@ -116,10 +172,10 @@
 		if (!DRM(stub_list)[i].fops) {
 			DRM(stub_list)[i].name = name;
 			DRM(stub_list)[i].fops = fops;
-			DRM(stub_root) = DRM(proc_init)(dev, i, DRM(stub_root),
-							&DRM(stub_list)[i]
-							.dev_root);
-			class_simple_device_add(drm_class, MKDEV(DRM_MAJOR, i), NULL, name);
+			DRM(proc_init)(dev, i, DRM(stub_info).proc_root,
+							&DRM(stub_list)[i].dev_root);
+			(*DRM(stub_info).info_count)++;
+			DRM_DEBUG("info count increased %d\n", *DRM(stub_info).info_count);
 			return i;
 		}
 	}
@@ -141,19 +197,25 @@
 	if (minor < 0 || minor >= DRM_STUB_MAXCARDS) return -1;
 	DRM(stub_list)[minor].name = NULL;
 	DRM(stub_list)[minor].fops = NULL;
-	DRM(proc_cleanup)(minor, DRM(stub_root),
+	DRM(proc_cleanup)(minor, DRM(stub_info).proc_root,
 			  DRM(stub_list)[minor].dev_root);
-	if (minor) {
-		class_simple_device_remove(MKDEV(DRM_MAJOR, minor));
-		inter_module_put("drm");
+
+	(*DRM(stub_info).info_count)--;
+
+	if ((*DRM(stub_info).info_count) != 0) {
+		if (DRM(numdevs) == 0) {
+			DRM_DEBUG("inter_module_put called %d\n", *DRM(stub_info).info_count);
+			inter_module_put("drm");
+		}
 	} else {
+		DRM_DEBUG("unregistering inter_module \n");
 		inter_module_unregister("drm");
 		DRM(free)(DRM(stub_list),
 			  sizeof(*DRM(stub_list)) * DRM_STUB_MAXCARDS,
 			  DRM_MEM_STUB);
+		remove_proc_entry("dri", NULL);
+		class_simple_destroy(DRM(stub_info).drm_class);
 		unregister_chrdev(DRM_MAJOR, "drm");
-		class_simple_device_remove(MKDEV(DRM_MAJOR, minor));
-		class_simple_destroy(drm_class);
 	}
 	return 0;
 }
@@ -166,9 +228,9 @@
  * \param dev DRM device.
  * \return zero on success or a negative number on failure.
  *
- * Attempt to register the char device and get the foreign "drm" data. If
- * successful then another module already registered so gets the stub info,
- * otherwise use this module stub info and make it available for other modules.
+ * Attempt to gets inter module "drm" information. If we are first
+ * then register the character device and inter module information.
+ * Try and register, if we fail to register, backout previous work.
  *
  * Finally calls stub_info::info_register.
  */
@@ -180,40 +242,64 @@
 	int ret2;
 
 	DRM_DEBUG("\n");
-	ret1 = register_chrdev(DRM_MAJOR, "drm", &DRM(stub_fops));
-	if (!ret1) {
-		drm_class = class_simple_create(THIS_MODULE, "drm");
-		if (IS_ERR(drm_class)) {
-			printk (KERN_ERR "Error creating drm class.\n");
-			unregister_chrdev(DRM_MAJOR, "drm");
-			return PTR_ERR(drm_class);
-		}
-	}
-	else if (ret1 == -EBUSY)
+
+	/* if we are registering a second device we don't need to worry
+	   about inter module get/put and other things as they've been
+	   done already */
+	if (DRM(numdevs) == 0) {
+		/* use the inter_module_get to check - as if the same module
+		   registers chrdev twice it succeeds */
 		i = (struct drm_stub_info *)inter_module_get("drm");
-	else
-		return -1;
+		if (i) {
+			/* Already registered */
+			DRM(stub_info).info_register   = i->info_register;
+			DRM(stub_info).info_unregister = i->info_unregister;
+			DRM(stub_info).drm_class = i->drm_class;
+			DRM(stub_info).info_count = i->info_count;
+			DRM_DEBUG("already registered %d\n", *i->info_count);
+		} else if (*DRM(stub_info).info_count == 0) {
+
+			ret1 = register_chrdev(DRM_MAJOR, "drm", &DRM(stub_fops));
+			if (ret1 < 0) {
+				printk (KERN_ERR "Error registering drm major number.\n");
+				return ret1;
+			}
+
+			DRM(stub_info).drm_class = class_simple_create(THIS_MODULE, "drm");
+			if (IS_ERR(DRM(stub_info).drm_class)) {
+				printk (KERN_ERR "Error creating drm class.\n");
+				unregister_chrdev(DRM_MAJOR, "drm");
+				return PTR_ERR(DRM(stub_info).drm_class);
+			}
+			class_simple_set_hotplug(DRM(stub_info).drm_class, drm_hotplug);
+
+			DRM_DEBUG("calling inter_module_register\n");
+			inter_module_register("drm", THIS_MODULE, &DRM(stub_info));
+			
+			DRM(stub_info).proc_root = create_proc_entry("dri", S_IFDIR, NULL);
+			if (!DRM(stub_info).proc_root) {
+				DRM_ERROR("Cannot create /proc/dri\n");
+				inter_module_unregister("drm");
+				unregister_chrdev(DRM_MAJOR, "drm");
+				class_simple_destroy(DRM(stub_info).drm_class);
+				return -1;
+			}
+		
+		}
+	} else
+		DRM_DEBUG("already retrieved inter_module information\n");
 
-	if (i) {
-				/* Already registered */
-		DRM(stub_info).info_register   = i->info_register;
-		DRM(stub_info).info_unregister = i->info_unregister;
-		DRM_DEBUG("already registered\n");
-	} else if (DRM(stub_info).info_register != DRM(stub_getminor)) {
-		DRM(stub_info).info_register   = DRM(stub_getminor);
-		DRM(stub_info).info_unregister = DRM(stub_putminor);
-		DRM_DEBUG("calling inter_module_register\n");
-		inter_module_register("drm", THIS_MODULE, &DRM(stub_info));
-	}
 	if (DRM(stub_info).info_register) {
 		ret2 = DRM(stub_info).info_register(name, fops, dev);
-		if (ret2) {
-			if (!ret1) {
+		if (ret2 < 0) {
+			if (DRM(numdevs) == 0 && !i) {
+				inter_module_unregister("drm");
 				unregister_chrdev(DRM_MAJOR, "drm");
-				class_simple_destroy(drm_class);
+				class_simple_destroy(DRM(stub_info).drm_class);
+				remove_proc_entry("dri", NULL);
+				DRM_DEBUG("info_register failed, deregistered everything\n");
 			}
-			if (!i)
-				inter_module_unregister("drm");
+			DRM_DEBUG("info_register failed\n");
 		}
 		return ret2;
 	}
@@ -234,3 +320,14 @@
 		return DRM(stub_info).info_unregister(minor);
 	return -1;
 }
+
+int DRM(stub_count);
+
+/** Stub information */
+struct drm_stub_info DRM(stub_info) = {
+	.info_register   = DRM(stub_getminor),
+	.info_unregister = DRM(stub_putminor),
+	.drm_class = NULL,
+	.info_count = &DRM(stub_count),
+	.proc_root = NULL,
+};
diff -Nru a/drivers/char/drm/gamma_old_dma.h b/drivers/char/drm/gamma_old_dma.h
--- a/drivers/char/drm/gamma_old_dma.h	2004-08-25 19:41:26 -07:00
+++ b/drivers/char/drm/gamma_old_dma.h	2004-08-25 19:41:26 -07:00
@@ -121,9 +121,10 @@
 	drm_buf_t	  *buf;
 	int		  idx;
 	int		  while_locked = 0;
+	int		  retcode   = 0;
 	drm_device_dma_t  *dma = dev->dma;
-	int		  *ind;
-	int		  err;
+	int		  *send_indices = NULL;
+	int		  *send_sizes = NULL;
 	DECLARE_WAITQUEUE(entry, current);
 
 	DRM_DEBUG("%d\n", d->send_count);
@@ -170,35 +171,48 @@
 		remove_wait_queue(&q->write_queue, &entry);
 	}
 
-	ind = DRM(alloc)(d->send_count * sizeof(int), DRM_MEM_DRIVER);
-	if (!ind)
+	send_indices = DRM(alloc)(d->send_count * sizeof(*send_indices),
+				  DRM_MEM_DRIVER);
+	if (send_indices == NULL)
 		return -ENOMEM;
-
-	if (copy_from_user(ind, d->send_indices, d->send_count * sizeof(int))) {
-		err = -EFAULT;
-                goto out;
+	if (copy_from_user(send_indices, d->send_indices, 
+			   d->send_count * sizeof(*send_indices))) {
+		retcode = -EFAULT;
+                goto cleanup;
+	}
+	
+	send_sizes = DRM(alloc)(d->send_count * sizeof(*send_sizes),
+				DRM_MEM_DRIVER);
+	if (send_sizes == NULL)
+		return -ENOMEM;
+	if (copy_from_user(send_sizes, d->send_sizes, 
+			   d->send_count * sizeof(*send_sizes))) {
+		retcode = -EFAULT;
+                goto cleanup;
 	}
 
-	err = -EINVAL;
 	for (i = 0; i < d->send_count; i++) {
-		idx = ind[i];
+		idx = send_indices[i];
 		if (idx < 0 || idx >= dma->buf_count) {
 			DRM_ERROR("Index %d (of %d max)\n",
-				  ind[i], dma->buf_count - 1);
-			goto out;
+				  send_indices[i], dma->buf_count - 1);
+			retcode = -EINVAL;
+			goto cleanup;
 		}
 		buf = dma->buflist[ idx ];
 		if (buf->filp != filp) {
 			DRM_ERROR("Process %d using buffer not owned\n",
 				  current->pid);
-			goto out;
+			retcode = -EINVAL;
+			goto cleanup;
 		}
 		if (buf->list != DRM_LIST_NONE) {
 			DRM_ERROR("Process %d using buffer %d on list %d\n",
 				  current->pid, buf->idx, buf->list);
-			goto out;
+			retcode = -EINVAL;
+			goto cleanup;
 		}
-		buf->used	  = ind[i];
+		buf->used	  = send_sizes[i];
 		buf->while_locked = while_locked;
 		buf->context	  = d->context;
 		if (!buf->used) {
@@ -207,14 +221,16 @@
 		if (buf->pending) {
 			DRM_ERROR("Queueing pending buffer:"
 				  " buffer %d, offset %d\n",
-				  ind[i], i);
-			goto out;
+				  send_indices[i], i);
+			retcode = -EINVAL;
+			goto cleanup;
 		}
 		if (buf->waiting) {
 			DRM_ERROR("Queueing waiting buffer:"
 				  " buffer %d, offset %d\n",
-				  ind[i], i);
-			goto out;
+				  send_indices[i], i);
+			retcode = -EINVAL;
+			goto cleanup;
 		}
 		buf->waiting = 1;
 		if (atomic_read(&q->use_count) == 1
@@ -225,14 +241,15 @@
 			atomic_inc(&q->total_queued);
 		}
 	}
+cleanup:
+	if (send_indices)
+		DRM(free)(send_indices, d->send_count * sizeof(*send_indices), 
+			  DRM_MEM_DRIVER);
+	if (send_sizes)
+		DRM(free)(send_sizes, d->send_count * sizeof(*send_sizes), 
+			  DRM_MEM_DRIVER);
 	atomic_dec(&q->use_count);
-
-	return 0;
-
-out:
-	DRM(free)(ind, d->send_count * sizeof(int), DRM_MEM_DRIVER);
-	atomic_dec(&q->use_count);
-	return err;
+	return retcode;
 }
 
 static int DRM(dma_get_buffers_of_order)(struct file *filp, drm_dma_t *d,
diff -Nru a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
--- a/drivers/char/drm/i810_dma.c	2004-08-25 19:41:26 -07:00
+++ b/drivers/char/drm/i810_dma.c	2004-08-25 19:41:26 -07:00
@@ -844,13 +844,10 @@
 	if (buf_priv->currently_mapped == I810_BUF_MAPPED) {
 		unsigned int prim = (sarea_priv->vertex_prim & PR_MASK);
 
-		put_user((GFX_OP_PRIMITIVE | prim |
-					     ((used/4)-2)),
-		(u32 __user *)buf_priv->virtual);
+		*(u32 *)buf_priv->kernel_virtual = ((GFX_OP_PRIMITIVE | prim | ((used/4)-2)));
 
 		if (used & 4) {
-			put_user(0,
-			(u32 __user *)((u32)buf_priv->virtual + used));
+			*(u32 *)((u32)buf_priv->kernel_virtual + used) = 0;
 			used += 4;
 		}
 
diff -Nru a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c
--- a/drivers/char/drm/i830_dma.c	2004-08-25 19:41:26 -07:00
+++ b/drivers/char/drm/i830_dma.c	2004-08-25 19:41:26 -07:00
@@ -1166,19 +1166,19 @@
    	DRM_DEBUG(  "start + used - 4 : %ld\n", start + used - 4);
 
 	if (buf_priv->currently_mapped == I830_BUF_MAPPED) {
-		u32  __user *vp = buf_priv->virtual;
+		u32 *vp = buf_priv->kernel_virtual;
 
-		put_user( (GFX_OP_PRIMITIVE |
-			 sarea_priv->vertex_prim |
-			  ((used/4)-2)), &vp[0]);
+		vp[0] = (GFX_OP_PRIMITIVE |
+			sarea_priv->vertex_prim |
+			((used/4)-2));
 
 		if (dev_priv->use_mi_batchbuffer_start) {
-			put_user(MI_BATCH_BUFFER_END, &vp[used/4]);
+			vp[used/4] = MI_BATCH_BUFFER_END;
 			used += 4; 
 		}
 		
 		if (used & 4) {
-			put_user(0, &vp[used/4]);
+			vp[used/4] = 0;
 			used += 4;
 		}
 
diff -Nru a/drivers/char/drm/i915.h b/drivers/char/drm/i915.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/char/drm/i915.h	2004-08-25 19:41:26 -07:00
@@ -0,0 +1,95 @@
+/* i915.h -- Intel I915 DRM template customization -*- linux-c -*-
+ */
+/**************************************************************************
+ * 
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ * 
+ **************************************************************************/
+
+#ifndef __I915_H__
+#define __I915_H__
+
+/* This remains constant for all DRM template files.
+ */
+#define DRM(x) i915_##x
+
+/* General customization:
+ */
+#define __HAVE_AGP		1
+#define __MUST_HAVE_AGP		1
+#define __HAVE_MTRR		1
+#define __HAVE_CTX_BITMAP	1
+
+#define DRIVER_AUTHOR		"Tungsten Graphics, Inc."
+
+#define DRIVER_NAME		"i915"
+#define DRIVER_DESC		"Intel Graphics"
+#define DRIVER_DATE		"20040405"
+
+/* Interface history:
+ *
+ * 1.1: Original.
+ */
+#define DRIVER_MAJOR		1
+#define DRIVER_MINOR		1
+#define DRIVER_PATCHLEVEL	0
+
+
+#define DRIVER_IOCTLS							    \
+	[DRM_IOCTL_NR(DRM_IOCTL_I915_INIT)]   = { i915_dma_init,    1, 1 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I915_FLUSH)]  = { i915_flush_ioctl, 1, 0 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I915_FLIP)]   = { i915_flip_bufs,   1, 0 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I915_BATCHBUFFER)] = { i915_batchbuffer, 1, 0 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I915_IRQ_EMIT)] = { i915_irq_emit,  1, 0 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I915_IRQ_WAIT)] = { i915_irq_wait,  1, 0 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I915_GETPARAM)] = { i915_getparam,  1, 0 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I915_SETPARAM)] = { i915_setparam,  1, 1 }, \
+        [DRM_IOCTL_NR(DRM_IOCTL_I915_ALLOC)]   = { i915_mem_alloc,  1, 0 }, \
+        [DRM_IOCTL_NR(DRM_IOCTL_I915_FREE)]    = { i915_mem_free,    1, 0 }, \
+        [DRM_IOCTL_NR(DRM_IOCTL_I915_INIT_HEAP)] = { i915_mem_init_heap, 1, 1 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I915_CMDBUFFER)] = { i915_cmdbuffer, 1, 0 }
+
+
+#define __HAVE_COUNTERS         4
+#define __HAVE_COUNTER6         _DRM_STAT_IRQ
+#define __HAVE_COUNTER7         _DRM_STAT_PRIMARY
+#define __HAVE_COUNTER8         _DRM_STAT_SECONDARY
+#define __HAVE_COUNTER9         _DRM_STAT_DMA
+
+/* Driver customization:
+ */
+#define DRIVER_PRETAKEDOWN() do {					\
+	if ( dev->dev_private ) {					\
+		drm_i915_private_t *dev_priv = dev->dev_private;	\
+	        i915_mem_takedown( &(dev_priv->agp_heap) );             \
+ 	}								\
+	i915_dma_cleanup( dev );					\
+} while (0)
+
+
+/* When a client dies:
+ *    - Free any alloced agp memory.
+ */
+#define DRIVER_PRERELEASE() 						\
+do {									\
+	if ( dev->dev_private ) {					\
+		drm_i915_private_t *dev_priv = dev->dev_private;	\
+                i915_mem_release( dev, filp, dev_priv->agp_heap );	\
+	}								\
+} while (0)
+
+
+
+
+/* We use our own dma mechanisms, not the drm template code.  However,
+ * the shared IRQ code is useful to us:
+ */
+#define __HAVE_DMA		0
+#define __HAVE_IRQ		1
+#define __HAVE_SHARED_IRQ	1
+
+
+#define __HAVE_PM		1
+
+#endif
diff -Nru a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/char/drm/i915_dma.c	2004-08-25 19:41:26 -07:00
@@ -0,0 +1,760 @@
+/* i915_dma.c -- DMA support for the I915 -*- linux-c -*-
+ */
+/**************************************************************************
+ * 
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ * 
+ **************************************************************************/
+
+#include "i915.h"
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+
+static inline void i915_print_status_page(drm_device_t *dev)
+{
+      	drm_i915_private_t *dev_priv = dev->dev_private;
+	u32 *temp = dev_priv->hw_status_page;
+
+	if (!temp) {
+		DRM_DEBUG("no status page\n");
+		return;
+	}
+
+   	DRM_DEBUG(  "hw_status: Interrupt Status : %x\n", temp[0]);
+   	DRM_DEBUG(  "hw_status: LpRing Head ptr : %x\n", temp[1]);
+   	DRM_DEBUG(  "hw_status: IRing Head ptr : %x\n", temp[2]);
+      	DRM_DEBUG(  "hw_status: Reserved : %x\n", temp[3]);
+   	DRM_DEBUG(  "hw_status: Driver Counter : %d\n", temp[5]);
+
+}
+
+
+
+
+/* Really want an OS-independent resettable timer.  Would like to have
+ * this loop run for (eg) 3 sec, but have the timer reset every time
+ * the head pointer changes, so that EBUSY only happens if the ring
+ * actually stalls for (eg) 3 seconds.
+ */
+int i915_wait_ring( drm_device_t *dev, int n, const char *caller )
+{
+   	drm_i915_private_t *dev_priv = dev->dev_private;
+   	drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
+	u32 last_head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+	int i;
+
+	for ( i = 0 ; i < 10000 ; i++ ) {
+		ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+	   	ring->space = ring->head - (ring->tail+8);
+		if (ring->space < 0) ring->space += ring->Size;
+		if ( ring->space >= n )
+			return 0;
+		
+		dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
+
+		if (ring->head != last_head) 
+			i = 0;
+
+		last_head = ring->head;
+	}
+
+	return DRM_ERR(EBUSY);
+}
+
+void i915_kernel_lost_context(drm_device_t *dev)
+{
+      	drm_i915_private_t *dev_priv = dev->dev_private;
+   	drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
+      
+   	ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+     	ring->tail = I915_READ(LP_RING + RING_TAIL) & TAIL_ADDR;
+     	ring->space = ring->head - (ring->tail+8);
+     	if (ring->space < 0) ring->space += ring->Size;
+
+	if (ring->head == ring->tail)
+		dev_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY;
+}
+
+
+int i915_dma_cleanup(drm_device_t *dev)
+{
+	/* Make sure interrupts are disabled here because the uninstall ioctl
+	 * may not have been called from userspace and after dev_private
+	 * is freed, it's too late.
+	 */
+	if (dev->irq) DRM(irq_uninstall)(dev);
+
+	if (dev->dev_private) {
+	   	drm_i915_private_t *dev_priv = 
+	     		(drm_i915_private_t *) dev->dev_private;
+	   
+	   	if (dev_priv->ring.virtual_start) {
+		   	DRM_IOREMAPFREE( &dev_priv->ring.map, dev);
+		}
+
+	   	if (dev_priv->hw_status_page) {
+			pci_free_consistent(dev->pdev, PAGE_SIZE,
+				      dev_priv->hw_status_page,
+				      dev_priv->dma_status_page);
+		   	/* Need to rewrite hardware status page */
+		   	I915_WRITE(0x02080, 0x1ffff000);
+		}
+
+	   	DRM(free)(dev->dev_private, sizeof(drm_i915_private_t), 
+			 DRM_MEM_DRIVER);
+
+	   	dev->dev_private = NULL;
+	}
+
+   	return 0;
+}
+
+
+
+static int i915_initialize(drm_device_t *dev, 
+			       drm_i915_private_t *dev_priv,
+			       drm_i915_init_t *init)
+{
+   	memset(dev_priv, 0, sizeof(drm_i915_private_t));
+
+	DRM_GETSAREA();
+	if(!dev_priv->sarea) {
+		DRM_ERROR("can not find sarea!\n");
+		dev->dev_private = (void *)dev_priv;
+		i915_dma_cleanup(dev);
+		return DRM_ERR(EINVAL);
+	}
+
+	DRM_FIND_MAP( dev_priv->mmio_map, init->mmio_offset );
+	if(!dev_priv->mmio_map) {
+		dev->dev_private = (void *)dev_priv;
+		i915_dma_cleanup(dev);
+		DRM_ERROR("can not find mmio map!\n");
+		return DRM_ERR(EINVAL);
+	}
+
+	dev_priv->sarea_priv = (drm_i915_sarea_t *)
+		((u8 *)dev_priv->sarea->handle +
+		 init->sarea_priv_offset);
+
+   	dev_priv->ring.Start = init->ring_start;
+   	dev_priv->ring.End = init->ring_end;
+   	dev_priv->ring.Size = init->ring_size;
+   	dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
+		
+	dev_priv->ring.map.offset = init->ring_start;
+	dev_priv->ring.map.size = init->ring_size;
+	dev_priv->ring.map.type = 0;
+	dev_priv->ring.map.flags = 0;
+	dev_priv->ring.map.mtrr = 0;
+
+	DRM_IOREMAP( &dev_priv->ring.map, dev );
+
+   	if (dev_priv->ring.map.handle == NULL) {
+		dev->dev_private = (void *) dev_priv;
+	   	i915_dma_cleanup(dev);
+	   	DRM_ERROR("can not ioremap virtual address for"
+			  " ring buffer\n");
+	   	return DRM_ERR(ENOMEM);
+	}
+
+   	dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
+   
+	dev_priv->back_offset = init->back_offset;
+	dev_priv->front_offset = init->front_offset;
+	dev_priv->current_page = 0;
+	dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
+
+	/* We are using separate values as placeholders for mechanisms for
+	 * private backbuffer/depthbuffer usage.
+	 */
+	dev_priv->use_mi_batchbuffer_start = 0;
+
+	/* Allow hardware batchbuffers unless told otherwise.
+	 */
+	dev_priv->allow_batchbuffer = 1;
+
+   	/* Program Hardware Status Page */
+   	dev_priv->hw_status_page =
+		pci_alloc_consistent( dev->pdev, PAGE_SIZE, 
+						&dev_priv->dma_status_page );
+
+   	if (!dev_priv->hw_status_page) {
+		dev->dev_private = (void *)dev_priv;
+		i915_dma_cleanup(dev);
+		DRM_ERROR("Can not allocate hardware status page\n");
+		return DRM_ERR(ENOMEM);
+	}
+   	memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
+	DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
+   
+   	I915_WRITE(0x02080, dev_priv->dma_status_page);
+	DRM_DEBUG("Enabled hardware status page\n");
+   
+	dev->dev_private = (void *)dev_priv;
+
+   	return 0;
+}
+
+
+static int i915_resume(drm_device_t *dev)
+{
+	drm_i915_private_t *dev_priv = 
+		(drm_i915_private_t *) dev->dev_private;
+
+	DRM_DEBUG( "%s\n", __FUNCTION__);
+		   
+	if(!dev_priv->sarea) {
+		DRM_ERROR("can not find sarea!\n");
+		return DRM_ERR(EINVAL);
+	}
+
+	if(!dev_priv->mmio_map) {
+		DRM_ERROR("can not find mmio map!\n");
+		return DRM_ERR(EINVAL);
+	}
+
+   	if (dev_priv->ring.map.handle == NULL) {
+	   	DRM_ERROR("can not ioremap virtual address for"
+			  " ring buffer\n");
+	   	return DRM_ERR(ENOMEM);
+	}
+
+   	/* Program Hardware Status Page */
+   	if (!dev_priv->hw_status_page) {
+		DRM_ERROR("Can not find hardware status page\n");
+		return DRM_ERR(EINVAL);
+	}
+	DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
+   
+   	I915_WRITE(0x02080, dev_priv->dma_status_page);
+	DRM_DEBUG("Enabled hardware status page\n");
+
+   	return 0;
+}
+
+
+int i915_dma_init( DRM_IOCTL_ARGS )
+{
+	DRM_DEVICE;
+   	drm_i915_private_t *dev_priv;
+   	drm_i915_init_t init;
+   	int retcode = 0;
+	
+  	DRM_COPY_FROM_USER_IOCTL( init, (drm_i915_init_t __user *)data, sizeof(init));
+	
+   	switch(init.func) {
+	 	case I915_INIT_DMA:
+			dev_priv = DRM(alloc)(sizeof(drm_i915_private_t), 
+					      DRM_MEM_DRIVER);
+	   		if(dev_priv == NULL) 
+				return DRM_ERR(ENOMEM);
+	   		retcode = i915_initialize(dev, dev_priv, &init);
+	   	break;
+	 	case I915_CLEANUP_DMA:
+	   		retcode = i915_dma_cleanup(dev);
+	   	break;
+		case I915_RESUME_DMA:
+			retcode = i915_resume(dev);
+	   	break;
+	 	default:
+	   		retcode = -EINVAL;
+	   	break;
+	}
+   
+   	return retcode;
+}
+
+
+
+/* Implement basically the same security restrictions as hardware does
+ * for MI_BATCH_NON_SECURE.  These can be made stricter at any time.
+ *
+ * Most of the calculations below involve calculating the size of a
+ * particular instruction.  It's important to get the size right as
+ * that tells us where the next instruction to check is.  Any illegal
+ * instruction detected will be given a size of zero, which is a
+ * signal to abort the rest of the buffer.
+ */
+static int do_validate_cmd( int cmd )
+{
+	switch (((cmd>>29) & 0x7)) {
+	case 0x0:
+		switch ((cmd>>23) & 0x3f) {
+		case 0x0: 
+			return 1; /* MI_NOOP */
+		case 0x4: 
+			return 1; /* MI_FLUSH */
+		default: 
+			return 0; /* disallow everything else */
+		}
+		break;
+	case 0x1: 
+		return 0;	/* reserved */
+	case 0x2: 
+		return (cmd & 0xff) + 2; /* 2d commands */
+	case 0x3:
+		if (((cmd>>24) & 0x1f) <= 0x18)
+			return 1;
+
+		switch ((cmd>>24) & 0x1f) {
+		case 0x1c: 
+			return 1;
+		case 0x1d:
+			switch ((cmd>>16)&0xff) {
+			case 0x3:
+				return (cmd & 0x1f) + 2;
+			case 0x4:
+				return (cmd & 0xf) + 2;
+			default:
+				return (cmd & 0xffff) + 2;
+			}
+		case 0x1e: 
+			if (cmd & (1<<23)) 
+				return (cmd & 0xffff) + 1;
+			else
+				return 1;
+		case 0x1f:
+			if ((cmd & (1<<23)) == 0) /* inline vertices */
+				return (cmd & 0x1ffff) + 2;
+			else if (cmd & (1<<17)) /* indirect random */
+				if ((cmd & 0xffff) == 0)
+					return 0; /* unknown length, too hard */
+				else
+					return (((cmd & 0xffff) + 1) / 2) + 1;
+			else
+				return 2; /* indirect sequential */
+		default: 
+			return 0;
+		}
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int validate_cmd( int cmd )
+{
+	int ret = do_validate_cmd( cmd );
+	
+/* 	printk("validate_cmd( %x ): %d\n", cmd, ret); */
+
+	return ret;
+}
+	
+	
+
+static int i915_emit_cmds( drm_device_t *dev,
+			   int __user *buffer,
+			   int dwords )
+{
+   	drm_i915_private_t *dev_priv = dev->dev_private;
+	int i;
+	RING_LOCALS;
+
+	for (i = 0 ; i < dwords ; ) {
+		int cmd, sz;
+
+		if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], sizeof(cmd)))
+			return DRM_ERR( EINVAL );
+
+/* 		printk("%d/%d ", i, dwords); */
+
+		if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords) 
+			return DRM_ERR( EINVAL );
+
+		BEGIN_LP_RING( sz );
+		OUT_RING(cmd);
+
+		while (++i, --sz) {
+			if (DRM_COPY_FROM_USER_UNCHECKED( &cmd, &buffer[i], 
+							  sizeof(cmd))) {
+				return DRM_ERR( EINVAL );
+			}
+			OUT_RING(cmd);
+		}
+		ADVANCE_LP_RING();
+	}
+
+	return 0;
+}
+
+static int i915_emit_box( drm_device_t *dev,
+			  drm_clip_rect_t __user *boxes,
+			  int i,
+			  int DR1,
+			  int DR4)
+{
+   	drm_i915_private_t *dev_priv = dev->dev_private;
+   	drm_clip_rect_t box;
+   	RING_LOCALS;
+
+	if (DRM_COPY_FROM_USER_UNCHECKED( &box, &boxes[i], sizeof(box) )) {
+		return EFAULT;
+	}
+
+	if (box.y2 <= box.y1 ||
+	    box.x2 <= box.x1 ||
+	    box.y2 <= 0 ||
+	    box.x2 <= 0) {
+		DRM_ERROR("Bad box %d,%d..%d,%d\n",
+			  box.x1, box.y1, box.x2, box.y2);
+		return DRM_ERR(EINVAL);
+	}
+				
+
+	BEGIN_LP_RING(6);
+	OUT_RING( GFX_OP_DRAWRECT_INFO );
+	OUT_RING( DR1 );
+	OUT_RING( (box.x1 & 0xffff) | (box.y1<<16) );
+	OUT_RING( ((box.x2-1) & 0xffff) | ((box.y2-1)<<16) );
+	OUT_RING( DR4 );
+	OUT_RING( 0 );
+	ADVANCE_LP_RING();
+	
+	return 0;
+}
+
+
+static int i915_dispatch_cmdbuffer(drm_device_t *dev, 
+				   drm_i915_cmdbuffer_t *cmd )
+{
+   	int nbox = cmd->num_cliprects;
+	int i = 0, count, ret;
+
+	if (cmd->sz & 0x3) {
+		DRM_ERROR("alignment");
+		return DRM_ERR(EINVAL);
+	}
+		
+   	i915_kernel_lost_context(dev);
+
+	count = nbox ? nbox : 1;
+
+	for (i = 0 ; i < count ; i++) {
+		if (i < nbox) {
+			ret = i915_emit_box( dev, cmd->cliprects, i, 
+					     cmd->DR1, cmd->DR4);
+			if (ret) 
+				return ret;
+		}
+
+		ret = i915_emit_cmds( dev, (int __user *)cmd->buf, cmd->sz / 4 );
+		if (ret) 
+			return ret;
+	}
+
+	return 0;
+}
+
+
+
+
+static int i915_dispatch_batchbuffer(drm_device_t *dev, 
+				    drm_i915_batchbuffer_t *batch )
+{
+   	drm_i915_private_t *dev_priv = dev->dev_private;
+   	drm_clip_rect_t __user *boxes = batch->cliprects;
+   	int nbox = batch->num_cliprects;
+	int i = 0, count;
+   	RING_LOCALS;
+
+	if ((batch->start | batch->used) & 0x7) {
+		DRM_ERROR("alignment");
+		return DRM_ERR(EINVAL);
+	}
+		
+   	i915_kernel_lost_context(dev);
+
+	count = nbox ? nbox : 1;
+
+	for (i = 0 ; i < count ; i++) {
+		if (i < nbox) {
+			int ret = i915_emit_box( dev, boxes, i,
+						 batch->DR1, batch->DR4);
+			if (ret) 
+				return ret;
+		}
+
+		if (dev_priv->use_mi_batchbuffer_start) {
+			BEGIN_LP_RING(2);
+			OUT_RING( MI_BATCH_BUFFER_START | (2<<6) );
+			OUT_RING( batch->start | MI_BATCH_NON_SECURE );
+			ADVANCE_LP_RING();
+		} 
+		else {
+			BEGIN_LP_RING(4);
+			OUT_RING( MI_BATCH_BUFFER );
+			OUT_RING( batch->start | MI_BATCH_NON_SECURE );
+			OUT_RING( batch->start + batch->used - 4 );
+			OUT_RING( 0 );
+			ADVANCE_LP_RING();
+		}
+	}
+
+	
+	dev_priv->sarea_priv->last_enqueue = dev_priv->counter++;
+
+	BEGIN_LP_RING(4);
+	OUT_RING( CMD_STORE_DWORD_IDX );
+	OUT_RING( 20 );
+	OUT_RING( dev_priv->counter );
+	OUT_RING( 0 );
+	ADVANCE_LP_RING();
+
+	return 0;
+}
+
+static int i915_dispatch_flip( drm_device_t *dev )
+{
+   	drm_i915_private_t *dev_priv = dev->dev_private;
+	RING_LOCALS;
+
+	DRM_DEBUG( "%s: page=%d pfCurrentPage=%d\n", 
+		   __FUNCTION__, 
+		   dev_priv->current_page,
+		   dev_priv->sarea_priv->pf_current_page);
+
+  	i915_kernel_lost_context(dev);
+
+
+	BEGIN_LP_RING( 2 );
+    	OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); 
+	OUT_RING( 0 );
+	ADVANCE_LP_RING();
+
+	BEGIN_LP_RING( 6 );
+	OUT_RING( CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP );	
+	OUT_RING( 0 );
+	if ( dev_priv->current_page == 0 ) {
+		OUT_RING( dev_priv->back_offset );
+		dev_priv->current_page = 1;
+	} else {
+		OUT_RING( dev_priv->front_offset );
+		dev_priv->current_page = 0;
+	}
+	OUT_RING(0);
+	ADVANCE_LP_RING();
+
+
+	BEGIN_LP_RING( 2 );
+	OUT_RING( MI_WAIT_FOR_EVENT |
+		  MI_WAIT_FOR_PLANE_A_FLIP );
+	OUT_RING( 0 );
+	ADVANCE_LP_RING();
+	
+
+	dev_priv->sarea_priv->last_enqueue = dev_priv->counter++;
+
+	BEGIN_LP_RING(4);
+	OUT_RING( CMD_STORE_DWORD_IDX );
+	OUT_RING( 20 );
+	OUT_RING( dev_priv->counter );
+	OUT_RING( 0 );
+	ADVANCE_LP_RING();
+
+	dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
+	return 0;
+}
+
+
+static int i915_quiescent(drm_device_t *dev)
+{
+   	drm_i915_private_t *dev_priv = dev->dev_private;
+
+  	i915_kernel_lost_context(dev);
+	return i915_wait_ring( dev, dev_priv->ring.Size - 8, __FUNCTION__ );
+}
+
+
+int i915_flush_ioctl( DRM_IOCTL_ARGS )
+{
+	DRM_DEVICE;
+
+   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i915_flush_ioctl called without lock held\n");
+		return DRM_ERR(EINVAL);
+	}
+
+    	return i915_quiescent(dev); 
+}
+
+int i915_batchbuffer( DRM_IOCTL_ARGS )
+{
+	DRM_DEVICE;
+   	drm_i915_private_t *dev_priv = (drm_i915_private_t *)dev->dev_private;
+      	u32 *hw_status = dev_priv->hw_status_page;
+   	drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) 
+     					dev_priv->sarea_priv; 
+	drm_i915_batchbuffer_t batch;
+	int ret;
+
+	if (!dev_priv->allow_batchbuffer) {
+		DRM_ERROR("Batchbuffer ioctl disabled\n");
+		return DRM_ERR(EINVAL);
+	}
+
+	DRM_COPY_FROM_USER_IOCTL( batch, (drm_i915_batchbuffer_t __user *)data, 
+				  sizeof(batch) );
+
+	DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d\n",
+		  batch.start, batch.used, batch.num_cliprects);
+
+
+   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i915_batchbuffer called without lock held\n");
+		return DRM_ERR(EINVAL);
+	}
+
+	if (batch.num_cliprects && DRM_VERIFYAREA_READ(batch.cliprects, 
+						       batch.num_cliprects *
+						       sizeof(drm_clip_rect_t)))
+		return DRM_ERR(EFAULT);
+
+	ret = i915_dispatch_batchbuffer( dev, &batch );
+
+   	sarea_priv->last_dispatch = (int) hw_status[5];   
+	return ret;
+}
+
+int i915_cmdbuffer( DRM_IOCTL_ARGS )
+{
+	DRM_DEVICE;
+   	drm_i915_private_t *dev_priv = (drm_i915_private_t *)dev->dev_private;
+      	u32 *hw_status = dev_priv->hw_status_page;
+   	drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) 
+		dev_priv->sarea_priv; 
+	drm_i915_cmdbuffer_t cmdbuf;
+	int ret;
+
+	DRM_COPY_FROM_USER_IOCTL( cmdbuf, (drm_i915_cmdbuffer_t __user *)data, 
+				  sizeof(cmdbuf) );
+
+	DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n",
+		  cmdbuf.buf, cmdbuf.sz, cmdbuf.num_cliprects);
+
+
+   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i915_cmdbuffer called without lock held\n");
+		return DRM_ERR(EINVAL);
+	}
+
+	if (cmdbuf.num_cliprects && 
+	    DRM_VERIFYAREA_READ(cmdbuf.cliprects, 
+				cmdbuf.num_cliprects *
+				sizeof(drm_clip_rect_t))) {
+		DRM_ERROR("Fault accessing cliprects\n");
+		return DRM_ERR(EFAULT);
+	}
+
+	ret = i915_dispatch_cmdbuffer( dev, &cmdbuf );
+	if (ret) {
+		DRM_ERROR("i915_dispatch_cmdbuffer failed\n");
+		return ret;
+	}
+
+   	sarea_priv->last_dispatch = (int) hw_status[5];   
+	return 0;
+}
+
+
+
+int i915_do_cleanup_pageflip( drm_device_t *dev )
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+	if (dev_priv->current_page != 0)
+		i915_dispatch_flip( dev );
+
+	return 0;
+}
+
+int i915_flip_bufs( DRM_IOCTL_ARGS )
+{
+	DRM_DEVICE;
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i915_flip_buf called without lock held\n");
+		return DRM_ERR(EINVAL);
+	}
+
+	return i915_dispatch_flip( dev );
+}
+
+
+
+int i915_getparam( DRM_IOCTL_ARGS )
+{
+	DRM_DEVICE;
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	drm_i915_getparam_t param;
+	int value;
+
+	if ( !dev_priv ) {
+		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+		return DRM_ERR(EINVAL);
+	}
+
+	DRM_COPY_FROM_USER_IOCTL(param, (drm_i915_getparam_t __user *)data, 
+				 sizeof(param));
+
+	switch( param.param ) {
+	case I915_PARAM_IRQ_ACTIVE:
+		value = dev->irq ? 1 : 0;
+		break;
+	case I915_PARAM_ALLOW_BATCHBUFFER:
+		value = dev_priv->allow_batchbuffer ? 1 : 0;
+		break;
+	default:
+		DRM_ERROR("Unkown parameter %d\n", param.param);
+		return DRM_ERR(EINVAL);
+	}
+
+	if ( DRM_COPY_TO_USER( param.value, &value, sizeof(int) ) ) {
+		DRM_ERROR("DRM_COPY_TO_USER failed\n");
+		return DRM_ERR(EFAULT);
+	}
+	
+	return 0;
+}
+
+
+int i915_setparam( DRM_IOCTL_ARGS )
+{
+	DRM_DEVICE;
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	drm_i915_setparam_t param;
+
+	if ( !dev_priv ) {
+		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+		return DRM_ERR(EINVAL);
+	}
+
+	DRM_COPY_FROM_USER_IOCTL( param, (drm_i915_setparam_t __user *)data, 
+				  sizeof(param) );
+
+	switch( param.param ) {
+	case I915_SETPARAM_USE_MI_BATCHBUFFER_START:
+		dev_priv->use_mi_batchbuffer_start = param.value;
+		break;
+	case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY:
+		dev_priv->tex_lru_log_granularity = param.value;
+		break;
+	case I915_SETPARAM_ALLOW_BATCHBUFFER:
+		dev_priv->allow_batchbuffer = param.value;
+		break;
+	default:
+		DRM_ERROR("unknown parameter %d\n", param.param);
+		return DRM_ERR(EINVAL);
+	}
+
+
+	return 0;
+}
diff -Nru a/drivers/char/drm/i915_drm.h b/drivers/char/drm/i915_drm.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/char/drm/i915_drm.h	2004-08-25 19:41:26 -07:00
@@ -0,0 +1,162 @@
+#ifndef _I915_DRM_H_
+#define _I915_DRM_H_
+
+/* Please note that modifications to all structs defined here are
+ * subject to backwards-compatibility constraints.
+ */
+
+#include "drm.h"
+
+/* Each region is a minimum of 16k, and there are at most 255 of them.
+ */
+#define I915_NR_TEX_REGIONS 255	/* table size 2k - maximum due to use
+				 * of chars for next/prev indices */
+#define I915_LOG_MIN_TEX_REGION_SIZE 14
+
+
+typedef struct _drm_i915_init {
+	enum {
+		I915_INIT_DMA = 0x01,
+		I915_CLEANUP_DMA = 0x02,
+		I915_RESUME_DMA = 0x03
+	} func;
+	unsigned int mmio_offset;
+	int sarea_priv_offset;
+	unsigned int ring_start;
+	unsigned int ring_end;
+	unsigned int ring_size;
+	unsigned int front_offset;
+	unsigned int back_offset;
+	unsigned int depth_offset;
+	unsigned int w;
+	unsigned int h;
+	unsigned int pitch;
+	unsigned int pitch_bits;
+	unsigned int back_pitch;
+	unsigned int depth_pitch;
+	unsigned int cpp;
+        unsigned int chipset;
+} drm_i915_init_t;
+
+
+typedef struct _drm_i915_sarea {
+	drm_tex_region_t texList[I915_NR_TEX_REGIONS+1];
+        int last_upload;	/* last time texture was uploaded */
+        int last_enqueue;	/* last time a buffer was enqueued */
+	int last_dispatch;	/* age of the most recently dispatched buffer */
+	int ctxOwner;		/* last context to upload state */
+	int texAge;
+        int pf_enabled;		/* is pageflipping allowed? */
+        int pf_active;               
+        int pf_current_page;	/* which buffer is being displayed? */
+        int perf_boxes;	        /* performance boxes to be displayed */   
+} drm_i915_sarea_t;
+
+/* Flags for perf_boxes
+ */
+#define I915_BOX_RING_EMPTY    0x1 
+#define I915_BOX_FLIP          0x2 
+#define I915_BOX_WAIT          0x4 
+#define I915_BOX_TEXTURE_LOAD  0x8 
+#define I915_BOX_LOST_CONTEXT  0x10 
+
+
+/* I915 specific ioctls
+ * The device specific ioctl range is 0x40 to 0x79.
+ */
+#define DRM_IOCTL_I915_INIT		DRM_IOW( 0x40, drm_i915_init_t)
+#define DRM_IOCTL_I915_FLUSH		DRM_IO ( 0x41)
+#define DRM_IOCTL_I915_FLIP		DRM_IO ( 0x42)
+#define DRM_IOCTL_I915_BATCHBUFFER	DRM_IOW( 0x43, drm_i915_batchbuffer_t)
+#define DRM_IOCTL_I915_IRQ_EMIT         DRM_IOWR(0x44, drm_i915_irq_emit_t)
+#define DRM_IOCTL_I915_IRQ_WAIT         DRM_IOW( 0x45, drm_i915_irq_wait_t)
+#define DRM_IOCTL_I915_GETPARAM         DRM_IOWR(0x46, drm_i915_getparam_t)
+#define DRM_IOCTL_I915_SETPARAM         DRM_IOW( 0x47, drm_i915_setparam_t)
+#define DRM_IOCTL_I915_ALLOC            DRM_IOWR(0x48, drm_i915_mem_alloc_t)
+#define DRM_IOCTL_I915_FREE             DRM_IOW( 0x49, drm_i915_mem_free_t)
+#define DRM_IOCTL_I915_INIT_HEAP        DRM_IOW( 0x4a, drm_i915_mem_init_heap_t)
+#define DRM_IOCTL_I915_CMDBUFFER	DRM_IOW( 0x4b, drm_i915_cmdbuffer_t)
+
+
+/* Allow drivers to submit batchbuffers directly to hardware, relying
+ * on the security mechanisms provided by hardware.
+ */
+typedef struct _drm_i915_batchbuffer {
+   	int start;		/* agp offset */
+	int used;		/* nr bytes in use */
+	int DR1;		/* hw flags for GFX_OP_DRAWRECT_INFO */
+        int DR4;		/* window origin for GFX_OP_DRAWRECT_INFO*/
+	int num_cliprects;	/* mulitpass with multiple cliprects? */
+        drm_clip_rect_t __user *cliprects; /* pointer to userspace cliprects */
+} drm_i915_batchbuffer_t;
+
+/* As above, but pass a pointer to userspace buffer which can be
+ * validated by the kernel prior to sending to hardware.
+ */
+typedef struct _drm_i915_cmdbuffer {
+   	char __user *buf;	/* pointer to userspace command buffer */
+	int sz;		        /* nr bytes in buf */
+	int DR1;		/* hw flags for GFX_OP_DRAWRECT_INFO */
+        int DR4;		/* window origin for GFX_OP_DRAWRECT_INFO*/
+	int num_cliprects;	/* mulitpass with multiple cliprects? */
+        drm_clip_rect_t __user *cliprects; /* pointer to userspace cliprects */
+} drm_i915_cmdbuffer_t;
+
+
+/* Userspace can request & wait on irq's:
+ */
+typedef struct drm_i915_irq_emit {
+	int __user *irq_seq;
+} drm_i915_irq_emit_t;
+
+typedef struct drm_i915_irq_wait {
+	int irq_seq;
+} drm_i915_irq_wait_t;
+
+
+/* Ioctl to query kernel params:
+ */
+#define I915_PARAM_IRQ_ACTIVE            1
+#define I915_PARAM_ALLOW_BATCHBUFFER     2
+
+typedef struct drm_i915_getparam {
+	int param;
+	int __user *value;
+} drm_i915_getparam_t;
+
+
+/* Ioctl to set kernel params:
+ */
+#define I915_SETPARAM_USE_MI_BATCHBUFFER_START            1
+#define I915_SETPARAM_TEX_LRU_LOG_GRANULARITY             2
+#define I915_SETPARAM_ALLOW_BATCHBUFFER                   3
+
+typedef struct drm_i915_setparam {
+	int param;
+	int value;
+} drm_i915_setparam_t;
+
+/* A memory manager for regions of shared memory:
+ */
+#define I915_MEM_REGION_AGP 1
+
+typedef struct drm_i915_mem_alloc {
+	int region;
+	int alignment;
+	int size;
+	int __user *region_offset;	/* offset from start of fb or agp */
+} drm_i915_mem_alloc_t;
+
+typedef struct drm_i915_mem_free {
+	int region;
+	int region_offset;
+} drm_i915_mem_free_t;
+
+typedef struct drm_i915_mem_init_heap {
+	int region;
+	int size;
+	int start;	
+} drm_i915_mem_init_heap_t;
+
+
+#endif /* _I915_DRM_H_ */
diff -Nru a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/char/drm/i915_drv.c	2004-08-25 19:41:26 -07:00
@@ -0,0 +1,31 @@
+/* i915_drv.c -- i830,i845,i855,i865,i915 driver -*- linux-c -*-
+ */
+
+/**************************************************************************
+ * 
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ * 
+ **************************************************************************/
+
+#include "i915.h"
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+#include "drm_agpsupport.h"	
+#include "drm_auth.h"		/* is this needed? */
+#include "drm_bufs.h"
+#include "drm_context.h"	/* is this needed? */
+#include "drm_drawable.h"	/* is this needed? */
+#include "drm_drv.h"
+#include "drm_fops.h"		
+#include "drm_init.h"
+#include "drm_irq.h"
+#include "drm_ioctl.h"
+#include "drm_lock.h"
+#include "drm_memory.h"		/*  */
+#include "drm_proc.h"
+#include "drm_vm.h"
+#include "drm_stub.h"	
diff -Nru a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/char/drm/i915_drv.h	2004-08-25 19:41:26 -07:00
@@ -0,0 +1,228 @@
+/* i915_drv.h -- Private header for the I915 driver -*- linux-c -*-
+ */
+/**************************************************************************
+ * 
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ * 
+ **************************************************************************/
+
+#ifndef _I915_DRV_H_
+#define _I915_DRV_H_
+
+
+typedef struct _drm_i915_ring_buffer{
+	int tail_mask;
+	unsigned long Start;
+	unsigned long End;
+	unsigned long Size;
+	u8 *virtual_start;
+	int head;
+	int tail;
+	int space;
+	drm_local_map_t map;
+} drm_i915_ring_buffer_t;
+
+struct mem_block {
+	struct mem_block *next;
+	struct mem_block *prev;
+	int start;
+	int size;
+	DRMFILE filp;		/* 0: free, -1: heap, other: real files */
+};
+
+typedef struct drm_i915_private {
+	drm_local_map_t *sarea;
+	drm_local_map_t *mmio_map;
+
+	drm_i915_sarea_t *sarea_priv;
+   	drm_i915_ring_buffer_t ring;
+
+      	void * hw_status_page;
+   	unsigned long counter;
+	dma_addr_t dma_status_page;
+
+	
+	int back_offset;
+	int front_offset;
+	int current_page;
+	int page_flipping;
+	int use_mi_batchbuffer_start;
+	
+
+	wait_queue_head_t irq_queue;
+   	atomic_t irq_received;
+   	atomic_t irq_emitted;
+
+	int tex_lru_log_granularity;
+	int allow_batchbuffer;
+	struct mem_block *agp_heap;
+} drm_i915_private_t;
+
+				/* i915_dma.c */
+extern int i915_dma_init( DRM_IOCTL_ARGS );
+extern int i915_dma_cleanup(drm_device_t *dev);
+extern int i915_flush_ioctl( DRM_IOCTL_ARGS );
+extern int i915_batchbuffer( DRM_IOCTL_ARGS );
+extern int i915_flip_bufs( DRM_IOCTL_ARGS );
+extern int i915_getparam(  DRM_IOCTL_ARGS );
+extern int i915_setparam(  DRM_IOCTL_ARGS );
+extern int i915_cmdbuffer( DRM_IOCTL_ARGS );
+extern void i915_kernel_lost_context(drm_device_t *dev);
+
+/* i915_irq.c */
+extern int i915_irq_emit(  DRM_IOCTL_ARGS );
+extern int i915_irq_wait(  DRM_IOCTL_ARGS );
+extern int i915_wait_irq(drm_device_t *dev, int irq_nr);
+extern int i915_emit_irq(drm_device_t *dev);
+
+
+/* i915_mem.c */
+extern int i915_mem_alloc( DRM_IOCTL_ARGS );
+extern int i915_mem_free( DRM_IOCTL_ARGS );
+extern int i915_mem_init_heap( DRM_IOCTL_ARGS );
+extern void i915_mem_takedown( struct mem_block **heap );
+extern void i915_mem_release( drm_device_t *dev, 
+			      DRMFILE filp, struct mem_block *heap );
+
+#define I915_READ(reg)          DRM_READ32(dev_priv->mmio_map, reg)
+#define I915_WRITE(reg,val)     DRM_WRITE32(dev_priv->mmio_map, reg, val)
+#define I915_READ16(reg) 	DRM_READ16(dev_priv->mmio_map, reg)
+#define I915_WRITE16(reg,val)	DRM_WRITE16(dev_priv->mmio_map, reg, val)
+
+
+
+#define I915_VERBOSE 0
+
+#define RING_LOCALS	unsigned int outring, ringmask, outcount; \
+                        volatile char *virt;
+
+#define BEGIN_LP_RING(n) do {				\
+	if (I915_VERBOSE)				\
+		DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n",	\
+			  n, __FUNCTION__);		\
+	if (dev_priv->ring.space < n*4)			\
+		i915_wait_ring(dev, n*4, __FUNCTION__);		\
+	outcount = 0;					\
+	outring = dev_priv->ring.tail;			\
+	ringmask = dev_priv->ring.tail_mask;		\
+	virt = dev_priv->ring.virtual_start;		\
+} while (0)
+
+
+#define OUT_RING(n) do {					\
+	if (I915_VERBOSE) DRM_DEBUG("   OUT_RING %x\n", (int)(n));	\
+	*(volatile unsigned int *)(virt + outring) = n;		\
+        outcount++;						\
+	outring += 4;						\
+	outring &= ringmask;					\
+} while (0)
+
+#define ADVANCE_LP_RING() do {						\
+	if (I915_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING %x\n", outring);	\
+	dev_priv->ring.tail = outring;					\
+	dev_priv->ring.space -= outcount * 4;				\
+	I915_WRITE(LP_RING + RING_TAIL, outring);			\
+} while(0)
+
+extern int i915_wait_ring(drm_device_t *dev, int n, const char *caller);
+
+
+#define GFX_OP_USER_INTERRUPT 		((0<<29)|(2<<23))
+#define GFX_OP_BREAKPOINT_INTERRUPT	((0<<29)|(1<<23))
+#define CMD_REPORT_HEAD			(7<<23)
+#define CMD_STORE_DWORD_IDX		((0x21<<23) | 0x1)
+#define CMD_OP_BATCH_BUFFER  ((0x0<<29)|(0x30<<23)|0x1)
+
+#define INST_PARSER_CLIENT   0x00000000
+#define INST_OP_FLUSH        0x02000000
+#define INST_FLUSH_MAP_CACHE 0x00000001
+
+
+#define BB1_START_ADDR_MASK   (~0x7)
+#define BB1_PROTECTED         (1<<0)
+#define BB1_UNPROTECTED       (0<<0)
+#define BB2_END_ADDR_MASK     (~0x7)
+
+#define I915REG_HWSTAM		0x02098
+#define I915REG_INT_IDENTITY_R	0x020a4
+#define I915REG_INT_MASK_R 	0x020a8
+#define I915REG_INT_ENABLE_R	0x020a0
+
+#define SRX_INDEX		0x3c4
+#define SRX_DATA		0x3c5
+#define SR01			1
+#define SR01_SCREEN_OFF 	(1<<5)
+
+#define PPCR			0x61204
+#define PPCR_ON			(1<<0)
+
+#define ADPA			0x61100
+#define ADPA_DPMS_MASK		(~(3<<10))
+#define ADPA_DPMS_ON		(0<<10)
+#define ADPA_DPMS_SUSPEND	(1<<10)
+#define ADPA_DPMS_STANDBY	(2<<10)
+#define ADPA_DPMS_OFF		(3<<10)
+
+#define NOPID                   0x2094
+#define LP_RING     		0x2030
+#define HP_RING     		0x2040
+#define RING_TAIL      		0x00
+#define TAIL_ADDR		0x001FFFF8
+#define RING_HEAD      		0x04
+#define HEAD_WRAP_COUNT     	0xFFE00000
+#define HEAD_WRAP_ONE       	0x00200000
+#define HEAD_ADDR           	0x001FFFFC
+#define RING_START     		0x08
+#define START_ADDR          	0x0xFFFFF000
+#define RING_LEN       		0x0C
+#define RING_NR_PAGES       	0x001FF000 
+#define RING_REPORT_MASK    	0x00000006
+#define RING_REPORT_64K     	0x00000002
+#define RING_REPORT_128K    	0x00000004
+#define RING_NO_REPORT      	0x00000000
+#define RING_VALID_MASK     	0x00000001
+#define RING_VALID          	0x00000001
+#define RING_INVALID        	0x00000000
+
+#define GFX_OP_SCISSOR         ((0x3<<29)|(0x1c<<24)|(0x10<<19))
+#define SC_UPDATE_SCISSOR       (0x1<<1)
+#define SC_ENABLE_MASK          (0x1<<0)
+#define SC_ENABLE               (0x1<<0)
+
+#define GFX_OP_SCISSOR_INFO    ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1))
+#define SCI_YMIN_MASK      (0xffff<<16)
+#define SCI_XMIN_MASK      (0xffff<<0)
+#define SCI_YMAX_MASK      (0xffff<<16)
+#define SCI_XMAX_MASK      (0xffff<<0)
+
+#define GFX_OP_SCISSOR_ENABLE	 ((0x3<<29)|(0x1c<<24)|(0x10<<19))
+#define GFX_OP_SCISSOR_RECT	 ((0x3<<29)|(0x1d<<24)|(0x81<<16)|1)
+#define GFX_OP_COLOR_FACTOR      ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0)
+#define GFX_OP_STIPPLE           ((0x3<<29)|(0x1d<<24)|(0x83<<16))
+#define GFX_OP_MAP_INFO          ((0x3<<29)|(0x1d<<24)|0x4)
+#define GFX_OP_DESTBUFFER_VARS   ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0)
+#define GFX_OP_DRAWRECT_INFO     ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3))
+
+
+#define MI_BATCH_BUFFER 	((0x30<<23)|1)
+#define MI_BATCH_BUFFER_START 	(0x31<<23)
+#define MI_BATCH_BUFFER_END 	(0xA<<23)
+#define MI_BATCH_NON_SECURE	(1)
+
+
+
+#define MI_WAIT_FOR_EVENT       ((0x3<<23))
+#define MI_WAIT_FOR_PLANE_A_FLIP      (1<<2) 
+#define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1) 
+
+
+#define MI_LOAD_SCAN_LINES_INCL  ((0x12<<23))
+
+#define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2)
+#define ASYNC_FLIP                (1<<22)
+
+#define CMD_OP_DESTBUFFER_INFO	 ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1)
+
+#endif
+
diff -Nru a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/char/drm/i915_irq.c	2004-08-25 19:41:26 -07:00
@@ -0,0 +1,173 @@
+/* i915_dma.c -- DMA support for the I915 -*- linux-c -*-
+ */
+/**************************************************************************
+ * 
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ * 
+ **************************************************************************/
+
+#define __NO_VERSION__
+#include "i915.h"
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+#define USER_INT_FLAG 0x2
+#define MAX_NOPID ((u32)~0)
+#define READ_BREADCRUMB(dev_priv)  (((u32*)(dev_priv->hw_status_page))[5])
+
+
+irqreturn_t DRM(irq_handler)( DRM_IRQ_ARGS )
+{
+	drm_device_t	 *dev = (drm_device_t *)arg;
+      	drm_i915_private_t *dev_priv = (drm_i915_private_t *)dev->dev_private;
+   	u16 temp;
+
+      	temp = I915_READ16(I915REG_INT_IDENTITY_R);
+	temp &= USER_INT_FLAG;
+	
+	DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp);
+
+   	if (temp == 0) 
+		return IRQ_NONE;
+
+	I915_WRITE16(I915REG_INT_IDENTITY_R, temp); 
+	DRM_WAKEUP( &dev_priv->irq_queue ); 
+
+	return IRQ_HANDLED;
+}
+
+
+int i915_emit_irq(drm_device_t *dev)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	u32 ret;
+	RING_LOCALS;
+
+   	i915_kernel_lost_context(dev);
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	ret = dev_priv->counter;
+
+   	BEGIN_LP_RING(2);
+      	OUT_RING( 0 );
+      	OUT_RING( GFX_OP_USER_INTERRUPT );
+      	ADVANCE_LP_RING();
+
+	return ret;
+}
+
+
+int i915_wait_irq(drm_device_t *dev, int irq_nr)
+{
+  	drm_i915_private_t *dev_priv = 
+	   (drm_i915_private_t *)dev->dev_private;
+	int ret = 0;
+
+	DRM_DEBUG("%s irq_nr=%d breadcrumb=%d\n", __FUNCTION__, irq_nr, READ_BREADCRUMB(dev_priv));
+
+ 	if (READ_BREADCRUMB(dev_priv) >= irq_nr)  
+ 		return 0; 
+
+	dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
+
+	DRM_WAIT_ON( ret, dev_priv->irq_queue, 3 * DRM_HZ,
+		     READ_BREADCRUMB(dev_priv) >= irq_nr );
+
+	if (ret == DRM_ERR(EBUSY)) {
+		DRM_ERROR("%s: EBUSY -- rec: %d emitted: %d\n", 
+			  __FUNCTION__,
+			  READ_BREADCRUMB(dev_priv),
+			  (int)dev_priv->counter);
+	}
+
+      	dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
+	return ret;
+}
+
+
+/* Needs the lock as it touches the ring.
+ */
+int i915_irq_emit( DRM_IOCTL_ARGS )
+{
+	DRM_DEVICE;
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	drm_i915_irq_emit_t emit;
+	int result;
+
+   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i915_irq_emit called without lock held\n");
+		return DRM_ERR(EINVAL);
+	}
+
+	if ( !dev_priv ) {
+		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+		return DRM_ERR(EINVAL);
+	}
+
+	DRM_COPY_FROM_USER_IOCTL( emit, (drm_i915_irq_emit_t __user *)data,
+				  sizeof(emit) );
+
+	result = i915_emit_irq( dev );
+
+	if ( DRM_COPY_TO_USER( emit.irq_seq, &result, sizeof(int) ) ) {
+		DRM_ERROR( "copy_to_user\n" );
+		return DRM_ERR(EFAULT);
+	}
+
+	return 0;
+}
+
+
+/* Doesn't need the hardware lock.
+ */
+int i915_irq_wait( DRM_IOCTL_ARGS )
+{
+	DRM_DEVICE;
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	drm_i915_irq_wait_t irqwait;
+
+	if ( !dev_priv ) {
+		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+		return DRM_ERR(EINVAL);
+	}
+
+	DRM_COPY_FROM_USER_IOCTL( irqwait, (drm_i915_irq_wait_t __user *)data, 
+				  sizeof(irqwait) );
+
+	return i915_wait_irq( dev, irqwait.irq_seq );
+}
+
+
+/* drm_dma.h hooks
+*/
+void DRM(driver_irq_preinstall)( drm_device_t *dev ) {
+	drm_i915_private_t *dev_priv =
+		(drm_i915_private_t *)dev->dev_private;
+
+	I915_WRITE16( I915REG_HWSTAM, 0xfffe );
+	I915_WRITE16( I915REG_INT_MASK_R, 0x0 );
+	I915_WRITE16( I915REG_INT_ENABLE_R, 0x0 );
+}
+
+void DRM(driver_irq_postinstall)( drm_device_t *dev ) {
+	drm_i915_private_t *dev_priv =
+		(drm_i915_private_t *)dev->dev_private;
+
+	I915_WRITE16( I915REG_INT_ENABLE_R, USER_INT_FLAG );
+	DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
+}
+
+void DRM(driver_irq_uninstall)( drm_device_t *dev ) {
+	drm_i915_private_t *dev_priv =
+		(drm_i915_private_t *)dev->dev_private;
+	if (!dev_priv)
+		return;
+
+	I915_WRITE16( I915REG_HWSTAM, 0xffff );
+	I915_WRITE16( I915REG_INT_MASK_R, 0xffff );
+	I915_WRITE16( I915REG_INT_ENABLE_R, 0x0 );
+}
diff -Nru a/drivers/char/drm/i915_mem.c b/drivers/char/drm/i915_mem.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/char/drm/i915_mem.c	2004-08-25 19:41:26 -07:00
@@ -0,0 +1,361 @@
+/* i915_mem.c -- Simple agp/fb memory manager for i915 -*- linux-c -*-
+ */
+/**************************************************************************
+ * 
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ * 
+ **************************************************************************/
+
+#include "i915.h"
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+/* This memory manager is integrated into the global/local lru
+ * mechanisms used by the clients.  Specifically, it operates by
+ * setting the 'in_use' fields of the global LRU to indicate whether
+ * this region is privately allocated to a client.
+ *
+ * This does require the client to actually respect that field.
+ *
+ * Currently no effort is made to allocate 'private' memory in any
+ * clever way - the LRU information isn't used to determine which
+ * block to allocate, and the ring is drained prior to allocations --
+ * in other words allocation is expensive.
+ */
+static void mark_block( drm_device_t *dev, struct mem_block *p,
+			int in_use )
+{
+   drm_i915_private_t *dev_priv = dev->dev_private;
+   drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
+   drm_tex_region_t *list;
+   unsigned   shift, nr;
+   unsigned   start;
+   unsigned   end;
+   unsigned   i;
+   int age;
+
+   shift = dev_priv->tex_lru_log_granularity;
+   nr = I915_NR_TEX_REGIONS;
+
+   start = p->start >> shift;
+   end = (p->start + p->size - 1) >> shift;
+
+   age = ++sarea_priv->texAge;
+   list = sarea_priv->texList;
+
+   /* Mark the regions with the new flag and update their age.  Move
+    * them to head of list to preserve LRU semantics.
+    */
+   for (i = start ; i <= end ; i++) {
+      list[i].in_use = in_use;
+      list[i].age = age;
+
+      /* remove_from_list(i)
+       */
+      list[(unsigned)list[i].next].prev = list[i].prev;
+      list[(unsigned)list[i].prev].next = list[i].next;
+
+      /* insert_at_head(list, i)
+       */
+      list[i].prev = nr;
+      list[i].next = list[nr].next;
+      list[(unsigned)list[nr].next].prev = i;
+      list[nr].next = i;
+   }
+}
+
+
+/* Very simple allocator for agp memory, working on a static range
+ * already mapped into each client's address space.  
+ */
+
+static struct mem_block *split_block(struct mem_block *p, int start, int size,
+				     DRMFILE filp )
+{
+	/* Maybe cut off the start of an existing block */
+	if (start > p->start) {
+		struct mem_block *newblock = DRM_MALLOC(sizeof(*newblock));
+		if (!newblock) 
+			goto out;
+		newblock->start = start;
+		newblock->size = p->size - (start - p->start);
+		newblock->filp = NULL;
+		newblock->next = p->next;
+		newblock->prev = p;
+		p->next->prev = newblock;
+		p->next = newblock;
+		p->size -= newblock->size;
+		p = newblock;
+	}
+   
+	/* Maybe cut off the end of an existing block */
+	if (size < p->size) {
+		struct mem_block *newblock = DRM_MALLOC(sizeof(*newblock));
+		if (!newblock)
+			goto out;
+		newblock->start = start + size;
+		newblock->size = p->size - size;
+		newblock->filp = NULL;
+		newblock->next = p->next;
+		newblock->prev = p;
+		p->next->prev = newblock;
+		p->next = newblock;
+		p->size = size;
+	}
+
+ out:
+	/* Our block is in the middle */
+	p->filp = filp;
+	return p;
+}
+
+static struct mem_block *alloc_block( struct mem_block *heap, int size, 
+				      int align2, DRMFILE filp )
+{
+	struct mem_block *p;
+	int mask = (1 << align2)-1;
+
+	for (p = heap->next ; p != heap ; p = p->next) {
+		int start = (p->start + mask) & ~mask;
+		if (p->filp == NULL && start + size <= p->start + p->size)
+			return split_block( p, start, size, filp );
+	}
+
+	return NULL;
+}
+
+static struct mem_block *find_block( struct mem_block *heap, int start )
+{
+	struct mem_block *p;
+
+	for (p = heap->next ; p != heap ; p = p->next) 
+		if (p->start == start)
+			return p;
+
+	return NULL;
+}
+
+
+static void free_block( struct mem_block *p )
+{
+	p->filp = NULL;
+
+	/* Assumes a single contiguous range.  Needs a special filp in
+	 * 'heap' to stop it being subsumed.
+	 */
+	if (p->next->filp == NULL) {
+		struct mem_block *q = p->next;
+		p->size += q->size;
+		p->next = q->next;
+		p->next->prev = p;
+		DRM_FREE(q, sizeof(*q));
+	}
+
+	if (p->prev->filp == NULL) {
+		struct mem_block *q = p->prev;
+		q->size += p->size;
+		q->next = p->next;
+		q->next->prev = q;
+		DRM_FREE(p, sizeof(*q));
+	}
+}
+
+/* Initialize.  How to check for an uninitialized heap?
+ */
+static int init_heap(struct mem_block **heap, int start, int size)
+{
+	struct mem_block *blocks = DRM_MALLOC(sizeof(*blocks));
+
+	if (!blocks) 
+		return -ENOMEM;
+	
+	*heap = DRM_MALLOC(sizeof(**heap));
+	if (!*heap) {
+		DRM_FREE( blocks, sizeof(*blocks) );
+		return -ENOMEM;
+	}
+
+	blocks->start = start;
+	blocks->size = size;
+	blocks->filp = NULL;
+	blocks->next = blocks->prev = *heap;
+
+	memset( *heap, 0, sizeof(**heap) );
+	(*heap)->filp = (DRMFILE) -1;
+	(*heap)->next = (*heap)->prev = blocks;
+	return 0;
+}
+
+
+/* Free all blocks associated with the releasing file.
+ */
+void i915_mem_release( drm_device_t *dev, 
+		       DRMFILE filp, struct mem_block *heap )
+{
+	struct mem_block *p;
+
+	if (!heap || !heap->next)
+		return;
+
+	for (p = heap->next ; p != heap ; p = p->next) {
+		if (p->filp == filp) {
+			p->filp = NULL;
+			mark_block( dev, p, 0 );
+		}
+	}
+
+	/* Assumes a single contiguous range.  Needs a special filp in
+	 * 'heap' to stop it being subsumed.
+	 */
+	for (p = heap->next ; p != heap ; p = p->next) {
+		while (p->filp == NULL && p->next->filp == NULL) {
+			struct mem_block *q = p->next;
+			p->size += q->size;
+			p->next = q->next;
+			p->next->prev = p;
+			DRM_FREE(q, sizeof(*q));
+		}
+	}
+}
+
+/* Shutdown.
+ */
+void i915_mem_takedown( struct mem_block **heap )
+{
+	struct mem_block *p;
+	
+	if (!*heap)
+		return;
+
+	for (p = (*heap)->next ; p != *heap ; ) {
+		struct mem_block *q = p;
+		p = p->next;
+		DRM_FREE(q, sizeof(*q));
+	}
+
+	DRM_FREE( *heap, sizeof(**heap) );
+	*heap = NULL;
+}
+
+
+
+static struct mem_block **get_heap( drm_i915_private_t *dev_priv,
+				   int region )
+{
+	switch( region ) {
+	case I915_MEM_REGION_AGP:
+ 		return &dev_priv->agp_heap; 
+	default:
+		return NULL;
+	}
+}
+
+
+/* IOCTL HANDLERS */
+
+int i915_mem_alloc( DRM_IOCTL_ARGS )
+{
+	DRM_DEVICE;
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	drm_i915_mem_alloc_t alloc;
+	struct mem_block *block, **heap;
+
+	if ( !dev_priv ) {
+		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+		return DRM_ERR(EINVAL);
+	}
+
+	DRM_COPY_FROM_USER_IOCTL( alloc, (drm_i915_mem_alloc_t __user *)data,
+				  sizeof(alloc) );
+
+	heap = get_heap( dev_priv, alloc.region );
+	if (!heap || !*heap)
+		return DRM_ERR(EFAULT);
+	
+	/* Make things easier on ourselves: all allocations at least
+	 * 4k aligned.
+	 */
+	if (alloc.alignment < 12)
+		alloc.alignment = 12;
+
+	block = alloc_block( *heap, alloc.size, alloc.alignment,
+			     filp );
+
+	if (!block) 
+		return DRM_ERR(ENOMEM);
+
+	mark_block( dev, block, 1 );
+
+	if ( DRM_COPY_TO_USER( alloc.region_offset, &block->start, 
+			       sizeof(int) ) ) {
+		DRM_ERROR( "copy_to_user\n" );
+		return DRM_ERR(EFAULT);
+	}
+	
+	return 0;
+}
+
+
+
+int i915_mem_free( DRM_IOCTL_ARGS )
+{
+	DRM_DEVICE;
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	drm_i915_mem_free_t memfree;
+	struct mem_block *block, **heap;
+
+	if ( !dev_priv ) {
+		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+		return DRM_ERR(EINVAL);
+	}
+
+	DRM_COPY_FROM_USER_IOCTL( memfree, (drm_i915_mem_free_t __user *)data,
+				  sizeof(memfree) );
+
+	heap = get_heap( dev_priv, memfree.region );
+	if (!heap || !*heap)
+		return DRM_ERR(EFAULT);
+	
+	block = find_block( *heap, memfree.region_offset );
+	if (!block)
+		return DRM_ERR(EFAULT);
+
+	if (block->filp != filp)
+		return DRM_ERR(EPERM);
+
+	mark_block( dev, block, 0 );
+	free_block( block );	
+	return 0;
+}
+
+int i915_mem_init_heap( DRM_IOCTL_ARGS )
+{
+	DRM_DEVICE;
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	drm_i915_mem_init_heap_t initheap;
+	struct mem_block **heap;
+
+	if ( !dev_priv ) {
+		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+		return DRM_ERR(EINVAL);
+	}
+
+	DRM_COPY_FROM_USER_IOCTL( initheap, (drm_i915_mem_init_heap_t __user *)data,
+				  sizeof(initheap) );
+
+	heap = get_heap( dev_priv, initheap.region );
+	if (!heap) 
+		return DRM_ERR(EFAULT);
+	
+	if (*heap) {
+		DRM_ERROR("heap already initialized?");
+		return DRM_ERR(EFAULT);
+	}
+		
+	return init_heap( heap, initheap.start, initheap.size );
+}
+
+
diff -Nru a/drivers/char/drm/sis_mm.c b/drivers/char/drm/sis_mm.c
--- a/drivers/char/drm/sis_mm.c	2004-08-25 19:41:26 -07:00
+++ b/drivers/char/drm/sis_mm.c	2004-08-25 19:41:26 -07:00
@@ -90,9 +90,10 @@
 {
 	drm_sis_mem_t fb;
 	struct sis_memreq req;
+	drm_sis_mem_t __user *argp = (void __user *)data;
 	int retval = 0;
 
-	DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t *)data, sizeof(fb));
+	DRM_COPY_FROM_USER_IOCTL(fb, argp, sizeof(fb));
 
 	req.size = fb.size;
 	sis_malloc(&req);
@@ -111,7 +112,7 @@
 		fb.free = 0;
 	}
 
-	DRM_COPY_TO_USER_IOCTL((drm_sis_mem_t *)data, fb, sizeof(fb));
+	DRM_COPY_TO_USER_IOCTL(argp, fb, sizeof(fb));
 
 	DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, req.offset);
 
@@ -123,7 +124,7 @@
 	drm_sis_mem_t fb;
 	int retval = 0;
 
-	DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t *)data, sizeof(fb));
+	DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t __user *)data, sizeof(fb));
 
 	if (!fb.free)
 		return DRM_ERR(EINVAL);