]> err.no Git - linux-2.6/commitdiff
Merge refs/heads/upstream from master.kernel.org:/pub/scm/linux/kernel/git/jgarzik...
authorLinus Torvalds <torvalds@g5.osdl.org>
Tue, 30 Aug 2005 18:16:30 +0000 (11:16 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Tue, 30 Aug 2005 18:16:30 +0000 (11:16 -0700)
146 files changed:
Documentation/sound/alsa/ALSA-Configuration.txt
Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
arch/i386/pci/common.c
arch/i386/pci/i386.c
arch/ppc/syslib/m8xx_setup.c
drivers/char/drm/Kconfig
drivers/char/drm/Makefile
drivers/char/drm/drm.h
drivers/char/drm/drmP.h
drivers/char/drm/drm_agpsupport.c
drivers/char/drm/drm_bufs.c
drivers/char/drm/drm_context.c
drivers/char/drm/drm_drv.c
drivers/char/drm/drm_fops.c
drivers/char/drm/drm_ioctl.c
drivers/char/drm/drm_memory.c
drivers/char/drm/drm_pci.c
drivers/char/drm/drm_pciids.h
drivers/char/drm/drm_proc.c
drivers/char/drm/drm_scatter.c
drivers/char/drm/drm_stub.c
drivers/char/drm/drm_vm.c
drivers/char/drm/ffb_drv.c
drivers/char/drm/gamma_context.h [deleted file]
drivers/char/drm/gamma_dma.c [deleted file]
drivers/char/drm/gamma_drm.h [deleted file]
drivers/char/drm/gamma_drv.c [deleted file]
drivers/char/drm/gamma_drv.h [deleted file]
drivers/char/drm/gamma_lists.h [deleted file]
drivers/char/drm/gamma_lock.h [deleted file]
drivers/char/drm/gamma_old_dma.h [deleted file]
drivers/char/drm/i810_dma.c
drivers/char/drm/i810_drv.c
drivers/char/drm/i810_drv.h
drivers/char/drm/i830_dma.c
drivers/char/drm/i830_drv.c
drivers/char/drm/i830_drv.h
drivers/char/drm/i915_dma.c
drivers/char/drm/i915_drv.c
drivers/char/drm/i915_drv.h
drivers/char/drm/mga_dma.c
drivers/char/drm/mga_drm.h
drivers/char/drm/mga_drv.c
drivers/char/drm/mga_drv.h
drivers/char/drm/mga_ioc32.c
drivers/char/drm/mga_irq.c
drivers/char/drm/mga_state.c
drivers/char/drm/mga_warp.c
drivers/char/drm/r128_cce.c
drivers/char/drm/r128_drm.h
drivers/char/drm/r300_cmdbuf.c [new file with mode: 0644]
drivers/char/drm/r300_reg.h [new file with mode: 0644]
drivers/char/drm/radeon_cp.c
drivers/char/drm/radeon_drm.h
drivers/char/drm/radeon_drv.c
drivers/char/drm/radeon_drv.h
drivers/char/drm/radeon_state.c
drivers/char/drm/savage_bci.c [new file with mode: 0644]
drivers/char/drm/savage_drm.h [new file with mode: 0644]
drivers/char/drm/savage_drv.c [new file with mode: 0644]
drivers/char/drm/savage_drv.h [new file with mode: 0644]
drivers/char/drm/savage_state.c [new file with mode: 0644]
drivers/pci/setup-bus.c
fs/jfs/namei.c
include/linux/sound.h
include/sound/ac97_codec.h
include/sound/ad1816a.h
include/sound/asound.h
include/sound/cs46xx.h
include/sound/emu10k1.h
include/sound/gus.h
include/sound/pcm.h
include/sound/version.h
include/sound/ymfpci.h
sound/arm/pxa2xx-ac97.c
sound/core/memalloc.c
sound/core/memory.c
sound/core/oss/pcm_oss.c
sound/core/pcm_compat.c
sound/core/pcm_lib.c
sound/core/pcm_native.c
sound/core/sound_oss.c
sound/core/timer.c
sound/drivers/vx/vx_mixer.c
sound/drivers/vx/vx_pcm.c
sound/isa/ad1816a/ad1816a.c
sound/isa/ad1816a/ad1816a_lib.c
sound/isa/ad1848/ad1848_lib.c
sound/isa/cmi8330.c
sound/isa/cs423x/cs4231_lib.c
sound/isa/gus/gus_io.c
sound/isa/opl3sa2.c
sound/isa/sb/sb16_main.c
sound/pci/Kconfig
sound/pci/ac97/Makefile
sound/pci/ac97/ac97_bus.c [new file with mode: 0644]
sound/pci/ac97/ac97_codec.c
sound/pci/ac97/ac97_patch.c
sound/pci/ac97/ac97_patch.h
sound/pci/ali5451/ali5451.c
sound/pci/atiixp.c
sound/pci/au88x0/au88x0_pcm.c
sound/pci/ca0106/ca0106_main.c
sound/pci/ca0106/ca0106_mixer.c
sound/pci/cmipci.c
sound/pci/cs46xx/cs46xx.c
sound/pci/cs46xx/cs46xx_lib.c
sound/pci/emu10k1/emu10k1.c
sound/pci/emu10k1/emu10k1_main.c
sound/pci/emu10k1/emu10k1x.c
sound/pci/emu10k1/emufx.c
sound/pci/emu10k1/emumixer.c
sound/pci/emu10k1/emupcm.c
sound/pci/ens1370.c
sound/pci/fm801.c
sound/pci/hda/Makefile
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_patch.h
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_cmedia.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_si3054.c [new file with mode: 0644]
sound/pci/ice1712/delta.c
sound/pci/ice1712/ice1712.c
sound/pci/ice1712/ice1724.c
sound/pci/intel8x0.c
sound/pci/korg1212/korg1212.c
sound/pci/nm256/nm256.c
sound/pci/rme32.c
sound/pci/rme96.c
sound/pci/rme9652/hdsp.c
sound/pci/rme9652/hdspm.c
sound/pci/rme9652/rme9652.c
sound/pci/trident/trident_main.c
sound/pci/via82xx.c
sound/pci/via82xx_modem.c
sound/pci/ymfpci/ymfpci_main.c
sound/pcmcia/vx/vxpocket.c
sound/sound_core.c
sound/synth/emux/emux_synth.c
sound/usb/usbaudio.c
sound/usb/usbmidi.c
sound/usb/usx2y/usx2yhwdeppcm.c

index a18ecb92b356798513d417b609ea3952c573f9cc..5c49ba07e709625516952f4d1147f0ae61464a37 100644 (file)
@@ -132,6 +132,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     mpu_irq    - IRQ # for MPU-401 UART (PnP setup)
     dma1       - first DMA # for AD1816A chip (PnP setup)
     dma2       - second DMA # for AD1816A chip (PnP setup)
+    clockfreq   - Clock frequency for AD1816A chip (default = 0, 33000Hz)
     
     Module supports up to 8 cards, autoprobe and PnP.
     
index db0b7d2dc477cfc01aa0bc10282c850e0c10ae9f..0475478c2484c90c3b14b6c74a4a8efe8fa4941b 100644 (file)
@@ -3422,10 +3422,17 @@ struct _snd_pcm_runtime {
 
       <para>
         The <structfield>iface</structfield> field specifies the type of
-      the control,
-      <constant>SNDRV_CTL_ELEM_IFACE_XXX</constant>. There are
-      <constant>MIXER</constant>, <constant>PCM</constant>,
-      <constant>CARD</constant>, etc.
+      the control, <constant>SNDRV_CTL_ELEM_IFACE_XXX</constant>, which
+      is usually <constant>MIXER</constant>.
+      Use <constant>CARD</constant> for global controls that are not
+      logically part of the mixer.
+      If the control is closely associated with some specific device on
+      the sound card, use <constant>HWDEP</constant>,
+      <constant>PCM</constant>, <constant>RAWMIDI</constant>,
+      <constant>TIMER</constant>, or <constant>SEQUENCER</constant>, and
+      specify the device number with the
+      <structfield>device</structfield> and
+      <structfield>subdevice</structfield> fields.
       </para>
 
       <para>
index ade5bc57c34ceffc54c0e1f3a79f52879bc062e9..c96bea14b98f51301c0ec5a2be83d6142a1b646c 100644 (file)
@@ -165,7 +165,6 @@ static int __init pcibios_init(void)
        if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT))
                pcibios_sort();
 #endif
-       pci_assign_unassigned_resources();
        return 0;
 }
 
index 93a364c82150cddbe8886f8fc35d026120ae0e75..3cc480998a47d4000013cd093aeb0e26b7a5d2ff 100644 (file)
@@ -170,43 +170,26 @@ static void __init pcibios_allocate_resources(int pass)
 static int __init pcibios_assign_resources(void)
 {
        struct pci_dev *dev = NULL;
-       int idx;
-       struct resource *r;
-
-       for_each_pci_dev(dev) {
-               int class = dev->class >> 8;
-
-               /* Don't touch classless devices and host bridges */
-               if (!class || class == PCI_CLASS_BRIDGE_HOST)
-                       continue;
-
-               for(idx=0; idx<6; idx++) {
-                       r = &dev->resource[idx];
-
-                       /*
-                        *  Don't touch IDE controllers and I/O ports of video cards!
-                        */
-                       if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) ||
-                           (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)))
-                               continue;
-
-                       /*
-                        *  We shall assign a new address to this resource, either because
-                        *  the BIOS forgot to do so or because we have decided the old
-                        *  address was unusable for some reason.
-                        */
-                       if (!r->start && r->end)
-                               pci_assign_resource(dev, idx);
-               }
+       struct resource *r, *pr;
 
-               if (pci_probe & PCI_ASSIGN_ROMS) {
+       if (!(pci_probe & PCI_ASSIGN_ROMS)) {
+               /* Try to use BIOS settings for ROMs, otherwise let
+                  pci_assign_unassigned_resources() allocate the new
+                  addresses. */
+               for_each_pci_dev(dev) {
                        r = &dev->resource[PCI_ROM_RESOURCE];
-                       r->end -= r->start;
-                       r->start = 0;
-                       if (r->end)
-                               pci_assign_resource(dev, PCI_ROM_RESOURCE);
+                       if (!r->flags || !r->start)
+                               continue;
+                       pr = pci_find_parent_resource(dev, r);
+                       if (!pr || request_resource(pr, r) < 0) {
+                               r->end -= r->start;
+                               r->start = 0;
+                       }
                }
        }
+
+       pci_assign_unassigned_resources();
+
        return 0;
 }
 
index a3702cfe8f7c70ff25c546b76f8b8cddc01e47eb..4c888da89b3c117c4aa709fc94a36b1165a7e150 100644 (file)
@@ -57,7 +57,7 @@ unsigned char __res[sizeof(bd_t)];
 extern void m8xx_ide_init(void);
 
 extern unsigned long find_available_memory(void);
-extern void m8xx_cpm_reset();
+extern void m8xx_cpm_reset(void);
 extern void m8xx_wdt_handler_install(bd_t *bp);
 extern void rpxfb_alloc_pages(void);
 extern void cpm_interrupt_init(void);
@@ -266,8 +266,8 @@ m8xx_show_percpuinfo(struct seq_file *m, int i)
 
        bp = (bd_t *)__res;
 
-       seq_printf(m, "clock\t\t: %ldMHz\n"
-                  "bus clock\t: %ldMHz\n",
+       seq_printf(m, "clock\t\t: %uMHz\n"
+                  "bus clock\t: %uMHz\n",
                   bp->bi_intfreq / 1000000,
                   bp->bi_busfreq / 1000000);
 
index 123417e430405285dbe282fd3a5d99dd0e53910f..56ace9d5e2aef75b4cd095b3424e4cbc00094b23 100644 (file)
@@ -23,13 +23,6 @@ config DRM_TDFX
          Choose this option if you have a 3dfx Banshee or Voodoo3 (or later),
          graphics card.  If M is selected, the module will be called tdfx.
 
-config DRM_GAMMA
-       tristate "3dlabs GMX 2000"
-       depends on DRM && BROKEN
-       help
-         This is the old gamma driver, please tell me if it might actually
-         work.
-
 config DRM_R128
        tristate "ATI Rage 128"
        depends on DRM && PCI
@@ -82,7 +75,7 @@ endchoice
 
 config DRM_MGA
        tristate "Matrox g200/g400"
-       depends on DRM && AGP
+       depends on DRM
        help
          Choose this option if you have a Matrox G200, G400 or G450 graphics
          card.  If M is selected, the module will be called mga.  AGP
@@ -103,3 +96,10 @@ config DRM_VIA
          Choose this option if you have a Via unichrome or compatible video
          chipset. If M is selected the module will be called via.
 
+config DRM_SAVAGE
+       tristate "Savage video cards"
+       depends on DRM
+       help
+         Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister
+         chipset. If M is selected the module will be called savage.
+
index ddd941045b1f96478742450ae26a1550f941a8df..e41060c76226cd66038d9abfe31b025245b25c72 100644 (file)
@@ -8,16 +8,16 @@ drm-objs    :=        drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \
                drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \
                drm_sysfs.o
 
-gamma-objs  := gamma_drv.o gamma_dma.o
 tdfx-objs   := tdfx_drv.o
 r128-objs   := r128_drv.o r128_cce.o r128_state.o r128_irq.o
 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
+radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o
 ffb-objs    := ffb_drv.o ffb_context.o
 sis-objs    := sis_drv.o sis_ds.o sis_mm.o
+savage-objs := savage_drv.o savage_bci.o savage_state.o
 via-objs    := via_irq.o via_drv.o via_ds.o via_map.o via_mm.o via_dma.o via_verifier.o via_video.o
 
 ifeq ($(CONFIG_COMPAT),y)
@@ -29,7 +29,6 @@ i915-objs   += i915_ioc32.o
 endif
 
 obj-$(CONFIG_DRM)      += drm.o
-obj-$(CONFIG_DRM_GAMMA) += gamma.o
 obj-$(CONFIG_DRM_TDFX) += tdfx.o
 obj-$(CONFIG_DRM_R128) += r128.o
 obj-$(CONFIG_DRM_RADEON)+= radeon.o
@@ -39,5 +38,7 @@ obj-$(CONFIG_DRM_I830)        += i830.o
 obj-$(CONFIG_DRM_I915)  += i915.o
 obj-$(CONFIG_DRM_FFB)   += ffb.o
 obj-$(CONFIG_DRM_SIS)   += sis.o
+obj-$(CONFIG_DRM_SAVAGE)+= savage.o
 obj-$(CONFIG_DRM_VIA)  +=via.o
 
+
index e8371dd87fbca0867953f1e53c07b5ec8b5a19d5..fc6598a81acdd5888fd11893f941e75fa0d13d70 100644 (file)
@@ -98,7 +98,7 @@
 #define _DRM_LOCKING_CONTEXT(lock) ((lock) & ~(_DRM_LOCK_HELD|_DRM_LOCK_CONT))
 
 
-typedef unsigned long drm_handle_t;
+typedef unsigned int  drm_handle_t;
 typedef unsigned int  drm_context_t;
 typedef unsigned int  drm_drawable_t;
 typedef unsigned int  drm_magic_t;
@@ -209,7 +209,8 @@ typedef enum drm_map_type {
        _DRM_REGISTERS      = 1,  /**< no caching, no core dump */
        _DRM_SHM            = 2,  /**< shared, cached */
        _DRM_AGP            = 3,  /**< AGP/GART */
-       _DRM_SCATTER_GATHER = 4   /**< Scatter/gather memory for PCI DMA */
+       _DRM_SCATTER_GATHER = 4,  /**< Scatter/gather memory for PCI DMA */
+       _DRM_CONSISTENT     = 5,  /**< Consistent memory for PCI DMA */
 } drm_map_type_t;
 
 
@@ -368,7 +369,8 @@ typedef struct drm_buf_desc {
        enum {
                _DRM_PAGE_ALIGN = 0x01, /**< Align on page boundaries for DMA */
                _DRM_AGP_BUFFER = 0x02, /**< Buffer is in AGP space */
-               _DRM_SG_BUFFER  = 0x04  /**< Scatter/gather memory buffer */
+               _DRM_SG_BUFFER  = 0x04, /**< Scatter/gather memory buffer */
+               _DRM_FB_BUFFER  = 0x08  /**< Buffer is in frame buffer */
        }             flags;
        unsigned long agp_start; /**< 
                                  * Start address of where the AGP buffers are
index 5df09cc8c6db62a7eab1a2a3e1d6061bbb54c997..6f98701dfe15da844eb19aa5e1483f6b73b21a97 100644 (file)
@@ -53,7 +53,6 @@
 #include <linux/init.h>
 #include <linux/file.h>
 #include <linux/pci.h>
-#include <linux/version.h>
 #include <linux/jiffies.h>
 #include <linux/smp_lock.h>    /* For (un)lock_kernel */
 #include <linux/mm.h>
@@ -96,6 +95,7 @@
 #define DRIVER_IRQ_SHARED  0x80
 #define DRIVER_IRQ_VBL     0x100
 #define DRIVER_DMA_QUEUE   0x200
+#define DRIVER_FB_DMA      0x400
 
 /***********************************************************************/
 /** \name Begin the DRM... */
 #define pte_unmap(pte)
 #endif
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)
-static inline struct page * vmalloc_to_page(void * vmalloc_addr)
-{
-       unsigned long addr = (unsigned long) vmalloc_addr;
-       struct page *page = NULL;
-       pgd_t *pgd = pgd_offset_k(addr);
-       pmd_t *pmd;
-       pte_t *ptep, pte;
-  
-       if (!pgd_none(*pgd)) {
-               pmd = pmd_offset(pgd, addr);
-               if (!pmd_none(*pmd)) {
-                       preempt_disable();
-                       ptep = pte_offset_map(pmd, addr);
-                       pte = *ptep;
-                       if (pte_present(pte))
-                               page = pte_page(pte);
-                       pte_unmap(ptep);
-                       preempt_enable();
-               }
-       }
-       return page;
-}
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#define DRM_RPR_ARG(vma)
-#else
 #define DRM_RPR_ARG(vma) vma,
-#endif
 
 #define VM_OFFSET(vma) ((vma)->vm_pgoff << PAGE_SHIFT)
 
@@ -474,7 +445,8 @@ typedef struct drm_device_dma {
        unsigned long     byte_count;
        enum {
                _DRM_DMA_USE_AGP = 0x01,
-               _DRM_DMA_USE_SG  = 0x02
+               _DRM_DMA_USE_SG  = 0x02,
+               _DRM_DMA_USE_FB  = 0x04
        } flags;
 
 } drm_device_dma_t;
@@ -525,12 +497,19 @@ typedef struct drm_sigdata {
        drm_hw_lock_t *lock;
 } drm_sigdata_t;
 
+typedef struct drm_dma_handle {
+       dma_addr_t busaddr;
+       void *vaddr;
+       size_t size;
+} drm_dma_handle_t;
+
 /**
  * Mappings list
  */
 typedef struct drm_map_list {
        struct list_head        head;   /**< list head */
        drm_map_t               *map;   /**< mapping */
+       unsigned int user_token;
 } drm_map_list_t;
 
 typedef drm_map_t drm_local_map_t;
@@ -578,7 +557,22 @@ struct drm_driver {
        int (*kernel_context_switch)(struct drm_device *dev, int old, int new);
        void (*kernel_context_switch_unlock)(struct drm_device *dev, drm_lock_t *lock);
        int (*vblank_wait)(struct drm_device *dev, unsigned int *sequence);
+       
+       /**
+        * Called by \c drm_device_is_agp.  Typically used to determine if a
+        * card is really attached to AGP or not.
+        *
+        * \param dev  DRM device handle
+        *
+        * \returns
+        * One of three values is returned depending on whether or not the
+        * card is absolutely \b not AGP (return of 0), absolutely \b is AGP
+        * (return of 1), or may or may not be AGP (return of 2).
+        */
+       int (*device_is_agp) (struct drm_device * dev);
+
        /* these have to be filled in */
+  
        int (*postinit)(struct drm_device *, unsigned long flags);
        irqreturn_t (*irq_handler)( DRM_IRQ_ARGS );
        void (*irq_preinstall)(struct drm_device *dev);
@@ -722,11 +716,7 @@ typedef struct drm_device {
        int               pci_slot;     /**< PCI slot number */
        int               pci_func;     /**< PCI function number */
 #ifdef __alpha__
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3)
-       struct pci_controler *hose;
-#else
        struct pci_controller *hose;
-#endif
 #endif
        drm_sg_mem_t      *sg;  /**< Scatter gather memory */
        unsigned long     *ctx_bitmap;  /**< context bitmap */
@@ -736,6 +726,7 @@ typedef struct drm_device {
 
        struct            drm_driver *driver;
        drm_local_map_t   *agp_buffer_map;
+       unsigned int agp_buffer_token;
        drm_head_t primary;             /**< primary screen head */
 } drm_device_t;
 
@@ -806,7 +797,7 @@ extern void      *drm_ioremap_nocache(unsigned long offset, unsigned long size,
                                           drm_device_t *dev);
 extern void         drm_ioremapfree(void *pt, unsigned long size, drm_device_t *dev);
 
-extern DRM_AGP_MEM   *drm_alloc_agp(struct agp_bridge_data *bridge, int pages, u32 type);
+extern DRM_AGP_MEM   *drm_alloc_agp(drm_device_t *dev, int pages, u32 type);
 extern int           drm_free_agp(DRM_AGP_MEM *handle, int pages);
 extern int           drm_bind_agp(DRM_AGP_MEM *handle, unsigned int start);
 extern int           drm_unbind_agp(DRM_AGP_MEM *handle);
@@ -881,11 +872,19 @@ extern int             drm_lock_free(drm_device_t *dev,
                                    unsigned int context);
 
                                /* Buffer management support (drm_bufs.h) */
+extern int drm_addbufs_agp(drm_device_t *dev, drm_buf_desc_t *request);
+extern int drm_addbufs_pci(drm_device_t *dev, drm_buf_desc_t *request);
+extern int drm_addmap(drm_device_t *dev, unsigned int offset,
+                     unsigned int size, drm_map_type_t type,
+                     drm_map_flags_t flags, drm_local_map_t **map_ptr);
+extern int drm_addmap_ioctl(struct inode *inode, struct file *filp,
+                           unsigned int cmd, unsigned long arg);
+extern int drm_rmmap(drm_device_t *dev, drm_local_map_t *map);
+extern int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map);
+extern int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
+                          unsigned int cmd, unsigned long arg);
+
 extern int          drm_order( unsigned long size );
-extern int          drm_addmap( struct inode *inode, struct file *filp,
-                                 unsigned int cmd, unsigned long arg );
-extern int          drm_rmmap( struct inode *inode, struct file *filp,
-                                unsigned int cmd, unsigned long arg );
 extern int          drm_addbufs( struct inode *inode, struct file *filp,
                                   unsigned int cmd, unsigned long arg );
 extern int          drm_infobufs( struct inode *inode, struct file *filp,
@@ -896,6 +895,10 @@ extern int      drm_freebufs( struct inode *inode, struct file *filp,
                                    unsigned int cmd, unsigned long arg );
 extern int          drm_mapbufs( struct inode *inode, struct file *filp,
                                   unsigned int cmd, unsigned long arg );
+extern unsigned long drm_get_resource_start(drm_device_t *dev,
+                                           unsigned int resource);
+extern unsigned long drm_get_resource_len(drm_device_t *dev,
+                                         unsigned int resource);
 
                                /* DMA support (drm_dma.h) */
 extern int          drm_dma_setup(drm_device_t *dev);
@@ -919,15 +922,18 @@ extern void          drm_vbl_send_signals( drm_device_t *dev );
 
                                /* AGP/GART support (drm_agpsupport.h) */
 extern drm_agp_head_t *drm_agp_init(drm_device_t *dev);
-extern int            drm_agp_acquire(struct inode *inode, struct file *filp,
-                                      unsigned int cmd, unsigned long arg);
-extern void           drm_agp_do_release(drm_device_t *dev);
-extern int            drm_agp_release(struct inode *inode, struct file *filp,
-                                      unsigned int cmd, unsigned long arg);
-extern int            drm_agp_enable(struct inode *inode, struct file *filp,
-                                     unsigned int cmd, unsigned long arg);
-extern int            drm_agp_info(struct inode *inode, struct file *filp,
-                                   unsigned int cmd, unsigned long arg);
+extern int drm_agp_acquire(drm_device_t * dev);
+extern int drm_agp_acquire_ioctl(struct inode *inode, struct file *filp,
+                          unsigned int cmd, unsigned long arg);
+extern int drm_agp_release(drm_device_t *dev);
+extern int drm_agp_release_ioctl(struct inode *inode, struct file *filp,
+                          unsigned int cmd, unsigned long arg);
+extern int drm_agp_enable(drm_device_t *dev, drm_agp_mode_t mode);
+extern int drm_agp_enable_ioctl(struct inode *inode, struct file *filp,
+                         unsigned int cmd, unsigned long arg);
+extern int drm_agp_info(drm_device_t * dev, drm_agp_info_t *info);
+extern int drm_agp_info_ioctl(struct inode *inode, struct file *filp,
+                       unsigned int cmd, unsigned long arg);
 extern int            drm_agp_alloc(struct inode *inode, struct file *filp,
                                     unsigned int cmd, unsigned long arg);
 extern int            drm_agp_free(struct inode *inode, struct file *filp,
@@ -976,12 +982,10 @@ extern int            drm_ati_pcigart_cleanup(drm_device_t *dev,
                                               unsigned long addr,
                                               dma_addr_t bus_addr);
 
-extern void *drm_pci_alloc(drm_device_t * dev, size_t size,
-                          size_t align, dma_addr_t maxaddr,
-                          dma_addr_t * busaddr);
-
-extern void drm_pci_free(drm_device_t * dev, size_t size,
-                        void *vaddr, dma_addr_t busaddr);
+extern drm_dma_handle_t *drm_pci_alloc(drm_device_t *dev, size_t size,
+                                      size_t align, dma_addr_t maxaddr);
+extern void __drm_pci_free(drm_device_t *dev, drm_dma_handle_t *dmah);
+extern void drm_pci_free(drm_device_t *dev, drm_dma_handle_t *dmah);
 
                               /* sysfs support (drm_sysfs.c) */
 struct drm_sysfs_class;
@@ -1012,17 +1016,26 @@ static __inline__ void drm_core_ioremapfree(struct drm_map *map, struct drm_devi
                drm_ioremapfree( map->handle, map->size, dev );
 }
 
-static __inline__ struct drm_map *drm_core_findmap(struct drm_device *dev, unsigned long offset)
+static __inline__ struct drm_map *drm_core_findmap(struct drm_device *dev, unsigned int token)
 {
-       struct list_head *_list;
-       list_for_each( _list, &dev->maplist->head ) {
-               drm_map_list_t *_entry = list_entry( _list, drm_map_list_t, head );
-               if ( _entry->map &&
-                    _entry->map->offset == offset ) {
+       drm_map_list_t *_entry;
+       list_for_each_entry(_entry, &dev->maplist->head, head)
+               if (_entry->user_token == token)
                        return _entry->map;
+       return NULL;
+}
+
+static __inline__ int drm_device_is_agp(drm_device_t *dev)
+{
+       if ( dev->driver->device_is_agp != NULL ) {
+               int err = (*dev->driver->device_is_agp)( dev );
+       
+               if (err != 2) {
+                       return err;
                }
        }
-       return NULL;
+
+       return pci_find_capability(dev->pdev, PCI_CAP_ID_AGP);
 }
 
 static __inline__ void drm_core_dropmap(struct drm_map *map)
index 8d94c0b5fa44f00c0859b3c63e1103d5876bc6bc..8c215adcb4b2b623e4848b50fba212a66956799a 100644 (file)
@@ -37,7 +37,7 @@
 #if __OS_HAS_AGP
 
 /**
- * AGP information ioctl.
+ * Get AGP information.
  *
  * \param inode device inode.
  * \param filp file pointer.
  * Verifies the AGP device has been initialized and acquired and fills in the
  * drm_agp_info structure with the information in drm_agp_head::agp_info.
  */
-int drm_agp_info(struct inode *inode, struct file *filp,
-                 unsigned int cmd, unsigned long arg)
+int drm_agp_info(drm_device_t *dev, drm_agp_info_t *info)
 {
-       drm_file_t       *priv   = filp->private_data;
-       drm_device_t     *dev    = priv->head->dev;
        DRM_AGP_KERN     *kern;
-       drm_agp_info_t   info;
 
        if (!dev->agp || !dev->agp->acquired)
                return -EINVAL;
 
        kern                   = &dev->agp->agp_info;
-       info.agp_version_major = kern->version.major;
-       info.agp_version_minor = kern->version.minor;
-       info.mode              = kern->mode;
-       info.aperture_base     = kern->aper_base;
-       info.aperture_size     = kern->aper_size * 1024 * 1024;
-       info.memory_allowed    = kern->max_memory << PAGE_SHIFT;
-       info.memory_used       = kern->current_memory << PAGE_SHIFT;
-       info.id_vendor         = kern->device->vendor;
-       info.id_device         = kern->device->device;
-
-       if (copy_to_user((drm_agp_info_t __user *)arg, &info, sizeof(info)))
+       info->agp_version_major = kern->version.major;
+       info->agp_version_minor = kern->version.minor;
+       info->mode              = kern->mode;
+       info->aperture_base     = kern->aper_base;
+       info->aperture_size     = kern->aper_size * 1024 * 1024;
+       info->memory_allowed    = kern->max_memory << PAGE_SHIFT;
+       info->memory_used       = kern->current_memory << PAGE_SHIFT;
+       info->id_vendor         = kern->device->vendor;
+       info->id_device         = kern->device->device;
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_agp_info);
+
+int drm_agp_info_ioctl(struct inode *inode, struct file *filp,
+                unsigned int cmd, unsigned long arg)
+{
+       drm_file_t *priv = filp->private_data;
+       drm_device_t *dev = priv->head->dev;
+       drm_agp_info_t info;
+       int err;
+
+       err = drm_agp_info(dev, &info);
+       if (err)
+               return err;
+       
+       if (copy_to_user((drm_agp_info_t __user *) arg, &info, sizeof(info)))
                return -EFAULT;
        return 0;
 }
 
 /**
- * Acquire the AGP device (ioctl).
+ * Acquire the AGP device.
  *
- * \param inode device inode.
- * \param filp file pointer.
- * \param cmd command.
- * \param arg user argument.
+ * \param dev DRM device that is to acquire AGP
  * \return zero on success or a negative number on failure. 
  *
  * Verifies the AGP device hasn't been acquired before and calls
- * agp_acquire().
+ * \c agp_backend_acquire.
  */
-int drm_agp_acquire(struct inode *inode, struct file *filp,
-                    unsigned int cmd, unsigned long arg)
+int drm_agp_acquire(drm_device_t *dev)
 {
-       drm_file_t       *priv   = filp->private_data;
-       drm_device_t     *dev    = priv->head->dev;
-
        if (!dev->agp)
                return -ENODEV;
        if (dev->agp->acquired)
@@ -102,9 +107,10 @@ int drm_agp_acquire(struct inode *inode, struct file *filp,
        dev->agp->acquired = 1;
        return 0;
 }
+EXPORT_SYMBOL(drm_agp_acquire);
 
 /**
- * Release the AGP device (ioctl).
+ * Acquire the AGP device (ioctl).
  *
  * \param inode device inode.
  * \param filp file pointer.
@@ -112,63 +118,80 @@ int drm_agp_acquire(struct inode *inode, struct file *filp,
  * \param arg user argument.
  * \return zero on success or a negative number on failure.
  *
- * Verifies the AGP device has been acquired and calls agp_backend_release().
+ * Verifies the AGP device hasn't been acquired before and calls
+ * \c agp_backend_acquire.
  */
-int drm_agp_release(struct inode *inode, struct file *filp,
-                    unsigned int cmd, unsigned long arg)
+int drm_agp_acquire_ioctl(struct inode *inode, struct file *filp,
+                         unsigned int cmd, unsigned long arg)
 {
-       drm_file_t       *priv   = filp->private_data;
-       drm_device_t     *dev    = priv->head->dev;
+       drm_file_t *priv = filp->private_data;
+       
+       return drm_agp_acquire( (drm_device_t *) priv->head->dev );
+}
 
+/**
+ * Release the AGP device.
+ *
+ * \param dev DRM device that is to release AGP
+ * \return zero on success or a negative number on failure.
+ *
+ * Verifies the AGP device has been acquired and calls \c agp_backend_release.
+ */
+int drm_agp_release(drm_device_t *dev)
+{
        if (!dev->agp || !dev->agp->acquired)
                return -EINVAL;
        agp_backend_release(dev->agp->bridge);
        dev->agp->acquired = 0;
        return 0;
-
 }
+EXPORT_SYMBOL(drm_agp_release);
 
-/**
- * Release the AGP device.
- *
- * Calls agp_backend_release().
- */
-void drm_agp_do_release(drm_device_t *dev)
+int drm_agp_release_ioctl(struct inode *inode, struct file *filp,
+                         unsigned int cmd, unsigned long arg)
 {
-  agp_backend_release(dev->agp->bridge);
+       drm_file_t *priv = filp->private_data;
+       drm_device_t *dev = priv->head->dev;
+       
+       return drm_agp_release(dev);
 }
 
 /**
  * Enable the AGP bus.
  * 
- * \param inode device inode.
- * \param filp file pointer.
- * \param cmd command.
- * \param arg pointer to a drm_agp_mode structure.
+ * \param dev DRM device that has previously acquired AGP.
+ * \param mode Requested AGP mode.
  * \return zero on success or a negative number on failure.
  *
  * Verifies the AGP device has been acquired but not enabled, and calls
- * agp_enable().
+ * \c agp_enable.
  */
-int drm_agp_enable(struct inode *inode, struct file *filp,
-                   unsigned int cmd, unsigned long arg)
+int drm_agp_enable(drm_device_t *dev, drm_agp_mode_t mode)
 {
-       drm_file_t       *priv   = filp->private_data;
-       drm_device_t     *dev    = priv->head->dev;
-       drm_agp_mode_t   mode;
-
        if (!dev->agp || !dev->agp->acquired)
                return -EINVAL;
 
-       if (copy_from_user(&mode, (drm_agp_mode_t __user *)arg, sizeof(mode)))
-               return -EFAULT;
-
        dev->agp->mode    = mode.mode;
        agp_enable(dev->agp->bridge, mode.mode);
        dev->agp->base    = dev->agp->agp_info.aper_base;
        dev->agp->enabled = 1;
        return 0;
 }
+EXPORT_SYMBOL(drm_agp_enable);
+
+int drm_agp_enable_ioctl(struct inode *inode, struct file *filp,
+                  unsigned int cmd, unsigned long arg)
+{
+       drm_file_t *priv = filp->private_data;
+       drm_device_t *dev = priv->head->dev;
+       drm_agp_mode_t mode;
+
+
+       if (copy_from_user(&mode, (drm_agp_mode_t __user *) arg, sizeof(mode)))
+               return -EFAULT;
+
+       return drm_agp_enable(dev, mode);
+}
 
 /**
  * Allocate AGP memory.
@@ -206,7 +229,7 @@ int drm_agp_alloc(struct inode *inode, struct file *filp,
        pages = (request.size + PAGE_SIZE - 1) / PAGE_SIZE;
        type = (u32) request.type;
 
-       if (!(memory = drm_alloc_agp(dev->agp->bridge, pages, type))) {
+       if (!(memory = drm_alloc_agp(dev, pages, type))) {
                drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
                return -ENOMEM;
        }
@@ -403,13 +426,8 @@ drm_agp_head_t *drm_agp_init(drm_device_t *dev)
                return NULL;
        }
        head->memory = NULL;
-#if LINUX_VERSION_CODE <= 0x020408
-       head->cant_use_aperture = 0;
-       head->page_mask = ~(0xfff);
-#else
        head->cant_use_aperture = head->agp_info.cant_use_aperture;
        head->page_mask = head->agp_info.page_mask;
-#endif
 
        return head;
 }
@@ -436,6 +454,7 @@ int drm_agp_bind_memory(DRM_AGP_MEM *handle, off_t start)
                return -EINVAL;
        return agp_bind_memory(handle, start);
 }
+EXPORT_SYMBOL(drm_agp_bind_memory);
 
 /** Calls agp_unbind_memory() */
 int drm_agp_unbind_memory(DRM_AGP_MEM *handle)
index 4c6191d231b8e06e20d876af0287d03df9335153..e0743ebbe4bdfd9f5b32064bed2492279671d3d9 100644 (file)
 #include <linux/vmalloc.h>
 #include "drmP.h"
 
-/**
- * Compute size order.  Returns the exponent of the smaller power of two which
- * is greater or equal to given number.
- * 
- * \param size size.
- * \return order.
- *
- * \todo Can be made faster.
- */
-int drm_order( unsigned long size )
+unsigned long drm_get_resource_start(drm_device_t *dev, unsigned int resource)
 {
-       int order;
-       unsigned long tmp;
+       return pci_resource_start(dev->pdev, resource);
+}
+EXPORT_SYMBOL(drm_get_resource_start);
 
-       for (order = 0, tmp = size >> 1; tmp; tmp >>= 1, order++)
-               ;
+unsigned long drm_get_resource_len(drm_device_t *dev, unsigned int resource)
+{
+       return pci_resource_len(dev->pdev, resource);
+}
+EXPORT_SYMBOL(drm_get_resource_len);
 
-       if (size & (size - 1))
-               ++order;
+static drm_local_map_t *drm_find_matching_map(drm_device_t *dev,
+                                             drm_local_map_t *map)
+{
+       struct list_head *list;
 
-       return order;
+       list_for_each(list, &dev->maplist->head) {
+               drm_map_list_t *entry = list_entry(list, drm_map_list_t, head);
+               if (entry->map && map->type == entry->map->type &&
+                   entry->map->offset == map->offset) {
+                       return entry->map;
+               }
+       }
+
+       return NULL;
 }
-EXPORT_SYMBOL(drm_order);
 
-#ifdef CONFIG_COMPAT
 /*
- * Used to allocate 32-bit handles for _DRM_SHM regions
- * The 0x10000000 value is chosen to be out of the way of
- * FB/register and GART physical addresses.
+ * Used to allocate 32-bit handles for mappings.
  */
-static unsigned int map32_handle = 0x10000000;
+#define START_RANGE 0x10000000
+#define END_RANGE 0x40000000
+
+#ifdef _LP64
+static __inline__ unsigned int HandleID(unsigned long lhandle, drm_device_t *dev) 
+{
+       static unsigned int map32_handle = START_RANGE;
+       unsigned int hash;
+
+       if (lhandle & 0xffffffff00000000) {
+               hash = map32_handle;
+               map32_handle += PAGE_SIZE;
+               if (map32_handle > END_RANGE)
+                       map32_handle = START_RANGE;
+       } else 
+               hash = lhandle;
+
+       while (1) {
+               drm_map_list_t *_entry;
+               list_for_each_entry(_entry, &dev->maplist->head,head) {
+                       if (_entry->user_token == hash)
+                               break;
+               }
+               if (&_entry->head == &dev->maplist->head)
+                       return hash;
+
+               hash += PAGE_SIZE;
+               map32_handle += PAGE_SIZE;
+       }
+}
+#else
+# define HandleID(x,dev) (unsigned int)(x)
 #endif
 
 /**
@@ -82,25 +114,23 @@ static unsigned int map32_handle = 0x10000000;
  * type.  Adds the map to the map list drm_device::maplist. Adds MTRR's where
  * applicable and if supported by the kernel.
  */
-int drm_addmap( struct inode *inode, struct file *filp,
-                unsigned int cmd, unsigned long arg )
+int drm_addmap(drm_device_t * dev, unsigned int offset,
+              unsigned int size, drm_map_type_t type,
+              drm_map_flags_t flags, drm_local_map_t ** map_ptr)
 {
-       drm_file_t *priv = filp->private_data;
-       drm_device_t *dev = priv->head->dev;
        drm_map_t *map;
-       drm_map_t __user *argp = (void __user *)arg;
        drm_map_list_t *list;
-
-       if ( !(filp->f_mode & 3) ) return -EACCES; /* Require read/write */
+       drm_dma_handle_t *dmah;
+       drm_local_map_t *found_map;
 
        map = drm_alloc( sizeof(*map), DRM_MEM_MAPS );
        if ( !map )
                return -ENOMEM;
 
-       if ( copy_from_user( map, argp, sizeof(*map) ) ) {
-               drm_free( map, sizeof(*map), DRM_MEM_MAPS );
-               return -EFAULT;
-       }
+       map->offset = offset;
+       map->size = size;
+       map->flags = flags;
+       map->type = type;
 
        /* Only allow shared memory to be removable since we only keep enough
         * book keeping information about shared memory to allow for removal
@@ -122,7 +152,7 @@ int drm_addmap( struct inode *inode, struct file *filp,
        switch ( map->type ) {
        case _DRM_REGISTERS:
        case _DRM_FRAME_BUFFER:
-#if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__)
+#if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__) && !defined(__powerpc64__) && !defined(__x86_64__)
                if ( map->offset + map->size < map->offset ||
                     map->offset < virt_to_phys(high_memory) ) {
                        drm_free( map, sizeof(*map), DRM_MEM_MAPS );
@@ -132,6 +162,24 @@ int drm_addmap( struct inode *inode, struct file *filp,
 #ifdef __alpha__
                map->offset += dev->hose->mem_space->start;
 #endif
+               /* Some drivers preinitialize some maps, without the X Server
+                * needing to be aware of it.  Therefore, we just return success
+                * when the server tries to create a duplicate map.
+                */
+               found_map = drm_find_matching_map(dev, map);
+               if (found_map != NULL) {
+                       if (found_map->size != map->size) {
+                               DRM_DEBUG("Matching maps of type %d with "
+                                  "mismatched sizes, (%ld vs %ld)\n",
+                                   map->type, map->size, found_map->size);
+                               found_map->size = map->size;
+                       }
+
+                       drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+                       *map_ptr = found_map;
+                       return 0;
+               }
+
                if (drm_core_has_MTRR(dev)) {
                        if ( map->type == _DRM_FRAME_BUFFER ||
                             (map->flags & _DRM_WRITE_COMBINING) ) {
@@ -178,9 +226,22 @@ int drm_addmap( struct inode *inode, struct file *filp,
                        drm_free(map, sizeof(*map), DRM_MEM_MAPS);
                        return -EINVAL;
                }
-               map->offset += dev->sg->handle;
+               map->offset += (unsigned long)dev->sg->virtual;
+               break;
+       case _DRM_CONSISTENT: 
+               /* dma_addr_t is 64bit on i386 with CONFIG_HIGHMEM64G,
+                * As we're limiting the address to 2^32-1 (or less),
+                * casting it down to 32 bits is no problem, but we
+                * need to point to a 64bit variable first. */
+               dmah = drm_pci_alloc(dev, map->size, map->size, 0xffffffffUL);
+               if (!dmah) {
+                       drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+                       return -ENOMEM;
+               }
+               map->handle = dmah->vaddr;
+               map->offset = (unsigned long)dmah->busaddr;
+               kfree(dmah);
                break;
-
        default:
                drm_free( map, sizeof(*map), DRM_MEM_MAPS );
                return -EINVAL;
@@ -196,17 +257,56 @@ int drm_addmap( struct inode *inode, struct file *filp,
 
        down(&dev->struct_sem);
        list_add(&list->head, &dev->maplist->head);
-#ifdef CONFIG_COMPAT
-       /* Assign a 32-bit handle for _DRM_SHM mappings */
+       /* Assign a 32-bit handle */
        /* We do it here so that dev->struct_sem protects the increment */
-       if (map->type == _DRM_SHM)
-               map->offset = map32_handle += PAGE_SIZE;
-#endif
+       list->user_token = HandleID(map->type==_DRM_SHM
+                                   ? (unsigned long)map->handle
+                                   : map->offset, dev);
        up(&dev->struct_sem);
 
-       if ( copy_to_user( argp, map, sizeof(*map) ) )
+       *map_ptr = map;
+       return 0;
+}
+EXPORT_SYMBOL(drm_addmap);
+
+int drm_addmap_ioctl(struct inode *inode, struct file *filp,
+                    unsigned int cmd, unsigned long arg)
+{
+       drm_file_t *priv = filp->private_data;
+       drm_device_t *dev = priv->head->dev;
+       drm_map_t map;
+       drm_map_t *map_ptr;
+       drm_map_t __user *argp = (void __user *)arg;
+       int err;
+       unsigned long handle = 0;
+
+       if (!(filp->f_mode & 3))
+               return -EACCES; /* Require read/write */
+
+       if (copy_from_user(& map, argp, sizeof(map))) {
+               return -EFAULT;
+       }
+
+       err = drm_addmap(dev, map.offset, map.size, map.type, map.flags,
+                        &map_ptr);
+
+       if (err) {
+               return err;
+       }
+
+       {
+               drm_map_list_t *_entry;
+               list_for_each_entry(_entry, &dev->maplist->head, head) {
+                       if (_entry->map == map_ptr)
+                               handle = _entry->user_token;
+               }
+               if (!handle)
+                       return -EFAULT;
+       }
+
+       if (copy_to_user(argp, map_ptr, sizeof(*map_ptr)))
                return -EFAULT;
-       if (copy_to_user(&argp->handle, &map->offset, sizeof(map->offset)))
+       if (put_user(handle, &argp->handle))
                return -EFAULT;
        return 0;
 }
@@ -226,81 +326,138 @@ int drm_addmap( struct inode *inode, struct file *filp,
  * its being used, and free any associate resource (such as MTRR's) if it's not
  * being on use.
  *
- * \sa addmap().
+ * \sa drm_addmap
  */
-int drm_rmmap(struct inode *inode, struct file *filp,
-              unsigned int cmd, unsigned long arg)
+int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map)
 {
-       drm_file_t      *priv   = filp->private_data;
-       drm_device_t    *dev    = priv->head->dev;
        struct list_head *list;
        drm_map_list_t *r_list = NULL;
-       drm_vma_entry_t *pt, *prev;
-       drm_map_t *map;
+       drm_dma_handle_t dmah;
+
+       /* Find the list entry for the map and remove it */
+       list_for_each(list, &dev->maplist->head) {
+               r_list = list_entry(list, drm_map_list_t, head);
+
+               if (r_list->map == map) {
+                       list_del(list);
+                       drm_free(list, sizeof(*list), DRM_MEM_MAPS);
+                       break;
+               }
+       }
+
+       /* List has wrapped around to the head pointer, or it's empty and we
+        * didn't find anything.
+        */
+       if (list == (&dev->maplist->head)) {
+               return -EINVAL;
+       }
+
+       switch (map->type) {
+       case _DRM_REGISTERS:
+               drm_ioremapfree(map->handle, map->size, dev);
+               /* FALLTHROUGH */
+       case _DRM_FRAME_BUFFER:
+               if (drm_core_has_MTRR(dev) && map->mtrr >= 0) {
+                       int retcode;
+                       retcode = mtrr_del(map->mtrr, map->offset,
+                                          map->size);
+                       DRM_DEBUG ("mtrr_del=%d\n", retcode);
+               }
+               break;
+       case _DRM_SHM:
+               vfree(map->handle);
+               break;
+       case _DRM_AGP:
+       case _DRM_SCATTER_GATHER:
+               break;
+       case _DRM_CONSISTENT:
+               dmah.vaddr = map->handle;
+               dmah.busaddr = map->offset;
+               dmah.size = map->size;
+               __drm_pci_free(dev, &dmah);
+               break;
+       }
+       drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_rmmap_locked);
+
+int drm_rmmap(drm_device_t *dev, drm_local_map_t *map)
+{
+       int ret;
+
+       down(&dev->struct_sem);
+       ret = drm_rmmap_locked(dev, map);
+       up(&dev->struct_sem);
+
+       return ret;
+}
+EXPORT_SYMBOL(drm_rmmap);
+
+/* The rmmap ioctl appears to be unnecessary.  All mappings are torn down on
+ * the last close of the device, and this is necessary for cleanup when things
+ * exit uncleanly.  Therefore, having userland manually remove mappings seems
+ * like a pointless exercise since they're going away anyway.
+ *
+ * One use case might be after addmap is allowed for normal users for SHM and
+ * gets used by drivers that the server doesn't need to care about.  This seems
+ * unlikely.
+ */
+int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
+                   unsigned int cmd, unsigned long arg)
+{
+       drm_file_t *priv = filp->private_data;
+       drm_device_t *dev = priv->head->dev;
        drm_map_t request;
-       int found_maps = 0;
+       drm_local_map_t *map = NULL;
+       struct list_head *list;
+       int ret;
 
-       if (copy_from_user(&request, (drm_map_t __user *)arg,
-                          sizeof(request))) {
+       if (copy_from_user(&request, (drm_map_t __user *)arg, sizeof(request))) {
                return -EFAULT;
        }
 
        down(&dev->struct_sem);
-       list = &dev->maplist->head;
        list_for_each(list, &dev->maplist->head) {
-               r_list = list_entry(list, drm_map_list_t, head);
+               drm_map_list_t *r_list = list_entry(list, drm_map_list_t, head);
 
-               if(r_list->map &&
-                  r_list->map->offset == (unsigned long) request.handle &&
-                  r_list->map->flags & _DRM_REMOVABLE) break;
+               if (r_list->map &&
+                   r_list->user_token == (unsigned long) request.handle &&
+                   r_list->map->flags & _DRM_REMOVABLE) {
+                       map = r_list->map;
+                       break;
+               }
        }
 
        /* List has wrapped around to the head pointer, or its empty we didn't
         * find anything.
         */
-       if(list == (&dev->maplist->head)) {
+       if (list == (&dev->maplist->head)) {
                up(&dev->struct_sem);
                return -EINVAL;
        }
-       map = r_list->map;
-       list_del(list);
-       drm_free(list, sizeof(*list), DRM_MEM_MAPS);
 
-       for (pt = dev->vmalist, prev = NULL; pt; prev = pt, pt = pt->next) {
-               if (pt->vma->vm_private_data == map) found_maps++;
-       }
+       if (!map)
+               return -EINVAL;
 
-       if(!found_maps) {
-               switch (map->type) {
-               case _DRM_REGISTERS:
-               case _DRM_FRAME_BUFFER:
-                 if (drm_core_has_MTRR(dev)) {
-                               if (map->mtrr >= 0) {
-                                       int retcode;
-                                       retcode = mtrr_del(map->mtrr,
-                                                          map->offset,
-                                                          map->size);
-                                       DRM_DEBUG("mtrr_del = %d\n", retcode);
-                               }
-                       }
-                       drm_ioremapfree(map->handle, map->size, dev);
-                       break;
-               case _DRM_SHM:
-                       vfree(map->handle);
-                       break;
-               case _DRM_AGP:
-               case _DRM_SCATTER_GATHER:
-                       break;
-               }
-               drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+       /* Register and framebuffer maps are permanent */
+       if ((map->type == _DRM_REGISTERS) || (map->type == _DRM_FRAME_BUFFER)) {
+               up(&dev->struct_sem);
+               return 0;
        }
+
+       ret = drm_rmmap_locked(dev, map);
+
        up(&dev->struct_sem);
-       return 0;
+
+       return ret;
 }
 
 /**
  * Cleanup after an error on one of the addbufs() functions.
  *
+ * \param dev DRM device.
  * \param entry buffer entry where the error occurred.
  *
  * Frees any pages and buffers associated with the given entry.
@@ -344,25 +501,19 @@ static void drm_cleanup_buf_error(drm_device_t *dev, drm_buf_entry_t *entry)
 
 #if __OS_HAS_AGP
 /**
- * Add AGP buffers for DMA transfers (ioctl).
+ * Add AGP buffers for DMA transfers.
  *
- * \param inode device inode.
- * \param filp file pointer.
- * \param cmd command.
- * \param arg pointer to a drm_buf_desc_t request.
+ * \param dev drm_device_t to which the buffers are to be added.
+ * \param request pointer to a drm_buf_desc_t describing the request.
  * \return zero on success or a negative number on failure.
  * 
  * After some sanity checks creates a drm_buf structure for each buffer and
  * reallocates the buffer list of the same size order to accommodate the new
  * buffers.
  */
-static int drm_addbufs_agp( struct inode *inode, struct file *filp,
-                           unsigned int cmd, unsigned long arg )
+int drm_addbufs_agp(drm_device_t *dev, drm_buf_desc_t *request)
 {
-       drm_file_t *priv = filp->private_data;
-       drm_device_t *dev = priv->head->dev;
        drm_device_dma_t *dma = dev->dma;
-       drm_buf_desc_t request;
        drm_buf_entry_t *entry;
        drm_buf_t *buf;
        unsigned long offset;
@@ -376,25 +527,20 @@ static int drm_addbufs_agp( struct inode *inode, struct file *filp,
        int byte_count;
        int i;
        drm_buf_t **temp_buflist;
-       drm_buf_desc_t __user *argp = (void __user *)arg;
 
        if ( !dma ) return -EINVAL;
 
-       if ( copy_from_user( &request, argp,
-                            sizeof(request) ) )
-               return -EFAULT;
-
-       count = request.count;
-       order = drm_order( request.size );
+       count = request->count;
+       order = drm_order(request->size);
        size = 1 << order;
 
-       alignment  = (request.flags & _DRM_PAGE_ALIGN)
+       alignment  = (request->flags & _DRM_PAGE_ALIGN)
                ? PAGE_ALIGN(size) : size;
        page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
        total = PAGE_SIZE << page_order;
 
        byte_count = 0;
-       agp_offset = dev->agp->base + request.agp_start;
+       agp_offset = dev->agp->base + request->agp_start;
 
        DRM_DEBUG( "count:      %d\n",  count );
        DRM_DEBUG( "order:      %d\n",  order );
@@ -508,26 +654,20 @@ static int drm_addbufs_agp( struct inode *inode, struct file *filp,
 
        up( &dev->struct_sem );
 
-       request.count = entry->buf_count;
-       request.size = size;
-
-       if ( copy_to_user( argp, &request, sizeof(request) ) )
-               return -EFAULT;
+       request->count = entry->buf_count;
+       request->size = size;
 
        dma->flags = _DRM_DMA_USE_AGP;
 
        atomic_dec( &dev->buf_alloc );
        return 0;
 }
+EXPORT_SYMBOL(drm_addbufs_agp);
 #endif /* __OS_HAS_AGP */
 
-static int drm_addbufs_pci( struct inode *inode, struct file *filp,
-                           unsigned int cmd, unsigned long arg )
+int drm_addbufs_pci(drm_device_t *dev, drm_buf_desc_t *request)
 {
-       drm_file_t *priv = filp->private_data;
-       drm_device_t *dev = priv->head->dev;
        drm_device_dma_t *dma = dev->dma;
-       drm_buf_desc_t request;
        int count;
        int order;
        int size;
@@ -543,26 +683,22 @@ static int drm_addbufs_pci( struct inode *inode, struct file *filp,
        int page_count;
        unsigned long *temp_pagelist;
        drm_buf_t **temp_buflist;
-       drm_buf_desc_t __user *argp = (void __user *)arg;
 
        if (!drm_core_check_feature(dev, DRIVER_PCI_DMA)) return -EINVAL;
        if ( !dma ) return -EINVAL;
 
-       if ( copy_from_user( &request, argp, sizeof(request) ) )
-               return -EFAULT;
-
-       count = request.count;
-       order = drm_order( request.size );
+       count = request->count;
+       order = drm_order(request->size);
        size = 1 << order;
 
        DRM_DEBUG( "count=%d, size=%d (%d), order=%d, queue_count=%d\n",
-                  request.count, request.size, size,
+                  request->count, request->size, size,
                   order, dev->queue_count );
 
        if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) return -EINVAL;
        if ( dev->queue_count ) return -EBUSY; /* Not while in use */
 
-       alignment = (request.flags & _DRM_PAGE_ALIGN)
+       alignment = (request->flags & _DRM_PAGE_ALIGN)
                ? PAGE_ALIGN(size) : size;
        page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
        total = PAGE_SIZE << page_order;
@@ -740,25 +876,18 @@ static int drm_addbufs_pci( struct inode *inode, struct file *filp,
 
        up( &dev->struct_sem );
 
-       request.count = entry->buf_count;
-       request.size = size;
-
-       if ( copy_to_user( argp, &request, sizeof(request) ) )
-               return -EFAULT;
+       request->count = entry->buf_count;
+       request->size = size;
 
        atomic_dec( &dev->buf_alloc );
        return 0;
 
 }
+EXPORT_SYMBOL(drm_addbufs_pci);
 
-static int drm_addbufs_sg( struct inode *inode, struct file *filp,
-                          unsigned int cmd, unsigned long arg )
+static int drm_addbufs_sg(drm_device_t *dev, drm_buf_desc_t *request)
 {
-       drm_file_t *priv = filp->private_data;
-       drm_device_t *dev = priv->head->dev;
        drm_device_dma_t *dma = dev->dma;
-       drm_buf_desc_t __user *argp = (void __user *)arg;
-       drm_buf_desc_t request;
        drm_buf_entry_t *entry;
        drm_buf_t *buf;
        unsigned long offset;
@@ -777,20 +906,17 @@ static int drm_addbufs_sg( struct inode *inode, struct file *filp,
        
        if ( !dma ) return -EINVAL;
 
-       if ( copy_from_user( &request, argp, sizeof(request) ) )
-               return -EFAULT;
-
-       count = request.count;
-       order = drm_order( request.size );
+       count = request->count;
+       order = drm_order(request->size);
        size = 1 << order;
 
-       alignment  = (request.flags & _DRM_PAGE_ALIGN)
+       alignment  = (request->flags & _DRM_PAGE_ALIGN)
                        ? PAGE_ALIGN(size) : size;
        page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
        total = PAGE_SIZE << page_order;
 
        byte_count = 0;
-       agp_offset = request.agp_start;
+       agp_offset = request->agp_start;
 
        DRM_DEBUG( "count:      %d\n",  count );
        DRM_DEBUG( "order:      %d\n",  order );
@@ -848,7 +974,8 @@ static int drm_addbufs_sg( struct inode *inode, struct file *filp,
 
                buf->offset  = (dma->byte_count + offset);
                buf->bus_address = agp_offset + offset;
-               buf->address = (void *)(agp_offset + offset + dev->sg->handle);
+               buf->address = (void *)(agp_offset + offset 
+                                       + (unsigned long)dev->sg->virtual);
                buf->next    = NULL;
                buf->waiting = 0;
                buf->pending = 0;
@@ -905,11 +1032,8 @@ static int drm_addbufs_sg( struct inode *inode, struct file *filp,
 
        up( &dev->struct_sem );
 
-       request.count = entry->buf_count;
-       request.size = size;
-
-       if ( copy_to_user( argp, &request, sizeof(request) ) )
-               return -EFAULT;
+       request->count = entry->buf_count;
+       request->size = size;
 
        dma->flags = _DRM_DMA_USE_SG;
 
@@ -917,6 +1041,161 @@ static int drm_addbufs_sg( struct inode *inode, struct file *filp,
        return 0;
 }
 
+int drm_addbufs_fb(drm_device_t *dev, drm_buf_desc_t *request)
+{
+       drm_device_dma_t *dma = dev->dma;
+       drm_buf_entry_t *entry;
+       drm_buf_t *buf;
+       unsigned long offset;
+       unsigned long agp_offset;
+       int count;
+       int order;
+       int size;
+       int alignment;
+       int page_order;
+       int total;
+       int byte_count;
+       int i;
+       drm_buf_t **temp_buflist;
+
+       if (!drm_core_check_feature(dev, DRIVER_FB_DMA))
+               return -EINVAL;
+    
+       if (!dma)
+               return -EINVAL;
+
+       count = request->count;
+       order = drm_order(request->size);
+       size = 1 << order;
+
+       alignment = (request->flags & _DRM_PAGE_ALIGN)
+           ? PAGE_ALIGN(size) : size;
+       page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
+       total = PAGE_SIZE << page_order;
+
+       byte_count = 0;
+       agp_offset = request->agp_start;
+
+       DRM_DEBUG("count:      %d\n", count);
+       DRM_DEBUG("order:      %d\n", order);
+       DRM_DEBUG("size:       %d\n", size);
+       DRM_DEBUG("agp_offset: %lu\n", agp_offset);
+       DRM_DEBUG("alignment:  %d\n", alignment);
+       DRM_DEBUG("page_order: %d\n", page_order);
+       DRM_DEBUG("total:      %d\n", total);
+
+       if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER)
+               return -EINVAL;
+       if (dev->queue_count)
+               return -EBUSY;  /* Not while in use */
+
+       spin_lock(&dev->count_lock);
+       if (dev->buf_use) {
+               spin_unlock(&dev->count_lock);
+               return -EBUSY;
+       }
+       atomic_inc(&dev->buf_alloc);
+       spin_unlock(&dev->count_lock);
+
+       down(&dev->struct_sem);
+       entry = &dma->bufs[order];
+       if (entry->buf_count) {
+               up(&dev->struct_sem);
+               atomic_dec(&dev->buf_alloc);
+               return -ENOMEM; /* May only call once for each order */
+       }
+
+       if (count < 0 || count > 4096) {
+               up(&dev->struct_sem);
+               atomic_dec(&dev->buf_alloc);
+               return -EINVAL;
+       }
+
+       entry->buflist = drm_alloc(count * sizeof(*entry->buflist),
+                                  DRM_MEM_BUFS);
+       if (!entry->buflist) {
+               up(&dev->struct_sem);
+               atomic_dec(&dev->buf_alloc);
+               return -ENOMEM;
+       }
+       memset(entry->buflist, 0, count * sizeof(*entry->buflist));
+
+       entry->buf_size = size;
+       entry->page_order = page_order;
+
+       offset = 0;
+
+       while (entry->buf_count < count) {
+               buf = &entry->buflist[entry->buf_count];
+               buf->idx = dma->buf_count + entry->buf_count;
+               buf->total = alignment;
+               buf->order = order;
+               buf->used = 0;
+
+               buf->offset = (dma->byte_count + offset);
+               buf->bus_address = agp_offset + offset;
+               buf->address = (void *)(agp_offset + offset);
+               buf->next = NULL;
+               buf->waiting = 0;
+               buf->pending = 0;
+               init_waitqueue_head(&buf->dma_wait);
+               buf->filp = NULL;
+
+               buf->dev_priv_size = dev->driver->dev_priv_size;
+               buf->dev_private = drm_alloc(buf->dev_priv_size, DRM_MEM_BUFS);
+               if (!buf->dev_private) {
+                       /* Set count correctly so we free the proper amount. */
+                       entry->buf_count = count;
+                       drm_cleanup_buf_error(dev, entry);
+                       up(&dev->struct_sem);
+                       atomic_dec(&dev->buf_alloc);
+                       return -ENOMEM;
+               }
+               memset(buf->dev_private, 0, buf->dev_priv_size);
+
+               DRM_DEBUG("buffer %d @ %p\n", entry->buf_count, buf->address);
+
+               offset += alignment;
+               entry->buf_count++;
+               byte_count += PAGE_SIZE << page_order;
+       }
+
+       DRM_DEBUG("byte_count: %d\n", byte_count);
+
+       temp_buflist = drm_realloc(dma->buflist,
+                                  dma->buf_count * sizeof(*dma->buflist),
+                                  (dma->buf_count + entry->buf_count)
+                                  * sizeof(*dma->buflist), DRM_MEM_BUFS);
+       if (!temp_buflist) {
+               /* Free the entry because it isn't valid */
+               drm_cleanup_buf_error(dev, entry);
+               up(&dev->struct_sem);
+               atomic_dec(&dev->buf_alloc);
+               return -ENOMEM;
+       }
+       dma->buflist = temp_buflist;
+
+       for (i = 0; i < entry->buf_count; i++) {
+               dma->buflist[i + dma->buf_count] = &entry->buflist[i];
+       }
+
+       dma->buf_count += entry->buf_count;
+       dma->byte_count += byte_count;
+
+       DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count);
+       DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count);
+
+       up(&dev->struct_sem);
+
+       request->count = entry->buf_count;
+       request->size = size;
+
+       dma->flags = _DRM_DMA_USE_FB;
+
+       atomic_dec(&dev->buf_alloc);
+       return 0;
+}
+
 /**
  * Add buffers for DMA transfers (ioctl).
  *
@@ -937,6 +1216,7 @@ int drm_addbufs( struct inode *inode, struct file *filp,
        drm_buf_desc_t request;
        drm_file_t *priv = filp->private_data;
        drm_device_t *dev = priv->head->dev;
+       int ret;
        
        if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))
                return -EINVAL;
@@ -947,13 +1227,23 @@ int drm_addbufs( struct inode *inode, struct file *filp,
 
 #if __OS_HAS_AGP
        if ( request.flags & _DRM_AGP_BUFFER )
-               return drm_addbufs_agp( inode, filp, cmd, arg );
+               ret=drm_addbufs_agp(dev, &request);
        else
 #endif
        if ( request.flags & _DRM_SG_BUFFER )
-               return drm_addbufs_sg( inode, filp, cmd, arg );
+               ret=drm_addbufs_sg(dev, &request);
+       else if ( request.flags & _DRM_FB_BUFFER)
+               ret=drm_addbufs_fb(dev, &request);
        else
-               return drm_addbufs_pci( inode, filp, cmd, arg );
+               ret=drm_addbufs_pci(dev, &request);
+
+       if (ret==0) {
+               if (copy_to_user((void __user *)arg, &request,
+                                sizeof(request))) {
+                       ret = -EFAULT;
+               }
+       }
+       return ret;
 }
 
 
@@ -1196,43 +1486,31 @@ int drm_mapbufs( struct inode *inode, struct file *filp,
                return -EFAULT;
 
        if ( request.count >= dma->buf_count ) {
-               if ((drm_core_has_AGP(dev) && (dma->flags & _DRM_DMA_USE_AGP)) ||
-                   (drm_core_check_feature(dev, DRIVER_SG) && (dma->flags & _DRM_DMA_USE_SG)) ) {
+               if ((drm_core_has_AGP(dev) && (dma->flags & _DRM_DMA_USE_AGP))
+                   || (drm_core_check_feature(dev, DRIVER_SG) 
+                       && (dma->flags & _DRM_DMA_USE_SG))
+                   || (drm_core_check_feature(dev, DRIVER_FB_DMA)
+                       && (dma->flags & _DRM_DMA_USE_FB))) {
                        drm_map_t *map = dev->agp_buffer_map;
+                       unsigned long token = dev->agp_buffer_token;
 
                        if ( !map ) {
                                retcode = -EINVAL;
                                goto done;
                        }
 
-#if LINUX_VERSION_CODE <= 0x020402
-                       down( &current->mm->mmap_sem );
-#else
                        down_write( &current->mm->mmap_sem );
-#endif
                        virtual = do_mmap( filp, 0, map->size,
                                           PROT_READ | PROT_WRITE,
                                           MAP_SHARED,
-                                          (unsigned long)map->offset );
-#if LINUX_VERSION_CODE <= 0x020402
-                       up( &current->mm->mmap_sem );
-#else
+                                          token );
                        up_write( &current->mm->mmap_sem );
-#endif
                } else {
-#if LINUX_VERSION_CODE <= 0x020402
-                       down( &current->mm->mmap_sem );
-#else
                        down_write( &current->mm->mmap_sem );
-#endif
                        virtual = do_mmap( filp, 0, dma->byte_count,
                                           PROT_READ | PROT_WRITE,
                                           MAP_SHARED, 0 );
-#if LINUX_VERSION_CODE <= 0x020402
-                       up( &current->mm->mmap_sem );
-#else
                        up_write( &current->mm->mmap_sem );
-#endif
                }
                if ( virtual > -1024UL ) {
                        /* Real error */
@@ -1279,3 +1557,26 @@ int drm_mapbufs( struct inode *inode, struct file *filp,
        return retcode;
 }
 
+/**
+ * Compute size order.  Returns the exponent of the smaller power of two which
+ * is greater or equal to given number.
+ * 
+ * \param size size.
+ * \return order.
+ *
+ * \todo Can be made faster.
+ */
+int drm_order( unsigned long size )
+{
+       int order;
+       unsigned long tmp;
+
+       for (order = 0, tmp = size >> 1; tmp; tmp >>= 1, order++)
+               ;
+
+       if (size & (size - 1))
+               ++order;
+
+       return order;
+}
+EXPORT_SYMBOL(drm_order);
index a7cfabd1ca2e9d0801c3e8c10b12cc1acbb0601c..f515567e5b6f3b9545b8023f365c471b55b9db2d 100644 (file)
@@ -212,6 +212,7 @@ int drm_getsareactx(struct inode *inode, struct file *filp,
        drm_ctx_priv_map_t __user *argp = (void __user *)arg;
        drm_ctx_priv_map_t request;
        drm_map_t *map;
+       drm_map_list_t *_entry;
 
        if (copy_from_user(&request, argp, sizeof(request)))
                return -EFAULT;
@@ -225,7 +226,17 @@ int drm_getsareactx(struct inode *inode, struct file *filp,
        map = dev->context_sareas[request.ctx_id];
        up(&dev->struct_sem);
 
-       request.handle = (void *) map->offset;
+       request.handle = 0;
+       list_for_each_entry(_entry, &dev->maplist->head,head) {
+               if (_entry->map == map) {
+                       request.handle = (void *)(unsigned long)_entry->user_token;
+                       break;
+               }
+       }
+       if (request.handle == 0)
+               return -EINVAL;
+
+
        if (copy_to_user(argp, &request, sizeof(request)))
                return -EFAULT;
        return 0;
@@ -262,7 +273,7 @@ int drm_setsareactx(struct inode *inode, struct file *filp,
        list_for_each(list, &dev->maplist->head) {
                r_list = list_entry(list, drm_map_list_t, head);
                if (r_list->map
-                   && r_list->map->offset == (unsigned long) request.handle)
+                   && r_list->user_token == (unsigned long) request.handle)
                        goto found;
        }
 bad:
@@ -369,7 +380,7 @@ int drm_resctx( struct inode *inode, struct file *filp,
                for ( i = 0 ; i < DRM_RESERVED_CONTEXTS ; i++ ) {
                        ctx.handle = i;
                        if ( copy_to_user( &res.contexts[i],
-                                          &i, sizeof(i) ) )
+                                          &ctx, sizeof(ctx) ) )
                                return -EFAULT;
                }
        }
index 3333c250c4d9995848053d4f8a3ecf1286b1ed6b..6ba48f346fcf2407d400e1d7217f10b2d72e0c7a 100644 (file)
@@ -70,8 +70,8 @@ static drm_ioctl_desc_t                 drm_ioctls[] = {
        [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)]       = { drm_noop,        1, 1 },
        [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)]    = { drm_authmagic,   1, 1 },
 
-       [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)]       = { drm_addmap,      1, 1 },
-       [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP)]        = { drm_rmmap,       1, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)]       = { drm_addmap_ioctl,1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP)]        = { drm_rmmap_ioctl, 1, 0 },
 
        [DRM_IOCTL_NR(DRM_IOCTL_SET_SAREA_CTX)] = { drm_setsareactx, 1, 1 },
        [DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX)] = { drm_getsareactx, 1, 0 },
@@ -102,10 +102,10 @@ static drm_ioctl_desc_t             drm_ioctls[] = {
        [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)]       = { drm_control,     1, 1 },
 
 #if __OS_HAS_AGP
-       [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)]   = { drm_agp_acquire, 1, 1 },
-       [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)]   = { drm_agp_release, 1, 1 },
-       [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)]    = { drm_agp_enable 1, 1 },
-       [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)]      = { drm_agp_info,    1, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)]   = { drm_agp_acquire_ioctl, 1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)]   = { drm_agp_release_ioctl, 1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)]    = { drm_agp_enable_ioctl, 1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)]      = { drm_agp_info_ioctl, 1, 0 },
        [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)]     = { drm_agp_alloc,   1, 1 },
        [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)]      = { drm_agp_free,    1, 1 },
        [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)]      = { drm_agp_bind,    1, 1 },
@@ -127,14 +127,12 @@ static drm_ioctl_desc_t             drm_ioctls[] = {
  *
  * Frees every resource in \p dev.
  *
- * \sa drm_device and setup().
+ * \sa drm_device
  */
 int drm_takedown( drm_device_t *dev )
 {
        drm_magic_entry_t *pt, *next;
-       drm_map_t *map;
        drm_map_list_t *r_list;
-       struct list_head *list, *list_next;
        drm_vma_entry_t *vma, *vma_next;
        int i;
 
@@ -142,6 +140,7 @@ int drm_takedown( drm_device_t *dev )
 
        if (dev->driver->pretakedown)
          dev->driver->pretakedown(dev);
+       DRM_DEBUG("driver pretakedown completed\n");
 
        if (dev->unique) {
                drm_free(dev->unique, strlen(dev->unique) + 1, DRM_MEM_DRIVER);
@@ -178,11 +177,16 @@ int drm_takedown( drm_device_t *dev )
                }
                dev->agp->memory = NULL;
 
-               if ( dev->agp->acquired ) drm_agp_do_release(dev);
+               if (dev->agp->acquired)
+                 drm_agp_release(dev);
 
                dev->agp->acquired = 0;
                dev->agp->enabled  = 0;
        }
+       if (drm_core_check_feature(dev, DRIVER_SG) && dev->sg) {
+               drm_sg_cleanup(dev->sg);
+               dev->sg = NULL;
+       }
 
                                /* Clear vma list (only built for debugging) */
        if ( dev->vmalist ) {
@@ -194,48 +198,11 @@ int drm_takedown( drm_device_t *dev )
        }
 
        if( dev->maplist ) {
-               list_for_each_safe( list, list_next, &dev->maplist->head ) {
-                       r_list = (drm_map_list_t *)list;
-
-                       if ( ( map = r_list->map ) ) {
-                               switch ( map->type ) {
-                               case _DRM_REGISTERS:
-                               case _DRM_FRAME_BUFFER:
-                                       if (drm_core_has_MTRR(dev)) {
-                                               if ( map->mtrr >= 0 ) {
-                                                       int retcode;
-                                                       retcode = mtrr_del( map->mtrr,
-                                                                           map->offset,
-                                                                           map->size );
-                                                       DRM_DEBUG( "mtrr_del=%d\n", retcode );
-                                               }
-                                       }
-                                       drm_ioremapfree( map->handle, map->size, dev );
-                                       break;
-                               case _DRM_SHM:
-                                       vfree(map->handle);
-                                       break;
-
-                               case _DRM_AGP:
-                                       /* Do nothing here, because this is all
-                                        * handled in the AGP/GART driver.
-                                        */
-                                       break;
-                               case _DRM_SCATTER_GATHER:
-                                       /* Handle it */
-                                       if (drm_core_check_feature(dev, DRIVER_SG) && dev->sg) {
-                                               drm_sg_cleanup(dev->sg);
-                                               dev->sg = NULL;
-                                       }
-                                       break;
-                               }
-                               drm_free(map, sizeof(*map), DRM_MEM_MAPS);
-                       }
-                       list_del( list );
-                       drm_free(r_list, sizeof(*r_list), DRM_MEM_MAPS);
-               }
-               drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
-               dev->maplist = NULL;
+               while (!list_empty(&dev->maplist->head)) {
+                       struct list_head *list = dev->maplist->head.next;
+                       r_list = list_entry(list, drm_map_list_t, head);
+                       drm_rmmap_locked(dev, r_list->map);
+               }
        }
 
        if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) && dev->queuelist ) {
@@ -264,6 +231,7 @@ int drm_takedown( drm_device_t *dev )
        }
        up( &dev->struct_sem );
 
+       DRM_DEBUG("takedown completed\n");
        return 0;
 }
 
@@ -312,7 +280,7 @@ EXPORT_SYMBOL(drm_init);
  *
  * Cleans up all DRM device, calling takedown().
  * 
- * \sa drm_init().
+ * \sa drm_init
  */
 static void drm_cleanup( drm_device_t *dev )
 {
@@ -325,6 +293,11 @@ static void drm_cleanup( drm_device_t *dev )
 
        drm_takedown( dev );    
 
+       if (dev->maplist) {
+               drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
+               dev->maplist = NULL;
+       }
+
        drm_ctxbitmap_cleanup( dev );
        
        if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) &&
index 10e64fde8d782ca23dbc3ef57a3348f97a40d87d..a1f4e9cd64edd17406cf2b6349c37a2039a9fac2 100644 (file)
@@ -71,12 +71,6 @@ static int drm_setup( drm_device_t *dev )
                dev->magiclist[i].tail = NULL;
        }
 
-       dev->maplist = drm_alloc(sizeof(*dev->maplist),
-                                 DRM_MEM_MAPS);
-       if(dev->maplist == NULL) return -ENOMEM;
-       memset(dev->maplist, 0, sizeof(*dev->maplist));
-       INIT_LIST_HEAD(&dev->maplist->head);
-
        dev->ctxlist = drm_alloc(sizeof(*dev->ctxlist),
                                  DRM_MEM_CTXLIST);
        if(dev->ctxlist == NULL) return -ENOMEM;
index 39afda0ccabe36d803e5bc89772d4b19edec6d94..d2ed3ba5aca9647259bfc932f3363adfec77ee26 100644 (file)
@@ -208,7 +208,7 @@ int drm_getmap( struct inode *inode, struct file *filp,
        map.size   = r_list->map->size;
        map.type   = r_list->map->type;
        map.flags  = r_list->map->flags;
-       map.handle = r_list->map->handle;
+       map.handle = (void *)(unsigned long) r_list->user_token;
        map.mtrr   = r_list->map->mtrr;
        up(&dev->struct_sem);
 
index ace3d42f4407e5df458d6578b79f0aaaa742127c..ff483fb418aae85e2d1d987747efc511a9b415a0 100644 (file)
@@ -142,27 +142,31 @@ void drm_free_pages(unsigned long address, int order, int area)
 
 #if __OS_HAS_AGP
 /** Wrapper around agp_allocate_memory() */
-DRM_AGP_MEM *drm_alloc_agp(struct agp_bridge_data *bridge, int pages, u32 type)
+DRM_AGP_MEM *drm_alloc_agp(drm_device_t *dev, int pages, u32 type)
 {
-       return drm_agp_allocate_memory(bridge, pages, type);
+       return drm_agp_allocate_memory(dev->agp->bridge, pages, type);
 }
+EXPORT_SYMBOL(drm_alloc_agp);
 
 /** Wrapper around agp_free_memory() */
 int drm_free_agp(DRM_AGP_MEM *handle, int pages)
 {
        return drm_agp_free_memory(handle) ? 0 : -EINVAL;
 }
+EXPORT_SYMBOL(drm_free_agp);
 
 /** Wrapper around agp_bind_memory() */
 int drm_bind_agp(DRM_AGP_MEM *handle, unsigned int start)
 {
        return drm_agp_bind_memory(handle, start);
 }
+EXPORT_SYMBOL(drm_bind_agp);
 
 /** Wrapper around agp_unbind_memory() */
 int drm_unbind_agp(DRM_AGP_MEM *handle)
 {
        return drm_agp_unbind_memory(handle);
 }
+EXPORT_SYMBOL(drm_unbind_agp);
 #endif /* agp */
 #endif /* debug_memory */
index 192e8762571c890b0b10d536234d326b0bfcac06..09ed712c1a7fe0c0d1dc4038d83db079517a9eb8 100644 (file)
 /**
  * \brief Allocate a PCI consistent memory block, for DMA.
  */
-void *drm_pci_alloc(drm_device_t * dev, size_t size, size_t align,
-                   dma_addr_t maxaddr, dma_addr_t * busaddr)
+drm_dma_handle_t *drm_pci_alloc(drm_device_t * dev, size_t size, size_t align,
+                               dma_addr_t maxaddr)
 {
-       void *address;
-#if DRM_DEBUG_MEMORY
+       drm_dma_handle_t *dmah;
+#ifdef DRM_DEBUG_MEMORY
        int area = DRM_MEM_DMA;
 
        spin_lock(&drm_mem_lock);
@@ -74,13 +74,19 @@ void *drm_pci_alloc(drm_device_t * dev, size_t size, size_t align,
                return NULL;
        }
 
-       address = pci_alloc_consistent(dev->pdev, size, busaddr);
+       dmah = kmalloc(sizeof(drm_dma_handle_t), GFP_KERNEL);
+       if (!dmah)
+               return NULL;
+       
+       dmah->size = size;
+       dmah->vaddr = pci_alloc_consistent(dev->pdev, size, &dmah->busaddr);
 
-#if DRM_DEBUG_MEMORY
-       if (address == NULL) {
+#ifdef DRM_DEBUG_MEMORY
+       if (dmah->vaddr == NULL) {
                spin_lock(&drm_mem_lock);
                ++drm_mem_stats[area].fail_count;
                spin_unlock(&drm_mem_lock);
+               kfree(dmah);
                return NULL;
        }
 
@@ -90,37 +96,42 @@ void *drm_pci_alloc(drm_device_t * dev, size_t size, size_t align,
        drm_ram_used += size;
        spin_unlock(&drm_mem_lock);
 #else
-       if (address == NULL)
+       if (dmah->vaddr == NULL) {
+               kfree(dmah);
                return NULL;
+       }
 #endif
 
-       memset(address, 0, size);
+       memset(dmah->vaddr, 0, size);
 
-       return address;
+       return dmah;
 }
 EXPORT_SYMBOL(drm_pci_alloc);
 
 /**
- * \brief Free a PCI consistent memory block.
+ * \brief Free a PCI consistent memory block with freeing its descriptor.
+ *
+ * This function is for internal use in the Linux-specific DRM core code.
  */
 void
-drm_pci_free(drm_device_t * dev, size_t size, void *vaddr, dma_addr_t busaddr)
+__drm_pci_free(drm_device_t * dev, drm_dma_handle_t *dmah)
 {
-#if DRM_DEBUG_MEMORY
+#ifdef DRM_DEBUG_MEMORY
        int area = DRM_MEM_DMA;
        int alloc_count;
        int free_count;
 #endif
 
-       if (!vaddr) {
-#if DRM_DEBUG_MEMORY
+       if (!dmah->vaddr) {
+#ifdef DRM_DEBUG_MEMORY
                DRM_MEM_ERROR(area, "Attempt to free address 0\n");
 #endif
        } else {
-               pci_free_consistent(dev->pdev, size, vaddr, busaddr);
+               pci_free_consistent(dev->pdev, dmah->size, dmah->vaddr,
+                                   dmah->busaddr);
        }
 
-#if DRM_DEBUG_MEMORY
+#ifdef DRM_DEBUG_MEMORY
        spin_lock(&drm_mem_lock);
        free_count = ++drm_mem_stats[area].free_count;
        alloc_count = drm_mem_stats[area].succeed_count;
@@ -135,6 +146,16 @@ drm_pci_free(drm_device_t * dev, size_t size, void *vaddr, dma_addr_t busaddr)
 #endif
 
 }
+
+/**
+ * \brief Free a PCI consistent memory block
+ */
+void
+drm_pci_free(drm_device_t *dev, drm_dma_handle_t *dmah)
+{
+       __drm_pci_free(dev, dmah);
+       kfree(dmah);
+}
 EXPORT_SYMBOL(drm_pci_free);
 
 /*@}*/
index 70ca4fa55c9dd2433a37951095e7661240402e18..58b1747cd44033f1056f2982d7e3c8a9e04803d6 100644 (file)
@@ -25,6 +25,8 @@
        {0x1002, 0x4965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250}, \
        {0x1002, 0x4966, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250}, \
        {0x1002, 0x4967, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250}, \
+       {0x1002, 0x4A49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420}, \
+       {0x1002, 0x4A4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420}, \
        {0x1002, 0x4C57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|CHIP_IS_MOBILITY}, \
        {0x1002, 0x4C58, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|CHIP_IS_MOBILITY}, \
        {0x1002, 0x4C59, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|CHIP_IS_MOBILITY}, \
        {0x1002, 0x4C65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250|CHIP_IS_MOBILITY}, \
        {0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250|CHIP_IS_MOBILITY}, \
        {0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250|CHIP_IS_MOBILITY}, \
+       {0x1002, 0x4E44, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
+       {0x1002, 0x4E45, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
+       {0x1002, 0x4E46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
+       {0x1002, 0x4E47, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
+       {0x1002, 0x4E48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
+       {0x1002, 0x4E49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
+       {0x1002, 0x4E4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
+       {0x1002, 0x4E4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
        {0x1002, 0x4E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
+       {0x1002, 0x4E51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
+       {0x1002, 0x4E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
        {0x1002, 0x5144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
        {0x1002, 0x5145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
        {0x1002, 0x5146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
@@ -56,6 +68,7 @@
        {0x1002, 0x516A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
        {0x1002, 0x516B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
        {0x1002, 0x516C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
+       {0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
        {0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP}, \
        {0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
        {0x1002, 0x5836, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP}, \
        {0, 0, 0}
 
 #define mga_PCI_IDS \
-       {0x102b, 0x0521, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x102b, 0x0525, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x102b, 0x2527, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+       {0x102b, 0x0520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MGA_CARD_TYPE_G200}, \
+       {0x102b, 0x0521, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MGA_CARD_TYPE_G200}, \
+       {0x102b, 0x0525, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MGA_CARD_TYPE_G400}, \
+       {0x102b, 0x2527, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MGA_CARD_TYPE_G550}, \
        {0, 0, 0}
 
 #define mach64_PCI_IDS \
 
 #define viadrv_PCI_IDS \
        {0x1106, 0x3022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+       {0x1106, 0x3118, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+       {0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0, 0, 0}
 
 #define i810_PCI_IDS \
        {0x8086, 0x2572, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0, 0, 0}
 
-#define gamma_PCI_IDS \
-       {0x3d3d, 0x0008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0, 0, 0}
-
 #define savage_PCI_IDS \
-       {0x5333, 0x8a22, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8a23, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c10, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c11, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c13, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c22, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c24, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c2a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c2b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c2c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c2d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c2e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c2f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8a25, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8a26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8d01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8d02, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8d04, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+       {0x5333, 0x8a20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE3D}, \
+       {0x5333, 0x8a21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE3D}, \
+       {0x5333, 0x8a22, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE4}, \
+       {0x5333, 0x8a23, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE4}, \
+       {0x5333, 0x8c10, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE_MX}, \
+       {0x5333, 0x8c11, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE_MX}, \
+       {0x5333, 0x8c12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE_MX}, \
+       {0x5333, 0x8c13, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE_MX}, \
+       {0x5333, 0x8c22, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \
+       {0x5333, 0x8c24, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \
+       {0x5333, 0x8c26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \
+       {0x5333, 0x8c2a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \
+       {0x5333, 0x8c2b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \
+       {0x5333, 0x8c2c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \
+       {0x5333, 0x8c2d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \
+       {0x5333, 0x8c2e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \
+       {0x5333, 0x8c2f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \
+       {0x5333, 0x8a25, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_PROSAVAGE}, \
+       {0x5333, 0x8a26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_PROSAVAGE}, \
+       {0x5333, 0x8d01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_TWISTER}, \
+       {0x5333, 0x8d02, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_TWISTER}, \
+       {0x5333, 0x8d03, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_PROSAVAGEDDR}, \
+       {0x5333, 0x8d04, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_PROSAVAGEDDR}, \
        {0, 0, 0}
 
 #define ffb_PCI_IDS \
        {0x8086, 0x2772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0, 0, 0}
 
-#define viadrv_PCI_IDS \
-       {0x1106, 0x3022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0, 0, 0}
-
index 4774087d2e9e82c64d0d05511d02743d9371375f..32d2bb99462c67d7b9ef4416abd3147445afc36e 100644 (file)
@@ -210,8 +210,8 @@ static int drm__vm_info(char *buf, char **start, off_t offset, int request,
 
                                /* Hardcoded from _DRM_FRAME_BUFFER,
                                    _DRM_REGISTERS, _DRM_SHM, _DRM_AGP, and
-                                   _DRM_SCATTER_GATHER. */
-       const char   *types[] = { "FB", "REG", "SHM", "AGP", "SG" };
+                                   _DRM_SCATTER_GATHER and _DRM_CONSISTENT */
+       const char   *types[] = { "FB", "REG", "SHM", "AGP", "SG", "PCI" };
        const char   *type;
        int          i;
 
@@ -229,16 +229,19 @@ static int drm__vm_info(char *buf, char **start, off_t offset, int request,
        if (dev->maplist != NULL) list_for_each(list, &dev->maplist->head) {
                r_list = list_entry(list, drm_map_list_t, head);
                map = r_list->map;
-               if(!map) continue;
-               if (map->type < 0 || map->type > 4) type = "??";
-               else                                type = types[map->type];
-               DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s  0x%02x 0x%08lx ",
+               if(!map)
+                       continue;
+               if (map->type < 0 || map->type > 5)
+                       type = "??";
+               else    
+                       type = types[map->type];
+               DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s  0x%02x 0x%08x ",
                               i,
                               map->offset,
                               map->size,
                               type,
                               map->flags,
-                              (unsigned long)map->handle);
+                              r_list->user_token);
                if (map->mtrr < 0) {
                        DRM_PROC_PRINT("none\n");
                } else {
index 54fddb6ea2d1398f1da3263c4105097ee2cbd63f..ed267d49bc6aa9c4dee72c006a41a61f9991e35b 100644 (file)
@@ -61,6 +61,12 @@ void drm_sg_cleanup( drm_sg_mem_t *entry )
                   DRM_MEM_SGLISTS );
 }
 
+#ifdef _LP64
+# define ScatterHandle(x) (unsigned int)((x >> 32) + (x & ((1L << 32) - 1)))
+#else
+# define ScatterHandle(x) (unsigned int)(x)
+#endif
+
 int drm_sg_alloc( struct inode *inode, struct file *filp,
                   unsigned int cmd, unsigned long arg )
 {
@@ -133,12 +139,13 @@ int drm_sg_alloc( struct inode *inode, struct file *filp,
         */
        memset( entry->virtual, 0, pages << PAGE_SHIFT );
 
-       entry->handle = (unsigned long)entry->virtual;
+       entry->handle = ScatterHandle((unsigned long)entry->virtual);
 
        DRM_DEBUG( "sg alloc handle  = %08lx\n", entry->handle );
        DRM_DEBUG( "sg alloc virtual = %p\n", entry->virtual );
 
-       for ( i = entry->handle, j = 0 ; j < pages ; i += PAGE_SIZE, j++ ) {
+       for (i = (unsigned long)entry->virtual, j = 0; j < pages; 
+               i += PAGE_SIZE, j++) {
                entry->pagelist[j] = vmalloc_to_page((void *)i);
                if (!entry->pagelist[j])
                        goto failed;
index 48829a1a086a94cba10327d6896f8e1dbfdc5e95..95a976c96eb8303c9df9cc249c8c3d9e99cc999c 100644 (file)
@@ -75,6 +75,11 @@ static int drm_fill_in_dev(drm_device_t *dev, struct pci_dev *pdev, const struct
        dev->pci_func = PCI_FUNC(pdev->devfn);
        dev->irq = pdev->irq;
 
+       dev->maplist = drm_calloc(1, sizeof(*dev->maplist), DRM_MEM_MAPS);
+       if (dev->maplist == NULL)
+               return -ENOMEM;
+       INIT_LIST_HEAD(&dev->maplist->head);
+
        /* the DRM has 6 basic counters */
        dev->counters = 6;
        dev->types[0]  = _DRM_STAT_LOCK;
@@ -91,7 +96,8 @@ static int drm_fill_in_dev(drm_device_t *dev, struct pci_dev *pdev, const struct
                        goto error_out_unreg;
 
        if (drm_core_has_AGP(dev)) {
-               dev->agp = drm_agp_init(dev);
+               if (drm_device_is_agp(dev))
+                       dev->agp = drm_agp_init(dev);
                if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP) && (dev->agp == NULL)) {
                        DRM_ERROR( "Cannot initialize the agpgart module.\n" );
                        retcode = -EINVAL;
index 621220f3f37207492ed8bfccdcef7d5e94cc0fda..ced4215e2275e71dad67a2db787054bb03bfc12f 100644 (file)
@@ -73,12 +73,13 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
                r_list = list_entry(list, drm_map_list_t, head);
                map = r_list->map;
                if (!map) continue;
-               if (map->offset == VM_OFFSET(vma)) break;
+               if (r_list->user_token == VM_OFFSET(vma))
+                       break;
        }
 
        if (map && map->type == _DRM_AGP) {
                unsigned long offset = address - vma->vm_start;
-               unsigned long baddr = VM_OFFSET(vma) + offset;
+               unsigned long baddr = map->offset + offset;
                struct drm_agp_mem *agpmem;
                struct page *page;
 
@@ -210,6 +211,8 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
                }
 
                if(!found_maps) {
+                       drm_dma_handle_t dmah;
+
                        switch (map->type) {
                        case _DRM_REGISTERS:
                        case _DRM_FRAME_BUFFER:
@@ -228,6 +231,12 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
                        case _DRM_AGP:
                        case _DRM_SCATTER_GATHER:
                                break;
+                       case _DRM_CONSISTENT:
+                               dmah.vaddr = map->handle;
+                               dmah.busaddr = map->offset;
+                               dmah.size = map->size;
+                               __drm_pci_free(dev, &dmah);
+                               break;
                        }
                        drm_free(map, sizeof(*map), DRM_MEM_MAPS);
                }
@@ -296,7 +305,7 @@ static __inline__ struct page *drm_do_vm_sg_nopage(struct vm_area_struct *vma,
 
 
        offset = address - vma->vm_start;
-       map_offset = map->offset - dev->sg->handle;
+       map_offset = map->offset - (unsigned long)dev->sg->virtual;
        page_offset = (offset >> PAGE_SHIFT) + (map_offset >> PAGE_SHIFT);
        page = entry->pagelist[page_offset];
        get_page(page);
@@ -305,8 +314,6 @@ static __inline__ struct page *drm_do_vm_sg_nopage(struct vm_area_struct *vma,
 }
 
 
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
-
 static struct page *drm_vm_nopage(struct vm_area_struct *vma,
                                   unsigned long address,
                                   int *type) {
@@ -335,35 +342,6 @@ static struct page *drm_vm_sg_nopage(struct vm_area_struct *vma,
        return drm_do_vm_sg_nopage(vma, address);
 }
 
-#else  /* LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,0) */
-
-static struct page *drm_vm_nopage(struct vm_area_struct *vma,
-                                  unsigned long address,
-                                  int unused) {
-       return drm_do_vm_nopage(vma, address);
-}
-
-static struct page *drm_vm_shm_nopage(struct vm_area_struct *vma,
-                                      unsigned long address,
-                                      int unused) {
-       return drm_do_vm_shm_nopage(vma, address);
-}
-
-static struct page *drm_vm_dma_nopage(struct vm_area_struct *vma,
-                                      unsigned long address,
-                                      int unused) {
-       return drm_do_vm_dma_nopage(vma, address);
-}
-
-static struct page *drm_vm_sg_nopage(struct vm_area_struct *vma,
-                                     unsigned long address,
-                                     int unused) {
-       return drm_do_vm_sg_nopage(vma, address);
-}
-
-#endif
-
-
 /** AGP virtual memory operations */
 static struct vm_operations_struct   drm_vm_ops = {
        .nopage = drm_vm_nopage,
@@ -487,11 +465,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
 
        vma->vm_ops   = &drm_vm_dma_ops;
 
-#if LINUX_VERSION_CODE <= 0x02040e /* KERNEL_VERSION(2,4,14) */
-       vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */
-#else
        vma->vm_flags |= VM_RESERVED; /* Don't swap */
-#endif
 
        vma->vm_file  =  filp;  /* Needed for drm_vm_open() */
        drm_vm_open(vma);
@@ -560,13 +534,12 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
                                   for performance, even if the list was a
                                   bit longer. */
        list_for_each(list, &dev->maplist->head) {
-               unsigned long off;
 
                r_list = list_entry(list, drm_map_list_t, head);
                map = r_list->map;
                if (!map) continue;
-               off = dev->driver->get_map_ofs(map);
-               if (off == VM_OFFSET(vma)) break;
+               if (r_list->user_token == VM_OFFSET(vma))
+                       break;
        }
 
        if (!map || ((map->flags&_DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN)))
@@ -605,17 +578,17 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
                 /* fall through to _DRM_FRAME_BUFFER... */        
        case _DRM_FRAME_BUFFER:
        case _DRM_REGISTERS:
-               if (VM_OFFSET(vma) >= __pa(high_memory)) {
 #if defined(__i386__) || defined(__x86_64__)
-                       if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) {
-                               pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
-                               pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT;
-                       }
+               if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) {
+                       pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
+                       pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT;
+               }
 #elif defined(__powerpc__)
-                       pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE | _PAGE_GUARDED;
+               pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
+               if (map->type == _DRM_REGISTERS)
+                       pgprot_val(vma->vm_page_prot) |= _PAGE_GUARDED;
 #endif
-                       vma->vm_flags |= VM_IO; /* not in core dump */
-               }
+               vma->vm_flags |= VM_IO; /* not in core dump */
 #if defined(__ia64__)
                if (efi_range_is_wc(vma->vm_start, vma->vm_end -
                                    vma->vm_start))
@@ -628,12 +601,12 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
                offset = dev->driver->get_reg_ofs(dev);
 #ifdef __sparc__
                if (io_remap_pfn_range(DRM_RPR_ARG(vma) vma->vm_start,
-                                       (VM_OFFSET(vma) + offset) >> PAGE_SHIFT,
+                                       (map->offset + offset) >> PAGE_SHIFT,
                                        vma->vm_end - vma->vm_start,
                                        vma->vm_page_prot))
 #else
                if (io_remap_pfn_range(vma, vma->vm_start,
-                                    (VM_OFFSET(vma) + offset) >> PAGE_SHIFT,
+                                    (map->offset + offset) >> PAGE_SHIFT,
                                     vma->vm_end - vma->vm_start,
                                     vma->vm_page_prot))
 #endif
@@ -641,37 +614,28 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
                DRM_DEBUG("   Type = %d; start = 0x%lx, end = 0x%lx,"
                          " offset = 0x%lx\n",
                          map->type,
-                         vma->vm_start, vma->vm_end, VM_OFFSET(vma) + offset);
+                         vma->vm_start, vma->vm_end, map->offset + offset);
                vma->vm_ops = &drm_vm_ops;
                break;
        case _DRM_SHM:
+       case _DRM_CONSISTENT:
+               /* Consistent memory is really like shared memory. It's only
+                * allocate in a different way */
                vma->vm_ops = &drm_vm_shm_ops;
                vma->vm_private_data = (void *)map;
                                /* Don't let this area swap.  Change when
                                   DRM_KERNEL advisory is supported. */
-#if LINUX_VERSION_CODE <= 0x02040e /* KERNEL_VERSION(2,4,14) */
-               vma->vm_flags |= VM_LOCKED;
-#else
                vma->vm_flags |= VM_RESERVED;
-#endif
                break;
        case _DRM_SCATTER_GATHER:
                vma->vm_ops = &drm_vm_sg_ops;
                vma->vm_private_data = (void *)map;
-#if LINUX_VERSION_CODE <= 0x02040e /* KERNEL_VERSION(2,4,14) */
-               vma->vm_flags |= VM_LOCKED;
-#else
                vma->vm_flags |= VM_RESERVED;
-#endif
                 break;
        default:
                return -EINVAL; /* This should never happen. */
        }
-#if LINUX_VERSION_CODE <= 0x02040e /* KERNEL_VERSION(2,4,14) */
-       vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */
-#else
        vma->vm_flags |= VM_RESERVED; /* Don't swap */
-#endif
 
        vma->vm_file  =  filp;  /* Needed for drm_vm_open() */
        drm_vm_open(vma);
index ec614fff8f0481d7f6f6044373328a3012c5196d..1bd0d55ee0f0b4f98cb5eb93c0b112dfd074e4f4 100644 (file)
@@ -152,14 +152,11 @@ static drm_map_t *ffb_find_map(struct file *filp, unsigned long off)
                return NULL;
 
        list_for_each(list, &dev->maplist->head) {
-               unsigned long uoff;
-
                r_list = (drm_map_list_t *)list;
                map = r_list->map;
                if (!map)
                        continue;
-               uoff = (map->offset & 0xffffffff);
-               if (uoff == off)
+               if (r_list->user_token == off)
                        return map;
        }
 
diff --git a/drivers/char/drm/gamma_context.h b/drivers/char/drm/gamma_context.h
deleted file mode 100644 (file)
index d11b507..0000000
+++ /dev/null
@@ -1,492 +0,0 @@
-/* drm_context.h -- IOCTLs for generic contexts -*- linux-c -*-
- * Created: Fri Nov 24 18:31:37 2000 by gareth@valinux.com
- *
- * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *    Rickard E. (Rik) Faith <faith@valinux.com>
- *    Gareth Hughes <gareth@valinux.com>
- * ChangeLog:
- *  2001-11-16 Torsten Duwe <duwe@caldera.de>
- *             added context constructor/destructor hooks,
- *             needed by SiS driver's memory management.
- */
-
-/* ================================================================
- * Old-style context support -- only used by gamma.  
- */
-
-
-/* The drm_read and drm_write_string code (especially that which manages
-   the circular buffer), is based on Alessandro Rubini's LINUX DEVICE
-   DRIVERS (Cambridge: O'Reilly, 1998), pages 111-113. */
-
-ssize_t gamma_fops_read(struct file *filp, char __user *buf, size_t count, loff_t *off)
-{
-       drm_file_t    *priv   = filp->private_data;
-       drm_device_t  *dev    = priv->dev;
-       int           left;
-       int           avail;
-       int           send;
-       int           cur;
-
-       DRM_DEBUG("%p, %p\n", dev->buf_rp, dev->buf_wp);
-
-       while (dev->buf_rp == dev->buf_wp) {
-               DRM_DEBUG("  sleeping\n");
-               if (filp->f_flags & O_NONBLOCK) {
-                       return -EAGAIN;
-               }
-               interruptible_sleep_on(&dev->buf_readers);
-               if (signal_pending(current)) {
-                       DRM_DEBUG("  interrupted\n");
-                       return -ERESTARTSYS;
-               }
-               DRM_DEBUG("  awake\n");
-       }
-
-       left  = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ;
-       avail = DRM_BSZ - left;
-       send  = DRM_MIN(avail, count);
-
-       while (send) {
-               if (dev->buf_wp > dev->buf_rp) {
-                       cur = DRM_MIN(send, dev->buf_wp - dev->buf_rp);
-               } else {
-                       cur = DRM_MIN(send, dev->buf_end - dev->buf_rp);
-               }
-               if (copy_to_user(buf, dev->buf_rp, cur))
-                       return -EFAULT;
-               dev->buf_rp += cur;
-               if (dev->buf_rp == dev->buf_end) dev->buf_rp = dev->buf;
-               send -= cur;
-       }
-
-       wake_up_interruptible(&dev->buf_writers);
-       return DRM_MIN(avail, count);
-}
-
-
-/* In an incredibly convoluted setup, the kernel module actually calls
- * back into the X server to perform context switches on behalf of the
- * 3d clients.
- */
-int DRM(write_string)(drm_device_t *dev, const char *s)
-{
-       int left   = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ;
-       int send   = strlen(s);
-       int count;
-
-       DRM_DEBUG("%d left, %d to send (%p, %p)\n",
-                 left, send, dev->buf_rp, dev->buf_wp);
-
-       if (left == 1 || dev->buf_wp != dev->buf_rp) {
-               DRM_ERROR("Buffer not empty (%d left, wp = %p, rp = %p)\n",
-                         left,
-                         dev->buf_wp,
-                         dev->buf_rp);
-       }
-
-       while (send) {
-               if (dev->buf_wp >= dev->buf_rp) {
-                       count = DRM_MIN(send, dev->buf_end - dev->buf_wp);
-                       if (count == left) --count; /* Leave a hole */
-               } else {
-                       count = DRM_MIN(send, dev->buf_rp - dev->buf_wp - 1);
-               }
-               strncpy(dev->buf_wp, s, count);
-               dev->buf_wp += count;
-               if (dev->buf_wp == dev->buf_end) dev->buf_wp = dev->buf;
-               send -= count;
-       }
-
-       if (dev->buf_async) kill_fasync(&dev->buf_async, SIGIO, POLL_IN);
-
-       DRM_DEBUG("waking\n");
-       wake_up_interruptible(&dev->buf_readers);
-       return 0;
-}
-
-unsigned int gamma_fops_poll(struct file *filp, struct poll_table_struct *wait)
-{
-       drm_file_t   *priv = filp->private_data;
-       drm_device_t *dev  = priv->dev;
-
-       poll_wait(filp, &dev->buf_readers, wait);
-       if (dev->buf_wp != dev->buf_rp) return POLLIN | POLLRDNORM;
-       return 0;
-}
-
-int DRM(context_switch)(drm_device_t *dev, int old, int new)
-{
-       char        buf[64];
-       drm_queue_t *q;
-
-       if (test_and_set_bit(0, &dev->context_flag)) {
-               DRM_ERROR("Reentering -- FIXME\n");
-               return -EBUSY;
-       }
-
-       DRM_DEBUG("Context switch from %d to %d\n", old, new);
-
-       if (new >= dev->queue_count) {
-               clear_bit(0, &dev->context_flag);
-               return -EINVAL;
-       }
-
-       if (new == dev->last_context) {
-               clear_bit(0, &dev->context_flag);
-               return 0;
-       }
-
-       q = dev->queuelist[new];
-       atomic_inc(&q->use_count);
-       if (atomic_read(&q->use_count) == 1) {
-               atomic_dec(&q->use_count);
-               clear_bit(0, &dev->context_flag);
-               return -EINVAL;
-       }
-
-       /* This causes the X server to wake up & do a bunch of hardware
-        * interaction to actually effect the context switch.
-        */
-       sprintf(buf, "C %d %d\n", old, new);
-       DRM(write_string)(dev, buf);
-
-       atomic_dec(&q->use_count);
-
-       return 0;
-}
-
-int DRM(context_switch_complete)(drm_device_t *dev, int new)
-{
-       drm_device_dma_t *dma = dev->dma;
-
-       dev->last_context = new;  /* PRE/POST: This is the _only_ writer. */
-       dev->last_switch  = jiffies;
-
-       if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
-               DRM_ERROR("Lock isn't held after context switch\n");
-       }
-
-       if (!dma || !(dma->next_buffer && dma->next_buffer->while_locked)) {
-               if (DRM(lock_free)(dev, &dev->lock.hw_lock->lock,
-                                 DRM_KERNEL_CONTEXT)) {
-                       DRM_ERROR("Cannot free lock\n");
-               }
-       }
-
-       clear_bit(0, &dev->context_flag);
-       wake_up_interruptible(&dev->context_wait);
-
-       return 0;
-}
-
-static int DRM(init_queue)(drm_device_t *dev, drm_queue_t *q, drm_ctx_t *ctx)
-{
-       DRM_DEBUG("\n");
-
-       if (atomic_read(&q->use_count) != 1
-           || atomic_read(&q->finalization)
-           || atomic_read(&q->block_count)) {
-               DRM_ERROR("New queue is already in use: u%d f%d b%d\n",
-                         atomic_read(&q->use_count),
-                         atomic_read(&q->finalization),
-                         atomic_read(&q->block_count));
-       }
-
-       atomic_set(&q->finalization,  0);
-       atomic_set(&q->block_count,   0);
-       atomic_set(&q->block_read,    0);
-       atomic_set(&q->block_write,   0);
-       atomic_set(&q->total_queued,  0);
-       atomic_set(&q->total_flushed, 0);
-       atomic_set(&q->total_locks,   0);
-
-       init_waitqueue_head(&q->write_queue);
-       init_waitqueue_head(&q->read_queue);
-       init_waitqueue_head(&q->flush_queue);
-
-       q->flags = ctx->flags;
-
-       DRM(waitlist_create)(&q->waitlist, dev->dma->buf_count);
-
-       return 0;
-}
-
-
-/* drm_alloc_queue:
-PRE: 1) dev->queuelist[0..dev->queue_count] is allocated and will not
-       disappear (so all deallocation must be done after IOCTLs are off)
-     2) dev->queue_count < dev->queue_slots
-     3) dev->queuelist[i].use_count == 0 and
-       dev->queuelist[i].finalization == 0 if i not in use
-POST: 1) dev->queuelist[i].use_count == 1
-      2) dev->queue_count < dev->queue_slots */
-
-static int DRM(alloc_queue)(drm_device_t *dev)
-{
-       int         i;
-       drm_queue_t *queue;
-       int         oldslots;
-       int         newslots;
-                               /* Check for a free queue */
-       for (i = 0; i < dev->queue_count; i++) {
-               atomic_inc(&dev->queuelist[i]->use_count);
-               if (atomic_read(&dev->queuelist[i]->use_count) == 1
-                   && !atomic_read(&dev->queuelist[i]->finalization)) {
-                       DRM_DEBUG("%d (free)\n", i);
-                       return i;
-               }
-               atomic_dec(&dev->queuelist[i]->use_count);
-       }
-                               /* Allocate a new queue */
-       down(&dev->struct_sem);
-
-       queue = DRM(alloc)(sizeof(*queue), DRM_MEM_QUEUES);
-       memset(queue, 0, sizeof(*queue));
-       atomic_set(&queue->use_count, 1);
-
-       ++dev->queue_count;
-       if (dev->queue_count >= dev->queue_slots) {
-               oldslots = dev->queue_slots * sizeof(*dev->queuelist);
-               if (!dev->queue_slots) dev->queue_slots = 1;
-               dev->queue_slots *= 2;
-               newslots = dev->queue_slots * sizeof(*dev->queuelist);
-
-               dev->queuelist = DRM(realloc)(dev->queuelist,
-                                             oldslots,
-                                             newslots,
-                                             DRM_MEM_QUEUES);
-               if (!dev->queuelist) {
-                       up(&dev->struct_sem);
-                       DRM_DEBUG("out of memory\n");
-                       return -ENOMEM;
-               }
-       }
-       dev->queuelist[dev->queue_count-1] = queue;
-
-       up(&dev->struct_sem);
-       DRM_DEBUG("%d (new)\n", dev->queue_count - 1);
-       return dev->queue_count - 1;
-}
-
-int DRM(resctx)(struct inode *inode, struct file *filp,
-               unsigned int cmd, unsigned long arg)
-{
-       drm_ctx_res_t __user *argp = (void __user *)arg;
-       drm_ctx_res_t   res;
-       drm_ctx_t       ctx;
-       int             i;
-
-       DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS);
-       if (copy_from_user(&res, argp, sizeof(res)))
-               return -EFAULT;
-       if (res.count >= DRM_RESERVED_CONTEXTS) {
-               memset(&ctx, 0, sizeof(ctx));
-               for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
-                       ctx.handle = i;
-                       if (copy_to_user(&res.contexts[i],
-                                        &i,
-                                        sizeof(i)))
-                               return -EFAULT;
-               }
-       }
-       res.count = DRM_RESERVED_CONTEXTS;
-       if (copy_to_user(argp, &res, sizeof(res)))
-               return -EFAULT;
-       return 0;
-}
-
-int DRM(addctx)(struct inode *inode, struct file *filp,
-               unsigned int cmd, unsigned long arg)
-{
-       drm_file_t      *priv   = filp->private_data;
-       drm_device_t    *dev    = priv->dev;
-       drm_ctx_t       ctx;
-       drm_ctx_t       __user *argp = (void __user *)arg;
-
-       if (copy_from_user(&ctx, argp, sizeof(ctx)))
-               return -EFAULT;
-       if ((ctx.handle = DRM(alloc_queue)(dev)) == DRM_KERNEL_CONTEXT) {
-                               /* Init kernel's context and get a new one. */
-               DRM(init_queue)(dev, dev->queuelist[ctx.handle], &ctx);
-               ctx.handle = DRM(alloc_queue)(dev);
-       }
-       DRM(init_queue)(dev, dev->queuelist[ctx.handle], &ctx);
-       DRM_DEBUG("%d\n", ctx.handle);
-       if (copy_to_user(argp, &ctx, sizeof(ctx)))
-               return -EFAULT;
-       return 0;
-}
-
-int DRM(modctx)(struct inode *inode, struct file *filp,
-               unsigned int cmd, unsigned long arg)
-{
-       drm_file_t      *priv   = filp->private_data;
-       drm_device_t    *dev    = priv->dev;
-       drm_ctx_t       ctx;
-       drm_queue_t     *q;
-
-       if (copy_from_user(&ctx, (drm_ctx_t __user *)arg, sizeof(ctx)))
-               return -EFAULT;
-
-       DRM_DEBUG("%d\n", ctx.handle);
-
-       if (ctx.handle < 0 || ctx.handle >= dev->queue_count) return -EINVAL;
-       q = dev->queuelist[ctx.handle];
-
-       atomic_inc(&q->use_count);
-       if (atomic_read(&q->use_count) == 1) {
-                               /* No longer in use */
-               atomic_dec(&q->use_count);
-               return -EINVAL;
-       }
-
-       if (DRM_BUFCOUNT(&q->waitlist)) {
-               atomic_dec(&q->use_count);
-               return -EBUSY;
-       }
-
-       q->flags = ctx.flags;
-
-       atomic_dec(&q->use_count);
-       return 0;
-}
-
-int DRM(getctx)(struct inode *inode, struct file *filp,
-               unsigned int cmd, unsigned long arg)
-{
-       drm_file_t      *priv   = filp->private_data;
-       drm_device_t    *dev    = priv->dev;
-       drm_ctx_t       __user *argp = (void __user *)arg;
-       drm_ctx_t       ctx;
-       drm_queue_t     *q;
-
-       if (copy_from_user(&ctx, argp, sizeof(ctx)))
-               return -EFAULT;
-
-       DRM_DEBUG("%d\n", ctx.handle);
-
-       if (ctx.handle >= dev->queue_count) return -EINVAL;
-       q = dev->queuelist[ctx.handle];
-
-       atomic_inc(&q->use_count);
-       if (atomic_read(&q->use_count) == 1) {
-                               /* No longer in use */
-               atomic_dec(&q->use_count);
-               return -EINVAL;
-       }
-
-       ctx.flags = q->flags;
-       atomic_dec(&q->use_count);
-
-       if (copy_to_user(argp, &ctx, sizeof(ctx)))
-               return -EFAULT;
-
-       return 0;
-}
-
-int DRM(switchctx)(struct inode *inode, struct file *filp,
-                  unsigned int cmd, unsigned long arg)
-{
-       drm_file_t      *priv   = filp->private_data;
-       drm_device_t    *dev    = priv->dev;
-       drm_ctx_t       ctx;
-
-       if (copy_from_user(&ctx, (drm_ctx_t __user *)arg, sizeof(ctx)))
-               return -EFAULT;
-       DRM_DEBUG("%d\n", ctx.handle);
-       return DRM(context_switch)(dev, dev->last_context, ctx.handle);
-}
-
-int DRM(newctx)(struct inode *inode, struct file *filp,
-               unsigned int cmd, unsigned long arg)
-{
-       drm_file_t      *priv   = filp->private_data;
-       drm_device_t    *dev    = priv->dev;
-       drm_ctx_t       ctx;
-
-       if (copy_from_user(&ctx, (drm_ctx_t __user *)arg, sizeof(ctx)))
-               return -EFAULT;
-       DRM_DEBUG("%d\n", ctx.handle);
-       DRM(context_switch_complete)(dev, ctx.handle);
-
-       return 0;
-}
-
-int DRM(rmctx)(struct inode *inode, struct file *filp,
-              unsigned int cmd, unsigned long arg)
-{
-       drm_file_t      *priv   = filp->private_data;
-       drm_device_t    *dev    = priv->dev;
-       drm_ctx_t       ctx;
-       drm_queue_t     *q;
-       drm_buf_t       *buf;
-
-       if (copy_from_user(&ctx, (drm_ctx_t __user *)arg, sizeof(ctx)))
-               return -EFAULT;
-       DRM_DEBUG("%d\n", ctx.handle);
-
-       if (ctx.handle >= dev->queue_count) return -EINVAL;
-       q = dev->queuelist[ctx.handle];
-
-       atomic_inc(&q->use_count);
-       if (atomic_read(&q->use_count) == 1) {
-                               /* No longer in use */
-               atomic_dec(&q->use_count);
-               return -EINVAL;
-       }
-
-       atomic_inc(&q->finalization); /* Mark queue in finalization state */
-       atomic_sub(2, &q->use_count); /* Mark queue as unused (pending
-                                        finalization) */
-
-       while (test_and_set_bit(0, &dev->interrupt_flag)) {
-               schedule();
-               if (signal_pending(current)) {
-                       clear_bit(0, &dev->interrupt_flag);
-                       return -EINTR;
-               }
-       }
-                               /* Remove queued buffers */
-       while ((buf = DRM(waitlist_get)(&q->waitlist))) {
-               DRM(free_buffer)(dev, buf);
-       }
-       clear_bit(0, &dev->interrupt_flag);
-
-                               /* Wakeup blocked processes */
-       wake_up_interruptible(&q->read_queue);
-       wake_up_interruptible(&q->write_queue);
-       wake_up_interruptible(&q->flush_queue);
-
-                               /* Finalization over.  Queue is made
-                                  available when both use_count and
-                                  finalization become 0, which won't
-                                  happen until all the waiting processes
-                                  stop waiting. */
-       atomic_dec(&q->finalization);
-       return 0;
-}
-
diff --git a/drivers/char/drm/gamma_dma.c b/drivers/char/drm/gamma_dma.c
deleted file mode 100644 (file)
index e486fb8..0000000
+++ /dev/null
@@ -1,946 +0,0 @@
-/* gamma_dma.c -- DMA support for GMX 2000 -*- linux-c -*-
- * Created: Fri Mar 19 14:30:16 1999 by faith@precisioninsight.com
- *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *    Rickard E. (Rik) Faith <faith@valinux.com>
- *
- */
-
-#include "gamma.h"
-#include "drmP.h"
-#include "drm.h"
-#include "gamma_drm.h"
-#include "gamma_drv.h"
-
-#include <linux/interrupt.h>   /* For task queue support */
-#include <linux/delay.h>
-
-static inline void gamma_dma_dispatch(drm_device_t *dev, unsigned long address,
-                                     unsigned long length)
-{
-       drm_gamma_private_t *dev_priv =
-                               (drm_gamma_private_t *)dev->dev_private;
-       mb();
-       while ( GAMMA_READ(GAMMA_INFIFOSPACE) < 2)
-               cpu_relax();
-
-       GAMMA_WRITE(GAMMA_DMAADDRESS, address);
-
-       while (GAMMA_READ(GAMMA_GCOMMANDSTATUS) != 4)
-               cpu_relax();
-
-       GAMMA_WRITE(GAMMA_DMACOUNT, length / 4);
-}
-
-void gamma_dma_quiescent_single(drm_device_t *dev)
-{
-       drm_gamma_private_t *dev_priv =
-                               (drm_gamma_private_t *)dev->dev_private;
-       while (GAMMA_READ(GAMMA_DMACOUNT))
-               cpu_relax();
-
-       while (GAMMA_READ(GAMMA_INFIFOSPACE) < 2)
-               cpu_relax();
-
-       GAMMA_WRITE(GAMMA_FILTERMODE, 1 << 10);
-       GAMMA_WRITE(GAMMA_SYNC, 0);
-
-       do {
-               while (!GAMMA_READ(GAMMA_OUTFIFOWORDS))
-                       cpu_relax();
-       } while (GAMMA_READ(GAMMA_OUTPUTFIFO) != GAMMA_SYNC_TAG);
-}
-
-void gamma_dma_quiescent_dual(drm_device_t *dev)
-{
-       drm_gamma_private_t *dev_priv =
-                               (drm_gamma_private_t *)dev->dev_private;
-       while (GAMMA_READ(GAMMA_DMACOUNT))
-               cpu_relax();
-
-       while (GAMMA_READ(GAMMA_INFIFOSPACE) < 3)
-               cpu_relax();
-
-       GAMMA_WRITE(GAMMA_BROADCASTMASK, 3);
-       GAMMA_WRITE(GAMMA_FILTERMODE, 1 << 10);
-       GAMMA_WRITE(GAMMA_SYNC, 0);
-
-       /* Read from first MX */
-       do {
-               while (!GAMMA_READ(GAMMA_OUTFIFOWORDS))
-                       cpu_relax();
-       } while (GAMMA_READ(GAMMA_OUTPUTFIFO) != GAMMA_SYNC_TAG);
-
-       /* Read from second MX */
-       do {
-               while (!GAMMA_READ(GAMMA_OUTFIFOWORDS + 0x10000))
-                       cpu_relax();
-       } while (GAMMA_READ(GAMMA_OUTPUTFIFO + 0x10000) != GAMMA_SYNC_TAG);
-}
-
-void gamma_dma_ready(drm_device_t *dev)
-{
-       drm_gamma_private_t *dev_priv =
-                               (drm_gamma_private_t *)dev->dev_private;
-       while (GAMMA_READ(GAMMA_DMACOUNT))
-               cpu_relax();
-}
-
-static inline int gamma_dma_is_ready(drm_device_t *dev)
-{
-       drm_gamma_private_t *dev_priv =
-                               (drm_gamma_private_t *)dev->dev_private;
-       return (!GAMMA_READ(GAMMA_DMACOUNT));
-}
-
-irqreturn_t gamma_driver_irq_handler( DRM_IRQ_ARGS )
-{
-       drm_device_t     *dev = (drm_device_t *)arg;
-       drm_device_dma_t *dma = dev->dma;
-       drm_gamma_private_t *dev_priv =
-                               (drm_gamma_private_t *)dev->dev_private;
-
-       /* FIXME: should check whether we're actually interested in the interrupt? */
-       atomic_inc(&dev->counts[6]); /* _DRM_STAT_IRQ */
-
-       while (GAMMA_READ(GAMMA_INFIFOSPACE) < 3)
-               cpu_relax();
-
-       GAMMA_WRITE(GAMMA_GDELAYTIMER, 0xc350/2); /* 0x05S */
-       GAMMA_WRITE(GAMMA_GCOMMANDINTFLAGS, 8);
-       GAMMA_WRITE(GAMMA_GINTFLAGS, 0x2001);
-       if (gamma_dma_is_ready(dev)) {
-                               /* Free previous buffer */
-               if (test_and_set_bit(0, &dev->dma_flag))
-                       return IRQ_HANDLED;
-               if (dma->this_buffer) {
-                       gamma_free_buffer(dev, dma->this_buffer);
-                       dma->this_buffer = NULL;
-               }
-               clear_bit(0, &dev->dma_flag);
-
-               /* Dispatch new buffer */
-               schedule_work(&dev->work);
-       }
-       return IRQ_HANDLED;
-}
-
-/* Only called by gamma_dma_schedule. */
-static int gamma_do_dma(drm_device_t *dev, int locked)
-{
-       unsigned long    address;
-       unsigned long    length;
-       drm_buf_t        *buf;
-       int              retcode = 0;
-       drm_device_dma_t *dma = dev->dma;
-
-       if (test_and_set_bit(0, &dev->dma_flag)) return -EBUSY;
-
-
-       if (!dma->next_buffer) {
-               DRM_ERROR("No next_buffer\n");
-               clear_bit(0, &dev->dma_flag);
-               return -EINVAL;
-       }
-
-       buf     = dma->next_buffer;
-       /* WE NOW ARE ON LOGICAL PAGES!! - using page table setup in dma_init */
-       /* So we pass the buffer index value into the physical page offset */
-       address = buf->idx << 12;
-       length  = buf->used;
-
-       DRM_DEBUG("context %d, buffer %d (%ld bytes)\n",
-                 buf->context, buf->idx, length);
-
-       if (buf->list == DRM_LIST_RECLAIM) {
-               gamma_clear_next_buffer(dev);
-               gamma_free_buffer(dev, buf);
-               clear_bit(0, &dev->dma_flag);
-               return -EINVAL;
-       }
-
-       if (!length) {
-               DRM_ERROR("0 length buffer\n");
-               gamma_clear_next_buffer(dev);
-               gamma_free_buffer(dev, buf);
-               clear_bit(0, &dev->dma_flag);
-               return 0;
-       }
-
-       if (!gamma_dma_is_ready(dev)) {
-               clear_bit(0, &dev->dma_flag);
-               return -EBUSY;
-       }
-
-       if (buf->while_locked) {
-               if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
-                       DRM_ERROR("Dispatching buffer %d from pid %d"
-                                 " \"while locked\", but no lock held\n",
-                                 buf->idx, current->pid);
-               }
-       } else {
-               if (!locked && !gamma_lock_take(&dev->lock.hw_lock->lock,
-                                             DRM_KERNEL_CONTEXT)) {
-                       clear_bit(0, &dev->dma_flag);
-                       return -EBUSY;
-               }
-       }
-
-       if (dev->last_context != buf->context
-           && !(dev->queuelist[buf->context]->flags
-                & _DRM_CONTEXT_PRESERVED)) {
-                               /* PRE: dev->last_context != buf->context */
-               if (DRM(context_switch)(dev, dev->last_context,
-                                       buf->context)) {
-                       DRM(clear_next_buffer)(dev);
-                       DRM(free_buffer)(dev, buf);
-               }
-               retcode = -EBUSY;
-               goto cleanup;
-
-                               /* POST: we will wait for the context
-                                  switch and will dispatch on a later call
-                                  when dev->last_context == buf->context.
-                                  NOTE WE HOLD THE LOCK THROUGHOUT THIS
-                                  TIME! */
-       }
-
-       gamma_clear_next_buffer(dev);
-       buf->pending     = 1;
-       buf->waiting     = 0;
-       buf->list        = DRM_LIST_PEND;
-
-       /* WE NOW ARE ON LOGICAL PAGES!!! - overriding address */
-       address = buf->idx << 12;
-
-       gamma_dma_dispatch(dev, address, length);
-       gamma_free_buffer(dev, dma->this_buffer);
-       dma->this_buffer = buf;
-
-       atomic_inc(&dev->counts[7]); /* _DRM_STAT_DMA */
-       atomic_add(length, &dev->counts[8]); /* _DRM_STAT_PRIMARY */
-
-       if (!buf->while_locked && !dev->context_flag && !locked) {
-               if (gamma_lock_free(dev, &dev->lock.hw_lock->lock,
-                                 DRM_KERNEL_CONTEXT)) {
-                       DRM_ERROR("\n");
-               }
-       }
-cleanup:
-
-       clear_bit(0, &dev->dma_flag);
-
-
-       return retcode;
-}
-
-static void gamma_dma_timer_bh(unsigned long dev)
-{
-       gamma_dma_schedule((drm_device_t *)dev, 0);
-}
-
-void gamma_irq_immediate_bh(void *dev)
-{
-       gamma_dma_schedule(dev, 0);
-}
-
-int gamma_dma_schedule(drm_device_t *dev, int locked)
-{
-       int              next;
-       drm_queue_t      *q;
-       drm_buf_t        *buf;
-       int              retcode   = 0;
-       int              processed = 0;
-       int              missed;
-       int              expire    = 20;
-       drm_device_dma_t *dma      = dev->dma;
-
-       if (test_and_set_bit(0, &dev->interrupt_flag)) {
-                               /* Not reentrant */
-               atomic_inc(&dev->counts[10]); /* _DRM_STAT_MISSED */
-               return -EBUSY;
-       }
-       missed = atomic_read(&dev->counts[10]);
-
-
-again:
-       if (dev->context_flag) {
-               clear_bit(0, &dev->interrupt_flag);
-               return -EBUSY;
-       }
-       if (dma->next_buffer) {
-                               /* Unsent buffer that was previously
-                                  selected, but that couldn't be sent
-                                  because the lock could not be obtained
-                                  or the DMA engine wasn't ready.  Try
-                                  again. */
-               if (!(retcode = gamma_do_dma(dev, locked))) ++processed;
-       } else {
-               do {
-                       next = gamma_select_queue(dev, gamma_dma_timer_bh);
-                       if (next >= 0) {
-                               q   = dev->queuelist[next];
-                               buf = gamma_waitlist_get(&q->waitlist);
-                               dma->next_buffer = buf;
-                               dma->next_queue  = q;
-                               if (buf && buf->list == DRM_LIST_RECLAIM) {
-                                       gamma_clear_next_buffer(dev);
-                                       gamma_free_buffer(dev, buf);
-                               }
-                       }
-               } while (next >= 0 && !dma->next_buffer);
-               if (dma->next_buffer) {
-                       if (!(retcode = gamma_do_dma(dev, locked))) {
-                               ++processed;
-                       }
-               }
-       }
-
-       if (--expire) {
-               if (missed != atomic_read(&dev->counts[10])) {
-                       if (gamma_dma_is_ready(dev)) goto again;
-               }
-               if (processed && gamma_dma_is_ready(dev)) {
-                       processed = 0;
-                       goto again;
-               }
-       }
-
-       clear_bit(0, &dev->interrupt_flag);
-
-       return retcode;
-}
-
-static int gamma_dma_priority(struct file *filp, 
-                             drm_device_t *dev, drm_dma_t *d)
-{
-       unsigned long     address;
-       unsigned long     length;
-       int               must_free = 0;
-       int               retcode   = 0;
-       int               i;
-       int               idx;
-       drm_buf_t         *buf;
-       drm_buf_t         *last_buf = NULL;
-       drm_device_dma_t  *dma      = dev->dma;
-       int               *send_indices = NULL;
-       int               *send_sizes = NULL;
-
-       DECLARE_WAITQUEUE(entry, current);
-
-                               /* Turn off interrupt handling */
-       while (test_and_set_bit(0, &dev->interrupt_flag)) {
-               schedule();
-               if (signal_pending(current)) return -EINTR;
-       }
-       if (!(d->flags & _DRM_DMA_WHILE_LOCKED)) {
-               while (!gamma_lock_take(&dev->lock.hw_lock->lock,
-                                     DRM_KERNEL_CONTEXT)) {
-                       schedule();
-                       if (signal_pending(current)) {
-                               clear_bit(0, &dev->interrupt_flag);
-                               return -EINTR;
-                       }
-               }
-               ++must_free;
-       }
-
-       send_indices = DRM(alloc)(d->send_count * sizeof(*send_indices),
-                                 DRM_MEM_DRIVER);
-       if (send_indices == NULL)
-               return -ENOMEM;
-       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;
-       }
-
-       for (i = 0; i < d->send_count; i++) {
-               idx = send_indices[i];
-               if (idx < 0 || idx >= dma->buf_count) {
-                       DRM_ERROR("Index %d (of %d max)\n",
-                                 send_indices[i], dma->buf_count - 1);
-                       continue;
-               }
-               buf = dma->buflist[ idx ];
-               if (buf->filp != filp) {
-                       DRM_ERROR("Process %d using buffer not owned\n",
-                                 current->pid);
-                       retcode = -EINVAL;
-                       goto cleanup;
-               }
-               if (buf->list != DRM_LIST_NONE) {
-                       DRM_ERROR("Process %d using buffer on list %d\n",
-                                 current->pid, buf->list);
-                       retcode = -EINVAL;
-                       goto cleanup;
-               }
-                               /* This isn't a race condition on
-                                  buf->list, since our concern is the
-                                  buffer reclaim during the time the
-                                  process closes the /dev/drm? handle, so
-                                  it can't also be doing DMA. */
-               buf->list         = DRM_LIST_PRIO;
-               buf->used         = send_sizes[i];
-               buf->context      = d->context;
-               buf->while_locked = d->flags & _DRM_DMA_WHILE_LOCKED;
-               address           = (unsigned long)buf->address;
-               length            = buf->used;
-               if (!length) {
-                       DRM_ERROR("0 length buffer\n");
-               }
-               if (buf->pending) {
-                       DRM_ERROR("Sending pending buffer:"
-                                 " buffer %d, offset %d\n",
-                                 send_indices[i], i);
-                       retcode = -EINVAL;
-                       goto cleanup;
-               }
-               if (buf->waiting) {
-                       DRM_ERROR("Sending waiting buffer:"
-                                 " buffer %d, offset %d\n",
-                                 send_indices[i], i);
-                       retcode = -EINVAL;
-                       goto cleanup;
-               }
-               buf->pending = 1;
-
-               if (dev->last_context != buf->context
-                   && !(dev->queuelist[buf->context]->flags
-                        & _DRM_CONTEXT_PRESERVED)) {
-                       add_wait_queue(&dev->context_wait, &entry);
-                       current->state = TASK_INTERRUPTIBLE;
-                               /* PRE: dev->last_context != buf->context */
-                       DRM(context_switch)(dev, dev->last_context,
-                                           buf->context);
-                               /* POST: we will wait for the context
-                                  switch and will dispatch on a later call
-                                  when dev->last_context == buf->context.
-                                  NOTE WE HOLD THE LOCK THROUGHOUT THIS
-                                  TIME! */
-                       schedule();
-                       current->state = TASK_RUNNING;
-                       remove_wait_queue(&dev->context_wait, &entry);
-                       if (signal_pending(current)) {
-                               retcode = -EINTR;
-                               goto cleanup;
-                       }
-                       if (dev->last_context != buf->context) {
-                               DRM_ERROR("Context mismatch: %d %d\n",
-                                         dev->last_context,
-                                         buf->context);
-                       }
-               }
-
-               gamma_dma_dispatch(dev, address, length);
-               atomic_inc(&dev->counts[9]); /* _DRM_STAT_SPECIAL */
-               atomic_add(length, &dev->counts[8]); /* _DRM_STAT_PRIMARY */
-
-               if (last_buf) {
-                       gamma_free_buffer(dev, last_buf);
-               }
-               last_buf = buf;
-       }
-
-
-cleanup:
-       if (last_buf) {
-               gamma_dma_ready(dev);
-               gamma_free_buffer(dev, last_buf);
-       }
-       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);
-
-       if (must_free && !dev->context_flag) {
-               if (gamma_lock_free(dev, &dev->lock.hw_lock->lock,
-                                 DRM_KERNEL_CONTEXT)) {
-                       DRM_ERROR("\n");
-               }
-       }
-       clear_bit(0, &dev->interrupt_flag);
-       return retcode;
-}
-
-static int gamma_dma_send_buffers(struct file *filp,
-                                 drm_device_t *dev, drm_dma_t *d)
-{
-       DECLARE_WAITQUEUE(entry, current);
-       drm_buf_t         *last_buf = NULL;
-       int               retcode   = 0;
-       drm_device_dma_t  *dma      = dev->dma;
-       int               send_index;
-
-       if (get_user(send_index, &d->send_indices[d->send_count-1]))
-               return -EFAULT;
-
-       if (d->flags & _DRM_DMA_BLOCK) {
-               last_buf = dma->buflist[send_index];
-               add_wait_queue(&last_buf->dma_wait, &entry);
-       }
-
-       if ((retcode = gamma_dma_enqueue(filp, d))) {
-               if (d->flags & _DRM_DMA_BLOCK)
-                       remove_wait_queue(&last_buf->dma_wait, &entry);
-               return retcode;
-       }
-
-       gamma_dma_schedule(dev, 0);
-
-       if (d->flags & _DRM_DMA_BLOCK) {
-               DRM_DEBUG("%d waiting\n", current->pid);
-               for (;;) {
-                       current->state = TASK_INTERRUPTIBLE;
-                       if (!last_buf->waiting && !last_buf->pending)
-                               break; /* finished */
-                       schedule();
-                       if (signal_pending(current)) {
-                               retcode = -EINTR; /* Can't restart */
-                               break;
-                       }
-               }
-               current->state = TASK_RUNNING;
-               DRM_DEBUG("%d running\n", current->pid);
-               remove_wait_queue(&last_buf->dma_wait, &entry);
-               if (!retcode
-                   || (last_buf->list==DRM_LIST_PEND && !last_buf->pending)) {
-                       if (!waitqueue_active(&last_buf->dma_wait)) {
-                               gamma_free_buffer(dev, last_buf);
-                       }
-               }
-               if (retcode) {
-                       DRM_ERROR("ctx%d w%d p%d c%ld i%d l%d pid:%d\n",
-                                 d->context,
-                                 last_buf->waiting,
-                                 last_buf->pending,
-                                 (long)DRM_WAITCOUNT(dev, d->context),
-                                 last_buf->idx,
-                                 last_buf->list,
-                                 current->pid);
-               }
-       }
-       return retcode;
-}
-
-int gamma_dma(struct inode *inode, struct file *filp, unsigned int cmd,
-             unsigned long arg)
-{
-       drm_file_t        *priv     = filp->private_data;
-       drm_device_t      *dev      = priv->dev;
-       drm_device_dma_t  *dma      = dev->dma;
-       int               retcode   = 0;
-       drm_dma_t         __user *argp = (void __user *)arg;
-       drm_dma_t         d;
-
-       if (copy_from_user(&d, argp, sizeof(d)))
-               return -EFAULT;
-
-       if (d.send_count < 0 || d.send_count > dma->buf_count) {
-               DRM_ERROR("Process %d trying to send %d buffers (of %d max)\n",
-                         current->pid, d.send_count, dma->buf_count);
-               return -EINVAL;
-       }
-
-       if (d.request_count < 0 || d.request_count > dma->buf_count) {
-               DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
-                         current->pid, d.request_count, dma->buf_count);
-               return -EINVAL;
-       }
-
-       if (d.send_count) {
-               if (d.flags & _DRM_DMA_PRIORITY)
-                       retcode = gamma_dma_priority(filp, dev, &d);
-               else
-                       retcode = gamma_dma_send_buffers(filp, dev, &d);
-       }
-
-       d.granted_count = 0;
-
-       if (!retcode && d.request_count) {
-               retcode = gamma_dma_get_buffers(filp, &d);
-       }
-
-       DRM_DEBUG("%d returning, granted = %d\n",
-                 current->pid, d.granted_count);
-       if (copy_to_user(argp, &d, sizeof(d)))
-               return -EFAULT;
-
-       return retcode;
-}
-
-/* =============================================================
- * DMA initialization, cleanup
- */
-
-static int gamma_do_init_dma( drm_device_t *dev, drm_gamma_init_t *init )
-{
-       drm_gamma_private_t *dev_priv;
-       drm_device_dma_t    *dma = dev->dma;
-       drm_buf_t           *buf;
-       int i;
-       struct list_head    *list;
-       unsigned long       *pgt;
-
-       DRM_DEBUG( "%s\n", __FUNCTION__ );
-
-       dev_priv = DRM(alloc)( sizeof(drm_gamma_private_t),
-                                                       DRM_MEM_DRIVER );
-       if ( !dev_priv )
-               return -ENOMEM;
-
-       dev->dev_private = (void *)dev_priv;
-
-       memset( dev_priv, 0, sizeof(drm_gamma_private_t) );
-
-       dev_priv->num_rast = init->num_rast;
-
-       list_for_each(list, &dev->maplist->head) {
-               drm_map_list_t *r_list = list_entry(list, drm_map_list_t, head);
-               if( r_list->map &&
-                   r_list->map->type == _DRM_SHM &&
-                   r_list->map->flags & _DRM_CONTAINS_LOCK ) {
-                       dev_priv->sarea = r_list->map;
-                       break;
-               }
-       }
-       
-       dev_priv->mmio0 = drm_core_findmap(dev, init->mmio0);
-       dev_priv->mmio1 = drm_core_findmap(dev, init->mmio1);
-       dev_priv->mmio2 = drm_core_findmap(dev, init->mmio2);
-       dev_priv->mmio3 = drm_core_findmap(dev, init->mmio3);
-       
-       dev_priv->sarea_priv = (drm_gamma_sarea_t *)
-               ((u8 *)dev_priv->sarea->handle +
-                init->sarea_priv_offset);
-
-       if (init->pcimode) {
-               buf = dma->buflist[GLINT_DRI_BUF_COUNT];
-               pgt = buf->address;
-
-               for (i = 0; i < GLINT_DRI_BUF_COUNT; i++) {
-                       buf = dma->buflist[i];
-                       *pgt = virt_to_phys((void*)buf->address) | 0x07;
-                       pgt++;
-               }
-
-               buf = dma->buflist[GLINT_DRI_BUF_COUNT];
-       } else {
-               dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
-               drm_core_ioremap( dev->agp_buffer_map, dev);
-
-               buf = dma->buflist[GLINT_DRI_BUF_COUNT];
-               pgt = buf->address;
-
-               for (i = 0; i < GLINT_DRI_BUF_COUNT; i++) {
-                       buf = dma->buflist[i];
-                       *pgt = (unsigned long)buf->address + 0x07;
-                       pgt++;
-               }
-
-               buf = dma->buflist[GLINT_DRI_BUF_COUNT];
-
-               while (GAMMA_READ(GAMMA_INFIFOSPACE) < 1);
-               GAMMA_WRITE( GAMMA_GDMACONTROL, 0xe);
-       }
-       while (GAMMA_READ(GAMMA_INFIFOSPACE) < 2);
-       GAMMA_WRITE( GAMMA_PAGETABLEADDR, virt_to_phys((void*)buf->address) );
-       GAMMA_WRITE( GAMMA_PAGETABLELENGTH, 2 );
-
-       return 0;
-}
-
-int gamma_do_cleanup_dma( drm_device_t *dev )
-{
-       DRM_DEBUG( "%s\n", __FUNCTION__ );
-
-       /* 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 (drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
-               if ( dev->irq_enabled ) 
-                       DRM(irq_uninstall)(dev);
-
-       if ( dev->dev_private ) {
-
-               if ( dev->agp_buffer_map != NULL )
-                       drm_core_ioremapfree( dev->agp_buffer_map, dev );
-
-               DRM(free)( dev->dev_private, sizeof(drm_gamma_private_t),
-                          DRM_MEM_DRIVER );
-               dev->dev_private = NULL;
-       }
-
-       return 0;
-}
-
-int gamma_dma_init( struct inode *inode, struct file *filp,
-                 unsigned int cmd, unsigned long arg )
-{
-       drm_file_t *priv = filp->private_data;
-       drm_device_t *dev = priv->dev;
-       drm_gamma_init_t init;
-
-       LOCK_TEST_WITH_RETURN( dev, filp );
-
-       if ( copy_from_user( &init, (drm_gamma_init_t __user *)arg, sizeof(init) ) )
-               return -EFAULT;
-
-       switch ( init.func ) {
-       case GAMMA_INIT_DMA:
-               return gamma_do_init_dma( dev, &init );
-       case GAMMA_CLEANUP_DMA:
-               return gamma_do_cleanup_dma( dev );
-       }
-
-       return -EINVAL;
-}
-
-static int gamma_do_copy_dma( drm_device_t *dev, drm_gamma_copy_t *copy )
-{
-       drm_device_dma_t    *dma = dev->dma;
-       unsigned int        *screenbuf;
-
-       DRM_DEBUG( "%s\n", __FUNCTION__ );
-
-       /* We've DRM_RESTRICTED this DMA buffer */
-
-       screenbuf = dma->buflist[ GLINT_DRI_BUF_COUNT + 1 ]->address;
-
-#if 0
-       *buffer++ = 0x180;      /* Tag (FilterMode) */
-       *buffer++ = 0x200;      /* Allow FBColor through */
-       *buffer++ = 0x53B;      /* Tag */
-       *buffer++ = copy->Pitch;
-       *buffer++ = 0x53A;      /* Tag */
-       *buffer++ = copy->SrcAddress;
-       *buffer++ = 0x539;      /* Tag */
-       *buffer++ = copy->WidthHeight; /* Initiates transfer */
-       *buffer++ = 0x53C;      /* Tag - DMAOutputAddress */
-       *buffer++ = virt_to_phys((void*)screenbuf);
-       *buffer++ = 0x53D;      /* Tag - DMAOutputCount */
-       *buffer++ = copy->Count; /* Reads HostOutFifo BLOCKS until ..*/
-
-       /* Data now sitting in dma->buflist[ GLINT_DRI_BUF_COUNT + 1 ] */
-       /* Now put it back to the screen */
-
-       *buffer++ = 0x180;      /* Tag (FilterMode) */
-       *buffer++ = 0x400;      /* Allow Sync through */
-       *buffer++ = 0x538;      /* Tag - DMARectangleReadTarget */
-       *buffer++ = 0x155;      /* FBSourceData | count */
-       *buffer++ = 0x537;      /* Tag */
-       *buffer++ = copy->Pitch;
-       *buffer++ = 0x536;      /* Tag */
-       *buffer++ = copy->DstAddress;
-       *buffer++ = 0x535;      /* Tag */
-       *buffer++ = copy->WidthHeight; /* Initiates transfer */
-       *buffer++ = 0x530;      /* Tag - DMAAddr */
-       *buffer++ = virt_to_phys((void*)screenbuf);
-       *buffer++ = 0x531;
-       *buffer++ = copy->Count; /* initiates DMA transfer of color data */
-#endif
-
-       /* need to dispatch it now */
-
-       return 0;
-}
-
-int gamma_dma_copy( struct inode *inode, struct file *filp,
-                 unsigned int cmd, unsigned long arg )
-{
-       drm_file_t *priv = filp->private_data;
-       drm_device_t *dev = priv->dev;
-       drm_gamma_copy_t copy;
-
-       if ( copy_from_user( &copy, (drm_gamma_copy_t __user *)arg, sizeof(copy) ) )
-               return -EFAULT;
-
-       return gamma_do_copy_dma( dev, &copy );
-}
-
-/* =============================================================
- * Per Context SAREA Support
- */
-
-int gamma_getsareactx(struct inode *inode, struct file *filp,
-                    unsigned int cmd, unsigned long arg)
-{
-       drm_file_t      *priv   = filp->private_data;
-       drm_device_t    *dev    = priv->dev;
-       drm_ctx_priv_map_t __user *argp = (void __user *)arg;
-       drm_ctx_priv_map_t request;
-       drm_map_t *map;
-
-       if (copy_from_user(&request, argp, sizeof(request)))
-               return -EFAULT;
-
-       down(&dev->struct_sem);
-       if ((int)request.ctx_id >= dev->max_context) {
-               up(&dev->struct_sem);
-               return -EINVAL;
-       }
-
-       map = dev->context_sareas[request.ctx_id];
-       up(&dev->struct_sem);
-
-       request.handle = map->handle;
-       if (copy_to_user(argp, &request, sizeof(request)))
-               return -EFAULT;
-       return 0;
-}
-
-int gamma_setsareactx(struct inode *inode, struct file *filp,
-                    unsigned int cmd, unsigned long arg)
-{
-       drm_file_t      *priv   = filp->private_data;
-       drm_device_t    *dev    = priv->dev;
-       drm_ctx_priv_map_t request;
-       drm_map_t *map = NULL;
-       drm_map_list_t *r_list;
-       struct list_head *list;
-
-       if (copy_from_user(&request,
-                          (drm_ctx_priv_map_t __user *)arg,
-                          sizeof(request)))
-               return -EFAULT;
-
-       down(&dev->struct_sem);
-       r_list = NULL;
-       list_for_each(list, &dev->maplist->head) {
-               r_list = list_entry(list, drm_map_list_t, head);
-               if(r_list->map &&
-                  r_list->map->handle == request.handle) break;
-       }
-       if (list == &(dev->maplist->head)) {
-               up(&dev->struct_sem);
-               return -EINVAL;
-       }
-       map = r_list->map;
-       up(&dev->struct_sem);
-
-       if (!map) return -EINVAL;
-
-       down(&dev->struct_sem);
-       if ((int)request.ctx_id >= dev->max_context) {
-               up(&dev->struct_sem);
-               return -EINVAL;
-       }
-       dev->context_sareas[request.ctx_id] = map;
-       up(&dev->struct_sem);
-       return 0;
-}
-
-void gamma_driver_irq_preinstall( drm_device_t *dev ) {
-       drm_gamma_private_t *dev_priv =
-                               (drm_gamma_private_t *)dev->dev_private;
-
-       while(GAMMA_READ(GAMMA_INFIFOSPACE) < 2)
-               cpu_relax();
-
-       GAMMA_WRITE( GAMMA_GCOMMANDMODE,        0x00000004 );
-       GAMMA_WRITE( GAMMA_GDMACONTROL,         0x00000000 );
-}
-
-void gamma_driver_irq_postinstall( drm_device_t *dev ) {
-       drm_gamma_private_t *dev_priv =
-                               (drm_gamma_private_t *)dev->dev_private;
-
-       while(GAMMA_READ(GAMMA_INFIFOSPACE) < 3)
-               cpu_relax();
-
-       GAMMA_WRITE( GAMMA_GINTENABLE,          0x00002001 );
-       GAMMA_WRITE( GAMMA_COMMANDINTENABLE,    0x00000008 );
-       GAMMA_WRITE( GAMMA_GDELAYTIMER,         0x00039090 );
-}
-
-void gamma_driver_irq_uninstall( drm_device_t *dev ) {
-       drm_gamma_private_t *dev_priv =
-                               (drm_gamma_private_t *)dev->dev_private;
-       if (!dev_priv)
-               return;
-
-       while(GAMMA_READ(GAMMA_INFIFOSPACE) < 3)
-               cpu_relax();
-
-       GAMMA_WRITE( GAMMA_GDELAYTIMER,         0x00000000 );
-       GAMMA_WRITE( GAMMA_COMMANDINTENABLE,    0x00000000 );
-       GAMMA_WRITE( GAMMA_GINTENABLE,          0x00000000 );
-}
-
-extern drm_ioctl_desc_t DRM(ioctls)[];
-
-static int gamma_driver_preinit(drm_device_t *dev)
-{
-       /* reset the finish ioctl */
-       DRM(ioctls)[DRM_IOCTL_NR(DRM_IOCTL_FINISH)].func = DRM(finish);
-       return 0;
-}
-
-static void gamma_driver_pretakedown(drm_device_t *dev)
-{
-       gamma_do_cleanup_dma(dev);
-}
-
-static void gamma_driver_dma_ready(drm_device_t *dev)
-{
-       gamma_dma_ready(dev);
-}
-
-static int gamma_driver_dma_quiescent(drm_device_t *dev)
-{
-       drm_gamma_private_t *dev_priv = (
-               drm_gamma_private_t *)dev->dev_private;
-       if (dev_priv->num_rast == 2)
-               gamma_dma_quiescent_dual(dev);
-       else gamma_dma_quiescent_single(dev);
-       return 0;
-}
-
-void gamma_driver_register_fns(drm_device_t *dev)
-{
-       dev->driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ;
-       DRM(fops).read = gamma_fops_read;
-       DRM(fops).poll = gamma_fops_poll;
-       dev->driver.preinit = gamma_driver_preinit;
-       dev->driver.pretakedown = gamma_driver_pretakedown;
-       dev->driver.dma_ready = gamma_driver_dma_ready;
-       dev->driver.dma_quiescent = gamma_driver_dma_quiescent;
-       dev->driver.dma_flush_block_and_flush = gamma_flush_block_and_flush;
-       dev->driver.dma_flush_unblock = gamma_flush_unblock;
-}
diff --git a/drivers/char/drm/gamma_drm.h b/drivers/char/drm/gamma_drm.h
deleted file mode 100644 (file)
index 20819de..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-#ifndef _GAMMA_DRM_H_
-#define _GAMMA_DRM_H_
-
-typedef struct _drm_gamma_tex_region {
-       unsigned char next, prev; /* indices to form a circular LRU  */
-       unsigned char in_use;   /* owned by a client, or free? */
-       int age;                /* tracked by clients to update local LRU's */
-} drm_gamma_tex_region_t;
-
-typedef struct {
-       unsigned int    GDeltaMode;
-       unsigned int    GDepthMode;
-       unsigned int    GGeometryMode;
-       unsigned int    GTransformMode;
-} drm_gamma_context_regs_t;
-
-typedef struct _drm_gamma_sarea {
-       drm_gamma_context_regs_t context_state;
-
-       unsigned int dirty;
-
-
-       /* Maintain an LRU of contiguous regions of texture space.  If
-        * you think you own a region of texture memory, and it has an
-        * age different to the one you set, then you are mistaken and
-        * it has been stolen by another client.  If global texAge
-        * hasn't changed, there is no need to walk the list.
-        *
-        * These regions can be used as a proxy for the fine-grained
-        * texture information of other clients - by maintaining them
-        * in the same lru which is used to age their own textures,
-        * clients have an approximate lru for the whole of global
-        * texture space, and can make informed decisions as to which
-        * areas to kick out.  There is no need to choose whether to
-        * kick out your own texture or someone else's - simply eject
-        * them all in LRU order.  
-        */
-   
-#define GAMMA_NR_TEX_REGIONS 64
-       drm_gamma_tex_region_t texList[GAMMA_NR_TEX_REGIONS+1]; 
-                               /* Last elt is sentinal */
-        int texAge;            /* 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 last_quiescent;     /*  */
-       int ctxOwner;           /* last context to upload state */
-
-       int vertex_prim;
-} drm_gamma_sarea_t;
-
-/* WARNING: If you change any of these defines, make sure to change the
- * defines in the Xserver file (xf86drmGamma.h)
- */
-
-/* Gamma specific ioctls
- * The device specific ioctl range is 0x40 to 0x79.
- */
-#define DRM_IOCTL_GAMMA_INIT           DRM_IOW( 0x40, drm_gamma_init_t)
-#define DRM_IOCTL_GAMMA_COPY           DRM_IOW( 0x41, drm_gamma_copy_t)
-
-typedef struct drm_gamma_copy {
-       unsigned int    DMAOutputAddress;
-       unsigned int    DMAOutputCount;
-       unsigned int    DMAReadGLINTSource;
-       unsigned int    DMARectangleWriteAddress;
-       unsigned int    DMARectangleWriteLinePitch;
-       unsigned int    DMARectangleWrite;
-       unsigned int    DMARectangleReadAddress;
-       unsigned int    DMARectangleReadLinePitch;
-       unsigned int    DMARectangleRead;
-       unsigned int    DMARectangleReadTarget;
-} drm_gamma_copy_t;
-
-typedef struct drm_gamma_init {
-       enum {
-               GAMMA_INIT_DMA    = 0x01,
-               GAMMA_CLEANUP_DMA = 0x02
-       } func;
-
-       int sarea_priv_offset;
-       int pcimode;
-       unsigned int mmio0;
-       unsigned int mmio1;
-       unsigned int mmio2;
-       unsigned int mmio3;
-       unsigned int buffers_offset;
-       int num_rast;
-} drm_gamma_init_t;
-
-#endif /* _GAMMA_DRM_H_ */
diff --git a/drivers/char/drm/gamma_drv.c b/drivers/char/drm/gamma_drv.c
deleted file mode 100644 (file)
index e7e64b6..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/* gamma.c -- 3dlabs GMX 2000 driver -*- linux-c -*-
- * Created: Mon Jan  4 08:58:31 1999 by faith@precisioninsight.com
- *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *    Rickard E. (Rik) Faith <faith@valinux.com>
- *    Gareth Hughes <gareth@valinux.com>
- */
-
-#include <linux/config.h>
-#include "gamma.h"
-#include "drmP.h"
-#include "drm.h"
-#include "gamma_drm.h"
-#include "gamma_drv.h"
-
-#include "drm_auth.h"
-#include "drm_agpsupport.h"
-#include "drm_bufs.h"
-#include "gamma_context.h"     /* NOTE! */
-#include "drm_dma.h"
-#include "gamma_old_dma.h"     /* NOTE */
-#include "drm_drawable.h"
-#include "drm_drv.h"
-
-#include "drm_fops.h"
-#include "drm_init.h"
-#include "drm_ioctl.h"
-#include "drm_irq.h"
-#include "gamma_lists.h"        /* NOTE */
-#include "drm_lock.h"
-#include "gamma_lock.h"                /* NOTE */
-#include "drm_memory.h"
-#include "drm_proc.h"
-#include "drm_vm.h"
-#include "drm_stub.h"
-#include "drm_scatter.h"
diff --git a/drivers/char/drm/gamma_drv.h b/drivers/char/drm/gamma_drv.h
deleted file mode 100644 (file)
index 146fcc6..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/* gamma_drv.h -- Private header for 3dlabs GMX 2000 driver -*- linux-c -*-
- * Created: Mon Jan  4 10:05:05 1999 by faith@precisioninsight.com
- *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *    Rickard E. (Rik) Faith <faith@valinux.com>
- *
- */
-
-#ifndef _GAMMA_DRV_H_
-#define _GAMMA_DRV_H_
-
-typedef struct drm_gamma_private {
-       drm_gamma_sarea_t *sarea_priv;
-       drm_map_t *sarea;
-       drm_map_t *mmio0;
-       drm_map_t *mmio1;
-       drm_map_t *mmio2;
-       drm_map_t *mmio3;
-       int num_rast;
-} drm_gamma_private_t;
-
-                               /* gamma_dma.c */
-extern int gamma_dma_init( struct inode *inode, struct file *filp,
-                        unsigned int cmd, unsigned long arg );
-extern int gamma_dma_copy( struct inode *inode, struct file *filp,
-                        unsigned int cmd, unsigned long arg );
-
-extern int gamma_do_cleanup_dma( drm_device_t *dev );
-extern void gamma_dma_ready(drm_device_t *dev);
-extern void gamma_dma_quiescent_single(drm_device_t *dev);
-extern void gamma_dma_quiescent_dual(drm_device_t *dev);
-
-                               /* gamma_dma.c */
-extern int  gamma_dma_schedule(drm_device_t *dev, int locked);
-extern int  gamma_dma(struct inode *inode, struct file *filp,
-                     unsigned int cmd, unsigned long arg);
-extern int  gamma_find_devices(void);
-extern int  gamma_found(void);
-
-/* Gamma-specific code pulled from drm_fops.h:
- */
-extern int          DRM(finish)(struct inode *inode, struct file *filp,
-                                unsigned int cmd, unsigned long arg);
-extern int          DRM(flush_unblock)(drm_device_t *dev, int context,
-                                       drm_lock_flags_t flags);
-extern int          DRM(flush_block_and_flush)(drm_device_t *dev, int context,
-                                               drm_lock_flags_t flags);
-
-/* Gamma-specific code pulled from drm_dma.h:
- */
-extern void         DRM(clear_next_buffer)(drm_device_t *dev);
-extern int          DRM(select_queue)(drm_device_t *dev,
-                                      void (*wrapper)(unsigned long));
-extern int          DRM(dma_enqueue)(struct file *filp, drm_dma_t *dma);
-extern int          DRM(dma_get_buffers)(struct file *filp, drm_dma_t *dma);
-
-
-/* Gamma-specific code pulled from drm_lists.h (now renamed gamma_lists.h):
- */
-extern int          DRM(waitlist_create)(drm_waitlist_t *bl, int count);
-extern int          DRM(waitlist_destroy)(drm_waitlist_t *bl);
-extern int          DRM(waitlist_put)(drm_waitlist_t *bl, drm_buf_t *buf);
-extern drm_buf_t     *DRM(waitlist_get)(drm_waitlist_t *bl);
-extern int          DRM(freelist_create)(drm_freelist_t *bl, int count);
-extern int          DRM(freelist_destroy)(drm_freelist_t *bl);
-extern int          DRM(freelist_put)(drm_device_t *dev, drm_freelist_t *bl,
-                                      drm_buf_t *buf);
-extern drm_buf_t     *DRM(freelist_get)(drm_freelist_t *bl, int block);
-
-/* externs for gamma changes to the ops */
-extern struct file_operations DRM(fops);
-extern unsigned int gamma_fops_poll(struct file *filp, struct poll_table_struct *wait);
-extern ssize_t gamma_fops_read(struct file *filp, char __user *buf, size_t count, loff_t *off);
-
-
-#define GLINT_DRI_BUF_COUNT 256
-
-#define GAMMA_OFF(reg)                                            \
-       ((reg < 0x1000)                                            \
-        ? reg                                                     \
-        : ((reg < 0x10000)                                        \
-           ? (reg - 0x1000)                                       \
-           : ((reg < 0x11000)                                     \
-              ? (reg - 0x10000)                                   \
-              : (reg - 0x11000))))
-
-#define GAMMA_BASE(reg)         ((unsigned long)                                    \
-                         ((reg < 0x1000)    ? dev_priv->mmio0->handle :     \
-                          ((reg < 0x10000)  ? dev_priv->mmio1->handle :     \
-                           ((reg < 0x11000) ? dev_priv->mmio2->handle :     \
-                                              dev_priv->mmio3->handle))))
-#define GAMMA_ADDR(reg)         (GAMMA_BASE(reg) + GAMMA_OFF(reg))
-#define GAMMA_DEREF(reg) *(__volatile__ int *)GAMMA_ADDR(reg)
-#define GAMMA_READ(reg)         GAMMA_DEREF(reg)
-#define GAMMA_WRITE(reg,val) do { GAMMA_DEREF(reg) = val; } while (0)
-
-#define GAMMA_BROADCASTMASK    0x9378
-#define GAMMA_COMMANDINTENABLE 0x0c48
-#define GAMMA_DMAADDRESS       0x0028
-#define GAMMA_DMACOUNT        0x0030
-#define GAMMA_FILTERMODE       0x8c00
-#define GAMMA_GCOMMANDINTFLAGS 0x0c50
-#define GAMMA_GCOMMANDMODE     0x0c40
-#define                GAMMA_QUEUED_DMA_MODE           1<<1
-#define GAMMA_GCOMMANDSTATUS   0x0c60
-#define GAMMA_GDELAYTIMER      0x0c38
-#define GAMMA_GDMACONTROL      0x0060
-#define        GAMMA_USE_AGP                   1<<1
-#define GAMMA_GINTENABLE       0x0808
-#define GAMMA_GINTFLAGS               0x0810
-#define GAMMA_INFIFOSPACE      0x0018
-#define GAMMA_OUTFIFOWORDS     0x0020
-#define GAMMA_OUTPUTFIFO       0x2000
-#define GAMMA_SYNC            0x8c40
-#define GAMMA_SYNC_TAG        0x0188
-#define GAMMA_PAGETABLEADDR    0x0C00
-#define GAMMA_PAGETABLELENGTH  0x0C08
-
-#define GAMMA_PASSTHROUGH      0x1FE
-#define GAMMA_DMAADDRTAG       0x530
-#define GAMMA_DMACOUNTTAG      0x531
-#define GAMMA_COMMANDINTTAG    0x532
-
-#endif
diff --git a/drivers/char/drm/gamma_lists.h b/drivers/char/drm/gamma_lists.h
deleted file mode 100644 (file)
index 2d93f41..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-/* drm_lists.h -- Buffer list handling routines -*- linux-c -*-
- * Created: Mon Apr 19 20:54:22 1999 by faith@valinux.com
- *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *    Rickard E. (Rik) Faith <faith@valinux.com>
- *    Gareth Hughes <gareth@valinux.com>
- */
-
-#include "drmP.h"
-
-
-int DRM(waitlist_create)(drm_waitlist_t *bl, int count)
-{
-       if (bl->count) return -EINVAL;
-
-       bl->bufs       = DRM(alloc)((bl->count + 2) * sizeof(*bl->bufs),
-                                   DRM_MEM_BUFLISTS);
-
-       if(!bl->bufs) return -ENOMEM;
-       memset(bl->bufs, 0, sizeof(*bl->bufs));
-       bl->count      = count;
-       bl->rp         = bl->bufs;
-       bl->wp         = bl->bufs;
-       bl->end        = &bl->bufs[bl->count+1];
-       spin_lock_init(&bl->write_lock);
-       spin_lock_init(&bl->read_lock);
-       return 0;
-}
-
-int DRM(waitlist_destroy)(drm_waitlist_t *bl)
-{
-       if (bl->rp != bl->wp) return -EINVAL;
-       if (bl->bufs) DRM(free)(bl->bufs,
-                               (bl->count + 2) * sizeof(*bl->bufs),
-                               DRM_MEM_BUFLISTS);
-       bl->count = 0;
-       bl->bufs  = NULL;
-       bl->rp    = NULL;
-       bl->wp    = NULL;
-       bl->end   = NULL;
-       return 0;
-}
-
-int DRM(waitlist_put)(drm_waitlist_t *bl, drm_buf_t *buf)
-{
-       int           left;
-       unsigned long flags;
-
-       left = DRM_LEFTCOUNT(bl);
-       if (!left) {
-               DRM_ERROR("Overflow while adding buffer %d from filp %p\n",
-                         buf->idx, buf->filp);
-               return -EINVAL;
-       }
-       buf->list        = DRM_LIST_WAIT;
-
-       spin_lock_irqsave(&bl->write_lock, flags);
-       *bl->wp = buf;
-       if (++bl->wp >= bl->end) bl->wp = bl->bufs;
-       spin_unlock_irqrestore(&bl->write_lock, flags);
-
-       return 0;
-}
-
-drm_buf_t *DRM(waitlist_get)(drm_waitlist_t *bl)
-{
-       drm_buf_t     *buf;
-       unsigned long flags;
-
-       spin_lock_irqsave(&bl->read_lock, flags);
-       buf = *bl->rp;
-       if (bl->rp == bl->wp) {
-               spin_unlock_irqrestore(&bl->read_lock, flags);
-               return NULL;
-       }
-       if (++bl->rp >= bl->end) bl->rp = bl->bufs;
-       spin_unlock_irqrestore(&bl->read_lock, flags);
-
-       return buf;
-}
-
-int DRM(freelist_create)(drm_freelist_t *bl, int count)
-{
-       atomic_set(&bl->count, 0);
-       bl->next      = NULL;
-       init_waitqueue_head(&bl->waiting);
-       bl->low_mark  = 0;
-       bl->high_mark = 0;
-       atomic_set(&bl->wfh,   0);
-       spin_lock_init(&bl->lock);
-       ++bl->initialized;
-       return 0;
-}
-
-int DRM(freelist_destroy)(drm_freelist_t *bl)
-{
-       atomic_set(&bl->count, 0);
-       bl->next = NULL;
-       return 0;
-}
-
-int DRM(freelist_put)(drm_device_t *dev, drm_freelist_t *bl, drm_buf_t *buf)
-{
-       drm_device_dma_t *dma  = dev->dma;
-
-       if (!dma) {
-               DRM_ERROR("No DMA support\n");
-               return 1;
-       }
-
-       if (buf->waiting || buf->pending || buf->list == DRM_LIST_FREE) {
-               DRM_ERROR("Freed buffer %d: w%d, p%d, l%d\n",
-                         buf->idx, buf->waiting, buf->pending, buf->list);
-       }
-       if (!bl) return 1;
-       buf->list       = DRM_LIST_FREE;
-
-       spin_lock(&bl->lock);
-       buf->next       = bl->next;
-       bl->next        = buf;
-       spin_unlock(&bl->lock);
-
-       atomic_inc(&bl->count);
-       if (atomic_read(&bl->count) > dma->buf_count) {
-               DRM_ERROR("%d of %d buffers free after addition of %d\n",
-                         atomic_read(&bl->count), dma->buf_count, buf->idx);
-               return 1;
-       }
-                               /* Check for high water mark */
-       if (atomic_read(&bl->wfh) && atomic_read(&bl->count)>=bl->high_mark) {
-               atomic_set(&bl->wfh, 0);
-               wake_up_interruptible(&bl->waiting);
-       }
-       return 0;
-}
-
-static drm_buf_t *DRM(freelist_try)(drm_freelist_t *bl)
-{
-       drm_buf_t         *buf;
-
-       if (!bl) return NULL;
-
-                               /* Get buffer */
-       spin_lock(&bl->lock);
-       if (!bl->next) {
-               spin_unlock(&bl->lock);
-               return NULL;
-       }
-       buf       = bl->next;
-       bl->next  = bl->next->next;
-       spin_unlock(&bl->lock);
-
-       atomic_dec(&bl->count);
-       buf->next = NULL;
-       buf->list = DRM_LIST_NONE;
-       if (buf->waiting || buf->pending) {
-               DRM_ERROR("Free buffer %d: w%d, p%d, l%d\n",
-                         buf->idx, buf->waiting, buf->pending, buf->list);
-       }
-
-       return buf;
-}
-
-drm_buf_t *DRM(freelist_get)(drm_freelist_t *bl, int block)
-{
-       drm_buf_t         *buf  = NULL;
-       DECLARE_WAITQUEUE(entry, current);
-
-       if (!bl || !bl->initialized) return NULL;
-
-                               /* Check for low water mark */
-       if (atomic_read(&bl->count) <= bl->low_mark) /* Became low */
-               atomic_set(&bl->wfh, 1);
-       if (atomic_read(&bl->wfh)) {
-               if (block) {
-                       add_wait_queue(&bl->waiting, &entry);
-                       for (;;) {
-                               current->state = TASK_INTERRUPTIBLE;
-                               if (!atomic_read(&bl->wfh)
-                                   && (buf = DRM(freelist_try)(bl))) break;
-                               schedule();
-                               if (signal_pending(current)) break;
-                       }
-                       current->state = TASK_RUNNING;
-                       remove_wait_queue(&bl->waiting, &entry);
-               }
-               return buf;
-       }
-
-       return DRM(freelist_try)(bl);
-}
-
diff --git a/drivers/char/drm/gamma_lock.h b/drivers/char/drm/gamma_lock.h
deleted file mode 100644 (file)
index ddec67e..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-/* lock.c -- IOCTLs for locking -*- linux-c -*-
- * Created: Tue Feb  2 08:37:54 1999 by faith@valinux.com
- *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *    Rickard E. (Rik) Faith <faith@valinux.com>
- *    Gareth Hughes <gareth@valinux.com>
- */
-
-
-/* Gamma-specific code extracted from drm_lock.h:
- */
-static int DRM(flush_queue)(drm_device_t *dev, int context)
-{
-       DECLARE_WAITQUEUE(entry, current);
-       int               ret   = 0;
-       drm_queue_t       *q    = dev->queuelist[context];
-
-       DRM_DEBUG("\n");
-
-       atomic_inc(&q->use_count);
-       if (atomic_read(&q->use_count) > 1) {
-               atomic_inc(&q->block_write);
-               add_wait_queue(&q->flush_queue, &entry);
-               atomic_inc(&q->block_count);
-               for (;;) {
-                       current->state = TASK_INTERRUPTIBLE;
-                       if (!DRM_BUFCOUNT(&q->waitlist)) break;
-                       schedule();
-                       if (signal_pending(current)) {
-                               ret = -EINTR; /* Can't restart */
-                               break;
-                       }
-               }
-               atomic_dec(&q->block_count);
-               current->state = TASK_RUNNING;
-               remove_wait_queue(&q->flush_queue, &entry);
-       }
-       atomic_dec(&q->use_count);
-
-                               /* NOTE: block_write is still incremented!
-                                  Use drm_flush_unlock_queue to decrement. */
-       return ret;
-}
-
-static int DRM(flush_unblock_queue)(drm_device_t *dev, int context)
-{
-       drm_queue_t       *q    = dev->queuelist[context];
-
-       DRM_DEBUG("\n");
-
-       atomic_inc(&q->use_count);
-       if (atomic_read(&q->use_count) > 1) {
-               if (atomic_read(&q->block_write)) {
-                       atomic_dec(&q->block_write);
-                       wake_up_interruptible(&q->write_queue);
-               }
-       }
-       atomic_dec(&q->use_count);
-       return 0;
-}
-
-int DRM(flush_block_and_flush)(drm_device_t *dev, int context,
-                              drm_lock_flags_t flags)
-{
-       int ret = 0;
-       int i;
-
-       DRM_DEBUG("\n");
-
-       if (flags & _DRM_LOCK_FLUSH) {
-               ret = DRM(flush_queue)(dev, DRM_KERNEL_CONTEXT);
-               if (!ret) ret = DRM(flush_queue)(dev, context);
-       }
-       if (flags & _DRM_LOCK_FLUSH_ALL) {
-               for (i = 0; !ret && i < dev->queue_count; i++) {
-                       ret = DRM(flush_queue)(dev, i);
-               }
-       }
-       return ret;
-}
-
-int DRM(flush_unblock)(drm_device_t *dev, int context, drm_lock_flags_t flags)
-{
-       int ret = 0;
-       int i;
-
-       DRM_DEBUG("\n");
-
-       if (flags & _DRM_LOCK_FLUSH) {
-               ret = DRM(flush_unblock_queue)(dev, DRM_KERNEL_CONTEXT);
-               if (!ret) ret = DRM(flush_unblock_queue)(dev, context);
-       }
-       if (flags & _DRM_LOCK_FLUSH_ALL) {
-               for (i = 0; !ret && i < dev->queue_count; i++) {
-                       ret = DRM(flush_unblock_queue)(dev, i);
-               }
-       }
-
-       return ret;
-}
-
-int DRM(finish)(struct inode *inode, struct file *filp, unsigned int cmd,
-               unsigned long arg)
-{
-       drm_file_t        *priv   = filp->private_data;
-       drm_device_t      *dev    = priv->dev;
-       int               ret     = 0;
-       drm_lock_t        lock;
-
-       DRM_DEBUG("\n");
-
-       if (copy_from_user(&lock, (drm_lock_t __user *)arg, sizeof(lock)))
-               return -EFAULT;
-       ret = DRM(flush_block_and_flush)(dev, lock.context, lock.flags);
-       DRM(flush_unblock)(dev, lock.context, lock.flags);
-       return ret;
-}
diff --git a/drivers/char/drm/gamma_old_dma.h b/drivers/char/drm/gamma_old_dma.h
deleted file mode 100644 (file)
index abdd454..0000000
+++ /dev/null
@@ -1,313 +0,0 @@
-/* drm_dma.c -- DMA IOCTL and function support -*- linux-c -*-
- * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com
- *
- * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *    Rickard E. (Rik) Faith <faith@valinux.com>
- *    Gareth Hughes <gareth@valinux.com>
- */
-
-
-/* Gamma-specific code pulled from drm_dma.h:
- */
-
-void DRM(clear_next_buffer)(drm_device_t *dev)
-{
-       drm_device_dma_t *dma = dev->dma;
-
-       dma->next_buffer = NULL;
-       if (dma->next_queue && !DRM_BUFCOUNT(&dma->next_queue->waitlist)) {
-               wake_up_interruptible(&dma->next_queue->flush_queue);
-       }
-       dma->next_queue  = NULL;
-}
-
-int DRM(select_queue)(drm_device_t *dev, void (*wrapper)(unsigned long))
-{
-       int        i;
-       int        candidate = -1;
-       int        j         = jiffies;
-
-       if (!dev) {
-               DRM_ERROR("No device\n");
-               return -1;
-       }
-       if (!dev->queuelist || !dev->queuelist[DRM_KERNEL_CONTEXT]) {
-                               /* This only happens between the time the
-                                  interrupt is initialized and the time
-                                  the queues are initialized. */
-               return -1;
-       }
-
-                               /* Doing "while locked" DMA? */
-       if (DRM_WAITCOUNT(dev, DRM_KERNEL_CONTEXT)) {
-               return DRM_KERNEL_CONTEXT;
-       }
-
-                               /* If there are buffers on the last_context
-                                  queue, and we have not been executing
-                                  this context very long, continue to
-                                  execute this context. */
-       if (dev->last_switch <= j
-           && dev->last_switch + DRM_TIME_SLICE > j
-           && DRM_WAITCOUNT(dev, dev->last_context)) {
-               return dev->last_context;
-       }
-
-                               /* Otherwise, find a candidate */
-       for (i = dev->last_checked + 1; i < dev->queue_count; i++) {
-               if (DRM_WAITCOUNT(dev, i)) {
-                       candidate = dev->last_checked = i;
-                       break;
-               }
-       }
-
-       if (candidate < 0) {
-               for (i = 0; i < dev->queue_count; i++) {
-                       if (DRM_WAITCOUNT(dev, i)) {
-                               candidate = dev->last_checked = i;
-                               break;
-                       }
-               }
-       }
-
-       if (wrapper
-           && candidate >= 0
-           && candidate != dev->last_context
-           && dev->last_switch <= j
-           && dev->last_switch + DRM_TIME_SLICE > j) {
-               if (dev->timer.expires != dev->last_switch + DRM_TIME_SLICE) {
-                       del_timer(&dev->timer);
-                       dev->timer.function = wrapper;
-                       dev->timer.data     = (unsigned long)dev;
-                       dev->timer.expires  = dev->last_switch+DRM_TIME_SLICE;
-                       add_timer(&dev->timer);
-               }
-               return -1;
-       }
-
-       return candidate;
-}
-
-
-int DRM(dma_enqueue)(struct file *filp, drm_dma_t *d)
-{
-       drm_file_t    *priv   = filp->private_data;
-       drm_device_t  *dev    = priv->dev;
-       int               i;
-       drm_queue_t       *q;
-       drm_buf_t         *buf;
-       int               idx;
-       int               while_locked = 0;
-       drm_device_dma_t  *dma = dev->dma;
-       int               *ind;
-       int               err;
-       DECLARE_WAITQUEUE(entry, current);
-
-       DRM_DEBUG("%d\n", d->send_count);
-
-       if (d->flags & _DRM_DMA_WHILE_LOCKED) {
-               int context = dev->lock.hw_lock->lock;
-
-               if (!_DRM_LOCK_IS_HELD(context)) {
-                       DRM_ERROR("No lock held during \"while locked\""
-                                 " request\n");
-                       return -EINVAL;
-               }
-               if (d->context != _DRM_LOCKING_CONTEXT(context)
-                   && _DRM_LOCKING_CONTEXT(context) != DRM_KERNEL_CONTEXT) {
-                       DRM_ERROR("Lock held by %d while %d makes"
-                                 " \"while locked\" request\n",
-                                 _DRM_LOCKING_CONTEXT(context),
-                                 d->context);
-                       return -EINVAL;
-               }
-               q = dev->queuelist[DRM_KERNEL_CONTEXT];
-               while_locked = 1;
-       } else {
-               q = dev->queuelist[d->context];
-       }
-
-
-       atomic_inc(&q->use_count);
-       if (atomic_read(&q->block_write)) {
-               add_wait_queue(&q->write_queue, &entry);
-               atomic_inc(&q->block_count);
-               for (;;) {
-                       current->state = TASK_INTERRUPTIBLE;
-                       if (!atomic_read(&q->block_write)) break;
-                       schedule();
-                       if (signal_pending(current)) {
-                               atomic_dec(&q->use_count);
-                               remove_wait_queue(&q->write_queue, &entry);
-                               return -EINTR;
-                       }
-               }
-               atomic_dec(&q->block_count);
-               current->state = TASK_RUNNING;
-               remove_wait_queue(&q->write_queue, &entry);
-       }
-
-       ind = DRM(alloc)(d->send_count * sizeof(int), DRM_MEM_DRIVER);
-       if (!ind)
-               return -ENOMEM;
-
-       if (copy_from_user(ind, d->send_indices, d->send_count * sizeof(int))) {
-               err = -EFAULT;
-                goto out;
-       }
-
-       err = -EINVAL;
-       for (i = 0; i < d->send_count; i++) {
-               idx = ind[i];
-               if (idx < 0 || idx >= dma->buf_count) {
-                       DRM_ERROR("Index %d (of %d max)\n",
-                                 ind[i], dma->buf_count - 1);
-                       goto out;
-               }
-               buf = dma->buflist[ idx ];
-               if (buf->filp != filp) {
-                       DRM_ERROR("Process %d using buffer not owned\n",
-                                 current->pid);
-                       goto out;
-               }
-               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;
-               }
-               buf->used         = ind[i];
-               buf->while_locked = while_locked;
-               buf->context      = d->context;
-               if (!buf->used) {
-                       DRM_ERROR("Queueing 0 length buffer\n");
-               }
-               if (buf->pending) {
-                       DRM_ERROR("Queueing pending buffer:"
-                                 " buffer %d, offset %d\n",
-                                 ind[i], i);
-                       goto out;
-               }
-               if (buf->waiting) {
-                       DRM_ERROR("Queueing waiting buffer:"
-                                 " buffer %d, offset %d\n",
-                                 ind[i], i);
-                       goto out;
-               }
-               buf->waiting = 1;
-               if (atomic_read(&q->use_count) == 1
-                   || atomic_read(&q->finalization)) {
-                       DRM(free_buffer)(dev, buf);
-               } else {
-                       DRM(waitlist_put)(&q->waitlist, buf);
-                       atomic_inc(&q->total_queued);
-               }
-       }
-       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;
-}
-
-static int DRM(dma_get_buffers_of_order)(struct file *filp, drm_dma_t *d,
-                                        int order)
-{
-       drm_file_t    *priv   = filp->private_data;
-       drm_device_t  *dev    = priv->dev;
-       int               i;
-       drm_buf_t         *buf;
-       drm_device_dma_t  *dma = dev->dma;
-
-       for (i = d->granted_count; i < d->request_count; i++) {
-               buf = DRM(freelist_get)(&dma->bufs[order].freelist,
-                                       d->flags & _DRM_DMA_WAIT);
-               if (!buf) break;
-               if (buf->pending || buf->waiting) {
-                       DRM_ERROR("Free buffer %d in use: filp %p (w%d, p%d)\n",
-                                 buf->idx,
-                                 buf->filp,
-                                 buf->waiting,
-                                 buf->pending);
-               }
-               buf->filp     = filp;
-               if (copy_to_user(&d->request_indices[i],
-                                &buf->idx,
-                                sizeof(buf->idx)))
-                       return -EFAULT;
-
-               if (copy_to_user(&d->request_sizes[i],
-                                &buf->total,
-                                sizeof(buf->total)))
-                       return -EFAULT;
-
-               ++d->granted_count;
-       }
-       return 0;
-}
-
-
-int DRM(dma_get_buffers)(struct file *filp, drm_dma_t *dma)
-{
-       int               order;
-       int               retcode = 0;
-       int               tmp_order;
-
-       order = DRM(order)(dma->request_size);
-
-       dma->granted_count = 0;
-       retcode            = DRM(dma_get_buffers_of_order)(filp, dma, order);
-
-       if (dma->granted_count < dma->request_count
-           && (dma->flags & _DRM_DMA_SMALLER_OK)) {
-               for (tmp_order = order - 1;
-                    !retcode
-                            && dma->granted_count < dma->request_count
-                            && tmp_order >= DRM_MIN_ORDER;
-                    --tmp_order) {
-
-                       retcode = DRM(dma_get_buffers_of_order)(filp, dma,
-                                                               tmp_order);
-               }
-       }
-
-       if (dma->granted_count < dma->request_count
-           && (dma->flags & _DRM_DMA_LARGER_OK)) {
-               for (tmp_order = order + 1;
-                    !retcode
-                            && dma->granted_count < dma->request_count
-                            && tmp_order <= DRM_MAX_ORDER;
-                    ++tmp_order) {
-
-                       retcode = DRM(dma_get_buffers_of_order)(filp, dma,
-                                                               tmp_order);
-               }
-       }
-       return 0;
-}
-
index 18e0b76228937d5236f4f55ee820b573353ed819..2f1659b96fd13771e64b24ad67c854baab4418a1 100644 (file)
 #define I810_BUF_UNMAPPED 0
 #define I810_BUF_MAPPED   1
 
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,2)
-#define down_write down
-#define up_write up
-#endif
-
 static drm_buf_t *i810_freelist_get(drm_device_t *dev)
 {
        drm_device_dma_t *dma = dev->dma;
@@ -351,6 +346,7 @@ static int i810_dma_initialize(drm_device_t *dev,
                DRM_ERROR("can not find mmio map!\n");
                return -EINVAL;
        }
+       dev->agp_buffer_token = init->buffers_offset;
        dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
        if (!dev->agp_buffer_map) {
                dev->dev_private = (void *)dev_priv;
@@ -1383,3 +1379,19 @@ drm_ioctl_desc_t i810_ioctls[] = {
 };
 
 int i810_max_ioctl = DRM_ARRAY_SIZE(i810_ioctls);
+
+/**
+ * Determine if the device really is AGP or not.
+ *
+ * All Intel graphics chipsets are treated as AGP, even if they are really
+ * PCI-e.
+ *
+ * \param dev   The device to be tested.
+ *
+ * \returns
+ * A value of 1 is always retured to indictate every i810 is AGP.
+ */
+int i810_driver_device_is_agp(drm_device_t * dev)
+{
+       return 1;
+}
index ff51b3259af9268ef4ac34e1743ed4d634ed43b9..00609329d5786be3e0671483dc07a5dacbd26116 100644 (file)
@@ -84,6 +84,7 @@ static struct drm_driver driver = {
        .dev_priv_size = sizeof(drm_i810_buf_priv_t),
        .pretakedown = i810_driver_pretakedown,
        .prerelease = i810_driver_prerelease,
+       .device_is_agp = i810_driver_device_is_agp,
        .release = i810_driver_release,
        .dma_quiescent = i810_driver_dma_quiescent,
        .reclaim_buffers = i810_reclaim_buffers,
index 1b40538d1725041d3dff8c603ef54b7adf4d1552..62ee4f58c59a97d7ab5186a0de5b6ad4719ea438 100644 (file)
@@ -120,6 +120,7 @@ extern int i810_driver_dma_quiescent(drm_device_t *dev);
 extern void i810_driver_release(drm_device_t *dev, struct file *filp);
 extern void i810_driver_pretakedown(drm_device_t *dev);
 extern void i810_driver_prerelease(drm_device_t *dev, DRMFILE filp);
+extern int i810_driver_device_is_agp(drm_device_t * dev);
 
 #define I810_BASE(reg)         ((unsigned long) \
                                dev_priv->mmio_map->handle)
index dc7733035864d9e2e058e0b86766bec7d1e11643..6f89d5796ef3b58f8d0e5bf113e6bb691de0e450 100644 (file)
 #define I830_BUF_UNMAPPED 0
 #define I830_BUF_MAPPED   1
 
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,2)
-#define down_write down
-#define up_write up
-#endif
-
 static drm_buf_t *i830_freelist_get(drm_device_t *dev)
 {
        drm_device_dma_t *dma = dev->dma;
@@ -358,6 +353,7 @@ static int i830_dma_initialize(drm_device_t *dev,
                DRM_ERROR("can not find mmio map!\n");
                return -EINVAL;
        }
+       dev->agp_buffer_token = init->buffers_offset;
        dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
        if(!dev->agp_buffer_map) {
                dev->dev_private = (void *)dev_priv;
@@ -1586,3 +1582,19 @@ drm_ioctl_desc_t i830_ioctls[] = {
 };
 
 int i830_max_ioctl = DRM_ARRAY_SIZE(i830_ioctls);
+
+/**
+ * Determine if the device really is AGP or not.
+ *
+ * All Intel graphics chipsets are treated as AGP, even if they are really
+ * PCI-e.
+ *
+ * \param dev   The device to be tested.
+ *
+ * \returns
+ * A value of 1 is always retured to indictate every i8xx is AGP.
+ */
+int i830_driver_device_is_agp(drm_device_t * dev)
+{
+       return 1;
+}
index bc36be76b8b238f79f13b4cdf0125fa7513a0cce..0da9cd19919e619369a480ae9bb707fa19b835a7 100644 (file)
@@ -88,6 +88,7 @@ static struct drm_driver driver = {
        .dev_priv_size = sizeof(drm_i830_buf_priv_t),
        .pretakedown = i830_driver_pretakedown,
        .prerelease = i830_driver_prerelease,
+       .device_is_agp = i830_driver_device_is_agp,
        .release = i830_driver_release,
        .dma_quiescent = i830_driver_dma_quiescent,
        .reclaim_buffers = i830_reclaim_buffers,
index df7746131dea80b1866d938c72cfda6c4e24e9a2..63f96a8b6a4a5bd77190ed07b49d69fe471f4b80 100644 (file)
@@ -137,6 +137,7 @@ extern void i830_driver_pretakedown(drm_device_t *dev);
 extern void i830_driver_release(drm_device_t *dev, struct file *filp);
 extern int i830_driver_dma_quiescent(drm_device_t *dev);
 extern void i830_driver_prerelease(drm_device_t *dev, DRMFILE filp);
+extern int i830_driver_device_is_agp(drm_device_t * dev);
 
 #define I830_BASE(reg)         ((unsigned long) \
                                dev_priv->mmio_map->handle)
index acf9e52a9507ff9293d0cd629a450289487d9774..34f552f90c4a82aaa857f8955e909c15c0ef28a3 100644 (file)
@@ -95,9 +95,8 @@ static int i915_dma_cleanup(drm_device_t * dev)
                        drm_core_ioremapfree( &dev_priv->ring.map, dev);
                }
 
-               if (dev_priv->hw_status_page) {
-                       drm_pci_free(dev, PAGE_SIZE, dev_priv->hw_status_page,
-                                    dev_priv->dma_status_page);
+               if (dev_priv->status_page_dmah) {
+                       drm_pci_free(dev, dev_priv->status_page_dmah);
                        /* Need to rewrite hardware status page */
                        I915_WRITE(0x02080, 0x1ffff000);
                }
@@ -174,16 +173,18 @@ static int i915_initialize(drm_device_t * dev,
        dev_priv->allow_batchbuffer = 1;
 
        /* Program Hardware Status Page */
-       dev_priv->hw_status_page = drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE,
-                                                0xffffffff, 
-                                                &dev_priv->dma_status_page);
+       dev_priv->status_page_dmah = drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE,
+                                                  0xffffffff);
 
-       if (!dev_priv->hw_status_page) {
+       if (!dev_priv->status_page_dmah) {
                dev->dev_private = (void *)dev_priv;
                i915_dma_cleanup(dev);
                DRM_ERROR("Can not allocate hardware status page\n");
                return DRM_ERR(ENOMEM);
        }
+       dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr;
+       dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr;
+
        memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
        DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
 
@@ -731,3 +732,19 @@ drm_ioctl_desc_t i915_ioctls[] = {
 };
 
 int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
+
+/**
+ * Determine if the device really is AGP or not.
+ *
+ * All Intel graphics chipsets are treated as AGP, even if they are really
+ * PCI-e.
+ *
+ * \param dev   The device to be tested.
+ *
+ * \returns
+ * A value of 1 is always retured to indictate every i9x5 is AGP.
+ */
+int i915_driver_device_is_agp(drm_device_t * dev)
+{
+       return 1;
+}
index 1f59d3fc79bcdabcbf0715556c3010c5be60a1b3..106b9ec022133316f67e9c5ae3d05c4764f09f5b 100644 (file)
@@ -79,6 +79,7 @@ static struct drm_driver driver = {
                                DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
        .pretakedown = i915_driver_pretakedown,
        .prerelease = i915_driver_prerelease,
+       .device_is_agp = i915_driver_device_is_agp,
        .irq_preinstall = i915_driver_irq_preinstall,
        .irq_postinstall = i915_driver_irq_postinstall,
        .irq_uninstall = i915_driver_irq_uninstall,
index 9c37d2367dd578bc6b6851c47cc5a82b560598d3..70ed4e68eac81e32158b762c4652b23eef2da905 100644 (file)
@@ -79,9 +79,10 @@ typedef struct drm_i915_private {
        drm_i915_sarea_t *sarea_priv;
        drm_i915_ring_buffer_t ring;
 
+       drm_dma_handle_t *status_page_dmah;
        void *hw_status_page;
-       unsigned long counter;
        dma_addr_t dma_status_page;
+       unsigned long counter;
 
        int back_offset;
        int front_offset;
@@ -102,6 +103,7 @@ typedef struct drm_i915_private {
 extern void i915_kernel_lost_context(drm_device_t * dev);
 extern void i915_driver_pretakedown(drm_device_t *dev);
 extern void i915_driver_prerelease(drm_device_t *dev, DRMFILE filp);
+extern int i915_driver_device_is_agp(drm_device_t *dev);
 
 /* i915_irq.c */
 extern int i915_irq_emit(DRM_IOCTL_ARGS);
index 832eaf8a5068db6ebe5d57e624ed76c4e32b5b93..567b425b784fc1695065fb652d8388d6a56f4f1c 100644 (file)
  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *    Rickard E. (Rik) Faith <faith@valinux.com>
- *    Jeff Hartmann <jhartmann@valinux.com>
- *    Keith Whitwell <keith@tungstengraphics.com>
- *
- * Rewritten by:
- *    Gareth Hughes <gareth@valinux.com>
+ */
+
+/**
+ * \file mga_dma.c
+ * DMA support for MGA G200 / G400.
+ * 
+ * \author Rickard E. (Rik) Faith <faith@valinux.com>
+ * \author Jeff Hartmann <jhartmann@valinux.com>
+ * \author Keith Whitwell <keith@tungstengraphics.com>
+ * \author Gareth Hughes <gareth@valinux.com>
  */
 
 #include "drmP.h"
 #include "drm.h"
+#include "drm_sarea.h"
 #include "mga_drm.h"
 #include "mga_drv.h"
 
@@ -148,7 +151,7 @@ void mga_do_dma_flush( drm_mga_private_t *dev_priv )
        DRM_DEBUG( "  space = 0x%06x\n", primary->space );
 
        mga_flush_write_combine();
-       MGA_WRITE( MGA_PRIMEND, tail | MGA_PAGPXFER );
+       MGA_WRITE(MGA_PRIMEND, tail | dev_priv->dma_access);
 
        DRM_DEBUG( "done.\n" );
 }
@@ -190,7 +193,7 @@ void mga_do_dma_wrap_start( drm_mga_private_t *dev_priv )
        DRM_DEBUG( "  space = 0x%06x\n", primary->space );
 
        mga_flush_write_combine();
-       MGA_WRITE( MGA_PRIMEND, tail | MGA_PAGPXFER );
+       MGA_WRITE(MGA_PRIMEND, tail | dev_priv->dma_access);
 
        set_bit( 0, &primary->wrapped );
        DRM_DEBUG( "done.\n" );
@@ -396,23 +399,383 @@ int mga_freelist_put( drm_device_t *dev, drm_buf_t *buf )
  * DMA initialization, cleanup
  */
 
+
+int mga_driver_preinit(drm_device_t *dev, unsigned long flags)
+{
+       drm_mga_private_t * dev_priv;
+
+       dev_priv = drm_alloc(sizeof(drm_mga_private_t), DRM_MEM_DRIVER);
+       if (!dev_priv)
+               return DRM_ERR(ENOMEM);
+
+       dev->dev_private = (void *)dev_priv;
+       memset(dev_priv, 0, sizeof(drm_mga_private_t));
+
+       dev_priv->usec_timeout = MGA_DEFAULT_USEC_TIMEOUT;
+       dev_priv->chipset = flags;
+
+       return 0;
+}
+
+/**
+ * Bootstrap the driver for AGP DMA.
+ * 
+ * \todo
+ * Investigate whether there is any benifit to storing the WARP microcode in
+ * AGP memory.  If not, the microcode may as well always be put in PCI
+ * memory.
+ *
+ * \todo
+ * This routine needs to set dma_bs->agp_mode to the mode actually configured
+ * in the hardware.  Looking just at the Linux AGP driver code, I don't see
+ * an easy way to determine this.
+ *
+ * \sa mga_do_dma_bootstrap, mga_do_pci_dma_bootstrap
+ */
+static int mga_do_agp_dma_bootstrap(drm_device_t * dev,
+                                   drm_mga_dma_bootstrap_t * dma_bs)
+{
+       drm_mga_private_t * const dev_priv = (drm_mga_private_t *) dev->dev_private;
+       const unsigned int warp_size = mga_warp_microcode_size(dev_priv);
+       int err;
+       unsigned  offset;
+       const unsigned secondary_size = dma_bs->secondary_bin_count
+               * dma_bs->secondary_bin_size;
+       const unsigned agp_size = (dma_bs->agp_size << 20);
+       drm_buf_desc_t req;
+       drm_agp_mode_t mode;
+       drm_agp_info_t info;
+
+       
+       /* Acquire AGP. */
+       err = drm_agp_acquire(dev);
+       if (err) {
+               DRM_ERROR("Unable to acquire AGP\n");
+               return err;
+       }
+
+       err = drm_agp_info(dev, &info);
+       if (err) {
+               DRM_ERROR("Unable to get AGP info\n");
+               return err;
+       }
+
+       mode.mode = (info.mode & ~0x07) | dma_bs->agp_mode;
+       err = drm_agp_enable(dev, mode);
+       if (err) {
+               DRM_ERROR("Unable to enable AGP (mode = 0x%lx)\n", mode.mode);
+               return err;
+       }
+
+
+       /* In addition to the usual AGP mode configuration, the G200 AGP cards
+        * need to have the AGP mode "manually" set.
+        */
+
+       if (dev_priv->chipset == MGA_CARD_TYPE_G200) {
+               if (mode.mode & 0x02) {
+                       MGA_WRITE(MGA_AGP_PLL, MGA_AGP2XPLL_ENABLE);
+               }
+               else {
+                       MGA_WRITE(MGA_AGP_PLL, MGA_AGP2XPLL_DISABLE);
+               }
+       }
+
+
+       /* Allocate and bind AGP memory. */
+       dev_priv->agp_pages = agp_size / PAGE_SIZE;
+       dev_priv->agp_mem = drm_alloc_agp( dev, dev_priv->agp_pages, 0 );
+       if (dev_priv->agp_mem == NULL) {
+               dev_priv->agp_pages = 0;
+               DRM_ERROR("Unable to allocate %uMB AGP memory\n",
+                         dma_bs->agp_size);
+               return DRM_ERR(ENOMEM);
+       }
+               
+       err = drm_bind_agp( dev_priv->agp_mem, 0 );
+       if (err) {
+               DRM_ERROR("Unable to bind AGP memory\n");
+               return err;
+       }
+
+       offset = 0;
+       err = drm_addmap( dev, offset, warp_size,
+                         _DRM_AGP, _DRM_READ_ONLY, & dev_priv->warp );
+       if (err) {
+               DRM_ERROR("Unable to map WARP microcode\n");
+               return err;
+       }
+
+       offset += warp_size;
+       err = drm_addmap( dev, offset, dma_bs->primary_size,
+                         _DRM_AGP, _DRM_READ_ONLY, & dev_priv->primary );
+       if (err) {
+               DRM_ERROR("Unable to map primary DMA region\n");
+               return err;
+       }
+
+       offset += dma_bs->primary_size;
+       err = drm_addmap( dev, offset, secondary_size,
+                         _DRM_AGP, 0, & dev->agp_buffer_map );
+       if (err) {
+               DRM_ERROR("Unable to map secondary DMA region\n");
+               return err;
+       }
+
+       (void) memset( &req, 0, sizeof(req) );
+       req.count = dma_bs->secondary_bin_count;
+       req.size = dma_bs->secondary_bin_size;
+       req.flags = _DRM_AGP_BUFFER;
+       req.agp_start = offset;
+
+       err = drm_addbufs_agp( dev, & req );
+       if (err) {
+               DRM_ERROR("Unable to add secondary DMA buffers\n");
+               return err;
+       }
+
+       offset += secondary_size;
+       err = drm_addmap( dev, offset, agp_size - offset,
+                         _DRM_AGP, 0, & dev_priv->agp_textures );
+       if (err) {
+               DRM_ERROR("Unable to map AGP texture region\n");
+               return err;
+       }
+
+       drm_core_ioremap(dev_priv->warp, dev);
+       drm_core_ioremap(dev_priv->primary, dev);
+       drm_core_ioremap(dev->agp_buffer_map, dev);
+
+       if (!dev_priv->warp->handle ||
+           !dev_priv->primary->handle || !dev->agp_buffer_map->handle) {
+               DRM_ERROR("failed to ioremap agp regions! (%p, %p, %p)\n",
+                         dev_priv->warp->handle, dev_priv->primary->handle,
+                         dev->agp_buffer_map->handle);
+               return DRM_ERR(ENOMEM);
+       }
+
+       dev_priv->dma_access = MGA_PAGPXFER;
+       dev_priv->wagp_enable = MGA_WAGP_ENABLE;
+
+       DRM_INFO("Initialized card for AGP DMA.\n");
+       return 0;
+}
+
+/**
+ * Bootstrap the driver for PCI DMA.
+ * 
+ * \todo
+ * The algorithm for decreasing the size of the primary DMA buffer could be
+ * better.  The size should be rounded up to the nearest page size, then
+ * decrease the request size by a single page each pass through the loop.
+ *
+ * \todo
+ * Determine whether the maximum address passed to drm_pci_alloc is correct.
+ * The same goes for drm_addbufs_pci.
+ * 
+ * \sa mga_do_dma_bootstrap, mga_do_agp_dma_bootstrap
+ */
+static int mga_do_pci_dma_bootstrap(drm_device_t * dev,
+                                   drm_mga_dma_bootstrap_t * dma_bs)
+{
+       drm_mga_private_t * const dev_priv = (drm_mga_private_t *) dev->dev_private;
+       const unsigned int warp_size = mga_warp_microcode_size(dev_priv);
+       unsigned int primary_size;
+       unsigned int bin_count;
+       int err;
+       drm_buf_desc_t req;
+
+       
+       if (dev->dma == NULL) {
+               DRM_ERROR("dev->dma is NULL\n");
+               return DRM_ERR(EFAULT);
+       }
+
+       /* The proper alignment is 0x100 for this mapping */
+       err = drm_addmap(dev, 0, warp_size, _DRM_CONSISTENT,
+                        _DRM_READ_ONLY, &dev_priv->warp);
+       if (err != 0) {
+               DRM_ERROR("Unable to create mapping for WARP microcode\n");
+               return err;
+       }
+
+       /* Other than the bottom two bits being used to encode other
+        * information, there don't appear to be any restrictions on the
+        * alignment of the primary or secondary DMA buffers.
+        */
+
+       for ( primary_size = dma_bs->primary_size
+             ; primary_size != 0
+             ; primary_size >>= 1 ) {
+               /* The proper alignment for this mapping is 0x04 */
+               err = drm_addmap(dev, 0, primary_size, _DRM_CONSISTENT,
+                                _DRM_READ_ONLY, &dev_priv->primary);
+               if (!err)
+                       break;
+       }
+
+       if (err != 0) {
+               DRM_ERROR("Unable to allocate primary DMA region\n");
+               return DRM_ERR(ENOMEM);
+       }
+
+       if (dev_priv->primary->size != dma_bs->primary_size) {
+               DRM_INFO("Primary DMA buffer size reduced from %u to %u.\n",
+                        dma_bs->primary_size, 
+                        (unsigned) dev_priv->primary->size);
+               dma_bs->primary_size = dev_priv->primary->size;
+       }
+
+       for ( bin_count = dma_bs->secondary_bin_count
+             ; bin_count > 0 
+             ; bin_count-- ) {
+               (void) memset( &req, 0, sizeof(req) );
+               req.count = bin_count;
+               req.size = dma_bs->secondary_bin_size;
+
+               err = drm_addbufs_pci( dev, & req );
+               if (!err) {
+                       break;
+               }
+       }
+       
+       if (bin_count == 0) {
+               DRM_ERROR("Unable to add secondary DMA buffers\n");
+               return err;
+       }
+
+       if (bin_count != dma_bs->secondary_bin_count) {
+               DRM_INFO("Secondary PCI DMA buffer bin count reduced from %u "
+                        "to %u.\n", dma_bs->secondary_bin_count, bin_count);
+
+               dma_bs->secondary_bin_count = bin_count;
+       }
+
+       dev_priv->dma_access = 0;
+       dev_priv->wagp_enable = 0;
+
+       dma_bs->agp_mode = 0;
+
+       DRM_INFO("Initialized card for PCI DMA.\n");
+       return 0;
+}
+
+
+static int mga_do_dma_bootstrap(drm_device_t * dev,
+                               drm_mga_dma_bootstrap_t * dma_bs)
+{
+       const int is_agp = (dma_bs->agp_mode != 0) && drm_device_is_agp(dev);
+       int err;
+       drm_mga_private_t * const dev_priv =
+               (drm_mga_private_t *) dev->dev_private;
+
+
+       dev_priv->used_new_dma_init = 1;
+
+       /* The first steps are the same for both PCI and AGP based DMA.  Map
+        * the cards MMIO registers and map a status page.
+        */
+       err = drm_addmap( dev, dev_priv->mmio_base, dev_priv->mmio_size,
+                         _DRM_REGISTERS, _DRM_READ_ONLY, & dev_priv->mmio );
+       if (err) {
+               DRM_ERROR("Unable to map MMIO region\n");
+               return err;
+       }
+
+
+       err = drm_addmap( dev, 0, SAREA_MAX, _DRM_SHM,
+                         _DRM_READ_ONLY | _DRM_LOCKED | _DRM_KERNEL,
+                         & dev_priv->status );
+       if (err) {
+               DRM_ERROR("Unable to map status region\n");
+               return err;
+       }
+
+
+       /* The DMA initialization procedure is slightly different for PCI and
+        * AGP cards.  AGP cards just allocate a large block of AGP memory and
+        * carve off portions of it for internal uses.  The remaining memory
+        * is returned to user-mode to be used for AGP textures.
+        */
+
+       if (is_agp) {
+               err = mga_do_agp_dma_bootstrap(dev, dma_bs);
+       }
+       
+       /* If we attempted to initialize the card for AGP DMA but failed,
+        * clean-up any mess that may have been created.
+        */
+
+       if (err) {
+               mga_do_cleanup_dma(dev);
+       }
+
+
+       /* Not only do we want to try and initialized PCI cards for PCI DMA,
+        * but we also try to initialized AGP cards that could not be
+        * initialized for AGP DMA.  This covers the case where we have an AGP
+        * card in a system with an unsupported AGP chipset.  In that case the
+        * card will be detected as AGP, but we won't be able to allocate any
+        * AGP memory, etc.
+        */
+
+       if (!is_agp || err) {
+               err = mga_do_pci_dma_bootstrap(dev, dma_bs);
+       }
+
+
+       return err;
+}
+
+int mga_dma_bootstrap(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_mga_dma_bootstrap_t bootstrap;
+       int err;
+
+
+       DRM_COPY_FROM_USER_IOCTL(bootstrap,
+                                (drm_mga_dma_bootstrap_t __user *) data,
+                                sizeof(bootstrap));
+
+       err = mga_do_dma_bootstrap(dev, & bootstrap);
+       if (! err) {
+               static const int modes[] = { 0, 1, 2, 2, 4, 4, 4, 4 };
+               const drm_mga_private_t * const dev_priv = 
+                       (drm_mga_private_t *) dev->dev_private;
+
+               if (dev_priv->agp_textures != NULL) {
+                       bootstrap.texture_handle = dev_priv->agp_textures->offset;
+                       bootstrap.texture_size = dev_priv->agp_textures->size;
+               }
+               else {
+                       bootstrap.texture_handle = 0;
+                       bootstrap.texture_size = 0;
+               }
+
+               bootstrap.agp_mode = modes[ bootstrap.agp_mode & 0x07 ];
+               if (DRM_COPY_TO_USER( (void __user *) data, & bootstrap,
+                                    sizeof(bootstrap))) {
+                       err = DRM_ERR(EFAULT);
+               }
+       }
+       else {
+               mga_do_cleanup_dma(dev);
+       }
+
+       return err;
+}
+
 static int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init )
 {
        drm_mga_private_t *dev_priv;
        int ret;
        DRM_DEBUG( "\n" );
 
-       dev_priv = drm_alloc( sizeof(drm_mga_private_t), DRM_MEM_DRIVER );
-       if ( !dev_priv )
-               return DRM_ERR(ENOMEM);
-
-       memset( dev_priv, 0, sizeof(drm_mga_private_t) );
 
-       dev_priv->chipset = init->chipset;
+       dev_priv = dev->dev_private;
 
-       dev_priv->usec_timeout = MGA_DEFAULT_USEC_TIMEOUT;
-
-       if ( init->sgram ) {
+       if (init->sgram) {
                dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_BLK;
        } else {
                dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_RSTR;
@@ -436,88 +799,66 @@ static int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init )
 
        DRM_GETSAREA();
 
-       if(!dev_priv->sarea) {
-               DRM_ERROR( "failed to find sarea!\n" );
-               /* Assign dev_private so we can do cleanup. */
-               dev->dev_private = (void *)dev_priv;
-               mga_do_cleanup_dma( dev );
+       if (!dev_priv->sarea) {
+               DRM_ERROR("failed to find sarea!\n");
                return DRM_ERR(EINVAL);
        }
 
-       dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset);
-       if(!dev_priv->mmio) {
-               DRM_ERROR( "failed to find mmio region!\n" );
-               /* Assign dev_private so we can do cleanup. */
-               dev->dev_private = (void *)dev_priv;
-               mga_do_cleanup_dma( dev );
-               return DRM_ERR(EINVAL);
-       }
-       dev_priv->status = drm_core_findmap(dev, init->status_offset);
-       if(!dev_priv->status) {
-               DRM_ERROR( "failed to find status page!\n" );
-               /* Assign dev_private so we can do cleanup. */
-               dev->dev_private = (void *)dev_priv;
-               mga_do_cleanup_dma( dev );
-               return DRM_ERR(EINVAL);
-       }
-       dev_priv->warp = drm_core_findmap(dev, init->warp_offset);
-       if(!dev_priv->warp) {
-               DRM_ERROR( "failed to find warp microcode region!\n" );
-               /* Assign dev_private so we can do cleanup. */
-               dev->dev_private = (void *)dev_priv;
-               mga_do_cleanup_dma( dev );
-               return DRM_ERR(EINVAL);
-       }
-       dev_priv->primary = drm_core_findmap(dev, init->primary_offset);
-       if(!dev_priv->primary) {
-               DRM_ERROR( "failed to find primary dma region!\n" );
-               /* Assign dev_private so we can do cleanup. */
-               dev->dev_private = (void *)dev_priv;
-               mga_do_cleanup_dma( dev );
-               return DRM_ERR(EINVAL);
-       }
-       dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
-       if(!dev->agp_buffer_map) {
-               DRM_ERROR( "failed to find dma buffer region!\n" );
-               /* Assign dev_private so we can do cleanup. */
-               dev->dev_private = (void *)dev_priv;
-               mga_do_cleanup_dma( dev );
-               return DRM_ERR(EINVAL);
+       if (! dev_priv->used_new_dma_init) {
+               dev_priv->status = drm_core_findmap(dev, init->status_offset);
+               if (!dev_priv->status) {
+                       DRM_ERROR("failed to find status page!\n");
+                       return DRM_ERR(EINVAL);
+               }
+               dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset);
+               if (!dev_priv->mmio) {
+                       DRM_ERROR("failed to find mmio region!\n");
+                       return DRM_ERR(EINVAL);
+               }
+               dev_priv->warp = drm_core_findmap(dev, init->warp_offset);
+               if (!dev_priv->warp) {
+                       DRM_ERROR("failed to find warp microcode region!\n");
+                       return DRM_ERR(EINVAL);
+               }
+               dev_priv->primary = drm_core_findmap(dev, init->primary_offset);
+               if (!dev_priv->primary) {
+                       DRM_ERROR("failed to find primary dma region!\n");
+                       return DRM_ERR(EINVAL);
+               }
+               dev->agp_buffer_token = init->buffers_offset;
+               dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
+               if (!dev->agp_buffer_map) {
+                       DRM_ERROR("failed to find dma buffer region!\n");
+                       return DRM_ERR(EINVAL);
+               }
+
+               drm_core_ioremap(dev_priv->warp, dev);
+               drm_core_ioremap(dev_priv->primary, dev);
+               drm_core_ioremap(dev->agp_buffer_map, dev);
        }
 
        dev_priv->sarea_priv =
                (drm_mga_sarea_t *)((u8 *)dev_priv->sarea->handle +
                                    init->sarea_priv_offset);
 
-       drm_core_ioremap( dev_priv->warp, dev );
-       drm_core_ioremap( dev_priv->primary, dev );
-       drm_core_ioremap( dev->agp_buffer_map, dev );
-
-       if(!dev_priv->warp->handle ||
-          !dev_priv->primary->handle ||
-          !dev->agp_buffer_map->handle ) {
-               DRM_ERROR( "failed to ioremap agp regions!\n" );
-               /* Assign dev_private so we can do cleanup. */
-               dev->dev_private = (void *)dev_priv;
-               mga_do_cleanup_dma( dev );
+       if (!dev_priv->warp->handle ||
+           !dev_priv->primary->handle ||
+           ((dev_priv->dma_access != 0) &&
+            ((dev->agp_buffer_map == NULL) ||
+             (dev->agp_buffer_map->handle == NULL)))) {
+               DRM_ERROR("failed to ioremap agp regions!\n");
                return DRM_ERR(ENOMEM);
        }
 
-       ret = mga_warp_install_microcode( dev_priv );
-       if ( ret < 0 ) {
-               DRM_ERROR( "failed to install WARP ucode!\n" );
-               /* Assign dev_private so we can do cleanup. */
-               dev->dev_private = (void *)dev_priv;
-               mga_do_cleanup_dma( dev );
+       ret = mga_warp_install_microcode(dev_priv);
+       if (ret < 0) {
+               DRM_ERROR("failed to install WARP ucode!\n");
                return ret;
        }
 
-       ret = mga_warp_init( dev_priv );
-       if ( ret < 0 ) {
-               DRM_ERROR( "failed to init WARP engine!\n" );
-               /* Assign dev_private so we can do cleanup. */
-               dev->dev_private = (void *)dev_priv;
-               mga_do_cleanup_dma( dev );
+       ret = mga_warp_init(dev_priv);
+       if (ret < 0) {
+               DRM_ERROR("failed to init WARP engine!\n");
                return ret;
        }
 
@@ -557,22 +898,18 @@ static int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init )
        dev_priv->sarea_priv->last_frame.head = 0;
        dev_priv->sarea_priv->last_frame.wrap = 0;
 
-       if ( mga_freelist_init( dev, dev_priv ) < 0 ) {
-               DRM_ERROR( "could not initialize freelist\n" );
-               /* Assign dev_private so we can do cleanup. */
-               dev->dev_private = (void *)dev_priv;
-               mga_do_cleanup_dma( dev );
+       if (mga_freelist_init(dev, dev_priv) < 0) {
+               DRM_ERROR("could not initialize freelist\n");
                return DRM_ERR(ENOMEM);
        }
 
-       /* Make dev_private visable to others. */
-       dev->dev_private = (void *)dev_priv;
        return 0;
 }
 
 static int mga_do_cleanup_dma( drm_device_t *dev )
 {
-       DRM_DEBUG( "\n" );
+       int err = 0;
+       DRM_DEBUG("\n");
 
        /* Make sure interrupts are disabled here because the uninstall ioctl
         * may not have been called from userspace and after dev_private
@@ -583,20 +920,49 @@ static int mga_do_cleanup_dma( drm_device_t *dev )
        if ( dev->dev_private ) {
                drm_mga_private_t *dev_priv = dev->dev_private;
 
-               if ( dev_priv->warp != NULL )
-                       drm_core_ioremapfree( dev_priv->warp, dev );
-               if ( dev_priv->primary != NULL )
-                       drm_core_ioremapfree( dev_priv->primary, dev );
-               if ( dev->agp_buffer_map != NULL )
-                       drm_core_ioremapfree( dev->agp_buffer_map, dev );
+               if ((dev_priv->warp != NULL) 
+                   && (dev_priv->mmio->type != _DRM_CONSISTENT))
+                       drm_core_ioremapfree(dev_priv->warp, dev);
+
+               if ((dev_priv->primary != NULL) 
+                   && (dev_priv->primary->type != _DRM_CONSISTENT))
+                       drm_core_ioremapfree(dev_priv->primary, dev);
 
-               if ( dev_priv->head != NULL ) {
-                       mga_freelist_cleanup( dev );
+               if (dev->agp_buffer_map != NULL)
+                       drm_core_ioremapfree(dev->agp_buffer_map, dev);
+
+               if (dev_priv->used_new_dma_init) {
+                       if (dev_priv->agp_mem != NULL) {
+                               dev_priv->agp_textures = NULL;
+                               drm_unbind_agp(dev_priv->agp_mem);
+
+                               drm_free_agp(dev_priv->agp_mem, dev_priv->agp_pages);
+                               dev_priv->agp_pages = 0;
+                               dev_priv->agp_mem = NULL;
+                       }
+
+                       if ((dev->agp != NULL) && dev->agp->acquired) {
+                               err = drm_agp_release(dev);
+                       }
+
+                       dev_priv->used_new_dma_init = 0;
                }
 
-               drm_free( dev->dev_private, sizeof(drm_mga_private_t),
-                          DRM_MEM_DRIVER );
-               dev->dev_private = NULL;
+               dev_priv->warp = NULL;
+               dev_priv->primary = NULL;
+               dev_priv->mmio = NULL;
+               dev_priv->status = NULL;
+               dev_priv->sarea = NULL;
+               dev_priv->sarea_priv = NULL;
+               dev->agp_buffer_map = NULL;
+
+               memset(&dev_priv->prim, 0, sizeof(dev_priv->prim));
+               dev_priv->warp_pipe = 0;
+               memset(dev_priv->warp_pipe_phys, 0, sizeof(dev_priv->warp_pipe_phys));
+
+               if (dev_priv->head != NULL) {
+                       mga_freelist_cleanup(dev);
+               }
        }
 
        return 0;
@@ -606,14 +972,20 @@ int mga_dma_init( DRM_IOCTL_ARGS )
 {
        DRM_DEVICE;
        drm_mga_init_t init;
+       int err;
 
        LOCK_TEST_WITH_RETURN( dev, filp );
 
-       DRM_COPY_FROM_USER_IOCTL( init, (drm_mga_init_t __user *)data, sizeof(init) );
+       DRM_COPY_FROM_USER_IOCTL(init, (drm_mga_init_t __user *) data,
+                                sizeof(init));
 
        switch ( init.func ) {
        case MGA_INIT_DMA:
-               return mga_do_init_dma( dev, &init );
+               err = mga_do_init_dma(dev, &init);
+               if (err) {
+                       (void) mga_do_cleanup_dma(dev);
+               }
+               return err;
        case MGA_CLEANUP_DMA:
                return mga_do_cleanup_dma( dev );
        }
@@ -742,7 +1114,21 @@ int mga_dma_buffers( DRM_IOCTL_ARGS )
        return ret;
 }
 
-void mga_driver_pretakedown(drm_device_t *dev)
+/**
+ * Called just before the module is unloaded.
+ */
+int mga_driver_postcleanup(drm_device_t * dev)
+{
+       drm_free(dev->dev_private, sizeof(drm_mga_private_t), DRM_MEM_DRIVER);
+       dev->dev_private = NULL;
+
+       return 0;
+}
+
+/**
+ * Called when the last opener of the device is closed.
+ */
+void mga_driver_pretakedown(drm_device_t * dev)
 {
        mga_do_cleanup_dma( dev );
 }
index 521d4451d012fd17dc3d852631535c0403ce6c84..d20aab3bd57bb66fdf6086f2d27a1d45cb0b1c6b 100644 (file)
@@ -73,7 +73,8 @@
 
 #define MGA_CARD_TYPE_G200     1
 #define MGA_CARD_TYPE_G400     2
-
+#define MGA_CARD_TYPE_G450     3       /* not currently used */
+#define MGA_CARD_TYPE_G550     4
 
 #define MGA_FRONT              0x1
 #define MGA_BACK               0x2
@@ -225,10 +226,6 @@ typedef struct _drm_mga_sarea {
 } drm_mga_sarea_t;
 
 
-/* WARNING: If you change any of these defines, make sure to change the
- * defines in the Xserver file (xf86drmMga.h)
- */
-
 /* MGA specific ioctls
  * The device specific ioctl range is 0x40 to 0x79.
  */
@@ -243,6 +240,14 @@ typedef struct _drm_mga_sarea {
 #define DRM_MGA_BLIT     0x08
 #define DRM_MGA_GETPARAM 0x09
 
+/* 3.2:
+ * ioctls for operating on fences.
+ */
+#define DRM_MGA_SET_FENCE      0x0a
+#define DRM_MGA_WAIT_FENCE     0x0b
+#define DRM_MGA_DMA_BOOTSTRAP  0x0c
+
+
 #define DRM_IOCTL_MGA_INIT     DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_INIT, drm_mga_init_t)
 #define DRM_IOCTL_MGA_FLUSH    DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_FLUSH, drm_lock_t)
 #define DRM_IOCTL_MGA_RESET    DRM_IO(  DRM_COMMAND_BASE + DRM_MGA_RESET)
@@ -253,6 +258,9 @@ typedef struct _drm_mga_sarea {
 #define DRM_IOCTL_MGA_ILOAD    DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_ILOAD, drm_mga_iload_t)
 #define DRM_IOCTL_MGA_BLIT     DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_BLIT, drm_mga_blit_t)
 #define DRM_IOCTL_MGA_GETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_GETPARAM, drm_mga_getparam_t)
+#define DRM_IOCTL_MGA_SET_FENCE     DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_SET_FENCE, uint32_t)
+#define DRM_IOCTL_MGA_WAIT_FENCE    DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_WAIT_FENCE, uint32_t)
+#define DRM_IOCTL_MGA_DMA_BOOTSTRAP DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_DMA_BOOTSTRAP, drm_mga_dma_bootstrap_t)
 
 typedef struct _drm_mga_warp_index {
        int installed;
@@ -291,12 +299,72 @@ typedef struct drm_mga_init {
        unsigned long buffers_offset;
 } drm_mga_init_t;
 
-typedef struct drm_mga_fullscreen {
-       enum {
-               MGA_INIT_FULLSCREEN    = 0x01,
-               MGA_CLEANUP_FULLSCREEN = 0x02
-       } func;
-} drm_mga_fullscreen_t;
+typedef struct drm_mga_dma_bootstrap {
+       /**
+        * \name AGP texture region
+        * 
+        * On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, these fields will
+        * be filled in with the actual AGP texture settings.
+        * 
+        * \warning
+        * If these fields are non-zero, but dma_mga_dma_bootstrap::agp_mode
+        * is zero, it means that PCI memory (most likely through the use of
+        * an IOMMU) is being used for "AGP" textures.
+        */
+       /*@{*/
+       unsigned long texture_handle; /**< Handle used to map AGP textures. */
+       uint32_t     texture_size;    /**< Size of the AGP texture region. */
+       /*@}*/
+
+
+       /**
+        * Requested size of the primary DMA region.
+        * 
+        * On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, this field will be
+        * filled in with the actual AGP mode.  If AGP was not available
+        */
+       uint32_t primary_size;
+
+
+       /**
+        * Requested number of secondary DMA buffers.
+        * 
+        * On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, this field will be
+        * filled in with the actual number of secondary DMA buffers
+        * allocated.  Particularly when PCI DMA is used, this may be
+        * (subtantially) less than the number requested.
+        */
+       uint32_t secondary_bin_count;
+       
+       
+       /**
+        * Requested size of each secondary DMA buffer.
+        * 
+        * While the kernel \b is free to reduce
+        * dma_mga_dma_bootstrap::secondary_bin_count, it is \b not allowed
+        * to reduce dma_mga_dma_bootstrap::secondary_bin_size.
+        */
+       uint32_t secondary_bin_size;
+
+
+       /**
+        * Bit-wise mask of AGPSTAT2_* values.  Currently only \c AGPSTAT2_1X,
+        * \c AGPSTAT2_2X, and \c AGPSTAT2_4X are supported.  If this value is
+        * zero, it means that PCI DMA should be used, even if AGP is
+        * possible.
+        * 
+        * On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, this field will be
+        * filled in with the actual AGP mode.  If AGP was not available
+        * (i.e., PCI DMA was used), this value will be zero.
+        */
+       uint32_t agp_mode;
+
+
+       /**
+        * Desired AGP GART size, measured in megabytes.
+        */
+       uint8_t agp_size;
+} drm_mga_dma_bootstrap_t;
 
 typedef struct drm_mga_clear {
        unsigned int flags;
@@ -341,6 +409,14 @@ typedef struct _drm_mga_blit {
  */
 #define MGA_PARAM_IRQ_NR            1
 
+/* 3.2: Query the actual card type.  The DDX only distinguishes between
+ * G200 chips and non-G200 chips, which it calls G400.  It turns out that
+ * there are some very sublte differences between the G4x0 chips and the G550
+ * chips.  Using this parameter query, a client-side driver can detect the
+ * difference between a G4x0 and a G550.
+ */
+#define MGA_PARAM_CARD_TYPE         2
+
 typedef struct drm_mga_getparam {
        int param;
        void __user *value;
index 844cca9cb29dfa65cf0d8bb3a44171846875c942..daabbba3b29789de0e1b662306e3fcbb9873e94e 100644 (file)
   
 #include "drm_pciids.h"
 
+static int mga_driver_device_is_agp(drm_device_t * dev);
 static int postinit( struct drm_device *dev, unsigned long flags )
 {
+       drm_mga_private_t * const dev_priv =
+               (drm_mga_private_t *) dev->dev_private;
+
+       dev_priv->mmio_base = pci_resource_start(dev->pdev, 1);
+       dev_priv->mmio_size = pci_resource_len(dev->pdev, 1);
+
        dev->counters += 3;
        dev->types[6] = _DRM_STAT_IRQ;
        dev->types[7] = _DRM_STAT_PRIMARY;
@@ -79,8 +86,11 @@ extern int mga_max_ioctl;
 
 static struct drm_driver driver = {
        .driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL,
+       .preinit = mga_driver_preinit,
+       .postcleanup = mga_driver_postcleanup,
        .pretakedown = mga_driver_pretakedown,
        .dma_quiescent = mga_driver_dma_quiescent,
+       .device_is_agp = mga_driver_device_is_agp,
        .vblank_wait = mga_driver_vblank_wait,
        .irq_preinstall = mga_driver_irq_preinstall,
        .irq_postinstall = mga_driver_irq_postinstall,
@@ -128,3 +138,38 @@ module_exit(mga_exit);
 MODULE_AUTHOR( DRIVER_AUTHOR );
 MODULE_DESCRIPTION( DRIVER_DESC );
 MODULE_LICENSE("GPL and additional rights");
+
+/**
+ * Determine if the device really is AGP or not.
+ *
+ * In addition to the usual tests performed by \c drm_device_is_agp, this
+ * function detects PCI G450 cards that appear to the system exactly like
+ * AGP G450 cards.
+ *
+ * \param dev   The device to be tested.
+ *
+ * \returns
+ * If the device is a PCI G450, zero is returned.  Otherwise 2 is returned.
+ */
+int mga_driver_device_is_agp(drm_device_t * dev)
+{
+       const struct pci_dev * const pdev = dev->pdev;
+
+
+       /* There are PCI versions of the G450.  These cards have the
+        * same PCI ID as the AGP G450, but have an additional PCI-to-PCI
+        * bridge chip.  We detect these cards, which are not currently
+        * supported by this driver, by looking at the device ID of the
+        * bus the "card" is on.  If vendor is 0x3388 (Hint Corp) and the
+        * device is 0x0021 (HB6 Universal PCI-PCI bridge), we reject the
+        * device.
+        */
+       
+       if ( (pdev->device == 0x0525)
+            && (pdev->bus->self->vendor == 0x3388)
+            && (pdev->bus->self->device == 0x0021) ) {
+               return 0;
+       }
+
+       return 2;
+}
index 9412e2816eb720d1794aeeb948c74b6ce274c495..b22fdbd4f830b561d058584383d107d42468144b 100644 (file)
 
 #define DRIVER_NAME            "mga"
 #define DRIVER_DESC            "Matrox G200/G400"
-#define DRIVER_DATE            "20021029"
+#define DRIVER_DATE            "20050607"
 
 #define DRIVER_MAJOR           3
-#define DRIVER_MINOR           1
+#define DRIVER_MINOR           2
 #define DRIVER_PATCHLEVEL      0
 
 typedef struct drm_mga_primary_buffer {
@@ -87,9 +87,43 @@ typedef struct drm_mga_private {
        int chipset;
        int usec_timeout;
 
+       /**
+        * If set, the new DMA initialization sequence was used.  This is
+        * primarilly used to select how the driver should uninitialized its
+        * internal DMA structures.
+        */
+       int used_new_dma_init;
+
+       /**
+        * If AGP memory is used for DMA buffers, this will be the value
+        * \c MGA_PAGPXFER.  Otherwise, it will be zero (for a PCI transfer).
+        */
+       u32 dma_access;
+
+       /**
+        * If AGP memory is used for DMA buffers, this will be the value
+        * \c MGA_WAGP_ENABLE.  Otherwise, it will be zero (for a PCI
+        * transfer).
+        */
+       u32 wagp_enable;
+
+       /**
+        * \name MMIO region parameters.
+        * 
+        * \sa drm_mga_private_t::mmio
+        */
+       /*@{*/
+       u32 mmio_base;             /**< Bus address of base of MMIO. */
+       u32 mmio_size;             /**< Size of the MMIO region. */
+       /*@}*/
+
        u32 clear_cmd;
        u32 maccess;
 
+       wait_queue_head_t fence_queue;
+       atomic_t last_fence_retired;
+       u32 next_fence_to_post;
+
        unsigned int fb_cpp;
        unsigned int front_offset;
        unsigned int front_pitch;
@@ -108,35 +142,43 @@ typedef struct drm_mga_private {
        drm_local_map_t *status;
        drm_local_map_t *warp;
        drm_local_map_t *primary;
-       drm_local_map_t *buffers;
        drm_local_map_t *agp_textures;
+       
+       DRM_AGP_MEM *agp_mem;
+       unsigned int agp_pages;
 } drm_mga_private_t;
 
                                /* mga_dma.c */
-extern int mga_dma_init( DRM_IOCTL_ARGS );
-extern int mga_dma_flush( DRM_IOCTL_ARGS );
-extern int mga_dma_reset( DRM_IOCTL_ARGS );
-extern int mga_dma_buffers( DRM_IOCTL_ARGS );
-extern void mga_driver_pretakedown(drm_device_t *dev);
-extern int mga_driver_dma_quiescent(drm_device_t *dev);
-
-extern int mga_do_wait_for_idle( drm_mga_private_t *dev_priv );
-
-extern void mga_do_dma_flush( drm_mga_private_t *dev_priv );
-extern void mga_do_dma_wrap_start( drm_mga_private_t *dev_priv );
-extern void mga_do_dma_wrap_end( drm_mga_private_t *dev_priv );
+extern int mga_driver_preinit(drm_device_t * dev, unsigned long flags);
+extern int mga_dma_bootstrap(DRM_IOCTL_ARGS);
+extern int mga_dma_init(DRM_IOCTL_ARGS);
+extern int mga_dma_flush(DRM_IOCTL_ARGS);
+extern int mga_dma_reset(DRM_IOCTL_ARGS);
+extern int mga_dma_buffers(DRM_IOCTL_ARGS);
+extern int mga_driver_postcleanup(drm_device_t * dev);
+extern void mga_driver_pretakedown(drm_device_t * dev);
+extern int mga_driver_dma_quiescent(drm_device_t * dev);
+
+extern int mga_do_wait_for_idle(drm_mga_private_t * dev_priv);
+
+extern void mga_do_dma_flush(drm_mga_private_t * dev_priv);
+extern void mga_do_dma_wrap_start(drm_mga_private_t * dev_priv);
+extern void mga_do_dma_wrap_end(drm_mga_private_t * dev_priv);
 
 extern int mga_freelist_put( drm_device_t *dev, drm_buf_t *buf );
 
                                /* mga_warp.c */
-extern int mga_warp_install_microcode( drm_mga_private_t *dev_priv );
-extern int mga_warp_init( drm_mga_private_t *dev_priv );
-
-extern int mga_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence);
-extern irqreturn_t mga_driver_irq_handler( DRM_IRQ_ARGS );
-extern void mga_driver_irq_preinstall( drm_device_t *dev );
-extern void mga_driver_irq_postinstall( drm_device_t *dev );
-extern void mga_driver_irq_uninstall( drm_device_t *dev );
+extern unsigned int mga_warp_microcode_size(const drm_mga_private_t * dev_priv);
+extern int mga_warp_install_microcode(drm_mga_private_t * dev_priv);
+extern int mga_warp_init(drm_mga_private_t * dev_priv);
+
+                               /* mga_irq.c */
+extern int mga_driver_fence_wait(drm_device_t * dev, unsigned int *sequence);
+extern int mga_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence);
+extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS);
+extern void mga_driver_irq_preinstall(drm_device_t * dev);
+extern void mga_driver_irq_postinstall(drm_device_t * dev);
+extern void mga_driver_irq_uninstall(drm_device_t * dev);
 extern long mga_compat_ioctl(struct file *filp, unsigned int cmd,
                             unsigned long arg);
 
@@ -527,6 +569,12 @@ do {                                                                       \
  */
 #define MGA_EXEC                       0x0100
 
+/* AGP PLL encoding (for G200 only).
+ */
+#define MGA_AGP_PLL                    0x1e4c
+#      define MGA_AGP2XPLL_DISABLE             (0 << 0)
+#      define MGA_AGP2XPLL_ENABLE              (1 << 0)
+
 /* Warp registers
  */
 #define MGA_WR0                                0x2d00
index bc745cfa2095dc7e5370ed909063bbeb8fcb1921..77d738e75a4df598b8a0a97d5d4377a0170efab7 100644 (file)
@@ -129,9 +129,76 @@ static int compat_mga_getparam(struct file *file, unsigned int cmd,
                         DRM_IOCTL_MGA_GETPARAM, (unsigned long)getparam);
 }
 
+typedef struct drm_mga_drm_bootstrap32 {
+       u32 texture_handle;
+       u32 texture_size;
+       u32 primary_size;
+       u32 secondary_bin_count;
+       u32 secondary_bin_size;
+       u32 agp_mode;
+       u8 agp_size;
+} drm_mga_dma_bootstrap32_t;
+
+static int compat_mga_dma_bootstrap(struct file *file, unsigned int cmd,
+                                   unsigned long arg)
+{
+       drm_mga_dma_bootstrap32_t dma_bootstrap32;
+       drm_mga_dma_bootstrap_t __user *dma_bootstrap;
+       int err;
+
+       if (copy_from_user(&dma_bootstrap32, (void __user *)arg,
+                          sizeof(dma_bootstrap32)))
+               return -EFAULT;
+
+       dma_bootstrap = compat_alloc_user_space(sizeof(*dma_bootstrap));
+       if (!access_ok(VERIFY_WRITE, dma_bootstrap, sizeof(*dma_bootstrap))
+           || __put_user(dma_bootstrap32.texture_handle,
+                         &dma_bootstrap->texture_handle)
+           || __put_user(dma_bootstrap32.texture_size,
+                         &dma_bootstrap->texture_size)
+           || __put_user(dma_bootstrap32.primary_size,
+                         &dma_bootstrap->primary_size)
+           || __put_user(dma_bootstrap32.secondary_bin_count,
+                         &dma_bootstrap->secondary_bin_count)
+           || __put_user(dma_bootstrap32.secondary_bin_size,
+                         &dma_bootstrap->secondary_bin_size)
+           || __put_user(dma_bootstrap32.agp_mode, &dma_bootstrap->agp_mode)
+           || __put_user(dma_bootstrap32.agp_size, &dma_bootstrap->agp_size))
+               return -EFAULT;
+
+       err = drm_ioctl(file->f_dentry->d_inode, file,
+                       DRM_IOCTL_MGA_DMA_BOOTSTRAP,
+                       (unsigned long)dma_bootstrap);
+       if (err)
+               return err;
+
+       if (__get_user(dma_bootstrap32.texture_handle,
+                      &dma_bootstrap->texture_handle)
+           || __get_user(dma_bootstrap32.texture_size,
+                         &dma_bootstrap->texture_size)
+           || __get_user(dma_bootstrap32.primary_size,
+                         &dma_bootstrap->primary_size)
+           || __get_user(dma_bootstrap32.secondary_bin_count,
+                         &dma_bootstrap->secondary_bin_count)
+           || __get_user(dma_bootstrap32.secondary_bin_size,
+                         &dma_bootstrap->secondary_bin_size)
+           || __get_user(dma_bootstrap32.agp_mode,
+                         &dma_bootstrap->agp_mode)
+           || __get_user(dma_bootstrap32.agp_size,
+                         &dma_bootstrap->agp_size))
+               return -EFAULT;
+
+       if (copy_to_user((void __user *)arg, &dma_bootstrap32,
+                        sizeof(dma_bootstrap32)))
+               return -EFAULT;
+
+       return 0;
+}
+
 drm_ioctl_compat_t *mga_compat_ioctls[] = {
        [DRM_MGA_INIT] = compat_mga_init,
        [DRM_MGA_GETPARAM] = compat_mga_getparam,
+       [DRM_MGA_DMA_BOOTSTRAP] = compat_mga_dma_bootstrap,
 };
 
 /**
index bc0b6b5d43a6de1de438d9ad5ce1e3ce2988cfc8..52eaa4e788f91f2cef5548b149ca648eed2b6550 100644 (file)
@@ -41,15 +41,40 @@ irqreturn_t mga_driver_irq_handler( DRM_IRQ_ARGS )
        drm_mga_private_t *dev_priv = 
           (drm_mga_private_t *)dev->dev_private;
        int status;
+       int handled = 0;
+
+       status = MGA_READ(MGA_STATUS);
 
-       status = MGA_READ( MGA_STATUS );
-       
        /* VBLANK interrupt */
        if ( status & MGA_VLINEPEN ) {
                MGA_WRITE( MGA_ICLEAR, MGA_VLINEICLR );
                atomic_inc(&dev->vbl_received);
                DRM_WAKEUP(&dev->vbl_queue);
-               drm_vbl_send_signals( dev );
+               drm_vbl_send_signals(dev);
+               handled = 1;
+       }
+
+       /* SOFTRAP interrupt */
+       if (status & MGA_SOFTRAPEN) {
+               const u32 prim_start = MGA_READ(MGA_PRIMADDRESS);
+               const u32 prim_end   = MGA_READ(MGA_PRIMEND);
+
+
+               MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR);
+
+               /* In addition to clearing the interrupt-pending bit, we
+                * have to write to MGA_PRIMEND to re-start the DMA operation.
+                */
+               if ( (prim_start & ~0x03) != (prim_end & ~0x03) ) {
+                       MGA_WRITE(MGA_PRIMEND, prim_end);
+               }
+
+               atomic_inc(&dev_priv->last_fence_retired);
+               DRM_WAKEUP(&dev_priv->fence_queue);
+               handled = 1;
+       }
+
+       if ( handled ) {
                return IRQ_HANDLED;
        }
        return IRQ_NONE;
@@ -73,9 +98,28 @@ int mga_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence)
        return ret;
 }
 
-void mga_driver_irq_preinstall( drm_device_t *dev ) {
-       drm_mga_private_t *dev_priv = 
-          (drm_mga_private_t *)dev->dev_private;
+int mga_driver_fence_wait(drm_device_t * dev, unsigned int *sequence)
+{
+       drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
+       unsigned int cur_fence;
+       int ret = 0;
+
+       /* Assume that the user has missed the current sequence number
+        * by about a day rather than she wants to wait for years
+        * using fences.
+        */
+       DRM_WAIT_ON(ret, dev_priv->fence_queue, 3 * DRM_HZ,
+                   (((cur_fence = atomic_read(&dev_priv->last_fence_retired))
+                     - *sequence) <= (1 << 23)));
+
+       *sequence = cur_fence;
+
+       return ret;
+}
+
+void mga_driver_irq_preinstall(drm_device_t * dev)
+{
+       drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
 
        /* Disable *all* interrupts */
        MGA_WRITE( MGA_IEN, 0 );
@@ -83,12 +127,14 @@ void mga_driver_irq_preinstall( drm_device_t *dev ) {
        MGA_WRITE( MGA_ICLEAR, ~0 );
 }
 
-void mga_driver_irq_postinstall( drm_device_t *dev ) {
-       drm_mga_private_t *dev_priv = 
-          (drm_mga_private_t *)dev->dev_private;
+void mga_driver_irq_postinstall(drm_device_t * dev)
+{
+       drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
+
+       DRM_INIT_WAITQUEUE( &dev_priv->fence_queue );
 
-       /* Turn on VBL interrupt */
-       MGA_WRITE( MGA_IEN, MGA_VLINEIEN );
+       /* Turn on vertical blank interrupt and soft trap interrupt. */
+       MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
 }
 
 void mga_driver_irq_uninstall( drm_device_t *dev ) {
@@ -98,5 +144,7 @@ void mga_driver_irq_uninstall( drm_device_t *dev ) {
                return;
 
        /* Disable *all* interrupts */
-       MGA_WRITE( MGA_IEN, 0 );
+       MGA_WRITE(MGA_IEN, 0);
+       
+       dev->irq_enabled = 0;
 }
index 3c7a8f5ba50133e3289971b05e52402418935a82..05bbb4719376ac9fe1f424f8633d29a5643c2005 100644 (file)
@@ -53,16 +53,16 @@ static void mga_emit_clip_rect( drm_mga_private_t *dev_priv,
 
        /* Force reset of DWGCTL on G400 (eliminates clip disable bit).
         */
-       if ( dev_priv->chipset == MGA_CARD_TYPE_G400 ) {
-               DMA_BLOCK( MGA_DWGCTL,          ctx->dwgctl,
-                          MGA_LEN + MGA_EXEC,  0x80000000,
-                          MGA_DWGCTL,          ctx->dwgctl,
-                          MGA_LEN + MGA_EXEC,  0x80000000 );
+       if (dev_priv->chipset == MGA_CARD_TYPE_G400) {
+               DMA_BLOCK(MGA_DWGCTL, ctx->dwgctl,
+                         MGA_LEN + MGA_EXEC, 0x80000000,
+                         MGA_DWGCTL, ctx->dwgctl,
+                         MGA_LEN + MGA_EXEC, 0x80000000);
        }
-       DMA_BLOCK( MGA_DMAPAD,  0x00000000,
-                  MGA_CXBNDRY, (box->x2 << 16) | box->x1,
-                  MGA_YTOP,    box->y1 * pitch,
-                  MGA_YBOT,    box->y2 * pitch );
+       DMA_BLOCK(MGA_DMAPAD, 0x00000000,
+                 MGA_CXBNDRY, ((box->x2 - 1) << 16) | box->x1,
+                 MGA_YTOP, box->y1 * pitch,
+                 MGA_YBOT, (box->y2 - 1) * pitch);
 
        ADVANCE_DMA();
 }
@@ -260,12 +260,11 @@ static __inline__ void mga_g200_emit_pipe( drm_mga_private_t *dev_priv )
 
        /* Padding required to to hardware bug.
         */
-       DMA_BLOCK( MGA_DMAPAD,  0xffffffff,
-                  MGA_DMAPAD,  0xffffffff,
-                  MGA_DMAPAD,  0xffffffff,
-                  MGA_WIADDR,  (dev_priv->warp_pipe_phys[pipe] |
-                                MGA_WMODE_START |
-                                MGA_WAGP_ENABLE) );
+       DMA_BLOCK(MGA_DMAPAD, 0xffffffff,
+                 MGA_DMAPAD, 0xffffffff,
+                 MGA_DMAPAD, 0xffffffff,
+                 MGA_WIADDR, (dev_priv->warp_pipe_phys[pipe] |
+                              MGA_WMODE_START | dev_priv->wagp_enable));
 
        ADVANCE_DMA();
 }
@@ -342,12 +341,11 @@ static __inline__ void mga_g400_emit_pipe( drm_mga_private_t *dev_priv )
                   MGA_WR60,    MGA_G400_WR_MAGIC );    /* tex1 height       */
 
        /* Padding required to to hardware bug */
-       DMA_BLOCK( MGA_DMAPAD,  0xffffffff,
-                  MGA_DMAPAD,  0xffffffff,
-                  MGA_DMAPAD,  0xffffffff,
-                  MGA_WIADDR2, (dev_priv->warp_pipe_phys[pipe] |
-                                MGA_WMODE_START |
-                                MGA_WAGP_ENABLE) );
+       DMA_BLOCK(MGA_DMAPAD, 0xffffffff,
+                 MGA_DMAPAD, 0xffffffff,
+                 MGA_DMAPAD, 0xffffffff,
+                 MGA_WIADDR2, (dev_priv->warp_pipe_phys[pipe] |
+                               MGA_WMODE_START | dev_priv->wagp_enable));
 
        ADVANCE_DMA();
 }
@@ -459,9 +457,9 @@ static int mga_verify_state( drm_mga_private_t *dev_priv )
        if ( dirty & MGA_UPLOAD_TEX0 )
                ret |= mga_verify_tex( dev_priv, 0 );
 
-       if ( dev_priv->chipset == MGA_CARD_TYPE_G400 ) {
-               if ( dirty & MGA_UPLOAD_TEX1 )
-                       ret |= mga_verify_tex( dev_priv, 1 );
+       if (dev_priv->chipset >= MGA_CARD_TYPE_G400) {
+               if (dirty & MGA_UPLOAD_TEX1)
+                       ret |= mga_verify_tex(dev_priv, 1);
 
                if ( dirty & MGA_UPLOAD_PIPE )
                        ret |= ( sarea_priv->warp_pipe > MGA_MAX_G400_PIPES );
@@ -686,12 +684,12 @@ static void mga_dma_dispatch_vertex( drm_device_t *dev, drm_buf_t *buf )
 
                        BEGIN_DMA( 1 );
 
-                       DMA_BLOCK( MGA_DMAPAD,          0x00000000,
-                                  MGA_DMAPAD,          0x00000000,
-                                  MGA_SECADDRESS,      (address |
-                                                        MGA_DMA_VERTEX),
-                                  MGA_SECEND,          ((address + length) |
-                                                        MGA_PAGPXFER) );
+                       DMA_BLOCK(MGA_DMAPAD, 0x00000000,
+                                 MGA_DMAPAD, 0x00000000,
+                                 MGA_SECADDRESS, (address |
+                                                  MGA_DMA_VERTEX),
+                                 MGA_SECEND, ((address + length) |
+                                              dev_priv->dma_access));
 
                        ADVANCE_DMA();
                } while ( ++i < sarea_priv->nbox );
@@ -733,11 +731,11 @@ static void mga_dma_dispatch_indices( drm_device_t *dev, drm_buf_t *buf,
 
                        BEGIN_DMA( 1 );
 
-                       DMA_BLOCK( MGA_DMAPAD,          0x00000000,
-                                  MGA_DMAPAD,          0x00000000,
-                                  MGA_SETUPADDRESS,    address + start,
-                                  MGA_SETUPEND,        ((address + end) |
-                                                        MGA_PAGPXFER) );
+                       DMA_BLOCK(MGA_DMAPAD, 0x00000000,
+                                 MGA_DMAPAD, 0x00000000,
+                                 MGA_SETUPADDRESS, address + start,
+                                 MGA_SETUPEND, ((address + end) |
+                                                dev_priv->dma_access));
 
                        ADVANCE_DMA();
                } while ( ++i < sarea_priv->nbox );
@@ -764,7 +762,7 @@ static void mga_dma_dispatch_iload( drm_device_t *dev, drm_buf_t *buf,
        drm_mga_private_t *dev_priv = dev->dev_private;
        drm_mga_buf_priv_t *buf_priv = buf->dev_private;
        drm_mga_context_regs_t *ctx = &dev_priv->sarea_priv->context_state;
-       u32 srcorg = buf->bus_address | MGA_SRCACC_AGP | MGA_SRCMAP_SYSMEM;
+       u32 srcorg = buf->bus_address | dev_priv->dma_access | MGA_SRCMAP_SYSMEM;
        u32 y2;
        DMA_LOCALS;
        DRM_DEBUG( "buf=%d used=%d\n", buf->idx, buf->used );
@@ -1095,6 +1093,9 @@ static int mga_getparam( DRM_IOCTL_ARGS )
        case MGA_PARAM_IRQ_NR:
                value = dev->irq;
                break;
+       case MGA_PARAM_CARD_TYPE:
+               value = dev_priv->chipset;
+               break;
        default:
                return DRM_ERR(EINVAL);
        }
@@ -1107,17 +1108,82 @@ static int mga_getparam( DRM_IOCTL_ARGS )
        return 0;
 }
 
+static int mga_set_fence(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_mga_private_t *dev_priv = dev->dev_private;
+       u32 temp;
+       DMA_LOCALS;
+
+       if (!dev_priv) {
+               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               return DRM_ERR(EINVAL);
+       }
+
+       DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
+
+       /* I would normal do this assignment in the declaration of temp,
+        * but dev_priv may be NULL.
+        */
+
+       temp = dev_priv->next_fence_to_post;
+       dev_priv->next_fence_to_post++;
+
+       BEGIN_DMA(1);
+       DMA_BLOCK(MGA_DMAPAD, 0x00000000,
+                 MGA_DMAPAD, 0x00000000,
+                 MGA_DMAPAD, 0x00000000,
+                 MGA_SOFTRAP, 0x00000000);
+       ADVANCE_DMA();
+
+       if (DRM_COPY_TO_USER( (u32 __user *) data, & temp, sizeof(u32))) {
+               DRM_ERROR("copy_to_user\n");
+               return DRM_ERR(EFAULT);
+       }
+
+       return 0;
+}
+
+static int mga_wait_fence(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_mga_private_t *dev_priv = dev->dev_private;
+       u32 fence;
+
+       if (!dev_priv) {
+               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               return DRM_ERR(EINVAL);
+       }
+
+       DRM_COPY_FROM_USER_IOCTL(fence, (u32 __user *) data, sizeof(u32));
+
+       DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
+
+       mga_driver_fence_wait(dev, & fence);
+
+       if (DRM_COPY_TO_USER( (u32 __user *) data, & fence, sizeof(u32))) {
+               DRM_ERROR("copy_to_user\n");
+               return DRM_ERR(EFAULT);
+       }
+
+       return 0;
+}
+
 drm_ioctl_desc_t mga_ioctls[] = {
-       [DRM_IOCTL_NR(DRM_MGA_INIT)]    = { mga_dma_init,    1, 1 },
-       [DRM_IOCTL_NR(DRM_MGA_FLUSH)]   = { mga_dma_flush,   1, 0 },
-       [DRM_IOCTL_NR(DRM_MGA_RESET)]   = { mga_dma_reset,   1, 0 },
-       [DRM_IOCTL_NR(DRM_MGA_SWAP)]    = { mga_dma_swap,    1, 0 },
-       [DRM_IOCTL_NR(DRM_MGA_CLEAR)]   = { mga_dma_clear,   1, 0 },
-       [DRM_IOCTL_NR(DRM_MGA_VERTEX)]  = { mga_dma_vertex,  1, 0 },
-       [DRM_IOCTL_NR(DRM_MGA_INDICES)] = { mga_dma_indices, 1, 0 },
-       [DRM_IOCTL_NR(DRM_MGA_ILOAD)]   = { mga_dma_iload,   1, 0 },
-       [DRM_IOCTL_NR(DRM_MGA_BLIT)]    = { mga_dma_blit,    1, 0 },
-       [DRM_IOCTL_NR(DRM_MGA_GETPARAM)]= { mga_getparam,    1, 0 },
+       [DRM_IOCTL_NR(DRM_MGA_INIT)] = {mga_dma_init, 1, 1},
+       [DRM_IOCTL_NR(DRM_MGA_FLUSH)] = {mga_dma_flush, 1, 0},
+       [DRM_IOCTL_NR(DRM_MGA_RESET)] = {mga_dma_reset, 1, 0},
+       [DRM_IOCTL_NR(DRM_MGA_SWAP)] = {mga_dma_swap, 1, 0},
+       [DRM_IOCTL_NR(DRM_MGA_CLEAR)] = {mga_dma_clear, 1, 0},
+       [DRM_IOCTL_NR(DRM_MGA_VERTEX)] = {mga_dma_vertex, 1, 0},
+       [DRM_IOCTL_NR(DRM_MGA_INDICES)] = {mga_dma_indices, 1, 0},
+       [DRM_IOCTL_NR(DRM_MGA_ILOAD)] = {mga_dma_iload, 1, 0},
+       [DRM_IOCTL_NR(DRM_MGA_BLIT)] = {mga_dma_blit, 1, 0},
+       [DRM_IOCTL_NR(DRM_MGA_GETPARAM)] = {mga_getparam, 1, 0},
+       [DRM_IOCTL_NR(DRM_MGA_SET_FENCE)] = {mga_set_fence, 1, 0},
+       [DRM_IOCTL_NR(DRM_MGA_WAIT_FENCE)] = {mga_wait_fence, 1, 0},
+       [DRM_IOCTL_NR(DRM_MGA_DMA_BOOTSTRAP)] = {mga_dma_bootstrap, 1, 1},
+
 };
 
 int mga_max_ioctl = DRM_ARRAY_SIZE(mga_ioctls);
index 0a3a0cc700dce028152916834d70c1ff9bf2c504..55ccc8a0ac2990d7d56f8065aedc109e904ec619 100644 (file)
@@ -48,65 +48,52 @@ do {                                                                        \
        vcbase += WARP_UCODE_SIZE( which );                             \
 } while (0)
 
-
-static unsigned int mga_warp_g400_microcode_size( drm_mga_private_t *dev_priv )
-{
-       unsigned int size;
-
-       size = ( WARP_UCODE_SIZE( warp_g400_tgz ) +
-                WARP_UCODE_SIZE( warp_g400_tgza ) +
-                WARP_UCODE_SIZE( warp_g400_tgzaf ) +
-                WARP_UCODE_SIZE( warp_g400_tgzf ) +
-                WARP_UCODE_SIZE( warp_g400_tgzs ) +
-                WARP_UCODE_SIZE( warp_g400_tgzsa ) +
-                WARP_UCODE_SIZE( warp_g400_tgzsaf ) +
-                WARP_UCODE_SIZE( warp_g400_tgzsf ) +
-                WARP_UCODE_SIZE( warp_g400_t2gz ) +
-                WARP_UCODE_SIZE( warp_g400_t2gza ) +
-                WARP_UCODE_SIZE( warp_g400_t2gzaf ) +
-                WARP_UCODE_SIZE( warp_g400_t2gzf ) +
-                WARP_UCODE_SIZE( warp_g400_t2gzs ) +
-                WARP_UCODE_SIZE( warp_g400_t2gzsa ) +
-                WARP_UCODE_SIZE( warp_g400_t2gzsaf ) +
-                WARP_UCODE_SIZE( warp_g400_t2gzsf ) );
-
-       size = PAGE_ALIGN( size );
-
-       DRM_DEBUG( "G400 ucode size = %d bytes\n", size );
-       return size;
-}
-
-static unsigned int mga_warp_g200_microcode_size( drm_mga_private_t *dev_priv )
+static const unsigned int mga_warp_g400_microcode_size =
+              (WARP_UCODE_SIZE(warp_g400_tgz) +
+               WARP_UCODE_SIZE(warp_g400_tgza) +
+               WARP_UCODE_SIZE(warp_g400_tgzaf) +
+               WARP_UCODE_SIZE(warp_g400_tgzf) +
+               WARP_UCODE_SIZE(warp_g400_tgzs) +
+               WARP_UCODE_SIZE(warp_g400_tgzsa) +
+               WARP_UCODE_SIZE(warp_g400_tgzsaf) +
+               WARP_UCODE_SIZE(warp_g400_tgzsf) +
+               WARP_UCODE_SIZE(warp_g400_t2gz) +
+               WARP_UCODE_SIZE(warp_g400_t2gza) +
+               WARP_UCODE_SIZE(warp_g400_t2gzaf) +
+               WARP_UCODE_SIZE(warp_g400_t2gzf) +
+               WARP_UCODE_SIZE(warp_g400_t2gzs) +
+               WARP_UCODE_SIZE(warp_g400_t2gzsa) +
+               WARP_UCODE_SIZE(warp_g400_t2gzsaf) +
+               WARP_UCODE_SIZE(warp_g400_t2gzsf));
+
+static const unsigned int mga_warp_g200_microcode_size =
+              (WARP_UCODE_SIZE(warp_g200_tgz) +
+               WARP_UCODE_SIZE(warp_g200_tgza) +
+               WARP_UCODE_SIZE(warp_g200_tgzaf) +
+               WARP_UCODE_SIZE(warp_g200_tgzf) +
+               WARP_UCODE_SIZE(warp_g200_tgzs) +
+               WARP_UCODE_SIZE(warp_g200_tgzsa) +
+               WARP_UCODE_SIZE(warp_g200_tgzsaf) +
+               WARP_UCODE_SIZE(warp_g200_tgzsf));
+
+
+unsigned int mga_warp_microcode_size(const drm_mga_private_t * dev_priv)
 {
-       unsigned int size;
-
-       size = ( WARP_UCODE_SIZE( warp_g200_tgz ) +
-                WARP_UCODE_SIZE( warp_g200_tgza ) +
-                WARP_UCODE_SIZE( warp_g200_tgzaf ) +
-                WARP_UCODE_SIZE( warp_g200_tgzf ) +
-                WARP_UCODE_SIZE( warp_g200_tgzs ) +
-                WARP_UCODE_SIZE( warp_g200_tgzsa ) +
-                WARP_UCODE_SIZE( warp_g200_tgzsaf ) +
-                WARP_UCODE_SIZE( warp_g200_tgzsf ) );
-
-       size = PAGE_ALIGN( size );
-
-       DRM_DEBUG( "G200 ucode size = %d bytes\n", size );
-       return size;
+       switch (dev_priv->chipset) {
+       case MGA_CARD_TYPE_G400:
+       case MGA_CARD_TYPE_G550:
+               return PAGE_ALIGN(mga_warp_g400_microcode_size);
+       case MGA_CARD_TYPE_G200:
+               return PAGE_ALIGN(mga_warp_g200_microcode_size);
+       default:
+               return 0;
+       }
 }
 
 static int mga_warp_install_g400_microcode( drm_mga_private_t *dev_priv )
 {
        unsigned char *vcbase = dev_priv->warp->handle;
        unsigned long pcbase = dev_priv->warp->offset;
-       unsigned int size;
-
-       size = mga_warp_g400_microcode_size( dev_priv );
-       if ( size > dev_priv->warp->size ) {
-               DRM_ERROR( "microcode too large! (%u > %lu)\n",
-                          size, dev_priv->warp->size );
-               return DRM_ERR(ENOMEM);
-       }
 
        memset( dev_priv->warp_pipe_phys, 0,
                sizeof(dev_priv->warp_pipe_phys) );
@@ -136,35 +123,36 @@ static int mga_warp_install_g200_microcode( drm_mga_private_t *dev_priv )
 {
        unsigned char *vcbase = dev_priv->warp->handle;
        unsigned long pcbase = dev_priv->warp->offset;
-       unsigned int size;
-
-       size = mga_warp_g200_microcode_size( dev_priv );
-       if ( size > dev_priv->warp->size ) {
-               DRM_ERROR( "microcode too large! (%u > %lu)\n",
-                          size, dev_priv->warp->size );
-               return DRM_ERR(ENOMEM);
-       }
 
-       memset( dev_priv->warp_pipe_phys, 0,
-               sizeof(dev_priv->warp_pipe_phys) );
+       memset(dev_priv->warp_pipe_phys, 0, sizeof(dev_priv->warp_pipe_phys));
 
-       WARP_UCODE_INSTALL( warp_g200_tgz,      MGA_WARP_TGZ );
-       WARP_UCODE_INSTALL( warp_g200_tgzf,     MGA_WARP_TGZF );
-       WARP_UCODE_INSTALL( warp_g200_tgza,     MGA_WARP_TGZA );
-       WARP_UCODE_INSTALL( warp_g200_tgzaf,    MGA_WARP_TGZAF );
-       WARP_UCODE_INSTALL( warp_g200_tgzs,     MGA_WARP_TGZS );
-       WARP_UCODE_INSTALL( warp_g200_tgzsf,    MGA_WARP_TGZSF );
-       WARP_UCODE_INSTALL( warp_g200_tgzsa,    MGA_WARP_TGZSA );
-       WARP_UCODE_INSTALL( warp_g200_tgzsaf,   MGA_WARP_TGZSAF );
+       WARP_UCODE_INSTALL(warp_g200_tgz, MGA_WARP_TGZ);
+       WARP_UCODE_INSTALL(warp_g200_tgzf, MGA_WARP_TGZF);
+       WARP_UCODE_INSTALL(warp_g200_tgza, MGA_WARP_TGZA);
+       WARP_UCODE_INSTALL(warp_g200_tgzaf, MGA_WARP_TGZAF);
+       WARP_UCODE_INSTALL(warp_g200_tgzs, MGA_WARP_TGZS);
+       WARP_UCODE_INSTALL(warp_g200_tgzsf, MGA_WARP_TGZSF);
+       WARP_UCODE_INSTALL(warp_g200_tgzsa, MGA_WARP_TGZSA);
+       WARP_UCODE_INSTALL(warp_g200_tgzsaf, MGA_WARP_TGZSAF);
 
        return 0;
 }
 
 int mga_warp_install_microcode(        drm_mga_private_t *dev_priv )
 {
-       switch ( dev_priv->chipset ) {
+       const unsigned int size = mga_warp_microcode_size(dev_priv);
+
+       DRM_DEBUG("MGA ucode size = %d bytes\n", size);
+       if (size > dev_priv->warp->size) {
+               DRM_ERROR("microcode too large! (%u > %lu)\n",
+                         size, dev_priv->warp->size);
+               return DRM_ERR(ENOMEM);
+       }
+
+       switch (dev_priv->chipset) {
        case MGA_CARD_TYPE_G400:
-               return mga_warp_install_g400_microcode( dev_priv );
+       case MGA_CARD_TYPE_G550:
+               return mga_warp_install_g400_microcode(dev_priv);
        case MGA_CARD_TYPE_G200:
                return mga_warp_install_g200_microcode( dev_priv );
        default:
@@ -182,10 +170,11 @@ int mga_warp_init( drm_mga_private_t *dev_priv )
         */
        switch ( dev_priv->chipset ) {
        case MGA_CARD_TYPE_G400:
-               MGA_WRITE( MGA_WIADDR2, MGA_WMODE_SUSPEND );
-               MGA_WRITE( MGA_WGETMSB, 0x00000E00 );
-               MGA_WRITE( MGA_WVRTXSZ, 0x00001807 );
-               MGA_WRITE( MGA_WACCEPTSEQ, 0x18000000 );
+       case MGA_CARD_TYPE_G550:
+               MGA_WRITE(MGA_WIADDR2, MGA_WMODE_SUSPEND);
+               MGA_WRITE(MGA_WGETMSB, 0x00000E00);
+               MGA_WRITE(MGA_WVRTXSZ, 0x00001807);
+               MGA_WRITE(MGA_WACCEPTSEQ, 0x18000000);
                break;
        case MGA_CARD_TYPE_G200:
                MGA_WRITE( MGA_WIADDR, MGA_WMODE_SUSPEND );
index 08ed8d01d9d95f6d7c2491ddd932ff8d8afc4e85..895152206b31f086c0b98ba6add5d07089e00324 100644 (file)
@@ -326,7 +326,8 @@ static void r128_cce_init_ring_buffer( drm_device_t *dev,
                ring_start = dev_priv->cce_ring->offset - dev->agp->base;
        else
 #endif
-               ring_start = dev_priv->cce_ring->offset - dev->sg->handle;
+               ring_start = dev_priv->cce_ring->offset - 
+                               (unsigned long)dev->sg->virtual;
 
        R128_WRITE( R128_PM4_BUFFER_OFFSET, ring_start | R128_AGP_OFFSET );
 
@@ -487,6 +488,7 @@ static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init )
                r128_do_cleanup_cce( dev );
                return DRM_ERR(EINVAL);
        }
+       dev->agp_buffer_token = init->buffers_offset;
        dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
        if(!dev->agp_buffer_map) {
                DRM_ERROR("could not find dma buffer region!\n");
@@ -537,7 +539,7 @@ static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init )
                dev_priv->cce_buffers_offset = dev->agp->base;
        else
 #endif
-               dev_priv->cce_buffers_offset = dev->sg->handle;
+               dev_priv->cce_buffers_offset = (unsigned long)dev->sg->virtual;
 
        dev_priv->ring.start = (u32 *)dev_priv->cce_ring->handle;
        dev_priv->ring.end = ((u32 *)dev_priv->cce_ring->handle
index 0cba17d1e0ffa9614b48b41ad30cfa752fdd705b..b616cd3ed2cd05fcbc1fc6e0834431242ec2d98a 100644 (file)
@@ -215,7 +215,7 @@ typedef struct drm_r128_sarea {
 #define DRM_IOCTL_R128_INDIRECT   DRM_IOWR(DRM_COMMAND_BASE + DRM_R128_INDIRECT, drm_r128_indirect_t)
 #define DRM_IOCTL_R128_FULLSCREEN DRM_IOW( DRM_COMMAND_BASE + DRM_R128_FULLSCREEN, drm_r128_fullscreen_t)
 #define DRM_IOCTL_R128_CLEAR2     DRM_IOW( DRM_COMMAND_BASE + DRM_R128_CLEAR2, drm_r128_clear2_t)
-#define DRM_IOCTL_R128_GETPARAM   DRM_IOW( DRM_COMMAND_BASE + DRM_R128_GETPARAM, drm_r128_getparam_t)
+#define DRM_IOCTL_R128_GETPARAM   DRM_IOWR( DRM_COMMAND_BASE + DRM_R128_GETPARAM, drm_r128_getparam_t)
 #define DRM_IOCTL_R128_FLIP       DRM_IO(  DRM_COMMAND_BASE + DRM_R128_FLIP)
 
 typedef struct drm_r128_init {
diff --git a/drivers/char/drm/r300_cmdbuf.c b/drivers/char/drm/r300_cmdbuf.c
new file mode 100644 (file)
index 0000000..623f1f4
--- /dev/null
@@ -0,0 +1,801 @@
+/* r300_cmdbuf.c -- Command buffer emission for R300 -*- linux-c -*-
+ *
+ * Copyright (C) The Weather Channel, Inc.  2002.
+ * Copyright (C) 2004 Nicolai Haehnle.
+ * All Rights Reserved.
+ *
+ * The Weather Channel (TM) funded Tungsten Graphics to develop the
+ * initial release of the Radeon 8500 driver under the XFree86 license.
+ * This notice must be preserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Nicolai Haehnle <prefect_@gmx.net>
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "radeon_drm.h"
+#include "radeon_drv.h"
+#include "r300_reg.h"
+
+
+#define R300_SIMULTANEOUS_CLIPRECTS            4
+
+/* Values for R300_RE_CLIPRECT_CNTL depending on the number of cliprects
+ */
+static const int r300_cliprect_cntl[4] = {
+       0xAAAA,
+       0xEEEE,
+       0xFEFE,
+       0xFFFE
+};
+
+
+/**
+ * Emit up to R300_SIMULTANEOUS_CLIPRECTS cliprects from the given command
+ * buffer, starting with index n.
+ */
+static int r300_emit_cliprects(drm_radeon_private_t* dev_priv,
+                              drm_radeon_cmd_buffer_t* cmdbuf,
+                              int n)
+{
+       drm_clip_rect_t box;
+       int nr;
+       int i;
+       RING_LOCALS;
+
+       nr = cmdbuf->nbox - n;
+       if (nr > R300_SIMULTANEOUS_CLIPRECTS)
+               nr = R300_SIMULTANEOUS_CLIPRECTS;
+
+       DRM_DEBUG("%i cliprects\n", nr);
+
+       if (nr) {
+               BEGIN_RING(6 + nr*2);
+               OUT_RING( CP_PACKET0( R300_RE_CLIPRECT_TL_0, nr*2 - 1 ) );
+
+               for(i = 0; i < nr; ++i) {
+                       if (DRM_COPY_FROM_USER_UNCHECKED(&box, &cmdbuf->boxes[n+i], sizeof(box))) {
+                               DRM_ERROR("copy cliprect faulted\n");
+                               return DRM_ERR(EFAULT);
+                       }
+
+                       box.x1 = (box.x1 + R300_CLIPRECT_OFFSET) & R300_CLIPRECT_MASK;
+                       box.y1 = (box.y1 + R300_CLIPRECT_OFFSET) & R300_CLIPRECT_MASK;
+                       box.x2 = (box.x2 + R300_CLIPRECT_OFFSET) & R300_CLIPRECT_MASK;
+                       box.y2 = (box.y2 + R300_CLIPRECT_OFFSET) & R300_CLIPRECT_MASK;
+
+                       OUT_RING((box.x1 << R300_CLIPRECT_X_SHIFT) |
+                                       (box.y1 << R300_CLIPRECT_Y_SHIFT));
+                       OUT_RING((box.x2 << R300_CLIPRECT_X_SHIFT) |
+                                       (box.y2 << R300_CLIPRECT_Y_SHIFT));
+               }
+
+               OUT_RING_REG( R300_RE_CLIPRECT_CNTL, r300_cliprect_cntl[nr-1] );
+
+               /* TODO/SECURITY: Force scissors to a safe value, otherwise the
+               * client might be able to trample over memory.
+               * The impact should be very limited, but I'd rather be safe than
+               * sorry.
+               */
+               OUT_RING( CP_PACKET0( R300_RE_SCISSORS_TL, 1 ) );
+               OUT_RING( 0 );
+               OUT_RING( R300_SCISSORS_X_MASK | R300_SCISSORS_Y_MASK );
+               ADVANCE_RING();
+               } else {
+               /* Why we allow zero cliprect rendering:
+                * There are some commands in a command buffer that must be submitted
+                * even when there are no cliprects, e.g. DMA buffer discard
+                * or state setting (though state setting could be avoided by
+                * simulating a loss of context).
+                *
+                * Now since the cmdbuf interface is so chaotic right now (and is
+                * bound to remain that way for a bit until things settle down),
+                * it is basically impossible to filter out the commands that are
+                * necessary and those that aren't.
+                *
+                * So I choose the safe way and don't do any filtering at all;
+                * instead, I simply set up the engine so that all rendering
+                * can't produce any fragments.
+                */
+               BEGIN_RING(2);
+               OUT_RING_REG( R300_RE_CLIPRECT_CNTL, 0 );
+               ADVANCE_RING();
+               }
+
+       return 0;
+}
+
+u8  r300_reg_flags[0x10000>>2];
+
+
+void r300_init_reg_flags(void)
+{
+       int i;
+       memset(r300_reg_flags, 0, 0x10000>>2);
+       #define ADD_RANGE_MARK(reg, count,mark) \
+               for(i=((reg)>>2);i<((reg)>>2)+(count);i++)\
+                       r300_reg_flags[i]|=(mark);
+       
+       #define MARK_SAFE               1
+       #define MARK_CHECK_OFFSET       2
+       
+       #define ADD_RANGE(reg, count)   ADD_RANGE_MARK(reg, count, MARK_SAFE)
+
+       /* these match cmducs() command in r300_driver/r300/r300_cmdbuf.c */
+       ADD_RANGE(R300_SE_VPORT_XSCALE, 6);
+       ADD_RANGE(0x2080, 1);
+       ADD_RANGE(R300_SE_VTE_CNTL, 2);
+       ADD_RANGE(0x2134, 2);
+       ADD_RANGE(0x2140, 1);
+       ADD_RANGE(R300_VAP_INPUT_CNTL_0, 2);
+       ADD_RANGE(0x21DC, 1);
+       ADD_RANGE(0x221C, 1);
+       ADD_RANGE(0x2220, 4);
+       ADD_RANGE(0x2288, 1);
+       ADD_RANGE(R300_VAP_OUTPUT_VTX_FMT_0, 2);
+       ADD_RANGE(R300_VAP_PVS_CNTL_1, 3);
+       ADD_RANGE(R300_GB_ENABLE, 1);
+       ADD_RANGE(R300_GB_MSPOS0, 5);
+       ADD_RANGE(R300_TX_ENABLE, 1);
+       ADD_RANGE(0x4200, 4);
+       ADD_RANGE(0x4214, 1);
+       ADD_RANGE(R300_RE_POINTSIZE, 1);
+       ADD_RANGE(0x4230, 3);
+       ADD_RANGE(R300_RE_LINE_CNT, 1);
+       ADD_RANGE(0x4238, 1);
+       ADD_RANGE(0x4260, 3);
+       ADD_RANGE(0x4274, 4);
+       ADD_RANGE(0x4288, 5);
+       ADD_RANGE(0x42A0, 1);
+       ADD_RANGE(R300_RE_ZBIAS_T_FACTOR, 4);
+       ADD_RANGE(0x42B4, 1);
+       ADD_RANGE(R300_RE_CULL_CNTL, 1);
+       ADD_RANGE(0x42C0, 2);
+       ADD_RANGE(R300_RS_CNTL_0, 2);
+       ADD_RANGE(R300_RS_INTERP_0, 8);
+       ADD_RANGE(R300_RS_ROUTE_0, 8);
+       ADD_RANGE(0x43A4, 2);
+       ADD_RANGE(0x43E8, 1);
+       ADD_RANGE(R300_PFS_CNTL_0, 3);
+       ADD_RANGE(R300_PFS_NODE_0, 4);
+       ADD_RANGE(R300_PFS_TEXI_0, 64);
+       ADD_RANGE(0x46A4, 5);
+       ADD_RANGE(R300_PFS_INSTR0_0, 64);
+       ADD_RANGE(R300_PFS_INSTR1_0, 64);
+       ADD_RANGE(R300_PFS_INSTR2_0, 64);
+       ADD_RANGE(R300_PFS_INSTR3_0, 64);
+       ADD_RANGE(0x4BC0, 1);
+       ADD_RANGE(0x4BC8, 3);
+       ADD_RANGE(R300_PP_ALPHA_TEST, 2);
+       ADD_RANGE(0x4BD8, 1);
+       ADD_RANGE(R300_PFS_PARAM_0_X, 64);
+       ADD_RANGE(0x4E00, 1);
+       ADD_RANGE(R300_RB3D_CBLEND, 2);
+       ADD_RANGE(R300_RB3D_COLORMASK, 1);
+       ADD_RANGE(0x4E10, 3);
+       ADD_RANGE_MARK(R300_RB3D_COLOROFFSET0, 1, MARK_CHECK_OFFSET); /* check offset */
+       ADD_RANGE(R300_RB3D_COLORPITCH0, 1);
+       ADD_RANGE(0x4E50, 9);
+       ADD_RANGE(0x4E88, 1);
+       ADD_RANGE(0x4EA0, 2);
+       ADD_RANGE(R300_RB3D_ZSTENCIL_CNTL_0, 3);
+       ADD_RANGE(0x4F10, 4);
+       ADD_RANGE_MARK(R300_RB3D_DEPTHOFFSET, 1, MARK_CHECK_OFFSET); /* check offset */
+       ADD_RANGE(R300_RB3D_DEPTHPITCH, 1); 
+       ADD_RANGE(0x4F28, 1);
+       ADD_RANGE(0x4F30, 2);
+       ADD_RANGE(0x4F44, 1);
+       ADD_RANGE(0x4F54, 1);
+
+       ADD_RANGE(R300_TX_FILTER_0, 16);
+       ADD_RANGE(R300_TX_UNK1_0, 16);
+       ADD_RANGE(R300_TX_SIZE_0, 16);
+       ADD_RANGE(R300_TX_FORMAT_0, 16);
+               /* Texture offset is dangerous and needs more checking */
+       ADD_RANGE_MARK(R300_TX_OFFSET_0, 16, MARK_CHECK_OFFSET);
+       ADD_RANGE(R300_TX_UNK4_0, 16);
+       ADD_RANGE(R300_TX_BORDER_COLOR_0, 16);
+
+       /* Sporadic registers used as primitives are emitted */
+       ADD_RANGE(0x4f18, 1);
+       ADD_RANGE(R300_RB3D_DSTCACHE_CTLSTAT, 1);
+       ADD_RANGE(R300_VAP_INPUT_ROUTE_0_0, 8);
+       ADD_RANGE(R300_VAP_INPUT_ROUTE_1_0, 8);
+
+}
+
+static __inline__ int r300_check_range(unsigned  reg, int count)
+{
+       int i;
+       if(reg & ~0xffff)return -1;
+       for(i=(reg>>2);i<(reg>>2)+count;i++)
+               if(r300_reg_flags[i]!=MARK_SAFE)return 1;
+       return 0;
+}
+
+  /* we expect offsets passed to the framebuffer to be either within video memory or
+      within AGP space */
+static __inline__ int r300_check_offset(drm_radeon_private_t* dev_priv, u32 offset)
+{
+       /* we realy want to check against end of video aperture
+               but this value is not being kept. 
+               This code is correct for now (does the same thing as the
+               code that sets MC_FB_LOCATION) in radeon_cp.c */
+       if((offset>=dev_priv->fb_location) && 
+               (offset<dev_priv->gart_vm_start))return 0;
+       if((offset>=dev_priv->gart_vm_start) &&
+                (offset<dev_priv->gart_vm_start+dev_priv->gart_size))return 0;
+       return 1;
+}
+
+static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t* dev_priv,
+                                               drm_radeon_cmd_buffer_t* cmdbuf,
+                                               drm_r300_cmd_header_t header)
+{
+       int reg;
+       int sz;
+       int i;
+       int values[64];
+       RING_LOCALS;
+
+       sz = header.packet0.count;
+       reg = (header.packet0.reghi << 8) | header.packet0.reglo;
+       
+       if((sz>64)||(sz<0)){
+               DRM_ERROR("Cannot emit more than 64 values at a time (reg=%04x sz=%d)\n", reg, sz);
+               return DRM_ERR(EINVAL);
+               }
+       for(i=0;i<sz;i++){
+               values[i]=((int __user*)cmdbuf->buf)[i];
+               switch(r300_reg_flags[(reg>>2)+i]){
+               case MARK_SAFE:
+                       break;
+               case MARK_CHECK_OFFSET:
+                       if(r300_check_offset(dev_priv, (u32)values[i])){
+                               DRM_ERROR("Offset failed range check (reg=%04x sz=%d)\n", reg, sz);
+                               return DRM_ERR(EINVAL);
+                               }
+                       break;
+               default:
+                       DRM_ERROR("Register %04x failed check as flag=%02x\n", reg+i*4, r300_reg_flags[(reg>>2)+i]);
+                       return DRM_ERR(EINVAL);
+                       }
+               }
+               
+       BEGIN_RING(1+sz);
+       OUT_RING( CP_PACKET0( reg, sz-1 ) );
+       OUT_RING_TABLE( values, sz );
+       ADVANCE_RING();
+
+       cmdbuf->buf += sz*4;
+       cmdbuf->bufsz -= sz*4;
+
+       return 0;
+}
+
+/**
+ * Emits a packet0 setting arbitrary registers.
+ * Called by r300_do_cp_cmdbuf.
+ *
+ * Note that checks are performed on contents and addresses of the registers
+ */
+static __inline__ int r300_emit_packet0(drm_radeon_private_t* dev_priv,
+                                               drm_radeon_cmd_buffer_t* cmdbuf,
+                                               drm_r300_cmd_header_t header)
+{
+       int reg;
+       int sz;
+       RING_LOCALS;
+
+       sz = header.packet0.count;
+       reg = (header.packet0.reghi << 8) | header.packet0.reglo;
+
+       if (!sz)
+               return 0;
+
+       if (sz*4 > cmdbuf->bufsz)
+               return DRM_ERR(EINVAL);
+               
+       if (reg+sz*4 >= 0x10000){
+               DRM_ERROR("No such registers in hardware reg=%04x sz=%d\n", reg, sz);
+               return DRM_ERR(EINVAL);
+               }
+
+       if(r300_check_range(reg, sz)){
+               /* go and check everything */
+               return r300_emit_carefully_checked_packet0(dev_priv, cmdbuf, header);
+               }
+       /* the rest of the data is safe to emit, whatever the values the user passed */
+
+       BEGIN_RING(1+sz);
+       OUT_RING( CP_PACKET0( reg, sz-1 ) );
+       OUT_RING_TABLE( (int __user*)cmdbuf->buf, sz );
+       ADVANCE_RING();
+
+       cmdbuf->buf += sz*4;
+       cmdbuf->bufsz -= sz*4;
+
+       return 0;
+}
+
+
+/**
+ * Uploads user-supplied vertex program instructions or parameters onto
+ * the graphics card.
+ * Called by r300_do_cp_cmdbuf.
+ */
+static __inline__ int r300_emit_vpu(drm_radeon_private_t* dev_priv,
+                                   drm_radeon_cmd_buffer_t* cmdbuf,
+                                   drm_r300_cmd_header_t header)
+{
+       int sz;
+       int addr;
+       RING_LOCALS;
+
+       sz = header.vpu.count;
+       addr = (header.vpu.adrhi << 8) | header.vpu.adrlo;
+
+       if (!sz)
+               return 0;
+       if (sz*16 > cmdbuf->bufsz)
+               return DRM_ERR(EINVAL);
+
+       BEGIN_RING(5+sz*4);
+       /* Wait for VAP to come to senses.. */
+       /* there is no need to emit it multiple times, (only once before VAP is programmed,
+          but this optimization is for later */
+       OUT_RING_REG( R300_VAP_PVS_WAITIDLE, 0 );
+       OUT_RING_REG( R300_VAP_PVS_UPLOAD_ADDRESS, addr );
+       OUT_RING( CP_PACKET0_TABLE( R300_VAP_PVS_UPLOAD_DATA, sz*4 - 1 ) );
+       OUT_RING_TABLE( (int __user*)cmdbuf->buf, sz*4 );
+
+       ADVANCE_RING();
+
+       cmdbuf->buf += sz*16;
+       cmdbuf->bufsz -= sz*16;
+
+       return 0;
+}
+
+
+/**
+ * Emit a clear packet from userspace.
+ * Called by r300_emit_packet3.
+ */
+static __inline__ int r300_emit_clear(drm_radeon_private_t* dev_priv,
+                                     drm_radeon_cmd_buffer_t* cmdbuf)
+{
+       RING_LOCALS;
+
+       if (8*4 > cmdbuf->bufsz)
+               return DRM_ERR(EINVAL);
+
+       BEGIN_RING(10);
+       OUT_RING( CP_PACKET3( R200_3D_DRAW_IMMD_2, 8 ) );
+       OUT_RING( R300_PRIM_TYPE_POINT|R300_PRIM_WALK_RING|
+                 (1<<R300_PRIM_NUM_VERTICES_SHIFT) );
+       OUT_RING_TABLE( (int __user*)cmdbuf->buf, 8 );
+       ADVANCE_RING();
+
+       cmdbuf->buf += 8*4;
+       cmdbuf->bufsz -= 8*4;
+
+       return 0;
+}
+
+static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t* dev_priv,
+                                     drm_radeon_cmd_buffer_t* cmdbuf,
+                                     u32 header)
+{
+       int count, i,k;
+       #define MAX_ARRAY_PACKET  64
+       u32 payload[MAX_ARRAY_PACKET];
+       u32 narrays;
+       RING_LOCALS;
+
+       count=(header>>16) & 0x3fff;
+       
+       if((count+1)>MAX_ARRAY_PACKET){
+               DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n", count);
+               return DRM_ERR(EINVAL);
+               }
+       memset(payload, 0, MAX_ARRAY_PACKET*4);
+       memcpy(payload, cmdbuf->buf+4, (count+1)*4);    
+       
+       /* carefully check packet contents */
+       
+       narrays=payload[0];
+       k=0;
+       i=1;
+       while((k<narrays) && (i<(count+1))){
+               i++; /* skip attribute field */
+               if(r300_check_offset(dev_priv, payload[i])){
+                       DRM_ERROR("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n", k, i);
+                       return DRM_ERR(EINVAL);
+                       }
+               k++;
+               i++;
+               if(k==narrays)break;
+               /* have one more to process, they come in pairs */
+               if(r300_check_offset(dev_priv, payload[i])){
+                       DRM_ERROR("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n", k, i);
+                       return DRM_ERR(EINVAL);
+                       }
+               k++;
+               i++;                    
+               }
+       /* do the counts match what we expect ? */
+       if((k!=narrays) || (i!=(count+1))){
+               DRM_ERROR("Malformed 3D_LOAD_VBPNTR packet (k=%d i=%d narrays=%d count+1=%d).\n", k, i, narrays, count+1);
+               return DRM_ERR(EINVAL);
+               }
+
+       /* all clear, output packet */
+
+       BEGIN_RING(count+2);
+       OUT_RING(header);
+       OUT_RING_TABLE(payload, count+1);
+       ADVANCE_RING();
+
+       cmdbuf->buf += (count+2)*4;
+       cmdbuf->bufsz -= (count+2)*4;
+
+       return 0;
+}
+
+static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t* dev_priv,
+                                     drm_radeon_cmd_buffer_t* cmdbuf)
+{
+       u32 header;
+       int count;
+       RING_LOCALS;
+
+       if (4 > cmdbuf->bufsz)
+               return DRM_ERR(EINVAL);
+
+        /* Fixme !! This simply emits a packet without much checking.
+          We need to be smarter. */
+
+       /* obtain first word - actual packet3 header */
+       header = *(u32 __user*)cmdbuf->buf;
+
+       /* Is it packet 3 ? */
+       if( (header>>30)!=0x3 ) {
+               DRM_ERROR("Not a packet3 header (0x%08x)\n", header);
+               return DRM_ERR(EINVAL);
+               }
+
+       count=(header>>16) & 0x3fff;
+
+       /* Check again now that we know how much data to expect */
+       if ((count+2)*4 > cmdbuf->bufsz){
+               DRM_ERROR("Expected packet3 of length %d but have only %d bytes left\n",
+                       (count+2)*4, cmdbuf->bufsz);
+               return DRM_ERR(EINVAL);
+               }
+
+       /* Is it a packet type we know about ? */
+       switch(header & 0xff00){
+       case RADEON_3D_LOAD_VBPNTR: /* load vertex array pointers */
+               return r300_emit_3d_load_vbpntr(dev_priv, cmdbuf, header);
+
+       case RADEON_CP_3D_DRAW_IMMD_2: /* triggers drawing using in-packet vertex data */
+       case RADEON_CP_3D_DRAW_VBUF_2: /* triggers drawing of vertex buffers setup elsewhere */
+       case RADEON_CP_3D_DRAW_INDX_2: /* triggers drawing using indices to vertex buffer */
+       case RADEON_CP_INDX_BUFFER: /* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */
+       case RADEON_WAIT_FOR_IDLE:
+       case RADEON_CP_NOP:
+               /* these packets are safe */
+               break;
+       default:
+               DRM_ERROR("Unknown packet3 header (0x%08x)\n", header);
+               return DRM_ERR(EINVAL);
+               }
+
+
+       BEGIN_RING(count+2);
+       OUT_RING(header);
+       OUT_RING_TABLE( (int __user*)(cmdbuf->buf+4), count+1);
+       ADVANCE_RING();
+
+       cmdbuf->buf += (count+2)*4;
+       cmdbuf->bufsz -= (count+2)*4;
+
+       return 0;
+}
+
+
+/**
+ * Emit a rendering packet3 from userspace.
+ * Called by r300_do_cp_cmdbuf.
+ */
+static __inline__ int r300_emit_packet3(drm_radeon_private_t* dev_priv,
+                                       drm_radeon_cmd_buffer_t* cmdbuf,
+                                       drm_r300_cmd_header_t header)
+{
+       int n;
+       int ret;
+       char __user* orig_buf = cmdbuf->buf;
+       int orig_bufsz = cmdbuf->bufsz;
+
+       /* This is a do-while-loop so that we run the interior at least once,
+        * even if cmdbuf->nbox is 0. Compare r300_emit_cliprects for rationale.
+        */
+       n = 0;
+       do {
+               if (cmdbuf->nbox > R300_SIMULTANEOUS_CLIPRECTS) {
+                       ret = r300_emit_cliprects(dev_priv, cmdbuf, n);
+                       if (ret)
+                               return ret;
+
+                       cmdbuf->buf = orig_buf;
+                       cmdbuf->bufsz = orig_bufsz;
+                       }
+
+               switch(header.packet3.packet) {
+               case R300_CMD_PACKET3_CLEAR:
+                       DRM_DEBUG("R300_CMD_PACKET3_CLEAR\n");
+                       ret = r300_emit_clear(dev_priv, cmdbuf);
+                       if (ret) {
+                               DRM_ERROR("r300_emit_clear failed\n");
+                               return ret;
+                               }
+                       break;
+
+               case R300_CMD_PACKET3_RAW:
+                       DRM_DEBUG("R300_CMD_PACKET3_RAW\n");
+                       ret = r300_emit_raw_packet3(dev_priv, cmdbuf);
+                       if (ret) {
+                               DRM_ERROR("r300_emit_raw_packet3 failed\n");
+                               return ret;
+                               }
+                       break;
+
+               default:
+                       DRM_ERROR("bad packet3 type %i at %p\n",
+                               header.packet3.packet,
+                               cmdbuf->buf - sizeof(header));
+                       return DRM_ERR(EINVAL);
+                       }
+
+               n += R300_SIMULTANEOUS_CLIPRECTS;
+       } while(n < cmdbuf->nbox);
+
+       return 0;
+}
+
+/* Some of the R300 chips seem to be extremely touchy about the two registers
+ * that are configured in r300_pacify.
+ * Among the worst offenders seems to be the R300 ND (0x4E44): When userspace
+ * sends a command buffer that contains only state setting commands and a
+ * vertex program/parameter upload sequence, this will eventually lead to a
+ * lockup, unless the sequence is bracketed by calls to r300_pacify.
+ * So we should take great care to *always* call r300_pacify before
+ * *anything* 3D related, and again afterwards. This is what the
+ * call bracket in r300_do_cp_cmdbuf is for.
+ */
+
+/**
+ * Emit the sequence to pacify R300.
+ */
+static __inline__ void r300_pacify(drm_radeon_private_t* dev_priv)
+{
+       RING_LOCALS;
+
+       BEGIN_RING(6);
+       OUT_RING( CP_PACKET0( R300_RB3D_DSTCACHE_CTLSTAT, 0 ) );
+       OUT_RING( 0xa );
+       OUT_RING( CP_PACKET0( 0x4f18, 0 ) );
+       OUT_RING( 0x3 );
+       OUT_RING( CP_PACKET3( RADEON_CP_NOP, 0 ) );
+       OUT_RING( 0x0 );
+       ADVANCE_RING();
+}
+
+
+/**
+ * Called by r300_do_cp_cmdbuf to update the internal buffer age and state.
+ * The actual age emit is done by r300_do_cp_cmdbuf, which is why you must
+ * be careful about how this function is called.
+ */
+static void r300_discard_buffer(drm_device_t * dev, drm_buf_t * buf)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
+
+       buf_priv->age = ++dev_priv->sarea_priv->last_dispatch;
+       buf->pending = 1;
+       buf->used = 0;
+}
+
+
+/**
+ * Parses and validates a user-supplied command buffer and emits appropriate
+ * commands on the DMA ring buffer.
+ * Called by the ioctl handler function radeon_cp_cmdbuf.
+ */
+int r300_do_cp_cmdbuf(drm_device_t* dev,
+                         DRMFILE filp,
+                     drm_file_t* filp_priv,
+                     drm_radeon_cmd_buffer_t* cmdbuf)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+        drm_device_dma_t *dma = dev->dma;
+        drm_buf_t *buf = NULL;
+       int emit_dispatch_age = 0;
+       int ret = 0;
+
+       DRM_DEBUG("\n");
+
+       /* See the comment above r300_emit_begin3d for why this call must be here,
+        * and what the cleanup gotos are for. */
+       r300_pacify(dev_priv);
+
+       if (cmdbuf->nbox <= R300_SIMULTANEOUS_CLIPRECTS) {
+               ret = r300_emit_cliprects(dev_priv, cmdbuf, 0);
+               if (ret)
+                       goto cleanup;
+               }
+
+       while(cmdbuf->bufsz >= sizeof(drm_r300_cmd_header_t)) {
+               int idx;
+               drm_r300_cmd_header_t header;
+
+               header.u = *(unsigned int *)cmdbuf->buf;
+
+               cmdbuf->buf += sizeof(header);
+               cmdbuf->bufsz -= sizeof(header);
+
+               switch(header.header.cmd_type) {
+               case R300_CMD_PACKET0: 
+                       DRM_DEBUG("R300_CMD_PACKET0\n");
+                       ret = r300_emit_packet0(dev_priv, cmdbuf, header);
+                       if (ret) {
+                               DRM_ERROR("r300_emit_packet0 failed\n");
+                               goto cleanup;
+                               }
+                       break;
+
+               case R300_CMD_VPU:
+                       DRM_DEBUG("R300_CMD_VPU\n");
+                       ret = r300_emit_vpu(dev_priv, cmdbuf, header);
+                       if (ret) {
+                               DRM_ERROR("r300_emit_vpu failed\n");
+                               goto cleanup;
+                               }
+                       break;
+
+               case R300_CMD_PACKET3:
+                       DRM_DEBUG("R300_CMD_PACKET3\n");
+                       ret = r300_emit_packet3(dev_priv, cmdbuf, header);
+                       if (ret) {
+                               DRM_ERROR("r300_emit_packet3 failed\n");
+                               goto cleanup;
+                               }
+                       break;
+
+               case R300_CMD_END3D:
+                       DRM_DEBUG("R300_CMD_END3D\n");
+                       /* TODO: 
+                               Ideally userspace driver should not need to issue this call, 
+                               i.e. the drm driver should issue it automatically and prevent
+                               lockups.
+                               
+                               In practice, we do not understand why this call is needed and what
+                               it does (except for some vague guesses that it has to do with cache
+                               coherence) and so the user space driver does it. 
+                               
+                               Once we are sure which uses prevent lockups the code could be moved
+                               into the kernel and the userspace driver will not
+                               need to use this command.
+
+                               Note that issuing this command does not hurt anything
+                               except, possibly, performance */
+                       r300_pacify(dev_priv);
+                       break;
+
+               case R300_CMD_CP_DELAY:
+                       /* simple enough, we can do it here */
+                       DRM_DEBUG("R300_CMD_CP_DELAY\n");
+                       {
+                               int i;
+                               RING_LOCALS;
+
+                               BEGIN_RING(header.delay.count);
+                               for(i=0;i<header.delay.count;i++)
+                                       OUT_RING(RADEON_CP_PACKET2);
+                               ADVANCE_RING();
+                       }
+                       break;
+
+               case R300_CMD_DMA_DISCARD:
+                       DRM_DEBUG("RADEON_CMD_DMA_DISCARD\n");
+                       idx = header.dma.buf_idx;
+                       if (idx < 0 || idx >= dma->buf_count) {
+                               DRM_ERROR("buffer index %d (of %d max)\n",
+                                       idx, dma->buf_count - 1);
+                               ret = DRM_ERR(EINVAL);
+                               goto cleanup;
+                               }
+
+                       buf = dma->buflist[idx];
+                       if (buf->filp != filp || buf->pending) {
+                               DRM_ERROR("bad buffer %p %p %d\n",
+                               buf->filp, filp, buf->pending);
+                               ret = DRM_ERR(EINVAL);
+                               goto cleanup;
+                               }
+
+                       emit_dispatch_age = 1;
+                       r300_discard_buffer(dev, buf);
+                       break;
+
+               case R300_CMD_WAIT:
+                       /* simple enough, we can do it here */
+                       DRM_DEBUG("R300_CMD_WAIT\n");
+                       if(header.wait.flags==0)break; /* nothing to do */
+
+                       {
+                               RING_LOCALS;
+
+                               BEGIN_RING(2);
+                               OUT_RING( CP_PACKET0( RADEON_WAIT_UNTIL, 0 ) );
+                               OUT_RING( (header.wait.flags & 0xf)<<14 );
+                               ADVANCE_RING();
+                       }
+                       break;
+
+               default:
+                       DRM_ERROR("bad cmd_type %i at %p\n",
+                                 header.header.cmd_type,
+                                 cmdbuf->buf - sizeof(header));
+                       ret = DRM_ERR(EINVAL);
+                       goto cleanup;
+                       }
+       }
+
+       DRM_DEBUG("END\n");
+
+cleanup:
+       r300_pacify(dev_priv);
+
+       /* We emit the vertex buffer age here, outside the pacifier "brackets"
+        * for two reasons:
+        *  (1) This may coalesce multiple age emissions into a single one and
+        *  (2) more importantly, some chips lock up hard when scratch registers
+        *      are written inside the pacifier bracket.
+        */
+       if (emit_dispatch_age) {
+               RING_LOCALS;
+
+               /* Emit the vertex buffer age */
+               BEGIN_RING(2);
+               RADEON_DISPATCH_AGE(dev_priv->sarea_priv->last_dispatch);
+               ADVANCE_RING();
+               }
+
+       COMMIT_RING();
+
+       return ret;
+}
+
diff --git a/drivers/char/drm/r300_reg.h b/drivers/char/drm/r300_reg.h
new file mode 100644 (file)
index 0000000..c3e7ca3
--- /dev/null
@@ -0,0 +1,1412 @@
+/**************************************************************************
+
+Copyright (C) 2004-2005 Nicolai Haehnle et al.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, and/or sell copies of the Software, and to permit persons to whom
+the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+#ifndef _R300_REG_H
+#define _R300_REG_H
+
+#define R300_MC_INIT_MISC_LAT_TIMER    0x180
+#      define R300_MC_MISC__MC_CPR_INIT_LAT_SHIFT      0
+#      define R300_MC_MISC__MC_VF_INIT_LAT_SHIFT       4
+#      define R300_MC_MISC__MC_DISP0R_INIT_LAT_SHIFT   8
+#      define R300_MC_MISC__MC_DISP1R_INIT_LAT_SHIFT   12
+#      define R300_MC_MISC__MC_FIXED_INIT_LAT_SHIFT    16
+#      define R300_MC_MISC__MC_E2R_INIT_LAT_SHIFT      20
+#      define R300_MC_MISC__MC_SAME_PAGE_PRIO_SHIFT    24
+#      define R300_MC_MISC__MC_GLOBW_INIT_LAT_SHIFT    28
+
+
+#define R300_MC_INIT_GFX_LAT_TIMER     0x154
+#      define R300_MC_MISC__MC_G3D0R_INIT_LAT_SHIFT    0
+#      define R300_MC_MISC__MC_G3D1R_INIT_LAT_SHIFT    4
+#      define R300_MC_MISC__MC_G3D2R_INIT_LAT_SHIFT    8
+#      define R300_MC_MISC__MC_G3D3R_INIT_LAT_SHIFT    12
+#      define R300_MC_MISC__MC_TX0R_INIT_LAT_SHIFT     16
+#      define R300_MC_MISC__MC_TX1R_INIT_LAT_SHIFT     20
+#      define R300_MC_MISC__MC_GLOBR_INIT_LAT_SHIFT    24
+#      define R300_MC_MISC__MC_GLOBW_FULL_LAT_SHIFT    28
+
+/*
+This file contains registers and constants for the R300. They have been
+found mostly by examining command buffers captured using glxtest, as well
+as by extrapolating some known registers and constants from the R200.
+
+I am fairly certain that they are correct unless stated otherwise in comments.
+*/
+
+#define R300_SE_VPORT_XSCALE                0x1D98
+#define R300_SE_VPORT_XOFFSET               0x1D9C
+#define R300_SE_VPORT_YSCALE                0x1DA0
+#define R300_SE_VPORT_YOFFSET               0x1DA4
+#define R300_SE_VPORT_ZSCALE                0x1DA8
+#define R300_SE_VPORT_ZOFFSET               0x1DAC
+
+
+/* This register is written directly and also starts data section in many 3d CP_PACKET3's */
+#define R300_VAP_VF_CNTL       0x2084
+
+#      define  R300_VAP_VF_CNTL__PRIM_TYPE__SHIFT                       0
+#      define  R300_VAP_VF_CNTL__PRIM_NONE                              (0<<0)
+#      define  R300_VAP_VF_CNTL__PRIM_POINTS                            (1<<0)
+#      define  R300_VAP_VF_CNTL__PRIM_LINES                             (2<<0)
+#      define  R300_VAP_VF_CNTL__PRIM_LINE_STRIP                        (3<<0)
+#      define  R300_VAP_VF_CNTL__PRIM_TRIANGLES                         (4<<0)
+#      define  R300_VAP_VF_CNTL__PRIM_TRIANGLE_FAN                      (5<<0)
+#      define  R300_VAP_VF_CNTL__PRIM_TRIANGLE_STRIP                    (6<<0)
+#      define  R300_VAP_VF_CNTL__PRIM_LINE_LOOP                         (12<<0)
+#      define  R300_VAP_VF_CNTL__PRIM_QUADS                             (13<<0)
+#      define  R300_VAP_VF_CNTL__PRIM_QUAD_STRIP                        (14<<0)
+#      define  R300_VAP_VF_CNTL__PRIM_POLYGON                           (15<<0)
+
+#      define  R300_VAP_VF_CNTL__PRIM_WALK__SHIFT                       4
+       /* State based - direct writes to registers trigger vertex generation */
+#      define  R300_VAP_VF_CNTL__PRIM_WALK_STATE_BASED                      (0<<4)
+#      define  R300_VAP_VF_CNTL__PRIM_WALK_INDICES                          (1<<4)
+#      define  R300_VAP_VF_CNTL__PRIM_WALK_VERTEX_LIST                      (2<<4)
+#      define  R300_VAP_VF_CNTL__PRIM_WALK_VERTEX_EMBEDDED                  (3<<4)
+
+               /* I don't think I saw these three used.. */
+#      define  R300_VAP_VF_CNTL__COLOR_ORDER__SHIFT                     6
+#      define  R300_VAP_VF_CNTL__TCL_OUTPUT_CTL_ENA__SHIFT              9
+#      define  R300_VAP_VF_CNTL__PROG_STREAM_ENA__SHIFT                 10
+
+               /* index size - when not set the indices are assumed to be 16 bit */
+#      define  R300_VAP_VF_CNTL__INDEX_SIZE_32bit                      (1<<11)
+                /* number of vertices */
+#      define  R300_VAP_VF_CNTL__NUM_VERTICES__SHIFT                    16
+
+/* BEGIN: Wild guesses */
+#define R300_VAP_OUTPUT_VTX_FMT_0           0x2090
+#       define R300_VAP_OUTPUT_VTX_FMT_0__POS_PRESENT     (1<<0)
+#       define R300_VAP_OUTPUT_VTX_FMT_0__COLOR_PRESENT   (1<<1)
+#       define R300_VAP_OUTPUT_VTX_FMT_0__COLOR_1_PRESENT (1<<2) /* GUESS */
+#       define R300_VAP_OUTPUT_VTX_FMT_0__COLOR_2_PRESENT (1<<3) /* GUESS */
+#       define R300_VAP_OUTPUT_VTX_FMT_0__COLOR_3_PRESENT (1<<4) /* GUESS */
+#       define R300_VAP_OUTPUT_VTX_FMT_0__PT_SIZE_PRESENT (1<<16) /* GUESS */
+
+#define R300_VAP_OUTPUT_VTX_FMT_1           0x2094
+#       define R300_VAP_OUTPUT_VTX_FMT_1__TEX_0_COMP_CNT_SHIFT 0
+#       define R300_VAP_OUTPUT_VTX_FMT_1__TEX_1_COMP_CNT_SHIFT 3
+#       define R300_VAP_OUTPUT_VTX_FMT_1__TEX_2_COMP_CNT_SHIFT 6
+#       define R300_VAP_OUTPUT_VTX_FMT_1__TEX_3_COMP_CNT_SHIFT 9
+#       define R300_VAP_OUTPUT_VTX_FMT_1__TEX_4_COMP_CNT_SHIFT 12
+#       define R300_VAP_OUTPUT_VTX_FMT_1__TEX_5_COMP_CNT_SHIFT 15
+#       define R300_VAP_OUTPUT_VTX_FMT_1__TEX_6_COMP_CNT_SHIFT 18
+#       define R300_VAP_OUTPUT_VTX_FMT_1__TEX_7_COMP_CNT_SHIFT 21
+/* END */
+
+#define R300_SE_VTE_CNTL                  0x20b0
+#      define     R300_VPORT_X_SCALE_ENA                0x00000001
+#      define     R300_VPORT_X_OFFSET_ENA               0x00000002
+#      define     R300_VPORT_Y_SCALE_ENA                0x00000004
+#      define     R300_VPORT_Y_OFFSET_ENA               0x00000008
+#      define     R300_VPORT_Z_SCALE_ENA                0x00000010
+#      define     R300_VPORT_Z_OFFSET_ENA               0x00000020
+#      define     R300_VTX_XY_FMT                       0x00000100
+#      define     R300_VTX_Z_FMT                        0x00000200
+#      define     R300_VTX_W0_FMT                       0x00000400
+#      define     R300_VTX_W0_NORMALIZE                 0x00000800
+#      define     R300_VTX_ST_DENORMALIZED              0x00001000
+
+/* BEGIN: Vertex data assembly - lots of uncertainties */
+/* gap */
+/* Where do we get our vertex data?
+//
+// Vertex data either comes either from immediate mode registers or from
+// vertex arrays.
+// There appears to be no mixed mode (though we can force the pitch of
+// vertex arrays to 0, effectively reusing the same element over and over
+// again).
+//
+// Immediate mode is controlled by the INPUT_CNTL registers. I am not sure
+// if these registers influence vertex array processing.
+//
+// Vertex arrays are controlled via the 3D_LOAD_VBPNTR packet3.
+//
+// In both cases, vertex attributes are then passed through INPUT_ROUTE.
+
+// Beginning with INPUT_ROUTE_0_0 is a list of WORDs that route vertex data
+// into the vertex processor's input registers.
+// The first word routes the first input, the second word the second, etc.
+// The corresponding input is routed into the register with the given index.
+// The list is ended by a word with INPUT_ROUTE_END set.
+//
+// Always set COMPONENTS_4 in immediate mode. */
+
+#define R300_VAP_INPUT_ROUTE_0_0            0x2150
+#       define R300_INPUT_ROUTE_COMPONENTS_1     (0 << 0)
+#       define R300_INPUT_ROUTE_COMPONENTS_2     (1 << 0)
+#       define R300_INPUT_ROUTE_COMPONENTS_3     (2 << 0)
+#       define R300_INPUT_ROUTE_COMPONENTS_4     (3 << 0)
+#       define R300_INPUT_ROUTE_COMPONENTS_RGBA  (4 << 0) /* GUESS */
+#       define R300_VAP_INPUT_ROUTE_IDX_SHIFT    8
+#       define R300_VAP_INPUT_ROUTE_IDX_MASK     (31 << 8) /* GUESS */
+#       define R300_VAP_INPUT_ROUTE_END          (1 << 13)
+#       define R300_INPUT_ROUTE_IMMEDIATE_MODE   (0 << 14) /* GUESS */
+#       define R300_INPUT_ROUTE_FLOAT            (1 << 14) /* GUESS */
+#       define R300_INPUT_ROUTE_UNSIGNED_BYTE    (2 << 14) /* GUESS */
+#       define R300_INPUT_ROUTE_FLOAT_COLOR      (3 << 14) /* GUESS */
+#define R300_VAP_INPUT_ROUTE_0_1            0x2154
+#define R300_VAP_INPUT_ROUTE_0_2            0x2158
+#define R300_VAP_INPUT_ROUTE_0_3            0x215C
+#define R300_VAP_INPUT_ROUTE_0_4            0x2160
+#define R300_VAP_INPUT_ROUTE_0_5            0x2164
+#define R300_VAP_INPUT_ROUTE_0_6            0x2168
+#define R300_VAP_INPUT_ROUTE_0_7            0x216C
+
+/* gap */
+/* Notes:
+//  - always set up to produce at least two attributes:
+//    if vertex program uses only position, fglrx will set normal, too
+//  - INPUT_CNTL_0_COLOR and INPUT_CNTL_COLOR bits are always equal */
+#define R300_VAP_INPUT_CNTL_0               0x2180
+#       define R300_INPUT_CNTL_0_COLOR           0x00000001
+#define R300_VAP_INPUT_CNTL_1               0x2184
+#       define R300_INPUT_CNTL_POS               0x00000001
+#       define R300_INPUT_CNTL_NORMAL            0x00000002
+#       define R300_INPUT_CNTL_COLOR             0x00000004
+#       define R300_INPUT_CNTL_TC0               0x00000400
+#       define R300_INPUT_CNTL_TC1               0x00000800
+#       define R300_INPUT_CNTL_TC2               0x00001000 /* GUESS */
+#       define R300_INPUT_CNTL_TC3               0x00002000 /* GUESS */
+#       define R300_INPUT_CNTL_TC4               0x00004000 /* GUESS */
+#       define R300_INPUT_CNTL_TC5               0x00008000 /* GUESS */
+#       define R300_INPUT_CNTL_TC6               0x00010000 /* GUESS */
+#       define R300_INPUT_CNTL_TC7               0x00020000 /* GUESS */
+
+/* gap */
+/* Words parallel to INPUT_ROUTE_0; All words that are active in INPUT_ROUTE_0
+// are set to a swizzling bit pattern, other words are 0.
+//
+// In immediate mode, the pattern is always set to xyzw. In vertex array
+// mode, the swizzling pattern is e.g. used to set zw components in texture
+// coordinates with only tweo components. */
+#define R300_VAP_INPUT_ROUTE_1_0            0x21E0
+#       define R300_INPUT_ROUTE_SELECT_X    0
+#       define R300_INPUT_ROUTE_SELECT_Y    1
+#       define R300_INPUT_ROUTE_SELECT_Z    2
+#       define R300_INPUT_ROUTE_SELECT_W    3
+#       define R300_INPUT_ROUTE_SELECT_ZERO 4
+#       define R300_INPUT_ROUTE_SELECT_ONE  5
+#       define R300_INPUT_ROUTE_SELECT_MASK 7
+#       define R300_INPUT_ROUTE_X_SHIFT          0
+#       define R300_INPUT_ROUTE_Y_SHIFT          3
+#       define R300_INPUT_ROUTE_Z_SHIFT          6
+#       define R300_INPUT_ROUTE_W_SHIFT          9
+#       define R300_INPUT_ROUTE_ENABLE           (15 << 12)
+#define R300_VAP_INPUT_ROUTE_1_1            0x21E4
+#define R300_VAP_INPUT_ROUTE_1_2            0x21E8
+#define R300_VAP_INPUT_ROUTE_1_3            0x21EC
+#define R300_VAP_INPUT_ROUTE_1_4            0x21F0
+#define R300_VAP_INPUT_ROUTE_1_5            0x21F4
+#define R300_VAP_INPUT_ROUTE_1_6            0x21F8
+#define R300_VAP_INPUT_ROUTE_1_7            0x21FC
+
+/* END */
+
+/* gap */
+/* BEGIN: Upload vertex program and data
+// The programmable vertex shader unit has a memory bank of unknown size
+// that can be written to in 16 byte units by writing the address into
+// UPLOAD_ADDRESS, followed by data in UPLOAD_DATA (multiples of 4 DWORDs).
+//
+// Pointers into the memory bank are always in multiples of 16 bytes.
+//
+// The memory bank is divided into areas with fixed meaning.
+//
+// Starting at address UPLOAD_PROGRAM: Vertex program instructions.
+// Native limits reported by drivers from ATI suggest size 256 (i.e. 4KB),
+// whereas the difference between known addresses suggests size 512.
+//
+// Starting at address UPLOAD_PARAMETERS: Vertex program parameters.
+// Native reported limits and the VPI layout suggest size 256, whereas
+// difference between known addresses suggests size 512.
+//
+// At address UPLOAD_POINTSIZE is a vector (0, 0, ps, 0), where ps is the
+// floating point pointsize. The exact purpose of this state is uncertain,
+// as there is also the R300_RE_POINTSIZE register.
+//
+// Multiple vertex programs and parameter sets can be loaded at once,
+// which could explain the size discrepancy. */
+#define R300_VAP_PVS_UPLOAD_ADDRESS         0x2200
+#       define R300_PVS_UPLOAD_PROGRAM           0x00000000
+#       define R300_PVS_UPLOAD_PARAMETERS        0x00000200
+#       define R300_PVS_UPLOAD_POINTSIZE         0x00000406
+/* gap */
+#define R300_VAP_PVS_UPLOAD_DATA            0x2208
+/* END */
+
+/* gap */
+/* I do not know the purpose of this register. However, I do know that
+// it is set to 221C_CLEAR for clear operations and to 221C_NORMAL
+// for normal rendering. */
+#define R300_VAP_UNKNOWN_221C               0x221C
+#       define R300_221C_NORMAL                  0x00000000
+#       define R300_221C_CLEAR                   0x0001C000
+
+/* gap */
+/* Sometimes, END_OF_PKT and 0x2284=0 are the only commands sent between
+// rendering commands and overwriting vertex program parameters.
+// Therefore, I suspect writing zero to 0x2284 synchronizes the engine and
+// avoids bugs caused by still running shaders reading bad data from memory. */
+#define R300_VAP_PVS_WAITIDLE               0x2284 /* GUESS */
+
+/* Absolutely no clue what this register is about. */
+#define R300_VAP_UNKNOWN_2288               0x2288
+#       define R300_2288_R300                    0x00750000 /* -- nh */
+#       define R300_2288_RV350                   0x0000FFFF /* -- Vladimir */
+
+/* gap */
+/* Addresses are relative to the vertex program instruction area of the
+// memory bank. PROGRAM_END points to the last instruction of the active
+// program
+//
+// The meaning of the two UNKNOWN fields is obviously not known. However,
+// experiments so far have shown that both *must* point to an instruction
+// inside the vertex program, otherwise the GPU locks up.
+// fglrx usually sets CNTL_3_UNKNOWN to the end of the program and
+// CNTL_1_UNKNOWN points to instruction where last write to position takes place. 
+// Most likely this is used to ignore rest of the program in cases where group of verts arent visible.
+// For some reason this "section" is sometimes accepted other instruction that have
+// no relationship with position calculations. 
+*/
+#define R300_VAP_PVS_CNTL_1                 0x22D0
+#       define R300_PVS_CNTL_1_PROGRAM_START_SHIFT   0
+#       define R300_PVS_CNTL_1_POS_END_SHIFT         10
+#       define R300_PVS_CNTL_1_PROGRAM_END_SHIFT     20
+/* Addresses are relative the the vertex program parameters area. */
+#define R300_VAP_PVS_CNTL_2                 0x22D4
+#       define R300_PVS_CNTL_2_PARAM_OFFSET_SHIFT 0
+#       define R300_PVS_CNTL_2_PARAM_COUNT_SHIFT  16
+#define R300_VAP_PVS_CNTL_3               0x22D8
+#       define R300_PVS_CNTL_3_PROGRAM_UNKNOWN_SHIFT 10
+#       define R300_PVS_CNTL_3_PROGRAM_UNKNOWN2_SHIFT 0
+
+/* The entire range from 0x2300 to 0x2AC inclusive seems to be used for
+// immediate vertices */
+#define R300_VAP_VTX_COLOR_R                0x2464
+#define R300_VAP_VTX_COLOR_G                0x2468
+#define R300_VAP_VTX_COLOR_B                0x246C
+#define R300_VAP_VTX_POS_0_X_1              0x2490 /* used for glVertex2*() */
+#define R300_VAP_VTX_POS_0_Y_1              0x2494
+#define R300_VAP_VTX_COLOR_PKD              0x249C /* RGBA */
+#define R300_VAP_VTX_POS_0_X_2              0x24A0 /* used for glVertex3*() */
+#define R300_VAP_VTX_POS_0_Y_2              0x24A4
+#define R300_VAP_VTX_POS_0_Z_2              0x24A8
+#define R300_VAP_VTX_END_OF_PKT             0x24AC /* write 0 to indicate end of packet? */
+
+/* gap */
+
+/* These are values from r300_reg/r300_reg.h - they are known to be correct
+   and are here so we can use one register file instead of several
+   - Vladimir */
+#define R300_GB_VAP_RASTER_VTX_FMT_0   0x4000
+#      define R300_GB_VAP_RASTER_VTX_FMT_0__POS_PRESENT        (1<<0)
+#      define R300_GB_VAP_RASTER_VTX_FMT_0__COLOR_0_PRESENT    (1<<1)
+#      define R300_GB_VAP_RASTER_VTX_FMT_0__COLOR_1_PRESENT    (1<<2)
+#      define R300_GB_VAP_RASTER_VTX_FMT_0__COLOR_2_PRESENT    (1<<3)
+#      define R300_GB_VAP_RASTER_VTX_FMT_0__COLOR_3_PRESENT    (1<<4)
+#      define R300_GB_VAP_RASTER_VTX_FMT_0__COLOR_SPACE        (0xf<<5)
+#      define R300_GB_VAP_RASTER_VTX_FMT_0__PT_SIZE_PRESENT    (0x1<<16)
+
+#define R300_GB_VAP_RASTER_VTX_FMT_1   0x4004
+       /* each of the following is 3 bits wide, specifies number
+          of components */
+#      define R300_GB_VAP_RASTER_VTX_FMT_1__TEX_0_COMP_CNT_SHIFT       0
+#      define R300_GB_VAP_RASTER_VTX_FMT_1__TEX_1_COMP_CNT_SHIFT       3
+#      define R300_GB_VAP_RASTER_VTX_FMT_1__TEX_2_COMP_CNT_SHIFT       6
+#      define R300_GB_VAP_RASTER_VTX_FMT_1__TEX_3_COMP_CNT_SHIFT       9
+#      define R300_GB_VAP_RASTER_VTX_FMT_1__TEX_4_COMP_CNT_SHIFT       12
+#      define R300_GB_VAP_RASTER_VTX_FMT_1__TEX_5_COMP_CNT_SHIFT       15
+#      define R300_GB_VAP_RASTER_VTX_FMT_1__TEX_6_COMP_CNT_SHIFT       18
+#      define R300_GB_VAP_RASTER_VTX_FMT_1__TEX_7_COMP_CNT_SHIFT       21
+
+/* UNK30 seems to enables point to quad transformation on textures
+   (or something closely related to that).
+   This bit is rather fatal at the time being due to lackings at pixel shader side */
+#define R300_GB_ENABLE 0x4008
+#      define R300_GB_POINT_STUFF_ENABLE       (1<<0)
+#      define R300_GB_LINE_STUFF_ENABLE        (1<<1)
+#      define R300_GB_TRIANGLE_STUFF_ENABLE    (1<<2)
+#      define R300_GB_STENCIL_AUTO_ENABLE      (1<<4)
+#      define R300_GB_UNK30                    (1<<30)
+       /* each of the following is 2 bits wide */
+#define R300_GB_TEX_REPLICATE  0
+#define R300_GB_TEX_ST         1
+#define R300_GB_TEX_STR                2
+#      define R300_GB_TEX0_SOURCE_SHIFT        16
+#      define R300_GB_TEX1_SOURCE_SHIFT        18
+#      define R300_GB_TEX2_SOURCE_SHIFT        20
+#      define R300_GB_TEX3_SOURCE_SHIFT        22
+#      define R300_GB_TEX4_SOURCE_SHIFT        24
+#      define R300_GB_TEX5_SOURCE_SHIFT        26
+#      define R300_GB_TEX6_SOURCE_SHIFT        28
+#      define R300_GB_TEX7_SOURCE_SHIFT        30
+
+/* MSPOS - positions for multisample antialiasing (?) */
+#define R300_GB_MSPOS0 0x4010
+       /* shifts - each of the fields is 4 bits */
+#      define R300_GB_MSPOS0__MS_X0_SHIFT      0
+#      define R300_GB_MSPOS0__MS_Y0_SHIFT      4
+#      define R300_GB_MSPOS0__MS_X1_SHIFT      8
+#      define R300_GB_MSPOS0__MS_Y1_SHIFT      12
+#      define R300_GB_MSPOS0__MS_X2_SHIFT      16
+#      define R300_GB_MSPOS0__MS_Y2_SHIFT      20
+#      define R300_GB_MSPOS0__MSBD0_Y          24
+#      define R300_GB_MSPOS0__MSBD0_X          28
+
+#define R300_GB_MSPOS1 0x4014
+#      define R300_GB_MSPOS1__MS_X3_SHIFT      0
+#      define R300_GB_MSPOS1__MS_Y3_SHIFT      4
+#      define R300_GB_MSPOS1__MS_X4_SHIFT      8
+#      define R300_GB_MSPOS1__MS_Y4_SHIFT      12
+#      define R300_GB_MSPOS1__MS_X5_SHIFT      16
+#      define R300_GB_MSPOS1__MS_Y5_SHIFT      20
+#      define R300_GB_MSPOS1__MSBD1            24
+
+
+#define R300_GB_TILE_CONFIG    0x4018
+#      define R300_GB_TILE_ENABLE      (1<<0)
+#      define R300_GB_TILE_PIPE_COUNT_RV300    0
+#      define R300_GB_TILE_PIPE_COUNT_R300     (3<<1)
+#      define R300_GB_TILE_PIPE_COUNT_R420     (7<<1)
+#      define R300_GB_TILE_SIZE_8              0
+#      define R300_GB_TILE_SIZE_16             (1<<4)
+#      define R300_GB_TILE_SIZE_32             (2<<4)
+#      define R300_GB_SUPER_SIZE_1             (0<<6)
+#      define R300_GB_SUPER_SIZE_2             (1<<6)
+#      define R300_GB_SUPER_SIZE_4             (2<<6)
+#      define R300_GB_SUPER_SIZE_8             (3<<6)
+#      define R300_GB_SUPER_SIZE_16            (4<<6)
+#      define R300_GB_SUPER_SIZE_32            (5<<6)
+#      define R300_GB_SUPER_SIZE_64            (6<<6)
+#      define R300_GB_SUPER_SIZE_128           (7<<6)
+#      define R300_GB_SUPER_X_SHIFT            9       /* 3 bits wide */
+#      define R300_GB_SUPER_Y_SHIFT            12      /* 3 bits wide */
+#      define R300_GB_SUPER_TILE_A             0
+#      define R300_GB_SUPER_TILE_B             (1<<15)
+#      define R300_GB_SUBPIXEL_1_12            0
+#      define R300_GB_SUBPIXEL_1_16            (1<<16)
+
+#define R300_GB_FIFO_SIZE      0x4024
+       /* each of the following is 2 bits wide */
+#define R300_GB_FIFO_SIZE_32   0
+#define R300_GB_FIFO_SIZE_64   1
+#define R300_GB_FIFO_SIZE_128  2
+#define R300_GB_FIFO_SIZE_256  3
+#      define R300_SC_IFIFO_SIZE_SHIFT 0
+#      define R300_SC_TZFIFO_SIZE_SHIFT        2
+#      define R300_SC_BFIFO_SIZE_SHIFT 4
+
+#      define R300_US_OFIFO_SIZE_SHIFT 12
+#      define R300_US_WFIFO_SIZE_SHIFT 14
+       /* the following use the same constants as above, but meaning is
+          is times 2 (i.e. instead of 32 words it means 64 */
+#      define R300_RS_TFIFO_SIZE_SHIFT 6
+#      define R300_RS_CFIFO_SIZE_SHIFT 8
+#      define R300_US_RAM_SIZE_SHIFT           10
+       /* watermarks, 3 bits wide */
+#      define R300_RS_HIGHWATER_COL_SHIFT      16
+#      define R300_RS_HIGHWATER_TEX_SHIFT      19
+#      define R300_OFIFO_HIGHWATER_SHIFT       22      /* two bits only */
+#      define R300_CUBE_FIFO_HIGHWATER_COL_SHIFT       24
+
+#define R300_GB_SELECT 0x401C
+#      define R300_GB_FOG_SELECT_C0A           0
+#      define R300_GB_FOG_SELECT_C1A           1
+#      define R300_GB_FOG_SELECT_C2A           2
+#      define R300_GB_FOG_SELECT_C3A           3
+#      define R300_GB_FOG_SELECT_1_1_W 4
+#      define R300_GB_FOG_SELECT_Z             5
+#      define R300_GB_DEPTH_SELECT_Z           0
+#      define R300_GB_DEPTH_SELECT_1_1_W       (1<<3)
+#      define R300_GB_W_SELECT_1_W             0
+#      define R300_GB_W_SELECT_1               (1<<4)
+
+#define R300_GB_AA_CONFIG              0x4020
+#      define R300_AA_ENABLE                   0x01
+#      define R300_AA_SUBSAMPLES_2             0
+#      define R300_AA_SUBSAMPLES_3             (1<<1)
+#      define R300_AA_SUBSAMPLES_4             (2<<1)
+#      define R300_AA_SUBSAMPLES_6             (3<<1)
+
+/* END */
+
+/* gap */
+/* The upper enable bits are guessed, based on fglrx reported limits. */
+#define R300_TX_ENABLE                      0x4104
+#       define R300_TX_ENABLE_0                  (1 << 0)
+#       define R300_TX_ENABLE_1                  (1 << 1)
+#       define R300_TX_ENABLE_2                  (1 << 2)
+#       define R300_TX_ENABLE_3                  (1 << 3)
+#       define R300_TX_ENABLE_4                  (1 << 4)
+#       define R300_TX_ENABLE_5                  (1 << 5)
+#       define R300_TX_ENABLE_6                  (1 << 6)
+#       define R300_TX_ENABLE_7                  (1 << 7)
+#       define R300_TX_ENABLE_8                  (1 << 8)
+#       define R300_TX_ENABLE_9                  (1 << 9)
+#       define R300_TX_ENABLE_10                 (1 << 10)
+#       define R300_TX_ENABLE_11                 (1 << 11)
+#       define R300_TX_ENABLE_12                 (1 << 12)
+#       define R300_TX_ENABLE_13                 (1 << 13)
+#       define R300_TX_ENABLE_14                 (1 << 14)
+#       define R300_TX_ENABLE_15                 (1 << 15)
+
+/* The pointsize is given in multiples of 6. The pointsize can be
+// enormous: Clear() renders a single point that fills the entire
+// framebuffer. */
+#define R300_RE_POINTSIZE                   0x421C
+#       define R300_POINTSIZE_Y_SHIFT            0
+#       define R300_POINTSIZE_Y_MASK             (0xFFFF << 0) /* GUESS */
+#       define R300_POINTSIZE_X_SHIFT            16
+#       define R300_POINTSIZE_X_MASK             (0xFFFF << 16) /* GUESS */
+#       define R300_POINTSIZE_MAX             (R300_POINTSIZE_Y_MASK / 6)
+
+/* The line width is given in multiples of 6.
+   In default mode lines are classified as vertical lines.
+   HO: horizontal
+   VE: vertical or horizontal
+   HO & VE: no classification
+*/
+#define R300_RE_LINE_CNT                      0x4234
+#       define R300_LINESIZE_SHIFT            0
+#       define R300_LINESIZE_MASK             (0xFFFF << 0) /* GUESS */
+#       define R300_LINESIZE_MAX             (R300_LINESIZE_MASK / 6)
+#       define R300_LINE_CNT_HO               (1 << 16)
+#       define R300_LINE_CNT_VE               (1 << 17)
+
+/* Some sort of scale or clamp value for texcoordless textures. */
+#define R300_RE_UNK4238                       0x4238
+
+#define R300_RE_SHADE_MODEL                   0x4278
+#      define R300_RE_SHADE_MODEL_SMOOTH     0x3aaaa
+#      define R300_RE_SHADE_MODEL_FLAT       0x39595
+
+/* Dangerous */
+#define R300_RE_POLYGON_MODE                  0x4288
+#      define R300_PM_ENABLED                (1 << 0)
+#      define R300_PM_FRONT_POINT            (0 << 0)
+#      define R300_PM_BACK_POINT             (0 << 0)
+#      define R300_PM_FRONT_LINE             (1 << 4)
+#      define R300_PM_FRONT_FILL             (1 << 5)
+#      define R300_PM_BACK_LINE              (1 << 7)
+#      define R300_PM_BACK_FILL              (1 << 8)
+
+/* Not sure why there are duplicate of factor and constant values. 
+   My best guess so far is that there are seperate zbiases for test and write. 
+   Ordering might be wrong.
+   Some of the tests indicate that fgl has a fallback implementation of zbias
+   via pixel shaders. */
+#define R300_RE_ZBIAS_T_FACTOR                0x42A4
+#define R300_RE_ZBIAS_T_CONSTANT              0x42A8
+#define R300_RE_ZBIAS_W_FACTOR                0x42AC
+#define R300_RE_ZBIAS_W_CONSTANT              0x42B0
+
+/* This register needs to be set to (1<<1) for RV350 to correctly
+   perform depth test (see --vb-triangles in r300_demo)
+   Don't know about other chips. - Vladimir
+   This is set to 3 when GL_POLYGON_OFFSET_FILL is on.
+   My guess is that there are two bits for each zbias primitive (FILL, LINE, POINT).
+   One to enable depth test and one for depth write.
+   Yet this doesnt explain why depth writes work ...
+    */
+#define R300_RE_OCCLUSION_CNTL             0x42B4
+#      define R300_OCCLUSION_ON                (1<<1)
+
+#define R300_RE_CULL_CNTL                   0x42B8
+#       define R300_CULL_FRONT                   (1 << 0)
+#       define R300_CULL_BACK                    (1 << 1)
+#       define R300_FRONT_FACE_CCW               (0 << 2)
+#       define R300_FRONT_FACE_CW                (1 << 2)
+
+
+/* BEGIN: Rasterization / Interpolators - many guesses
+// 0_UNKNOWN_18 has always been set except for clear operations.
+// TC_CNT is the number of incoming texture coordinate sets (i.e. it depends
+// on the vertex program, *not* the fragment program) */
+#define R300_RS_CNTL_0                      0x4300
+#       define R300_RS_CNTL_TC_CNT_SHIFT         2
+#       define R300_RS_CNTL_TC_CNT_MASK          (7 << 2)
+#              define R300_RS_CNTL_CI_CNT_SHIFT         7 /* number of color interpolators used */
+#       define R300_RS_CNTL_0_UNKNOWN_18         (1 << 18)
+/* Guess: RS_CNTL_1 holds the index of the highest used RS_ROUTE_n register. */
+#define R300_RS_CNTL_1                      0x4304
+
+/* gap */
+/* Only used for texture coordinates.
+// Use the source field to route texture coordinate input from the vertex program
+// to the desired interpolator. Note that the source field is relative to the
+// outputs the vertex program *actually* writes. If a vertex program only writes
+// texcoord[1], this will be source index 0.
+// Set INTERP_USED on all interpolators that produce data used by the
+// fragment program. INTERP_USED looks like a swizzling mask, but
+// I haven't seen it used that way.
+//
+// Note: The _UNKNOWN constants are always set in their respective register.
+// I don't know if this is necessary. */
+#define R300_RS_INTERP_0                    0x4310
+#define R300_RS_INTERP_1                    0x4314
+#       define R300_RS_INTERP_1_UNKNOWN          0x40
+#define R300_RS_INTERP_2                    0x4318
+#       define R300_RS_INTERP_2_UNKNOWN          0x80
+#define R300_RS_INTERP_3                    0x431C
+#       define R300_RS_INTERP_3_UNKNOWN          0xC0
+#define R300_RS_INTERP_4                    0x4320
+#define R300_RS_INTERP_5                    0x4324
+#define R300_RS_INTERP_6                    0x4328
+#define R300_RS_INTERP_7                    0x432C
+#       define R300_RS_INTERP_SRC_SHIFT          2
+#       define R300_RS_INTERP_SRC_MASK           (7 << 2)
+#       define R300_RS_INTERP_USED               0x00D10000
+
+/* These DWORDs control how vertex data is routed into fragment program
+// registers, after interpolators. */
+#define R300_RS_ROUTE_0                     0x4330
+#define R300_RS_ROUTE_1                     0x4334
+#define R300_RS_ROUTE_2                     0x4338
+#define R300_RS_ROUTE_3                     0x433C /* GUESS */
+#define R300_RS_ROUTE_4                     0x4340 /* GUESS */
+#define R300_RS_ROUTE_5                     0x4344 /* GUESS */
+#define R300_RS_ROUTE_6                     0x4348 /* GUESS */
+#define R300_RS_ROUTE_7                     0x434C /* GUESS */
+#       define R300_RS_ROUTE_SOURCE_INTERP_0     0
+#       define R300_RS_ROUTE_SOURCE_INTERP_1     1
+#       define R300_RS_ROUTE_SOURCE_INTERP_2     2
+#       define R300_RS_ROUTE_SOURCE_INTERP_3     3
+#       define R300_RS_ROUTE_SOURCE_INTERP_4     4
+#       define R300_RS_ROUTE_SOURCE_INTERP_5     5 /* GUESS */
+#       define R300_RS_ROUTE_SOURCE_INTERP_6     6 /* GUESS */
+#       define R300_RS_ROUTE_SOURCE_INTERP_7     7 /* GUESS */
+#       define R300_RS_ROUTE_ENABLE              (1 << 3) /* GUESS */
+#       define R300_RS_ROUTE_DEST_SHIFT          6
+#       define R300_RS_ROUTE_DEST_MASK           (31 << 6) /* GUESS */
+
+/* Special handling for color: When the fragment program uses color,
+// the ROUTE_0_COLOR bit is set and ROUTE_0_COLOR_DEST contains the
+// color register index. */
+#       define R300_RS_ROUTE_0_COLOR             (1 << 14)
+#       define R300_RS_ROUTE_0_COLOR_DEST_SHIFT  17
+#       define R300_RS_ROUTE_0_COLOR_DEST_MASK   (31 << 17) /* GUESS */
+/* As above, but for secondary color */
+#              define R300_RS_ROUTE_1_COLOR1            (1 << 14)
+#              define R300_RS_ROUTE_1_COLOR1_DEST_SHIFT 17
+#              define R300_RS_ROUTE_1_COLOR1_DEST_MASK  (31 << 17)
+#              define R300_RS_ROUTE_1_UNKNOWN11         (1 << 11)
+/* END */
+
+/* BEGIN: Scissors and cliprects
+// There are four clipping rectangles. Their corner coordinates are inclusive.
+// Every pixel is assigned a number from 0 and 15 by setting bits 0-3 depending
+// on whether the pixel is inside cliprects 0-3, respectively. For example,
+// if a pixel is inside cliprects 0 and 1, but outside 2 and 3, it is assigned
+// the number 3 (binary 0011).
+// Iff the bit corresponding to the pixel's number in RE_CLIPRECT_CNTL is set,
+// the pixel is rasterized.
+//
+// In addition to this, there is a scissors rectangle. Only pixels inside the
+// scissors rectangle are drawn. (coordinates are inclusive)
+//
+// For some reason, the top-left corner of the framebuffer is at (1440, 1440)
+// for the purpose of clipping and scissors. */
+#define R300_RE_CLIPRECT_TL_0               0x43B0
+#define R300_RE_CLIPRECT_BR_0               0x43B4
+#define R300_RE_CLIPRECT_TL_1               0x43B8
+#define R300_RE_CLIPRECT_BR_1               0x43BC
+#define R300_RE_CLIPRECT_TL_2               0x43C0
+#define R300_RE_CLIPRECT_BR_2               0x43C4
+#define R300_RE_CLIPRECT_TL_3               0x43C8
+#define R300_RE_CLIPRECT_BR_3               0x43CC
+#       define R300_CLIPRECT_OFFSET              1440
+#       define R300_CLIPRECT_MASK                0x1FFF
+#       define R300_CLIPRECT_X_SHIFT             0
+#       define R300_CLIPRECT_X_MASK              (0x1FFF << 0)
+#       define R300_CLIPRECT_Y_SHIFT             13
+#       define R300_CLIPRECT_Y_MASK              (0x1FFF << 13)
+#define R300_RE_CLIPRECT_CNTL               0x43D0
+#       define R300_CLIP_OUT                     (1 << 0)
+#       define R300_CLIP_0                       (1 << 1)
+#       define R300_CLIP_1                       (1 << 2)
+#       define R300_CLIP_10                      (1 << 3)
+#       define R300_CLIP_2                       (1 << 4)
+#       define R300_CLIP_20                      (1 << 5)
+#       define R300_CLIP_21                      (1 << 6)
+#       define R300_CLIP_210                     (1 << 7)
+#       define R300_CLIP_3                       (1 << 8)
+#       define R300_CLIP_30                      (1 << 9)
+#       define R300_CLIP_31                      (1 << 10)
+#       define R300_CLIP_310                     (1 << 11)
+#       define R300_CLIP_32                      (1 << 12)
+#       define R300_CLIP_320                     (1 << 13)
+#       define R300_CLIP_321                     (1 << 14)
+#       define R300_CLIP_3210                    (1 << 15)
+
+/* gap */
+#define R300_RE_SCISSORS_TL                 0x43E0
+#define R300_RE_SCISSORS_BR                 0x43E4
+#       define R300_SCISSORS_OFFSET              1440
+#       define R300_SCISSORS_X_SHIFT             0
+#       define R300_SCISSORS_X_MASK              (0x1FFF << 0)
+#       define R300_SCISSORS_Y_SHIFT             13
+#       define R300_SCISSORS_Y_MASK              (0x1FFF << 13)
+/* END */
+
+/* BEGIN: Texture specification
+// The texture specification dwords are grouped by meaning and not by texture unit.
+// This means that e.g. the offset for texture image unit N is found in register
+// TX_OFFSET_0 + (4*N) */
+#define R300_TX_FILTER_0                    0x4400
+#       define R300_TX_REPEAT                    0
+#       define R300_TX_MIRRORED                  1
+#       define R300_TX_CLAMP                     4
+#       define R300_TX_CLAMP_TO_EDGE             2
+#       define R300_TX_CLAMP_TO_BORDER           6
+#       define R300_TX_WRAP_S_SHIFT              0
+#       define R300_TX_WRAP_S_MASK               (7 << 0)
+#       define R300_TX_WRAP_T_SHIFT              3
+#       define R300_TX_WRAP_T_MASK               (7 << 3)
+#       define R300_TX_WRAP_Q_SHIFT              6
+#       define R300_TX_WRAP_Q_MASK               (7 << 6)
+#       define R300_TX_MAG_FILTER_NEAREST        (1 << 9)
+#       define R300_TX_MAG_FILTER_LINEAR         (2 << 9)
+#       define R300_TX_MAG_FILTER_MASK           (3 << 9)
+#       define R300_TX_MIN_FILTER_NEAREST        (1 << 11)
+#       define R300_TX_MIN_FILTER_LINEAR         (2 << 11)
+#      define R300_TX_MIN_FILTER_NEAREST_MIP_NEAREST       (5  <<  11)
+#      define R300_TX_MIN_FILTER_NEAREST_MIP_LINEAR        (9  <<  11)
+#      define R300_TX_MIN_FILTER_LINEAR_MIP_NEAREST        (6  <<  11)
+#      define R300_TX_MIN_FILTER_LINEAR_MIP_LINEAR         (10 <<  11)
+
+/* NOTE: NEAREST doesnt seem to exist.
+   Im not seting MAG_FILTER_MASK and (3 << 11) on for all
+   anisotropy modes because that would void selected mag filter */
+#      define R300_TX_MIN_FILTER_ANISO_NEAREST             ((0 << 13) /*|R300_TX_MAG_FILTER_MASK|(3<<11)*/)
+#      define R300_TX_MIN_FILTER_ANISO_LINEAR              ((0 << 13) /*|R300_TX_MAG_FILTER_MASK|(3<<11)*/)
+#      define R300_TX_MIN_FILTER_ANISO_NEAREST_MIP_NEAREST ((1 << 13) /*|R300_TX_MAG_FILTER_MASK|(3<<11)*/)
+#      define R300_TX_MIN_FILTER_ANISO_NEAREST_MIP_LINEAR  ((2 << 13) /*|R300_TX_MAG_FILTER_MASK|(3<<11)*/)
+#       define R300_TX_MIN_FILTER_MASK           ( (15 << 11) | (3 << 13) )
+#      define R300_TX_MAX_ANISO_1_TO_1  (0 << 21)
+#      define R300_TX_MAX_ANISO_2_TO_1  (2 << 21)
+#      define R300_TX_MAX_ANISO_4_TO_1  (4 << 21)
+#      define R300_TX_MAX_ANISO_8_TO_1  (6 << 21)
+#      define R300_TX_MAX_ANISO_16_TO_1 (8 << 21)
+#      define R300_TX_MAX_ANISO_MASK    (14 << 21)
+
+#define R300_TX_UNK1_0                      0x4440
+#      define R300_LOD_BIAS_MASK           0x1fff
+
+#define R300_TX_SIZE_0                      0x4480
+#       define R300_TX_WIDTHMASK_SHIFT           0
+#       define R300_TX_WIDTHMASK_MASK            (2047 << 0)
+#       define R300_TX_HEIGHTMASK_SHIFT          11
+#       define R300_TX_HEIGHTMASK_MASK           (2047 << 11)
+#       define R300_TX_UNK23                     (1 << 23)
+#       define R300_TX_SIZE_SHIFT                26 /* largest of width, height */
+#       define R300_TX_SIZE_MASK                 (15 << 26)
+#define R300_TX_FORMAT_0                    0x44C0
+       /* The interpretation of the format word by Wladimir van der Laan */
+       /* The X, Y, Z and W refer to the layout of the components.
+          They are given meanings as R, G, B and Alpha by the swizzle
+          specification */
+#      define R300_TX_FORMAT_X8                    0x0
+#      define R300_TX_FORMAT_X16                   0x1
+#      define R300_TX_FORMAT_Y4X4                  0x2
+#      define R300_TX_FORMAT_Y8X8                  0x3
+#      define R300_TX_FORMAT_Y16X16                0x4
+#      define R300_TX_FORMAT_Z3Y3X2                0x5
+#      define R300_TX_FORMAT_Z5Y6X5                0x6
+#      define R300_TX_FORMAT_Z6Y5X5                0x7
+#      define R300_TX_FORMAT_Z11Y11X10             0x8
+#      define R300_TX_FORMAT_Z10Y11X11             0x9
+#      define R300_TX_FORMAT_W4Z4Y4X4              0xA
+#      define R300_TX_FORMAT_W1Z5Y5X5              0xB
+#      define R300_TX_FORMAT_W8Z8Y8X8              0xC
+#      define R300_TX_FORMAT_W2Z10Y10X10           0xD
+#      define R300_TX_FORMAT_W16Z16Y16X16          0xE
+#      define R300_TX_FORMAT_DXT1                  0xF
+#      define R300_TX_FORMAT_DXT3                  0x10
+#      define R300_TX_FORMAT_DXT5                  0x11
+#      define R300_TX_FORMAT_D3DMFT_CxV8U8         0x12     /* no swizzle */
+#      define R300_TX_FORMAT_A8R8G8B8              0x13     /* no swizzle */
+#      define R300_TX_FORMAT_B8G8_B8G8             0x14     /* no swizzle */
+#      define R300_TX_FORMAT_G8R8_G8B8             0x15     /* no swizzle */
+                                                 /* 0x16 - some 16 bit green format.. ?? */
+#      define R300_TX_FORMAT_UNK25                (1 << 25) /* no swizzle */
+
+       /* gap */
+       /* Floating point formats */
+       /* Note - hardware supports both 16 and 32 bit floating point */
+#      define R300_TX_FORMAT_FL_I16                0x18
+#      define R300_TX_FORMAT_FL_I16A16             0x19
+#      define R300_TX_FORMAT_FL_R16G16B16A16       0x1A
+#      define R300_TX_FORMAT_FL_I32                0x1B
+#      define R300_TX_FORMAT_FL_I32A32             0x1C
+#      define R300_TX_FORMAT_FL_R32G32B32A32       0x1D
+       /* alpha modes, convenience mostly */
+       /* if you have alpha, pick constant appropriate to the
+          number of channels (1 for I8, 2 for I8A8, 4 for R8G8B8A8, etc */
+#      define R300_TX_FORMAT_ALPHA_1CH             0x000
+#      define R300_TX_FORMAT_ALPHA_2CH             0x200
+#      define R300_TX_FORMAT_ALPHA_4CH             0x600
+#      define R300_TX_FORMAT_ALPHA_NONE            0xA00
+       /* Swizzling */
+       /* constants */
+#      define R300_TX_FORMAT_X         0
+#      define R300_TX_FORMAT_Y         1
+#      define R300_TX_FORMAT_Z         2
+#      define R300_TX_FORMAT_W         3
+#      define R300_TX_FORMAT_ZERO      4
+#      define R300_TX_FORMAT_ONE       5
+#      define R300_TX_FORMAT_CUT_Z     6               /* 2.0*Z, everything above 1.0 is set to 0.0 */
+#      define R300_TX_FORMAT_CUT_W     7               /* 2.0*W, everything above 1.0 is set to 0.0 */
+
+#      define R300_TX_FORMAT_B_SHIFT   18
+#      define R300_TX_FORMAT_G_SHIFT   15
+#      define R300_TX_FORMAT_R_SHIFT   12
+#      define R300_TX_FORMAT_A_SHIFT   9
+       /* Convenience macro to take care of layout and swizzling */
+#      define R300_EASY_TX_FORMAT(B, G, R, A, FMT)     (\
+         ((R300_TX_FORMAT_##B)<<R300_TX_FORMAT_B_SHIFT) \
+       | ((R300_TX_FORMAT_##G)<<R300_TX_FORMAT_G_SHIFT) \
+       | ((R300_TX_FORMAT_##R)<<R300_TX_FORMAT_R_SHIFT) \
+       | ((R300_TX_FORMAT_##A)<<R300_TX_FORMAT_A_SHIFT) \
+       | (R300_TX_FORMAT_##FMT) \
+         )
+       /* These can be ORed with result of R300_EASY_TX_FORMAT() */
+       /* We don't really know what they do. Take values from a constant color ? */
+#      define R300_TX_FORMAT_CONST_X           (1<<5)
+#      define R300_TX_FORMAT_CONST_Y           (2<<5)
+#      define R300_TX_FORMAT_CONST_Z           (4<<5)
+#      define R300_TX_FORMAT_CONST_W           (8<<5)
+
+#      define R300_TX_FORMAT_YUV_MODE          0x00800000
+
+#define R300_TX_OFFSET_0                    0x4540
+/* BEGIN: Guess from R200 */
+#       define R300_TXO_ENDIAN_NO_SWAP           (0 << 0)
+#       define R300_TXO_ENDIAN_BYTE_SWAP         (1 << 0)
+#       define R300_TXO_ENDIAN_WORD_SWAP         (2 << 0)
+#       define R300_TXO_ENDIAN_HALFDW_SWAP       (3 << 0)
+#       define R300_TXO_OFFSET_MASK              0xffffffe0
+#       define R300_TXO_OFFSET_SHIFT             5
+/* END */
+#define R300_TX_UNK4_0                      0x4580
+#define R300_TX_BORDER_COLOR_0              0x45C0 //ff00ff00 == { 0, 1.0, 0, 1.0 }
+
+/* END */
+
+/* BEGIN: Fragment program instruction set
+// Fragment programs are written directly into register space.
+// There are separate instruction streams for texture instructions and ALU
+// instructions.
+// In order to synchronize these streams, the program is divided into up
+// to 4 nodes. Each node begins with a number of TEX operations, followed
+// by a number of ALU operations.
+// The first node can have zero TEX ops, all subsequent nodes must have at least
+// one TEX ops.
+// All nodes must have at least one ALU op.
+//
+// The index of the last node is stored in PFS_CNTL_0: A value of 0 means
+// 1 node, a value of 3 means 4 nodes.
+// The total amount of instructions is defined in PFS_CNTL_2. The offsets are
+// offsets into the respective instruction streams, while *_END points to the
+// last instruction relative to this offset. */
+#define R300_PFS_CNTL_0                     0x4600
+#       define R300_PFS_CNTL_LAST_NODES_SHIFT    0
+#       define R300_PFS_CNTL_LAST_NODES_MASK     (3 << 0)
+#       define R300_PFS_CNTL_FIRST_NODE_HAS_TEX  (1 << 3)
+#define R300_PFS_CNTL_1                     0x4604
+/* There is an unshifted value here which has so far always been equal to the
+// index of the highest used temporary register. */
+#define R300_PFS_CNTL_2                     0x4608
+#       define R300_PFS_CNTL_ALU_OFFSET_SHIFT    0
+#       define R300_PFS_CNTL_ALU_OFFSET_MASK     (63 << 0)
+#       define R300_PFS_CNTL_ALU_END_SHIFT       6
+#       define R300_PFS_CNTL_ALU_END_MASK        (63 << 0)
+#       define R300_PFS_CNTL_TEX_OFFSET_SHIFT    12
+#       define R300_PFS_CNTL_TEX_OFFSET_MASK     (31 << 12) /* GUESS */
+#       define R300_PFS_CNTL_TEX_END_SHIFT       18
+#       define R300_PFS_CNTL_TEX_END_MASK        (31 << 18) /* GUESS */
+
+/* gap */
+/* Nodes are stored backwards. The last active node is always stored in
+// PFS_NODE_3.
+// Example: In a 2-node program, NODE_0 and NODE_1 are set to 0. The
+// first node is stored in NODE_2, the second node is stored in NODE_3.
+//
+// Offsets are relative to the master offset from PFS_CNTL_2.
+// LAST_NODE is set for the last node, and only for the last node. */
+#define R300_PFS_NODE_0                     0x4610
+#define R300_PFS_NODE_1                     0x4614
+#define R300_PFS_NODE_2                     0x4618
+#define R300_PFS_NODE_3                     0x461C
+#       define R300_PFS_NODE_ALU_OFFSET_SHIFT    0
+#       define R300_PFS_NODE_ALU_OFFSET_MASK     (63 << 0)
+#       define R300_PFS_NODE_ALU_END_SHIFT       6
+#       define R300_PFS_NODE_ALU_END_MASK        (63 << 6)
+#       define R300_PFS_NODE_TEX_OFFSET_SHIFT    12
+#       define R300_PFS_NODE_TEX_OFFSET_MASK     (31 << 12)
+#       define R300_PFS_NODE_TEX_END_SHIFT       17
+#       define R300_PFS_NODE_TEX_END_MASK        (31 << 17)
+#       define R300_PFS_NODE_LAST_NODE           (1 << 22)
+
+/* TEX
+// As far as I can tell, texture instructions cannot write into output
+// registers directly. A subsequent ALU instruction is always necessary,
+// even if it's just MAD o0, r0, 1, 0 */
+#define R300_PFS_TEXI_0                     0x4620
+#       define R300_FPITX_SRC_SHIFT              0
+#       define R300_FPITX_SRC_MASK               (31 << 0)
+#       define R300_FPITX_SRC_CONST              (1 << 5) /* GUESS */
+#       define R300_FPITX_DST_SHIFT              6
+#       define R300_FPITX_DST_MASK               (31 << 6)
+#       define R300_FPITX_IMAGE_SHIFT            11
+#       define R300_FPITX_IMAGE_MASK             (15 << 11) /* GUESS based on layout and native limits */
+/* Unsure if these are opcodes, or some kind of bitfield, but this is how
+ * they were set when I checked
+ */
+#              define R300_FPITX_OPCODE_SHIFT                  15
+#                      define R300_FPITX_OP_TEX                        1
+#                      define R300_FPITX_OP_TXP                        3
+#                      define R300_FPITX_OP_TXB                        4
+
+/* ALU
+// The ALU instructions register blocks are enumerated according to the order
+// in which fglrx. I assume there is space for 64 instructions, since
+// each block has space for a maximum of 64 DWORDs, and this matches reported
+// native limits.
+//
+// The basic functional block seems to be one MAD for each color and alpha,
+// and an adder that adds all components after the MUL.
+//  - ADD, MUL, MAD etc.: use MAD with appropriate neutral operands
+//  - DP4: Use OUTC_DP4, OUTA_DP4
+//  - DP3: Use OUTC_DP3, OUTA_DP4, appropriate alpha operands
+//  - DPH: Use OUTC_DP4, OUTA_DP4, appropriate alpha operands
+//  - CMP: If ARG2 < 0, return ARG1, else return ARG0
+//  - FLR: use FRC+MAD
+//  - XPD: use MAD+MAD
+//  - SGE, SLT: use MAD+CMP
+//  - RSQ: use ABS modifier for argument
+//  - Use OUTC_REPL_ALPHA to write results of an alpha-only operation (e.g. RCP)
+//    into color register
+//  - apparently, there's no quick DST operation
+//  - fglrx set FPI2_UNKNOWN_31 on a "MAD fragment.color, tmp0, tmp1, tmp2"
+//  - fglrx set FPI2_UNKNOWN_31 on a "MAX r2, r1, c0"
+//  - fglrx once set FPI0_UNKNOWN_31 on a "FRC r1, r1"
+//
+// Operand selection
+// First stage selects three sources from the available registers and
+// constant parameters. This is defined in INSTR1 (color) and INSTR3 (alpha).
+// fglrx sorts the three source fields: Registers before constants,
+// lower indices before higher indices; I do not know whether this is necessary.
+// fglrx fills unused sources with "read constant 0"
+// According to specs, you cannot select more than two different constants.
+//
+// Second stage selects the operands from the sources. This is defined in
+// INSTR0 (color) and INSTR2 (alpha). You can also select the special constants
+// zero and one.
+// Swizzling and negation happens in this stage, as well.
+//
+// Important: Color and alpha seem to be mostly separate, i.e. their sources
+// selection appears to be fully independent (the register storage is probably
+// physically split into a color and an alpha section).
+// However (because of the apparent physical split), there is some interaction
+// WRT swizzling. If, for example, you want to load an R component into an
+// Alpha operand, this R component is taken from a *color* source, not from
+// an alpha source. The corresponding register doesn't even have to appear in
+// the alpha sources list. (I hope this alll makes sense to you)
+//
+// Destination selection
+// The destination register index is in FPI1 (color) and FPI3 (alpha) together
+// with enable bits.
+// There are separate enable bits for writing into temporary registers
+// (DSTC_REG_* /DSTA_REG) and and program output registers (DSTC_OUTPUT_* /DSTA_OUTPUT).
+// You can write to both at once, or not write at all (the same index
+// must be used for both).
+//
+// Note: There is a special form for LRP
+//  - Argument order is the same as in ARB_fragment_program.
+//  - Operation is MAD
+//  - ARG1 is set to ARGC_SRC1C_LRP/ARGC_SRC1A_LRP
+//  - Set FPI0/FPI2_SPECIAL_LRP
+// Arbitrary LRP (including support for swizzling) requires vanilla MAD+MAD */
+#define R300_PFS_INSTR1_0                   0x46C0
+#       define R300_FPI1_SRC0C_SHIFT             0
+#       define R300_FPI1_SRC0C_MASK              (31 << 0)
+#       define R300_FPI1_SRC0C_CONST             (1 << 5)
+#       define R300_FPI1_SRC1C_SHIFT             6
+#       define R300_FPI1_SRC1C_MASK              (31 << 6)
+#       define R300_FPI1_SRC1C_CONST             (1 << 11)
+#       define R300_FPI1_SRC2C_SHIFT             12
+#       define R300_FPI1_SRC2C_MASK              (31 << 12)
+#       define R300_FPI1_SRC2C_CONST             (1 << 17)
+#       define R300_FPI1_DSTC_SHIFT              18
+#       define R300_FPI1_DSTC_MASK               (31 << 18)
+#       define R300_FPI1_DSTC_REG_X              (1 << 23)
+#       define R300_FPI1_DSTC_REG_Y              (1 << 24)
+#       define R300_FPI1_DSTC_REG_Z              (1 << 25)
+#       define R300_FPI1_DSTC_OUTPUT_X           (1 << 26)
+#       define R300_FPI1_DSTC_OUTPUT_Y           (1 << 27)
+#       define R300_FPI1_DSTC_OUTPUT_Z           (1 << 28)
+
+#define R300_PFS_INSTR3_0                   0x47C0
+#       define R300_FPI3_SRC0A_SHIFT             0
+#       define R300_FPI3_SRC0A_MASK              (31 << 0)
+#       define R300_FPI3_SRC0A_CONST             (1 << 5)
+#       define R300_FPI3_SRC1A_SHIFT             6
+#       define R300_FPI3_SRC1A_MASK              (31 << 6)
+#       define R300_FPI3_SRC1A_CONST             (1 << 11)
+#       define R300_FPI3_SRC2A_SHIFT             12
+#       define R300_FPI3_SRC2A_MASK              (31 << 12)
+#       define R300_FPI3_SRC2A_CONST             (1 << 17)
+#       define R300_FPI3_DSTA_SHIFT              18
+#       define R300_FPI3_DSTA_MASK               (31 << 18)
+#       define R300_FPI3_DSTA_REG                (1 << 23)
+#       define R300_FPI3_DSTA_OUTPUT             (1 << 24)
+
+#define R300_PFS_INSTR0_0                   0x48C0
+#       define R300_FPI0_ARGC_SRC0C_XYZ          0
+#       define R300_FPI0_ARGC_SRC0C_XXX          1
+#       define R300_FPI0_ARGC_SRC0C_YYY          2
+#       define R300_FPI0_ARGC_SRC0C_ZZZ          3
+#       define R300_FPI0_ARGC_SRC1C_XYZ          4
+#       define R300_FPI0_ARGC_SRC1C_XXX          5
+#       define R300_FPI0_ARGC_SRC1C_YYY          6
+#       define R300_FPI0_ARGC_SRC1C_ZZZ          7
+#       define R300_FPI0_ARGC_SRC2C_XYZ          8
+#       define R300_FPI0_ARGC_SRC2C_XXX          9
+#       define R300_FPI0_ARGC_SRC2C_YYY          10
+#       define R300_FPI0_ARGC_SRC2C_ZZZ          11
+#       define R300_FPI0_ARGC_SRC0A              12
+#       define R300_FPI0_ARGC_SRC1A              13
+#       define R300_FPI0_ARGC_SRC2A              14
+#       define R300_FPI0_ARGC_SRC1C_LRP          15
+#       define R300_FPI0_ARGC_ZERO               20
+#       define R300_FPI0_ARGC_ONE                21
+#       define R300_FPI0_ARGC_HALF               22 /* GUESS */
+#       define R300_FPI0_ARGC_SRC0C_YZX          23
+#       define R300_FPI0_ARGC_SRC1C_YZX          24
+#       define R300_FPI0_ARGC_SRC2C_YZX          25
+#       define R300_FPI0_ARGC_SRC0C_ZXY          26
+#       define R300_FPI0_ARGC_SRC1C_ZXY          27
+#       define R300_FPI0_ARGC_SRC2C_ZXY          28
+#       define R300_FPI0_ARGC_SRC0CA_WZY         29
+#       define R300_FPI0_ARGC_SRC1CA_WZY         30
+#       define R300_FPI0_ARGC_SRC2CA_WZY         31
+
+#       define R300_FPI0_ARG0C_SHIFT             0
+#       define R300_FPI0_ARG0C_MASK              (31 << 0)
+#       define R300_FPI0_ARG0C_NEG               (1 << 5)
+#       define R300_FPI0_ARG0C_ABS               (1 << 6)
+#       define R300_FPI0_ARG1C_SHIFT             7
+#       define R300_FPI0_ARG1C_MASK              (31 << 7)
+#       define R300_FPI0_ARG1C_NEG               (1 << 12)
+#       define R300_FPI0_ARG1C_ABS               (1 << 13)
+#       define R300_FPI0_ARG2C_SHIFT             14
+#       define R300_FPI0_ARG2C_MASK              (31 << 14)
+#       define R300_FPI0_ARG2C_NEG               (1 << 19)
+#       define R300_FPI0_ARG2C_ABS               (1 << 20)
+#       define R300_FPI0_SPECIAL_LRP             (1 << 21)
+#       define R300_FPI0_OUTC_MAD                (0 << 23)
+#       define R300_FPI0_OUTC_DP3                (1 << 23)
+#       define R300_FPI0_OUTC_DP4                (2 << 23)
+#       define R300_FPI0_OUTC_MIN                (4 << 23)
+#       define R300_FPI0_OUTC_MAX                (5 << 23)
+#       define R300_FPI0_OUTC_CMP                (8 << 23)
+#       define R300_FPI0_OUTC_FRC                (9 << 23)
+#       define R300_FPI0_OUTC_REPL_ALPHA         (10 << 23)
+#       define R300_FPI0_OUTC_SAT                (1 << 30)
+#       define R300_FPI0_UNKNOWN_31              (1 << 31)
+
+#define R300_PFS_INSTR2_0                   0x49C0
+#       define R300_FPI2_ARGA_SRC0C_X            0
+#       define R300_FPI2_ARGA_SRC0C_Y            1
+#       define R300_FPI2_ARGA_SRC0C_Z            2
+#       define R300_FPI2_ARGA_SRC1C_X            3
+#       define R300_FPI2_ARGA_SRC1C_Y            4
+#       define R300_FPI2_ARGA_SRC1C_Z            5
+#       define R300_FPI2_ARGA_SRC2C_X            6
+#       define R300_FPI2_ARGA_SRC2C_Y            7
+#       define R300_FPI2_ARGA_SRC2C_Z            8
+#       define R300_FPI2_ARGA_SRC0A              9
+#       define R300_FPI2_ARGA_SRC1A              10
+#       define R300_FPI2_ARGA_SRC2A              11
+#       define R300_FPI2_ARGA_SRC1A_LRP          15
+#       define R300_FPI2_ARGA_ZERO               16
+#       define R300_FPI2_ARGA_ONE                17
+#       define R300_FPI2_ARGA_HALF               18 /* GUESS */
+
+#       define R300_FPI2_ARG0A_SHIFT             0
+#       define R300_FPI2_ARG0A_MASK              (31 << 0)
+#       define R300_FPI2_ARG0A_NEG               (1 << 5)
+#              define R300_FPI2_ARG0A_ABS                               (1 << 6) /* GUESS */
+#       define R300_FPI2_ARG1A_SHIFT             7
+#       define R300_FPI2_ARG1A_MASK              (31 << 7)
+#       define R300_FPI2_ARG1A_NEG               (1 << 12)
+#              define R300_FPI2_ARG1A_ABS                               (1 << 13) /* GUESS */
+#       define R300_FPI2_ARG2A_SHIFT             14
+#       define R300_FPI2_ARG2A_MASK              (31 << 14)
+#       define R300_FPI2_ARG2A_NEG               (1 << 19)
+#              define R300_FPI2_ARG2A_ABS                               (1 << 20) /* GUESS */
+#       define R300_FPI2_SPECIAL_LRP             (1 << 21)
+#       define R300_FPI2_OUTA_MAD                (0 << 23)
+#       define R300_FPI2_OUTA_DP4                (1 << 23)
+#       define R300_FPI2_OUTA_MIN                (2 << 23)
+#       define R300_FPI2_OUTA_MAX                (3 << 23)
+#       define R300_FPI2_OUTA_CMP                (6 << 23)
+#       define R300_FPI2_OUTA_FRC                (7 << 23)
+#       define R300_FPI2_OUTA_EX2                (8 << 23)
+#       define R300_FPI2_OUTA_LG2                (9 << 23)
+#       define R300_FPI2_OUTA_RCP                (10 << 23)
+#       define R300_FPI2_OUTA_RSQ                (11 << 23)
+#       define R300_FPI2_OUTA_SAT                (1 << 30)
+#       define R300_FPI2_UNKNOWN_31              (1 << 31)
+/* END */
+
+/* gap */
+#define R300_PP_ALPHA_TEST                  0x4BD4
+#       define R300_REF_ALPHA_MASK               0x000000ff
+#       define R300_ALPHA_TEST_FAIL              (0 << 8)
+#       define R300_ALPHA_TEST_LESS              (1 << 8)
+#       define R300_ALPHA_TEST_LEQUAL            (3 << 8)
+#       define R300_ALPHA_TEST_EQUAL             (2 << 8)
+#       define R300_ALPHA_TEST_GEQUAL            (6 << 8)
+#       define R300_ALPHA_TEST_GREATER           (4 << 8)
+#       define R300_ALPHA_TEST_NEQUAL            (5 << 8)
+#       define R300_ALPHA_TEST_PASS              (7 << 8)
+#       define R300_ALPHA_TEST_OP_MASK           (7 << 8)
+#       define R300_ALPHA_TEST_ENABLE            (1 << 11)
+
+/* gap */
+/* Fragment program parameters in 7.16 floating point */
+#define R300_PFS_PARAM_0_X                  0x4C00
+#define R300_PFS_PARAM_0_Y                  0x4C04
+#define R300_PFS_PARAM_0_Z                  0x4C08
+#define R300_PFS_PARAM_0_W                  0x4C0C
+/* GUESS: PARAM_31 is last, based on native limits reported by fglrx */
+#define R300_PFS_PARAM_31_X                 0x4DF0
+#define R300_PFS_PARAM_31_Y                 0x4DF4
+#define R300_PFS_PARAM_31_Z                 0x4DF8
+#define R300_PFS_PARAM_31_W                 0x4DFC
+
+/* Notes:
+// - AFAIK fglrx always sets BLEND_UNKNOWN when blending is used in the application
+// - AFAIK fglrx always sets BLEND_NO_SEPARATE when CBLEND and ABLEND are set to the same
+//   function (both registers are always set up completely in any case)
+// - Most blend flags are simply copied from R200 and not tested yet */
+#define R300_RB3D_CBLEND                    0x4E04
+#define R300_RB3D_ABLEND                    0x4E08
+ /* the following only appear in CBLEND */
+#       define R300_BLEND_ENABLE                     (1 << 0)
+#       define R300_BLEND_UNKNOWN                    (3 << 1)
+#       define R300_BLEND_NO_SEPARATE                (1 << 3)
+ /* the following are shared between CBLEND and ABLEND */
+#       define R300_FCN_MASK                         (3  << 12)
+#       define R300_COMB_FCN_ADD_CLAMP               (0  << 12)
+#       define R300_COMB_FCN_ADD_NOCLAMP             (1  << 12)
+#       define R300_COMB_FCN_SUB_CLAMP               (2  << 12)
+#       define R300_COMB_FCN_SUB_NOCLAMP             (3  << 12)
+#       define R300_SRC_BLEND_GL_ZERO                (32 << 16)
+#       define R300_SRC_BLEND_GL_ONE                 (33 << 16)
+#       define R300_SRC_BLEND_GL_SRC_COLOR           (34 << 16)
+#       define R300_SRC_BLEND_GL_ONE_MINUS_SRC_COLOR (35 << 16)
+#       define R300_SRC_BLEND_GL_DST_COLOR           (36 << 16)
+#       define R300_SRC_BLEND_GL_ONE_MINUS_DST_COLOR (37 << 16)
+#       define R300_SRC_BLEND_GL_SRC_ALPHA           (38 << 16)
+#       define R300_SRC_BLEND_GL_ONE_MINUS_SRC_ALPHA (39 << 16)
+#       define R300_SRC_BLEND_GL_DST_ALPHA           (40 << 16)
+#       define R300_SRC_BLEND_GL_ONE_MINUS_DST_ALPHA (41 << 16)
+#       define R300_SRC_BLEND_GL_SRC_ALPHA_SATURATE  (42 << 16)
+#       define R300_SRC_BLEND_MASK                   (63 << 16)
+#       define R300_DST_BLEND_GL_ZERO                (32 << 24)
+#       define R300_DST_BLEND_GL_ONE                 (33 << 24)
+#       define R300_DST_BLEND_GL_SRC_COLOR           (34 << 24)
+#       define R300_DST_BLEND_GL_ONE_MINUS_SRC_COLOR (35 << 24)
+#       define R300_DST_BLEND_GL_DST_COLOR           (36 << 24)
+#       define R300_DST_BLEND_GL_ONE_MINUS_DST_COLOR (37 << 24)
+#       define R300_DST_BLEND_GL_SRC_ALPHA           (38 << 24)
+#       define R300_DST_BLEND_GL_ONE_MINUS_SRC_ALPHA (39 << 24)
+#       define R300_DST_BLEND_GL_DST_ALPHA           (40 << 24)
+#       define R300_DST_BLEND_GL_ONE_MINUS_DST_ALPHA (41 << 24)
+#       define R300_DST_BLEND_MASK                   (63 << 24)
+#define R300_RB3D_COLORMASK                 0x4E0C
+#       define R300_COLORMASK0_B                 (1<<0)
+#       define R300_COLORMASK0_G                 (1<<1)
+#       define R300_COLORMASK0_R                 (1<<2)
+#       define R300_COLORMASK0_A                 (1<<3)
+
+/* gap */
+#define R300_RB3D_COLOROFFSET0              0x4E28
+#       define R300_COLOROFFSET_MASK             0xFFFFFFF0 /* GUESS */
+#define R300_RB3D_COLOROFFSET1              0x4E2C /* GUESS */
+#define R300_RB3D_COLOROFFSET2              0x4E30 /* GUESS */
+#define R300_RB3D_COLOROFFSET3              0x4E34 /* GUESS */
+/* gap */
+/* Bit 16: Larger tiles
+// Bit 17: 4x2 tiles
+// Bit 18: Extremely weird tile like, but some pixels duplicated? */
+#define R300_RB3D_COLORPITCH0               0x4E38
+#       define R300_COLORPITCH_MASK              0x00001FF8 /* GUESS */
+#       define R300_COLOR_TILE_ENABLE            (1 << 16) /* GUESS */
+#       define R300_COLOR_MICROTILE_ENABLE       (1 << 17) /* GUESS */
+#       define R300_COLOR_ENDIAN_NO_SWAP         (0 << 18) /* GUESS */
+#       define R300_COLOR_ENDIAN_WORD_SWAP       (1 << 18) /* GUESS */
+#       define R300_COLOR_ENDIAN_DWORD_SWAP      (2 << 18) /* GUESS */
+#       define R300_COLOR_FORMAT_RGB565          (2 << 22)
+#       define R300_COLOR_FORMAT_ARGB8888        (3 << 22)
+#define R300_RB3D_COLORPITCH1               0x4E3C /* GUESS */
+#define R300_RB3D_COLORPITCH2               0x4E40 /* GUESS */
+#define R300_RB3D_COLORPITCH3               0x4E44 /* GUESS */
+
+/* gap */
+/* Guess by Vladimir.
+// Set to 0A before 3D operations, set to 02 afterwards. */
+#define R300_RB3D_DSTCACHE_CTLSTAT          0x4E4C
+#       define R300_RB3D_DSTCACHE_02             0x00000002
+#       define R300_RB3D_DSTCACHE_0A             0x0000000A
+
+/* gap */
+/* There seems to be no "write only" setting, so use Z-test = ALWAYS for this. */
+/* Bit (1<<8) is the "test" bit. so plain write is 6  - vd */
+#define R300_RB3D_ZSTENCIL_CNTL_0                   0x4F00
+#       define R300_RB3D_Z_DISABLED_1            0x00000010 /* GUESS */
+#       define R300_RB3D_Z_DISABLED_2            0x00000014 /* GUESS */
+#       define R300_RB3D_Z_TEST                  0x00000012
+#       define R300_RB3D_Z_TEST_AND_WRITE        0x00000016
+#       define R300_RB3D_Z_WRITE_ONLY           0x00000006
+
+#       define R300_RB3D_Z_TEST                  0x00000012
+#       define R300_RB3D_Z_TEST_AND_WRITE        0x00000016
+#       define R300_RB3D_Z_WRITE_ONLY           0x00000006
+#      define R300_RB3D_STENCIL_ENABLE          0x00000001
+
+#define R300_RB3D_ZSTENCIL_CNTL_1                   0x4F04
+               /* functions */
+#      define R300_ZS_NEVER                    0
+#      define R300_ZS_LESS                     1
+#      define R300_ZS_LEQUAL                   2
+#      define R300_ZS_EQUAL                    3
+#      define R300_ZS_GEQUAL                   4
+#      define R300_ZS_GREATER                  5
+#      define R300_ZS_NOTEQUAL                 6
+#      define R300_ZS_ALWAYS                   7
+#       define R300_ZS_MASK                     7
+               /* operations */
+#      define R300_ZS_KEEP                     0
+#      define R300_ZS_ZERO                     1
+#      define R300_ZS_REPLACE                  2
+#      define R300_ZS_INCR                     3
+#      define R300_ZS_DECR                     4
+#      define R300_ZS_INVERT                   5
+#      define R300_ZS_INCR_WRAP                6
+#      define R300_ZS_DECR_WRAP                7
+
+       /* front and back refer to operations done for front
+          and back faces, i.e. separate stencil function support */
+#      define R300_RB3D_ZS1_DEPTH_FUNC_SHIFT           0
+#      define R300_RB3D_ZS1_FRONT_FUNC_SHIFT           3
+#      define R300_RB3D_ZS1_FRONT_FAIL_OP_SHIFT        6
+#      define R300_RB3D_ZS1_FRONT_ZPASS_OP_SHIFT       9
+#      define R300_RB3D_ZS1_FRONT_ZFAIL_OP_SHIFT      12
+#      define R300_RB3D_ZS1_BACK_FUNC_SHIFT           15
+#      define R300_RB3D_ZS1_BACK_FAIL_OP_SHIFT        18
+#      define R300_RB3D_ZS1_BACK_ZPASS_OP_SHIFT       21
+#      define R300_RB3D_ZS1_BACK_ZFAIL_OP_SHIFT       24
+
+
+
+#define R300_RB3D_ZSTENCIL_CNTL_2                   0x4F08
+#      define R300_RB3D_ZS2_STENCIL_REF_SHIFT          0
+#      define R300_RB3D_ZS2_STENCIL_MASK               0xFF
+#      define R300_RB3D_ZS2_STENCIL_MASK_SHIFT         8
+#      define R300_RB3D_ZS2_STENCIL_WRITE_MASK_SHIFT   16
+
+/* gap */
+
+#define R300_RB3D_ZSTENCIL_FORMAT                   0x4F10
+#      define R300_DEPTH_FORMAT_16BIT_INT_Z     (0 << 0)
+#      define R300_DEPTH_FORMAT_24BIT_INT_Z     (2 << 0)
+
+/* gap */
+#define R300_RB3D_DEPTHOFFSET               0x4F20
+#define R300_RB3D_DEPTHPITCH                0x4F24
+#       define R300_DEPTHPITCH_MASK              0x00001FF8 /* GUESS */
+#       define R300_DEPTH_TILE_ENABLE            (1 << 16) /* GUESS */
+#       define R300_DEPTH_MICROTILE_ENABLE       (1 << 17) /* GUESS */
+#       define R300_DEPTH_ENDIAN_NO_SWAP         (0 << 18) /* GUESS */
+#       define R300_DEPTH_ENDIAN_WORD_SWAP       (1 << 18) /* GUESS */
+#       define R300_DEPTH_ENDIAN_DWORD_SWAP      (2 << 18) /* GUESS */
+
+/* BEGIN: Vertex program instruction set
+// Every instruction is four dwords long:
+//  DWORD 0: output and opcode
+//  DWORD 1: first argument
+//  DWORD 2: second argument
+//  DWORD 3: third argument
+//
+// Notes:
+//  - ABS r, a is implemented as MAX r, a, -a
+//  - MOV is implemented as ADD to zero
+//  - XPD is implemented as MUL + MAD
+//  - FLR is implemented as FRC + ADD
+//  - apparently, fglrx tries to schedule instructions so that there is at least
+//    one instruction between the write to a temporary and the first read
+//    from said temporary; however, violations of this scheduling are allowed
+//  - register indices seem to be unrelated with OpenGL aliasing to conventional state
+//  - only one attribute and one parameter can be loaded at a time; however, the
+//    same attribute/parameter can be used for more than one argument
+//  - the second software argument for POW is the third hardware argument (no idea why)
+//  - MAD with only temporaries as input seems to use VPI_OUT_SELECT_MAD_2
+//
+// There is some magic surrounding LIT:
+//  The single argument is replicated across all three inputs, but swizzled:
+//   First argument: xyzy
+//   Second argument: xyzx
+//   Third argument: xyzw
+//  Whenever the result is used later in the fragment program, fglrx forces x and w
+//  to be 1.0 in the input selection; I don't know whether this is strictly necessary */
+#define R300_VPI_OUT_OP_DOT                     (1 << 0)
+#define R300_VPI_OUT_OP_MUL                     (2 << 0)
+#define R300_VPI_OUT_OP_ADD                     (3 << 0)
+#define R300_VPI_OUT_OP_MAD                     (4 << 0)
+#define R300_VPI_OUT_OP_DST                     (5 << 0)
+#define R300_VPI_OUT_OP_FRC                     (6 << 0)
+#define R300_VPI_OUT_OP_MAX                     (7 << 0)
+#define R300_VPI_OUT_OP_MIN                     (8 << 0)
+#define R300_VPI_OUT_OP_SGE                     (9 << 0)
+#define R300_VPI_OUT_OP_SLT                     (10 << 0)
+#define R300_VPI_OUT_OP_UNK12                   (12 << 0) /* Used in GL_POINT_DISTANCE_ATTENUATION_ARB, vector(scalar, vector) */
+#define R300_VPI_OUT_OP_EXP                     (65 << 0)
+#define R300_VPI_OUT_OP_LOG                     (66 << 0)
+#define R300_VPI_OUT_OP_UNK67                   (67 << 0) /* Used in fog computations, scalar(scalar) */
+#define R300_VPI_OUT_OP_LIT                     (68 << 0)
+#define R300_VPI_OUT_OP_POW                     (69 << 0)
+#define R300_VPI_OUT_OP_RCP                     (70 << 0)
+#define R300_VPI_OUT_OP_RSQ                     (72 << 0)
+#define R300_VPI_OUT_OP_UNK73                   (73 << 0) /* Used in GL_POINT_DISTANCE_ATTENUATION_ARB, scalar(scalar) */
+#define R300_VPI_OUT_OP_EX2                     (75 << 0)
+#define R300_VPI_OUT_OP_LG2                     (76 << 0)
+#define R300_VPI_OUT_OP_MAD_2                   (128 << 0)
+#define R300_VPI_OUT_OP_UNK129                  (129 << 0) /* all temps, vector(scalar, vector, vector) */
+
+#define R300_VPI_OUT_REG_CLASS_TEMPORARY        (0 << 8)
+#define R300_VPI_OUT_REG_CLASS_RESULT           (2 << 8)
+#define R300_VPI_OUT_REG_CLASS_MASK             (31 << 8)
+
+#define R300_VPI_OUT_REG_INDEX_SHIFT            13
+#define R300_VPI_OUT_REG_INDEX_MASK             (31 << 13) /* GUESS based on fglrx native limits */
+
+#define R300_VPI_OUT_WRITE_X                    (1 << 20)
+#define R300_VPI_OUT_WRITE_Y                    (1 << 21)
+#define R300_VPI_OUT_WRITE_Z                    (1 << 22)
+#define R300_VPI_OUT_WRITE_W                    (1 << 23)
+
+#define R300_VPI_IN_REG_CLASS_TEMPORARY         (0 << 0)
+#define R300_VPI_IN_REG_CLASS_ATTRIBUTE         (1 << 0)
+#define R300_VPI_IN_REG_CLASS_PARAMETER         (2 << 0)
+#define R300_VPI_IN_REG_CLASS_NONE              (9 << 0)
+#define R300_VPI_IN_REG_CLASS_MASK              (31 << 0) /* GUESS */
+
+#define R300_VPI_IN_REG_INDEX_SHIFT             5
+#define R300_VPI_IN_REG_INDEX_MASK              (255 << 5) /* GUESS based on fglrx native limits */
+
+/* The R300 can select components from the input register arbitrarily.
+// Use the following constants, shifted by the component shift you
+// want to select */
+#define R300_VPI_IN_SELECT_X    0
+#define R300_VPI_IN_SELECT_Y    1
+#define R300_VPI_IN_SELECT_Z    2
+#define R300_VPI_IN_SELECT_W    3
+#define R300_VPI_IN_SELECT_ZERO 4
+#define R300_VPI_IN_SELECT_ONE  5
+#define R300_VPI_IN_SELECT_MASK 7
+
+#define R300_VPI_IN_X_SHIFT                     13
+#define R300_VPI_IN_Y_SHIFT                     16
+#define R300_VPI_IN_Z_SHIFT                     19
+#define R300_VPI_IN_W_SHIFT                     22
+
+#define R300_VPI_IN_NEG_X                       (1 << 25)
+#define R300_VPI_IN_NEG_Y                       (1 << 26)
+#define R300_VPI_IN_NEG_Z                       (1 << 27)
+#define R300_VPI_IN_NEG_W                       (1 << 28)
+/* END */
+
+//BEGIN: Packet 3 commands
+
+// A primitive emission dword.
+#define R300_PRIM_TYPE_NONE                     (0 << 0)
+#define R300_PRIM_TYPE_POINT                    (1 << 0)
+#define R300_PRIM_TYPE_LINE                     (2 << 0)
+#define R300_PRIM_TYPE_LINE_STRIP               (3 << 0)
+#define R300_PRIM_TYPE_TRI_LIST                 (4 << 0)
+#define R300_PRIM_TYPE_TRI_FAN                  (5 << 0)
+#define R300_PRIM_TYPE_TRI_STRIP                (6 << 0)
+#define R300_PRIM_TYPE_TRI_TYPE2                (7 << 0)
+#define R300_PRIM_TYPE_RECT_LIST                (8 << 0)
+#define R300_PRIM_TYPE_3VRT_POINT_LIST          (9 << 0)
+#define R300_PRIM_TYPE_3VRT_LINE_LIST           (10 << 0)
+#define R300_PRIM_TYPE_POINT_SPRITES            (11 << 0) // GUESS (based on r200)
+#define R300_PRIM_TYPE_LINE_LOOP                (12 << 0)
+#define R300_PRIM_TYPE_QUADS                    (13 << 0)
+#define R300_PRIM_TYPE_QUAD_STRIP               (14 << 0)
+#define R300_PRIM_TYPE_POLYGON                  (15 << 0)
+#define R300_PRIM_TYPE_MASK                     0xF
+#define R300_PRIM_WALK_IND                      (1 << 4)
+#define R300_PRIM_WALK_LIST                     (2 << 4)
+#define R300_PRIM_WALK_RING                     (3 << 4)
+#define R300_PRIM_WALK_MASK                     (3 << 4)
+#define R300_PRIM_COLOR_ORDER_BGRA              (0 << 6) // GUESS (based on r200)
+#define R300_PRIM_COLOR_ORDER_RGBA              (1 << 6) // GUESS
+#define R300_PRIM_NUM_VERTICES_SHIFT            16
+
+// Draw a primitive from vertex data in arrays loaded via 3D_LOAD_VBPNTR.
+// Two parameter dwords:
+// 0. The first parameter appears to be always 0
+// 1. The second parameter is a standard primitive emission dword.
+#define R300_PACKET3_3D_DRAW_VBUF           0x00002800
+
+// Specify the full set of vertex arrays as (address, stride).
+// The first parameter is the number of vertex arrays specified.
+// The rest of the command is a variable length list of blocks, where
+// each block is three dwords long and specifies two arrays.
+// The first dword of a block is split into two words, the lower significant
+// word refers to the first array, the more significant word to the second
+// array in the block.
+// The low byte of each word contains the size of an array entry in dwords,
+// the high byte contains the stride of the array.
+// The second dword of a block contains the pointer to the first array,
+// the third dword of a block contains the pointer to the second array.
+// Note that if the total number of arrays is odd, the third dword of
+// the last block is omitted.
+#define R300_PACKET3_3D_LOAD_VBPNTR         0x00002F00
+
+#define R300_PACKET3_INDX_BUFFER            0x00003300
+#    define R300_EB_UNK1_SHIFT                      24
+#    define R300_EB_UNK1                    (0x80<<24)
+#    define R300_EB_UNK2                        0x0810
+#define R300_PACKET3_3D_DRAW_INDX_2         0x00003600
+
+//END
+
+#endif /* _R300_REG_H */
index 20bcf872b348859fec8ca7ccab6270d2d400a192..6d9080a3ca7e97fefb3302959bb445ce3dc0aac0 100644 (file)
@@ -32,6 +32,7 @@
 #include "drm.h"
 #include "radeon_drm.h"
 #include "radeon_drv.h"
+#include "r300_reg.h"
 
 #define RADEON_FIFO_DEBUG      0
 
@@ -1151,6 +1152,8 @@ static void radeon_cp_init_ring_buffer( drm_device_t *dev,
 
 #if __OS_HAS_AGP
        if ( !dev_priv->is_pci ) {
+               /* set RADEON_AGP_BASE here instead of relying on X from user space */
+               RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base);
                RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR,
                              dev_priv->ring_rptr->offset
                              - dev->agp->base
@@ -1407,6 +1410,7 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init )
                radeon_do_cleanup_cp(dev);
                return DRM_ERR(EINVAL);
        }
+       dev->agp_buffer_token = init->buffers_offset;
        dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
        if(!dev->agp_buffer_map) {
                DRM_ERROR("could not find dma buffer region!\n");
@@ -1625,6 +1629,9 @@ int radeon_cp_init( DRM_IOCTL_ARGS )
 
        DRM_COPY_FROM_USER_IOCTL( init, (drm_radeon_init_t __user *)data, sizeof(init) );
 
+       if(init.func == RADEON_INIT_R300_CP)
+               r300_init_reg_flags();
+
        switch ( init.func ) {
        case RADEON_INIT_CP:
        case RADEON_INIT_R200_CP:
@@ -2039,15 +2046,43 @@ int radeon_driver_preinit(struct drm_device *dev, unsigned long flags)
        case CHIP_RV200:
        case CHIP_R200:
        case CHIP_R300:
+       case CHIP_R420:
                dev_priv->flags |= CHIP_HAS_HIERZ;
                break;
        default:
        /* all other chips have no hierarchical z buffer */
                break;
        }
+
+       if (drm_device_is_agp(dev))
+               dev_priv->flags |= CHIP_IS_AGP;
+       
+       DRM_DEBUG("%s card detected\n",
+                 ((dev_priv->flags & CHIP_IS_AGP) ? "AGP" : "PCI"));
        return ret;
 }
 
+int radeon_presetup(struct drm_device *dev)
+{
+       int ret;
+       drm_local_map_t *map;
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+
+       ret = drm_addmap(dev, drm_get_resource_start(dev, 2),
+                        drm_get_resource_len(dev, 2), _DRM_REGISTERS,
+                        _DRM_READ_ONLY, &dev_priv->mmio);
+       if (ret != 0)
+               return ret;
+
+       ret = drm_addmap(dev, drm_get_resource_start(dev, 0),
+                        drm_get_resource_len(dev, 0), _DRM_FRAME_BUFFER,
+                        _DRM_WRITE_COMBINING, &map);
+       if (ret != 0)
+               return ret;
+
+       return 0;
+}
+
 int radeon_driver_postcleanup(struct drm_device *dev)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
index c1e62d047989aa6e61d34367ace2863810b65248..3792798270a4341bda91d0c2dc6f3d13a87554da 100644 (file)
@@ -195,6 +195,52 @@ typedef union {
 #define RADEON_WAIT_2D  0x1
 #define RADEON_WAIT_3D  0x2
 
+/* Allowed parameters for R300_CMD_PACKET3
+ */
+#define R300_CMD_PACKET3_CLEAR         0
+#define R300_CMD_PACKET3_RAW           1
+
+/* Commands understood by cmd_buffer ioctl for R300.
+ * The interface has not been stabilized, so some of these may be removed
+ * and eventually reordered before stabilization.
+ */
+#define R300_CMD_PACKET0               1 
+#define R300_CMD_VPU                   2 /* emit vertex program upload */
+#define R300_CMD_PACKET3               3 /* emit a packet3 */
+#define R300_CMD_END3D                 4 /* emit sequence ending 3d rendering */
+#define R300_CMD_CP_DELAY              5
+#define R300_CMD_DMA_DISCARD           6
+#define R300_CMD_WAIT                  7
+#      define R300_WAIT_2D             0x1
+#      define R300_WAIT_3D             0x2
+#      define R300_WAIT_2D_CLEAN       0x3
+#      define R300_WAIT_3D_CLEAN       0x4
+
+typedef union {
+       unsigned int u;
+       struct {
+               unsigned char cmd_type, pad0, pad1, pad2;
+       } header;
+       struct {
+               unsigned char cmd_type, count, reglo, reghi;
+       } packet0;
+       struct {
+               unsigned char cmd_type, count, adrlo, adrhi;
+       } vpu;
+       struct {
+               unsigned char cmd_type, packet, pad0, pad1;
+       } packet3;
+       struct {
+               unsigned char cmd_type, packet;
+               unsigned short count; /* amount of packet2 to emit */
+       } delay;
+       struct {
+               unsigned char cmd_type, buf_idx, pad0, pad1;
+       } dma;
+       struct {
+               unsigned char cmd_type, flags, pad0, pad1;      
+       } wait;
+} drm_r300_cmd_header_t;
 
 #define RADEON_FRONT                   0x1
 #define RADEON_BACK                    0x2
index 18e4e5b0952f4f60c5143253f57b476949fd23c2..e0682f64b400c48de09cb9b43cbb488d6c7c173c 100644 (file)
@@ -76,6 +76,7 @@ static struct drm_driver driver = {
        .driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL,
        .dev_priv_size = sizeof(drm_radeon_buf_priv_t),
        .preinit = radeon_driver_preinit,
+       .presetup = radeon_presetup,
        .postcleanup = radeon_driver_postcleanup,
        .prerelease = radeon_driver_prerelease,
        .pretakedown = radeon_driver_pretakedown,
index 771aa80a5e8c24233193b0c73566e03f4ebc1248..f12a963ede18986a73391f69bc260c42c233bc5a 100644 (file)
  *     - Add support for r100 cube maps
  * 1.16- Add R200_EMIT_PP_TRI_PERF_CNTL packet to support brilinear
  *       texture filtering on r200
+ * 1.17- Add initial support for R300 (3D).
  */
 #define DRIVER_MAJOR           1
-#define DRIVER_MINOR           16
+#define DRIVER_MINOR           17
 #define DRIVER_PATCHLEVEL      0
 
 #define GET_RING_HEAD(dev_priv)                DRM_READ32(  (dev_priv)->ring_rptr, 0 )
@@ -106,7 +107,9 @@ enum radeon_family {
        CHIP_RV280,
        CHIP_R300,
        CHIP_RS300,
+       CHIP_R350,
        CHIP_RV350,
+       CHIP_R420,
        CHIP_LAST,
 };
 
@@ -290,6 +293,7 @@ extern int radeon_wait_ring( drm_radeon_private_t *dev_priv, int n );
 extern int radeon_do_cp_idle( drm_radeon_private_t *dev_priv );
 
 extern int radeon_driver_preinit(struct drm_device *dev, unsigned long flags);
+extern int radeon_presetup(struct drm_device *dev);
 extern int radeon_driver_postcleanup(struct drm_device *dev);
 
 extern int radeon_mem_alloc( DRM_IOCTL_ARGS );
@@ -320,6 +324,14 @@ extern int radeon_postcleanup( struct drm_device *dev );
 extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd,
                                unsigned long arg);
 
+
+/* r300_cmdbuf.c */
+extern void r300_init_reg_flags(void);
+
+extern int r300_do_cp_cmdbuf(drm_device_t* dev, DRMFILE filp,
+                            drm_file_t* filp_priv,
+                            drm_radeon_cmd_buffer_t* cmdbuf);
+
 /* Flags for stats.boxes
  */
 #define RADEON_BOX_DMA_IDLE      0x1
@@ -357,6 +369,11 @@ extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd,
 #define RADEON_CRTC2_OFFSET            0x0324
 #define RADEON_CRTC2_OFFSET_CNTL       0x0328
 
+#define RADEON_MPP_TB_CONFIG           0x01c0
+#define RADEON_MEM_CNTL                        0x0140
+#define RADEON_MEM_SDRAM_MODE_REG      0x0158
+#define RADEON_AGP_BASE                        0x0170
+
 #define RADEON_RB3D_COLOROFFSET                0x1c40
 #define RADEON_RB3D_COLORPITCH         0x1c48
 
@@ -651,16 +668,27 @@ extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd,
 #define RADEON_CP_PACKET1              0x40000000
 #define RADEON_CP_PACKET2              0x80000000
 #define RADEON_CP_PACKET3              0xC0000000
+#       define RADEON_CP_NOP                    0x00001000
+#       define RADEON_CP_NEXT_CHAR              0x00001900
+#       define RADEON_CP_PLY_NEXTSCAN           0x00001D00
+#       define RADEON_CP_SET_SCISSORS           0x00001E00
+             /* GEN_INDX_PRIM is unsupported starting with R300 */
 #      define RADEON_3D_RNDR_GEN_INDX_PRIM     0x00002300
 #      define RADEON_WAIT_FOR_IDLE             0x00002600
 #      define RADEON_3D_DRAW_VBUF              0x00002800
 #      define RADEON_3D_DRAW_IMMD              0x00002900
 #      define RADEON_3D_DRAW_INDX              0x00002A00
+#       define RADEON_CP_LOAD_PALETTE           0x00002C00
 #      define RADEON_3D_LOAD_VBPNTR            0x00002F00
 #      define RADEON_MPEG_IDCT_MACROBLOCK      0x00003000
 #      define RADEON_MPEG_IDCT_MACROBLOCK_REV  0x00003100
 #      define RADEON_3D_CLEAR_ZMASK            0x00003200
+#      define RADEON_CP_INDX_BUFFER            0x00003300
+#       define RADEON_CP_3D_DRAW_VBUF_2         0x00003400
+#       define RADEON_CP_3D_DRAW_IMMD_2         0x00003500
+#       define RADEON_CP_3D_DRAW_INDX_2         0x00003600
 #      define RADEON_3D_CLEAR_HIZ              0x00003700
+#       define RADEON_CP_3D_CLEAR_CMASK         0x00003802
 #      define RADEON_CNTL_HOSTDATA_BLT         0x00009400
 #      define RADEON_CNTL_PAINT_MULTI          0x00009A00
 #      define RADEON_CNTL_BITBLT_MULTI         0x00009B00
index 1f79e249146c9585a8ae1d968b47dc852924760b..64a3e3a406ef74dea8088f6fb05b2f0f0b5dd504 100644 (file)
@@ -1493,7 +1493,7 @@ static void radeon_cp_dispatch_indices( drm_device_t *dev,
 
 }
 
-#define RADEON_MAX_TEXTURE_SIZE (RADEON_BUFFER_SIZE - 8 * sizeof(u32))
+#define RADEON_MAX_TEXTURE_SIZE RADEON_BUFFER_SIZE
 
 static int radeon_cp_dispatch_texture( DRMFILE filp,
                                       drm_device_t *dev,
@@ -1506,10 +1506,11 @@ static int radeon_cp_dispatch_texture( DRMFILE filp,
        u32 format;
        u32 *buffer;
        const u8 __user *data;
-       int size, dwords, tex_width, blit_width;
+       int size, dwords, tex_width, blit_width, spitch;
        u32 height;
        int i;
        u32 texpitch, microtile;
+       u32 offset;
        RING_LOCALS;
 
        DRM_GET_PRIV_WITH_RETURN( filp_priv, filp );
@@ -1530,17 +1531,6 @@ static int radeon_cp_dispatch_texture( DRMFILE filp,
        RADEON_WAIT_UNTIL_IDLE();
        ADVANCE_RING();
 
-#ifdef __BIG_ENDIAN
-       /* The Mesa texture functions provide the data in little endian as the
-        * chip wants it, but we need to compensate for the fact that the CP
-        * ring gets byte-swapped
-        */
-       BEGIN_RING( 2 );
-       OUT_RING_REG( RADEON_RBBM_GUICNTL, RADEON_HOST_DATA_SWAP_32BIT );
-       ADVANCE_RING();
-#endif
-
-
        /* The compiler won't optimize away a division by a variable,
         * even if the only legal values are powers of two.  Thus, we'll
         * use a shift instead.
@@ -1572,6 +1562,10 @@ static int radeon_cp_dispatch_texture( DRMFILE filp,
                DRM_ERROR( "invalid texture format %d\n", tex->format );
                return DRM_ERR(EINVAL);
        }
+       spitch = blit_width >> 6;
+       if (spitch == 0 && image->height > 1)
+               return DRM_ERR(EINVAL);
+
        texpitch = tex->pitch;
        if ((texpitch << 22) & RADEON_DST_TILE_MICRO) {
                microtile = 1;
@@ -1624,25 +1618,6 @@ static int radeon_cp_dispatch_texture( DRMFILE filp,
                 */
                buffer = (u32*)((char*)dev->agp_buffer_map->handle + buf->offset);
                dwords = size / 4;
-               buffer[0] = CP_PACKET3( RADEON_CNTL_HOSTDATA_BLT, dwords + 6 );
-               buffer[1] = (RADEON_GMC_DST_PITCH_OFFSET_CNTL |
-                            RADEON_GMC_BRUSH_NONE |
-                            (format << 8) |
-                            RADEON_GMC_SRC_DATATYPE_COLOR |
-                            RADEON_ROP3_S |
-                            RADEON_DP_SRC_SOURCE_HOST_DATA |
-                            RADEON_GMC_CLR_CMP_CNTL_DIS |
-                            RADEON_GMC_WR_MSK_DIS);
-               
-               buffer[2] = (texpitch << 22) | (tex->offset >> 10);
-               buffer[3] = 0xffffffff;
-               buffer[4] = 0xffffffff;
-               buffer[5] = (image->y << 16) | image->x;
-               buffer[6] = (height << 16) | image->width;
-               buffer[7] = dwords;
-               buffer += 8;
-
-               
 
                if (microtile) {
                        /* texture micro tiling in use, minimum texture width is thus 16 bytes.
@@ -1750,9 +1725,28 @@ static int radeon_cp_dispatch_texture( DRMFILE filp,
                }
 
                buf->filp = filp;
-               buf->used = (dwords + 8) * sizeof(u32);
-               radeon_cp_dispatch_indirect( dev, buf, 0, buf->used );
-               radeon_cp_discard_buffer( dev, buf );
+               buf->used = size;
+               offset = dev_priv->gart_buffers_offset + buf->offset;
+               BEGIN_RING(9);
+               OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5));
+               OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
+                        RADEON_GMC_DST_PITCH_OFFSET_CNTL |
+                        RADEON_GMC_BRUSH_NONE |
+                        (format << 8) |
+                        RADEON_GMC_SRC_DATATYPE_COLOR |
+                        RADEON_ROP3_S |
+                        RADEON_DP_SRC_SOURCE_MEMORY |
+                        RADEON_GMC_CLR_CMP_CNTL_DIS |
+                        RADEON_GMC_WR_MSK_DIS );
+               OUT_RING((spitch << 22) | (offset >> 10));
+               OUT_RING((texpitch << 22) | (tex->offset >> 10));
+               OUT_RING(0);
+               OUT_RING((image->x << 16) | image->y);
+               OUT_RING((image->width << 16) | height);
+               RADEON_WAIT_UNTIL_2D_IDLE();
+               ADVANCE_RING();
+
+               radeon_cp_discard_buffer(dev, buf);
 
                /* Update the input parameters for next time */
                image->y += height;
@@ -2797,6 +2791,17 @@ static int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
 
        orig_nbox = cmdbuf.nbox;
 
+       if(dev_priv->microcode_version == UCODE_R300) {
+               int temp;
+               temp=r300_do_cp_cmdbuf(dev, filp, filp_priv, &cmdbuf);
+       
+               if (orig_bufsz != 0)
+                       drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
+       
+               return temp;
+       }
+
+       /* microcode_version != r300 */
        while ( cmdbuf.bufsz >= sizeof(header) ) {
 
                header.i = *(int *)cmdbuf.buf;
diff --git a/drivers/char/drm/savage_bci.c b/drivers/char/drm/savage_bci.c
new file mode 100644 (file)
index 0000000..2fd40ba
--- /dev/null
@@ -0,0 +1,1096 @@
+/* savage_bci.c -- BCI support for Savage
+ *
+ * Copyright 2004  Felix Kuehling
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT. IN NO EVENT SHALL FELIX KUEHLING BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "drmP.h"
+#include "savage_drm.h"
+#include "savage_drv.h"
+
+/* Need a long timeout for shadow status updates can take a while
+ * and so can waiting for events when the queue is full. */
+#define SAVAGE_DEFAULT_USEC_TIMEOUT    1000000 /* 1s */
+#define SAVAGE_EVENT_USEC_TIMEOUT      5000000 /* 5s */
+#define SAVAGE_FREELIST_DEBUG          0
+
+static int
+savage_bci_wait_fifo_shadow(drm_savage_private_t *dev_priv, unsigned int n)
+{
+       uint32_t mask = dev_priv->status_used_mask;
+       uint32_t threshold = dev_priv->bci_threshold_hi;
+       uint32_t status;
+       int i;
+
+#if SAVAGE_BCI_DEBUG
+       if (n > dev_priv->cob_size + SAVAGE_BCI_FIFO_SIZE - threshold)
+               DRM_ERROR("Trying to emit %d words "
+                         "(more than guaranteed space in COB)\n", n);
+#endif
+
+       for (i = 0; i < SAVAGE_DEFAULT_USEC_TIMEOUT; i++) {
+               DRM_MEMORYBARRIER();
+               status = dev_priv->status_ptr[0];
+               if ((status & mask) < threshold)
+                       return 0;
+               DRM_UDELAY(1);
+       }
+
+#if SAVAGE_BCI_DEBUG
+       DRM_ERROR("failed!\n");
+       DRM_INFO("   status=0x%08x, threshold=0x%08x\n", status, threshold);
+#endif
+       return DRM_ERR(EBUSY);
+}
+
+static int
+savage_bci_wait_fifo_s3d(drm_savage_private_t *dev_priv, unsigned int n)
+{
+       uint32_t maxUsed = dev_priv->cob_size + SAVAGE_BCI_FIFO_SIZE - n;
+       uint32_t status;
+       int i;
+
+       for (i = 0; i < SAVAGE_DEFAULT_USEC_TIMEOUT; i++) {
+               status = SAVAGE_READ(SAVAGE_STATUS_WORD0);
+               if ((status & SAVAGE_FIFO_USED_MASK_S3D) <= maxUsed)
+                       return 0;
+               DRM_UDELAY(1);
+       }
+
+#if SAVAGE_BCI_DEBUG
+       DRM_ERROR("failed!\n");
+       DRM_INFO("   status=0x%08x\n", status);
+#endif
+       return DRM_ERR(EBUSY);
+}
+
+static int
+savage_bci_wait_fifo_s4(drm_savage_private_t *dev_priv, unsigned int n)
+{
+       uint32_t maxUsed = dev_priv->cob_size + SAVAGE_BCI_FIFO_SIZE - n;
+       uint32_t status;
+       int i;
+
+       for (i = 0; i < SAVAGE_DEFAULT_USEC_TIMEOUT; i++) {
+               status = SAVAGE_READ(SAVAGE_ALT_STATUS_WORD0);
+               if ((status & SAVAGE_FIFO_USED_MASK_S4) <= maxUsed)
+                       return 0;
+               DRM_UDELAY(1);
+       }
+
+#if SAVAGE_BCI_DEBUG
+       DRM_ERROR("failed!\n");
+       DRM_INFO("   status=0x%08x\n", status);
+#endif
+       return DRM_ERR(EBUSY);
+}
+
+/*
+ * Waiting for events.
+ *
+ * The BIOSresets the event tag to 0 on mode changes. Therefore we
+ * never emit 0 to the event tag. If we find a 0 event tag we know the
+ * BIOS stomped on it and return success assuming that the BIOS waited
+ * for engine idle.
+ *
+ * Note: if the Xserver uses the event tag it has to follow the same
+ * rule. Otherwise there may be glitches every 2^16 events.
+ */
+static int
+savage_bci_wait_event_shadow(drm_savage_private_t *dev_priv, uint16_t e)
+{
+       uint32_t status;
+       int i;
+
+       for (i = 0; i < SAVAGE_EVENT_USEC_TIMEOUT; i++) {
+               DRM_MEMORYBARRIER();
+               status = dev_priv->status_ptr[1];
+               if ((((status & 0xffff) - e) & 0xffff) <= 0x7fff ||
+                   (status & 0xffff) == 0)
+                       return 0;
+               DRM_UDELAY(1);
+       }
+
+#if SAVAGE_BCI_DEBUG
+       DRM_ERROR("failed!\n");
+       DRM_INFO("   status=0x%08x, e=0x%04x\n", status, e);
+#endif
+
+       return DRM_ERR(EBUSY);
+}
+
+static int
+savage_bci_wait_event_reg(drm_savage_private_t *dev_priv, uint16_t e)
+{
+       uint32_t status;
+       int i;
+
+       for (i = 0; i < SAVAGE_EVENT_USEC_TIMEOUT; i++) {
+               status = SAVAGE_READ(SAVAGE_STATUS_WORD1);
+               if ((((status & 0xffff) - e) & 0xffff) <= 0x7fff ||
+                   (status & 0xffff) == 0)
+                       return 0;
+               DRM_UDELAY(1);
+       }
+
+#if SAVAGE_BCI_DEBUG
+       DRM_ERROR("failed!\n");
+       DRM_INFO("   status=0x%08x, e=0x%04x\n", status, e);
+#endif
+
+       return DRM_ERR(EBUSY);
+}
+
+uint16_t savage_bci_emit_event(drm_savage_private_t *dev_priv,
+                              unsigned int flags)
+{
+       uint16_t count;
+       BCI_LOCALS;
+
+       if (dev_priv->status_ptr) {
+               /* coordinate with Xserver */
+               count = dev_priv->status_ptr[1023];
+               if (count < dev_priv->event_counter)
+                       dev_priv->event_wrap++;
+       } else {
+               count = dev_priv->event_counter;
+       }
+       count = (count + 1) & 0xffff;
+       if (count == 0) {
+               count++; /* See the comment above savage_wait_event_*. */
+               dev_priv->event_wrap++;
+       }
+       dev_priv->event_counter = count;
+       if (dev_priv->status_ptr)
+               dev_priv->status_ptr[1023] = (uint32_t)count;
+
+       if ((flags & (SAVAGE_WAIT_2D | SAVAGE_WAIT_3D))) {
+               unsigned int wait_cmd = BCI_CMD_WAIT;
+               if ((flags & SAVAGE_WAIT_2D))
+                       wait_cmd |= BCI_CMD_WAIT_2D;
+               if ((flags & SAVAGE_WAIT_3D))
+                       wait_cmd |= BCI_CMD_WAIT_3D;
+               BEGIN_BCI(2);
+               BCI_WRITE(wait_cmd);
+       } else {
+               BEGIN_BCI(1);
+       }
+       BCI_WRITE(BCI_CMD_UPDATE_EVENT_TAG | (uint32_t)count);
+
+       return count;
+}
+
+/*
+ * Freelist management
+ */
+static int savage_freelist_init(drm_device_t *dev)
+{
+       drm_savage_private_t *dev_priv = dev->dev_private;
+       drm_device_dma_t *dma = dev->dma;
+       drm_buf_t *buf;
+       drm_savage_buf_priv_t *entry;
+       int i;
+       DRM_DEBUG("count=%d\n", dma->buf_count);
+
+       dev_priv->head.next = &dev_priv->tail;
+       dev_priv->head.prev = NULL;
+       dev_priv->head.buf = NULL;
+
+       dev_priv->tail.next = NULL;
+       dev_priv->tail.prev = &dev_priv->head;
+       dev_priv->tail.buf = NULL;
+
+       for (i = 0; i < dma->buf_count; i++) {
+               buf = dma->buflist[i];
+               entry = buf->dev_private;
+
+               SET_AGE(&entry->age, 0, 0);
+               entry->buf = buf;
+
+               entry->next = dev_priv->head.next;
+               entry->prev = &dev_priv->head;
+               dev_priv->head.next->prev = entry;
+               dev_priv->head.next = entry;
+       }
+
+       return 0;
+}
+
+static drm_buf_t *savage_freelist_get(drm_device_t *dev)
+{
+       drm_savage_private_t *dev_priv = dev->dev_private;
+       drm_savage_buf_priv_t *tail = dev_priv->tail.prev;
+       uint16_t event;
+       unsigned int wrap;
+       DRM_DEBUG("\n");
+
+       UPDATE_EVENT_COUNTER();
+       if (dev_priv->status_ptr)
+               event = dev_priv->status_ptr[1] & 0xffff;
+       else
+               event = SAVAGE_READ(SAVAGE_STATUS_WORD1) & 0xffff;
+       wrap = dev_priv->event_wrap;
+       if (event > dev_priv->event_counter)
+               wrap--; /* hardware hasn't passed the last wrap yet */
+
+       DRM_DEBUG("   tail=0x%04x %d\n", tail->age.event, tail->age.wrap);
+       DRM_DEBUG("   head=0x%04x %d\n", event, wrap);
+
+       if (tail->buf && (TEST_AGE(&tail->age, event, wrap) || event == 0)) {
+               drm_savage_buf_priv_t *next = tail->next;
+               drm_savage_buf_priv_t *prev = tail->prev;
+               prev->next = next;
+               next->prev = prev;
+               tail->next = tail->prev = NULL;
+               return tail->buf;
+       }
+
+       DRM_DEBUG("returning NULL, tail->buf=%p!\n", tail->buf);
+       return NULL;
+}
+
+void savage_freelist_put(drm_device_t *dev, drm_buf_t *buf)
+{
+       drm_savage_private_t *dev_priv = dev->dev_private;
+       drm_savage_buf_priv_t *entry = buf->dev_private, *prev, *next;
+
+       DRM_DEBUG("age=0x%04x wrap=%d\n", entry->age.event, entry->age.wrap);
+
+       if (entry->next != NULL || entry->prev != NULL) {
+               DRM_ERROR("entry already on freelist.\n");
+               return;
+       }
+
+       prev = &dev_priv->head;
+       next = prev->next;
+       prev->next = entry;
+       next->prev = entry;
+       entry->prev = prev;
+       entry->next = next;
+}
+
+/*
+ * Command DMA
+ */
+static int savage_dma_init(drm_savage_private_t *dev_priv)
+{
+       unsigned int i;
+
+       dev_priv->nr_dma_pages = dev_priv->cmd_dma->size /
+               (SAVAGE_DMA_PAGE_SIZE*4);
+       dev_priv->dma_pages = drm_alloc(sizeof(drm_savage_dma_page_t) *
+                                       dev_priv->nr_dma_pages,
+                                       DRM_MEM_DRIVER);
+       if (dev_priv->dma_pages == NULL)
+               return DRM_ERR(ENOMEM);
+
+       for (i = 0; i < dev_priv->nr_dma_pages; ++i) {
+               SET_AGE(&dev_priv->dma_pages[i].age, 0, 0);
+               dev_priv->dma_pages[i].used = 0;
+               dev_priv->dma_pages[i].flushed = 0;
+       }
+       SET_AGE(&dev_priv->last_dma_age, 0, 0);
+
+       dev_priv->first_dma_page = 0;
+       dev_priv->current_dma_page = 0;
+
+       return 0;
+}
+
+void savage_dma_reset(drm_savage_private_t *dev_priv)
+{
+       uint16_t event;
+       unsigned int wrap, i;
+       event = savage_bci_emit_event(dev_priv, 0);
+       wrap = dev_priv->event_wrap;
+       for (i = 0; i < dev_priv->nr_dma_pages; ++i) {
+               SET_AGE(&dev_priv->dma_pages[i].age, event, wrap);
+               dev_priv->dma_pages[i].used = 0;
+               dev_priv->dma_pages[i].flushed = 0;
+       }
+       SET_AGE(&dev_priv->last_dma_age, event, wrap);
+       dev_priv->first_dma_page = dev_priv->current_dma_page = 0;
+}
+
+void savage_dma_wait(drm_savage_private_t *dev_priv, unsigned int page)
+{
+       uint16_t event;
+       unsigned int wrap;
+
+       /* Faked DMA buffer pages don't age. */
+       if (dev_priv->cmd_dma == &dev_priv->fake_dma)
+               return;
+
+       UPDATE_EVENT_COUNTER();
+       if (dev_priv->status_ptr)
+               event = dev_priv->status_ptr[1] & 0xffff;
+       else
+               event = SAVAGE_READ(SAVAGE_STATUS_WORD1) & 0xffff;
+       wrap = dev_priv->event_wrap;
+       if (event > dev_priv->event_counter)
+               wrap--; /* hardware hasn't passed the last wrap yet */
+
+       if (dev_priv->dma_pages[page].age.wrap > wrap ||
+           (dev_priv->dma_pages[page].age.wrap == wrap &&
+            dev_priv->dma_pages[page].age.event > event)) {
+               if (dev_priv->wait_evnt(dev_priv,
+                                       dev_priv->dma_pages[page].age.event)
+                   < 0)
+                       DRM_ERROR("wait_evnt failed!\n");
+       }
+}
+
+uint32_t *savage_dma_alloc(drm_savage_private_t *dev_priv, unsigned int n)
+{
+       unsigned int cur = dev_priv->current_dma_page;
+       unsigned int rest = SAVAGE_DMA_PAGE_SIZE -
+               dev_priv->dma_pages[cur].used;
+       unsigned int nr_pages = (n - rest + SAVAGE_DMA_PAGE_SIZE-1) /
+               SAVAGE_DMA_PAGE_SIZE;
+       uint32_t *dma_ptr;
+       unsigned int i;
+
+       DRM_DEBUG("cur=%u, cur->used=%u, n=%u, rest=%u, nr_pages=%u\n",
+                 cur, dev_priv->dma_pages[cur].used, n, rest, nr_pages);
+
+       if (cur + nr_pages < dev_priv->nr_dma_pages) {
+               dma_ptr = (uint32_t *)dev_priv->cmd_dma->handle +
+                       cur*SAVAGE_DMA_PAGE_SIZE +
+                       dev_priv->dma_pages[cur].used;
+               if (n < rest)
+                       rest = n;
+               dev_priv->dma_pages[cur].used += rest;
+               n -= rest;
+               cur++;
+       } else {
+               dev_priv->dma_flush(dev_priv);
+               nr_pages = (n + SAVAGE_DMA_PAGE_SIZE-1) / SAVAGE_DMA_PAGE_SIZE;
+               for (i = cur; i < dev_priv->nr_dma_pages; ++i) {
+                       dev_priv->dma_pages[i].age = dev_priv->last_dma_age;
+                       dev_priv->dma_pages[i].used = 0;
+                       dev_priv->dma_pages[i].flushed = 0;
+               }
+               dma_ptr = (uint32_t *)dev_priv->cmd_dma->handle;
+               dev_priv->first_dma_page = cur = 0;
+       }
+       for (i = cur; nr_pages > 0; ++i, --nr_pages) {
+#if SAVAGE_DMA_DEBUG
+               if (dev_priv->dma_pages[i].used) {
+                       DRM_ERROR("unflushed page %u: used=%u\n",
+                                 i, dev_priv->dma_pages[i].used);
+               }
+#endif
+               if (n > SAVAGE_DMA_PAGE_SIZE)
+                       dev_priv->dma_pages[i].used = SAVAGE_DMA_PAGE_SIZE;
+               else
+                       dev_priv->dma_pages[i].used = n;
+               n -= SAVAGE_DMA_PAGE_SIZE;
+       }
+       dev_priv->current_dma_page = --i;
+
+       DRM_DEBUG("cur=%u, cur->used=%u, n=%u\n",
+                 i, dev_priv->dma_pages[i].used, n);
+
+       savage_dma_wait(dev_priv, dev_priv->current_dma_page);
+
+       return dma_ptr;
+}
+
+static void savage_dma_flush(drm_savage_private_t *dev_priv)
+{
+       unsigned int first = dev_priv->first_dma_page;
+       unsigned int cur = dev_priv->current_dma_page;
+       uint16_t event;
+       unsigned int wrap, pad, align, len, i;
+       unsigned long phys_addr;
+       BCI_LOCALS;
+
+       if (first == cur &&
+           dev_priv->dma_pages[cur].used == dev_priv->dma_pages[cur].flushed)
+               return;
+
+       /* pad length to multiples of 2 entries
+        * align start of next DMA block to multiles of 8 entries */
+       pad = -dev_priv->dma_pages[cur].used & 1;
+       align = -(dev_priv->dma_pages[cur].used + pad) & 7;
+
+       DRM_DEBUG("first=%u, cur=%u, first->flushed=%u, cur->used=%u, "
+                 "pad=%u, align=%u\n",
+                 first, cur, dev_priv->dma_pages[first].flushed,
+                 dev_priv->dma_pages[cur].used, pad, align);
+
+       /* pad with noops */
+       if (pad) {
+               uint32_t *dma_ptr = (uint32_t *)dev_priv->cmd_dma->handle +
+                       cur * SAVAGE_DMA_PAGE_SIZE +
+                       dev_priv->dma_pages[cur].used;
+               dev_priv->dma_pages[cur].used += pad;
+               while(pad != 0) {
+                       *dma_ptr++ = BCI_CMD_WAIT;
+                       pad--;
+               }
+       }
+
+       DRM_MEMORYBARRIER();
+
+       /* do flush ... */
+       phys_addr = dev_priv->cmd_dma->offset +
+               (first * SAVAGE_DMA_PAGE_SIZE +
+                dev_priv->dma_pages[first].flushed) * 4;
+       len = (cur - first) * SAVAGE_DMA_PAGE_SIZE +
+               dev_priv->dma_pages[cur].used -
+               dev_priv->dma_pages[first].flushed;
+
+       DRM_DEBUG("phys_addr=%lx, len=%u\n",
+                 phys_addr | dev_priv->dma_type, len);
+
+       BEGIN_BCI(3);
+       BCI_SET_REGISTERS(SAVAGE_DMABUFADDR, 1);
+       BCI_WRITE(phys_addr | dev_priv->dma_type);
+       BCI_DMA(len);
+
+       /* fix alignment of the start of the next block */
+       dev_priv->dma_pages[cur].used += align;
+
+       /* age DMA pages */
+       event = savage_bci_emit_event(dev_priv, 0);
+       wrap = dev_priv->event_wrap;
+       for (i = first; i < cur; ++i) {
+               SET_AGE(&dev_priv->dma_pages[i].age, event, wrap);
+               dev_priv->dma_pages[i].used = 0;
+               dev_priv->dma_pages[i].flushed = 0;
+       }
+       /* age the current page only when it's full */
+       if (dev_priv->dma_pages[cur].used == SAVAGE_DMA_PAGE_SIZE) {
+               SET_AGE(&dev_priv->dma_pages[cur].age, event, wrap);
+               dev_priv->dma_pages[cur].used = 0;
+               dev_priv->dma_pages[cur].flushed = 0;
+               /* advance to next page */
+               cur++;
+               if (cur == dev_priv->nr_dma_pages)
+                       cur = 0;
+               dev_priv->first_dma_page = dev_priv->current_dma_page = cur;
+       } else {
+               dev_priv->first_dma_page = cur;
+               dev_priv->dma_pages[cur].flushed = dev_priv->dma_pages[i].used;
+       }
+       SET_AGE(&dev_priv->last_dma_age, event, wrap);
+
+       DRM_DEBUG("first=cur=%u, cur->used=%u, cur->flushed=%u\n", cur,
+                 dev_priv->dma_pages[cur].used,
+                 dev_priv->dma_pages[cur].flushed);
+}
+
+static void savage_fake_dma_flush(drm_savage_private_t *dev_priv)
+{
+       unsigned int i, j;
+       BCI_LOCALS;
+
+       if (dev_priv->first_dma_page == dev_priv->current_dma_page &&
+           dev_priv->dma_pages[dev_priv->current_dma_page].used == 0)
+               return;
+
+       DRM_DEBUG("first=%u, cur=%u, cur->used=%u\n",
+                 dev_priv->first_dma_page, dev_priv->current_dma_page,
+                 dev_priv->dma_pages[dev_priv->current_dma_page].used);
+
+       for (i = dev_priv->first_dma_page;
+            i <= dev_priv->current_dma_page && dev_priv->dma_pages[i].used;
+            ++i) {
+               uint32_t *dma_ptr = (uint32_t *)dev_priv->cmd_dma->handle +
+                       i * SAVAGE_DMA_PAGE_SIZE;
+#if SAVAGE_DMA_DEBUG
+               /* Sanity check: all pages except the last one must be full. */
+               if (i < dev_priv->current_dma_page &&
+                   dev_priv->dma_pages[i].used != SAVAGE_DMA_PAGE_SIZE) {
+                       DRM_ERROR("partial DMA page %u: used=%u",
+                                 i, dev_priv->dma_pages[i].used);
+               }
+#endif
+               BEGIN_BCI(dev_priv->dma_pages[i].used);
+               for (j = 0; j < dev_priv->dma_pages[i].used; ++j) {
+                       BCI_WRITE(dma_ptr[j]);
+               }
+               dev_priv->dma_pages[i].used = 0;
+       }
+
+       /* reset to first page */
+       dev_priv->first_dma_page = dev_priv->current_dma_page = 0;
+}
+
+/*
+ * Initalize mappings. On Savage4 and SavageIX the alignment
+ * and size of the aperture is not suitable for automatic MTRR setup
+ * in drm_addmap. Therefore we do it manually before the maps are
+ * initialized. We also need to take care of deleting the MTRRs in
+ * postcleanup.
+ */
+int savage_preinit(drm_device_t *dev, unsigned long chipset)
+{
+       drm_savage_private_t *dev_priv;
+       unsigned long mmio_base, fb_base, fb_size, aperture_base;
+       /* fb_rsrc and aper_rsrc aren't really used currently, but still exist
+        * in case we decide we need information on the BAR for BSD in the
+        * future.
+        */
+       unsigned int fb_rsrc, aper_rsrc;
+       int ret = 0;
+
+       dev_priv = drm_alloc(sizeof(drm_savage_private_t), DRM_MEM_DRIVER);
+       if (dev_priv == NULL)
+               return DRM_ERR(ENOMEM);
+
+       memset(dev_priv, 0, sizeof(drm_savage_private_t));
+       dev->dev_private = (void *)dev_priv;
+       dev_priv->chipset = (enum savage_family)chipset;
+
+       dev_priv->mtrr[0].handle = -1;
+       dev_priv->mtrr[1].handle = -1;
+       dev_priv->mtrr[2].handle = -1;
+       if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
+               fb_rsrc = 0;
+               fb_base = drm_get_resource_start(dev, 0);
+               fb_size = SAVAGE_FB_SIZE_S3;
+               mmio_base = fb_base + SAVAGE_FB_SIZE_S3;
+               aper_rsrc = 0;
+               aperture_base = fb_base + SAVAGE_APERTURE_OFFSET;
+               /* this should always be true */
+               if (drm_get_resource_len(dev, 0) == 0x08000000) {
+                       /* Don't make MMIO write-cobining! We need 3
+                        * MTRRs. */
+                       dev_priv->mtrr[0].base = fb_base;
+                       dev_priv->mtrr[0].size = 0x01000000;
+                       dev_priv->mtrr[0].handle = mtrr_add(
+                               dev_priv->mtrr[0].base, dev_priv->mtrr[0].size,
+                               MTRR_TYPE_WRCOMB, 1);
+                       dev_priv->mtrr[1].base = fb_base+0x02000000;
+                       dev_priv->mtrr[1].size = 0x02000000;
+                       dev_priv->mtrr[1].handle = mtrr_add(
+                               dev_priv->mtrr[1].base, dev_priv->mtrr[1].size,
+                               MTRR_TYPE_WRCOMB, 1);
+                       dev_priv->mtrr[2].base = fb_base+0x04000000;
+                       dev_priv->mtrr[2].size = 0x04000000;
+                       dev_priv->mtrr[2].handle = mtrr_add(
+                               dev_priv->mtrr[2].base, dev_priv->mtrr[2].size,
+                               MTRR_TYPE_WRCOMB, 1);
+               } else {
+                       DRM_ERROR("strange pci_resource_len %08lx\n",
+                                 drm_get_resource_len(dev, 0));
+               }
+       } else if (chipset != S3_SUPERSAVAGE && chipset != S3_SAVAGE2000) {
+               mmio_base = drm_get_resource_start(dev, 0);
+               fb_rsrc = 1;
+               fb_base = drm_get_resource_start(dev, 1);
+               fb_size = SAVAGE_FB_SIZE_S4;
+               aper_rsrc = 1;
+               aperture_base = fb_base + SAVAGE_APERTURE_OFFSET;
+               /* this should always be true */
+               if (drm_get_resource_len(dev, 1) == 0x08000000) {
+                       /* Can use one MTRR to cover both fb and
+                        * aperture. */
+                       dev_priv->mtrr[0].base = fb_base;
+                       dev_priv->mtrr[0].size = 0x08000000;
+                       dev_priv->mtrr[0].handle = mtrr_add(
+                               dev_priv->mtrr[0].base, dev_priv->mtrr[0].size,
+                               MTRR_TYPE_WRCOMB, 1);
+               } else {
+                       DRM_ERROR("strange pci_resource_len %08lx\n",
+                                 drm_get_resource_len(dev, 1));
+               }
+       } else {
+               mmio_base = drm_get_resource_start(dev, 0);
+               fb_rsrc = 1;
+               fb_base = drm_get_resource_start(dev, 1);
+               fb_size = drm_get_resource_len(dev, 1);
+               aper_rsrc = 2;
+               aperture_base = drm_get_resource_start(dev, 2);
+               /* Automatic MTRR setup will do the right thing. */
+       }
+
+       ret = drm_addmap(dev, mmio_base, SAVAGE_MMIO_SIZE, _DRM_REGISTERS,
+                        _DRM_READ_ONLY, &dev_priv->mmio);
+       if (ret)
+               return ret;
+
+       ret = drm_addmap(dev, fb_base, fb_size, _DRM_FRAME_BUFFER,
+                        _DRM_WRITE_COMBINING, &dev_priv->fb);
+       if (ret)
+               return ret;
+
+       ret = drm_addmap(dev, aperture_base, SAVAGE_APERTURE_SIZE,
+                        _DRM_FRAME_BUFFER, _DRM_WRITE_COMBINING,
+                        &dev_priv->aperture);
+       if (ret)
+               return ret;
+
+       return ret;
+}
+
+/*
+ * Delete MTRRs and free device-private data.
+ */
+int savage_postcleanup(drm_device_t *dev)
+{
+       drm_savage_private_t *dev_priv = dev->dev_private;
+       int i;
+
+       for (i = 0; i < 3; ++i)
+               if (dev_priv->mtrr[i].handle >= 0)
+                       mtrr_del(dev_priv->mtrr[i].handle,
+                                dev_priv->mtrr[i].base,
+                                dev_priv->mtrr[i].size);
+
+       drm_free(dev_priv, sizeof(drm_savage_private_t), DRM_MEM_DRIVER);
+
+       return 0;
+}
+
+static int savage_do_init_bci(drm_device_t *dev, drm_savage_init_t *init)
+{
+       drm_savage_private_t *dev_priv = dev->dev_private;
+
+       if (init->fb_bpp != 16 && init->fb_bpp != 32) {
+               DRM_ERROR("invalid frame buffer bpp %d!\n", init->fb_bpp);
+               return DRM_ERR(EINVAL);
+       }
+       if (init->depth_bpp != 16 && init->depth_bpp != 32) {
+               DRM_ERROR("invalid depth buffer bpp %d!\n", init->fb_bpp);
+               return DRM_ERR(EINVAL);
+       }
+       if (init->dma_type != SAVAGE_DMA_AGP &&
+           init->dma_type != SAVAGE_DMA_PCI) {
+               DRM_ERROR("invalid dma memory type %d!\n", init->dma_type);
+               return DRM_ERR(EINVAL);
+       }
+
+       dev_priv->cob_size = init->cob_size;
+       dev_priv->bci_threshold_lo = init->bci_threshold_lo;
+       dev_priv->bci_threshold_hi = init->bci_threshold_hi;
+       dev_priv->dma_type = init->dma_type;
+
+       dev_priv->fb_bpp = init->fb_bpp;
+       dev_priv->front_offset = init->front_offset;
+       dev_priv->front_pitch = init->front_pitch;
+       dev_priv->back_offset = init->back_offset;
+       dev_priv->back_pitch = init->back_pitch;
+       dev_priv->depth_bpp = init->depth_bpp;
+       dev_priv->depth_offset = init->depth_offset;
+       dev_priv->depth_pitch = init->depth_pitch;
+
+       dev_priv->texture_offset = init->texture_offset;
+       dev_priv->texture_size = init->texture_size;
+
+       DRM_GETSAREA();
+       if (!dev_priv->sarea) {
+               DRM_ERROR("could not find sarea!\n");
+               savage_do_cleanup_bci(dev);
+               return DRM_ERR(EINVAL);
+       }
+       if (init->status_offset != 0) {
+               dev_priv->status = drm_core_findmap(dev, init->status_offset);
+               if (!dev_priv->status) {
+                       DRM_ERROR("could not find shadow status region!\n");
+                       savage_do_cleanup_bci(dev);
+                       return DRM_ERR(EINVAL);
+               }
+       } else {
+               dev_priv->status = NULL;
+       }
+       if (dev_priv->dma_type == SAVAGE_DMA_AGP && init->buffers_offset) {
+               dev->agp_buffer_map = drm_core_findmap(dev,
+                                                      init->buffers_offset);
+               if (!dev->agp_buffer_map) {
+                       DRM_ERROR("could not find DMA buffer region!\n");
+                       savage_do_cleanup_bci(dev);
+                       return DRM_ERR(EINVAL);
+               }
+               drm_core_ioremap(dev->agp_buffer_map, dev);
+               if (!dev->agp_buffer_map) {
+                       DRM_ERROR("failed to ioremap DMA buffer region!\n");
+                       savage_do_cleanup_bci(dev);
+                       return DRM_ERR(ENOMEM);
+               }
+       }
+       if (init->agp_textures_offset) {
+               dev_priv->agp_textures =
+                       drm_core_findmap(dev, init->agp_textures_offset);
+               if (!dev_priv->agp_textures) {
+                       DRM_ERROR("could not find agp texture region!\n");
+                       savage_do_cleanup_bci(dev);
+                       return DRM_ERR(EINVAL);
+               }
+       } else {
+               dev_priv->agp_textures = NULL;
+       }
+
+       if (init->cmd_dma_offset) {
+               if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
+                       DRM_ERROR("command DMA not supported on "
+                                 "Savage3D/MX/IX.\n");
+                       savage_do_cleanup_bci(dev);
+                       return DRM_ERR(EINVAL);
+               }
+               if (dev->dma && dev->dma->buflist) {
+                       DRM_ERROR("command and vertex DMA not supported "
+                                 "at the same time.\n");
+                       savage_do_cleanup_bci(dev);
+                       return DRM_ERR(EINVAL);
+               }
+               dev_priv->cmd_dma = drm_core_findmap(dev, init->cmd_dma_offset);
+               if (!dev_priv->cmd_dma) {
+                       DRM_ERROR("could not find command DMA region!\n");
+                       savage_do_cleanup_bci(dev);
+                       return DRM_ERR(EINVAL);
+               }
+               if (dev_priv->dma_type == SAVAGE_DMA_AGP) {
+                       if (dev_priv->cmd_dma->type != _DRM_AGP) {
+                               DRM_ERROR("AGP command DMA region is not a "
+                                         "_DRM_AGP map!\n");
+                               savage_do_cleanup_bci(dev);
+                               return DRM_ERR(EINVAL);
+                       }
+                       drm_core_ioremap(dev_priv->cmd_dma, dev);
+                       if (!dev_priv->cmd_dma->handle) {
+                               DRM_ERROR("failed to ioremap command "
+                                         "DMA region!\n");
+                               savage_do_cleanup_bci(dev);
+                               return DRM_ERR(ENOMEM);
+                       }
+               } else if (dev_priv->cmd_dma->type != _DRM_CONSISTENT) {
+                       DRM_ERROR("PCI command DMA region is not a "
+                                 "_DRM_CONSISTENT map!\n");
+                       savage_do_cleanup_bci(dev);
+                       return DRM_ERR(EINVAL);
+               }
+       } else {
+               dev_priv->cmd_dma = NULL;
+       }
+
+       dev_priv->dma_flush = savage_dma_flush;
+       if (!dev_priv->cmd_dma) {
+               DRM_DEBUG("falling back to faked command DMA.\n");
+               dev_priv->fake_dma.offset = 0;
+               dev_priv->fake_dma.size = SAVAGE_FAKE_DMA_SIZE;
+               dev_priv->fake_dma.type = _DRM_SHM;
+               dev_priv->fake_dma.handle = drm_alloc(SAVAGE_FAKE_DMA_SIZE,
+                                                     DRM_MEM_DRIVER);
+               if (!dev_priv->fake_dma.handle) {
+                       DRM_ERROR("could not allocate faked DMA buffer!\n");
+                       savage_do_cleanup_bci(dev);
+                       return DRM_ERR(ENOMEM);
+               }
+               dev_priv->cmd_dma = &dev_priv->fake_dma;
+               dev_priv->dma_flush = savage_fake_dma_flush;
+       }
+
+       dev_priv->sarea_priv =
+               (drm_savage_sarea_t *)((uint8_t *)dev_priv->sarea->handle +
+                                      init->sarea_priv_offset);
+
+       /* setup bitmap descriptors */
+       {
+               unsigned int color_tile_format;
+               unsigned int depth_tile_format;
+               unsigned int front_stride, back_stride, depth_stride;
+               if (dev_priv->chipset <= S3_SAVAGE4) {
+                       color_tile_format = dev_priv->fb_bpp == 16 ?
+                               SAVAGE_BD_TILE_16BPP : SAVAGE_BD_TILE_32BPP;
+                       depth_tile_format = dev_priv->depth_bpp == 16 ?
+                               SAVAGE_BD_TILE_16BPP : SAVAGE_BD_TILE_32BPP;
+               } else {
+                       color_tile_format = SAVAGE_BD_TILE_DEST;
+                       depth_tile_format = SAVAGE_BD_TILE_DEST;
+               }
+               front_stride = dev_priv->front_pitch / (dev_priv->fb_bpp/8);
+               back_stride  = dev_priv-> back_pitch / (dev_priv->fb_bpp/8);
+               depth_stride = dev_priv->depth_pitch / (dev_priv->depth_bpp/8);
+
+               dev_priv->front_bd = front_stride | SAVAGE_BD_BW_DISABLE |
+                       (dev_priv->fb_bpp << SAVAGE_BD_BPP_SHIFT) |
+                       (color_tile_format << SAVAGE_BD_TILE_SHIFT);
+
+               dev_priv-> back_bd =  back_stride | SAVAGE_BD_BW_DISABLE |
+                       (dev_priv->fb_bpp << SAVAGE_BD_BPP_SHIFT) |
+                       (color_tile_format << SAVAGE_BD_TILE_SHIFT);
+
+               dev_priv->depth_bd = depth_stride | SAVAGE_BD_BW_DISABLE |
+                       (dev_priv->depth_bpp << SAVAGE_BD_BPP_SHIFT) |
+                       (depth_tile_format << SAVAGE_BD_TILE_SHIFT);
+       }
+
+       /* setup status and bci ptr */
+       dev_priv->event_counter = 0;
+       dev_priv->event_wrap = 0;
+       dev_priv->bci_ptr = (volatile uint32_t *)
+           ((uint8_t *)dev_priv->mmio->handle + SAVAGE_BCI_OFFSET);
+       if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
+               dev_priv->status_used_mask = SAVAGE_FIFO_USED_MASK_S3D;
+       } else {
+               dev_priv->status_used_mask = SAVAGE_FIFO_USED_MASK_S4;
+       }
+       if (dev_priv->status != NULL) {
+               dev_priv->status_ptr =
+                       (volatile uint32_t *)dev_priv->status->handle;
+               dev_priv->wait_fifo = savage_bci_wait_fifo_shadow;
+               dev_priv->wait_evnt = savage_bci_wait_event_shadow;
+               dev_priv->status_ptr[1023] = dev_priv->event_counter;
+       } else {
+               dev_priv->status_ptr = NULL;
+               if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
+                       dev_priv->wait_fifo = savage_bci_wait_fifo_s3d;
+               } else {
+                       dev_priv->wait_fifo = savage_bci_wait_fifo_s4;
+               }
+               dev_priv->wait_evnt = savage_bci_wait_event_reg;
+       }
+
+       /* cliprect functions */
+       if (S3_SAVAGE3D_SERIES(dev_priv->chipset))
+               dev_priv->emit_clip_rect = savage_emit_clip_rect_s3d;
+       else
+               dev_priv->emit_clip_rect = savage_emit_clip_rect_s4;
+
+       if (savage_freelist_init(dev) < 0) {
+               DRM_ERROR("could not initialize freelist\n");
+               savage_do_cleanup_bci(dev);
+               return DRM_ERR(ENOMEM);
+       }
+
+       if (savage_dma_init(dev_priv) <  0) {
+               DRM_ERROR("could not initialize command DMA\n");
+               savage_do_cleanup_bci(dev);
+               return DRM_ERR(ENOMEM);
+       }
+
+       return 0;
+}
+
+int savage_do_cleanup_bci(drm_device_t *dev)
+{
+       drm_savage_private_t *dev_priv = dev->dev_private;
+
+       if (dev_priv->cmd_dma == &dev_priv->fake_dma) {
+               if (dev_priv->fake_dma.handle)
+                       drm_free(dev_priv->fake_dma.handle,
+                                SAVAGE_FAKE_DMA_SIZE, DRM_MEM_DRIVER);
+       } else if (dev_priv->cmd_dma && dev_priv->cmd_dma->handle &&
+                  dev_priv->cmd_dma->type == _DRM_AGP &&
+                  dev_priv->dma_type == SAVAGE_DMA_AGP)
+               drm_core_ioremapfree(dev_priv->cmd_dma, dev);
+
+       if (dev_priv->dma_type == SAVAGE_DMA_AGP &&
+           dev->agp_buffer_map && dev->agp_buffer_map->handle) {
+               drm_core_ioremapfree(dev->agp_buffer_map, dev);
+               /* make sure the next instance (which may be running
+                * in PCI mode) doesn't try to use an old
+                * agp_buffer_map. */
+               dev->agp_buffer_map = NULL;
+       }
+
+       if (dev_priv->dma_pages)
+               drm_free(dev_priv->dma_pages,
+                        sizeof(drm_savage_dma_page_t)*dev_priv->nr_dma_pages,
+                        DRM_MEM_DRIVER);
+
+       return 0;
+}
+
+static int savage_bci_init(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_savage_init_t init;
+
+       LOCK_TEST_WITH_RETURN(dev, filp);
+
+       DRM_COPY_FROM_USER_IOCTL(init, (drm_savage_init_t __user *)data,
+                                sizeof(init));
+
+       switch (init.func) {
+       case SAVAGE_INIT_BCI:
+               return savage_do_init_bci(dev, &init);
+       case SAVAGE_CLEANUP_BCI:
+               return savage_do_cleanup_bci(dev);
+       }
+
+       return DRM_ERR(EINVAL);
+}
+
+static int savage_bci_event_emit(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_savage_private_t *dev_priv = dev->dev_private;
+       drm_savage_event_emit_t event;
+
+       DRM_DEBUG("\n");
+
+       LOCK_TEST_WITH_RETURN(dev, filp);
+
+       DRM_COPY_FROM_USER_IOCTL(event, (drm_savage_event_emit_t __user *)data,
+                                sizeof(event));
+
+       event.count = savage_bci_emit_event(dev_priv, event.flags);
+       event.count |= dev_priv->event_wrap << 16;
+       DRM_COPY_TO_USER_IOCTL(&((drm_savage_event_emit_t __user *)data)->count,
+                              event.count, sizeof(event.count));
+       return 0;
+}
+
+static int savage_bci_event_wait(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_savage_private_t *dev_priv = dev->dev_private;
+       drm_savage_event_wait_t event;
+       unsigned int event_e, hw_e;
+       unsigned int event_w, hw_w;
+
+       DRM_DEBUG("\n");
+
+       DRM_COPY_FROM_USER_IOCTL(event, (drm_savage_event_wait_t __user *)data,
+                                sizeof(event));
+
+       UPDATE_EVENT_COUNTER();
+       if (dev_priv->status_ptr)
+               hw_e = dev_priv->status_ptr[1] & 0xffff;
+       else
+               hw_e = SAVAGE_READ(SAVAGE_STATUS_WORD1) & 0xffff;
+       hw_w = dev_priv->event_wrap;
+       if (hw_e > dev_priv->event_counter)
+               hw_w--; /* hardware hasn't passed the last wrap yet */
+
+       event_e = event.count & 0xffff;
+       event_w = event.count >> 16;
+
+       /* Don't need to wait if
+        * - event counter wrapped since the event was emitted or
+        * - the hardware has advanced up to or over the event to wait for.
+        */
+       if (event_w < hw_w || (event_w == hw_w && event_e <= hw_e) )
+               return 0;
+       else
+               return dev_priv->wait_evnt(dev_priv, event_e);
+}
+
+/*
+ * DMA buffer management
+ */
+
+static int savage_bci_get_buffers(DRMFILE filp, drm_device_t *dev, drm_dma_t *d)
+{
+       drm_buf_t *buf;
+       int i;
+
+       for (i = d->granted_count; i < d->request_count; i++) {
+               buf = savage_freelist_get(dev);
+               if (!buf)
+                       return DRM_ERR(EAGAIN);
+
+               buf->filp = filp;
+
+               if (DRM_COPY_TO_USER(&d->request_indices[i],
+                                    &buf->idx, sizeof(buf->idx)))
+                       return DRM_ERR(EFAULT);
+               if (DRM_COPY_TO_USER(&d->request_sizes[i],
+                                    &buf->total, sizeof(buf->total)))
+                       return DRM_ERR(EFAULT);
+
+               d->granted_count++;
+       }
+       return 0;
+}
+
+int savage_bci_buffers(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_device_dma_t *dma = dev->dma;
+       drm_dma_t d;
+       int ret = 0;
+
+       LOCK_TEST_WITH_RETURN(dev, filp);
+
+       DRM_COPY_FROM_USER_IOCTL(d, (drm_dma_t __user *)data, sizeof(d));
+
+       /* Please don't send us buffers.
+        */
+       if (d.send_count != 0) {
+               DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
+                         DRM_CURRENTPID, d.send_count);
+               return DRM_ERR(EINVAL);
+       }
+
+       /* We'll send you buffers.
+        */
+       if (d.request_count < 0 || d.request_count > dma->buf_count) {
+               DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
+                         DRM_CURRENTPID, d.request_count, dma->buf_count);
+               return DRM_ERR(EINVAL);
+       }
+
+       d.granted_count = 0;
+
+       if (d.request_count) {
+               ret = savage_bci_get_buffers(filp, dev, &d);
+       }
+
+       DRM_COPY_TO_USER_IOCTL((drm_dma_t __user *)data, d, sizeof(d));
+
+       return ret;
+}
+
+void savage_reclaim_buffers(drm_device_t *dev, DRMFILE filp) {
+       drm_device_dma_t *dma = dev->dma;
+       drm_savage_private_t *dev_priv = dev->dev_private;
+       int i;
+
+       if (!dma)
+               return;
+       if (!dev_priv)
+               return;
+       if (!dma->buflist)
+               return;
+
+       /*i830_flush_queue(dev);*/
+
+       for (i = 0; i < dma->buf_count; i++) {
+               drm_buf_t *buf = dma->buflist[i];
+               drm_savage_buf_priv_t *buf_priv = buf->dev_private;
+
+               if (buf->filp == filp && buf_priv &&
+                   buf_priv->next == NULL && buf_priv->prev == NULL) {
+                       uint16_t event;
+                       DRM_DEBUG("reclaimed from client\n");
+                       event = savage_bci_emit_event(dev_priv, SAVAGE_WAIT_3D);
+                       SET_AGE(&buf_priv->age, event, dev_priv->event_wrap);
+                       savage_freelist_put(dev, buf);
+               }
+       }
+
+       drm_core_reclaim_buffers(dev, filp);
+}
+
+
+drm_ioctl_desc_t savage_ioctls[] = {
+       [DRM_IOCTL_NR(DRM_SAVAGE_BCI_INIT)] = {savage_bci_init, 1, 1},
+       [DRM_IOCTL_NR(DRM_SAVAGE_BCI_CMDBUF)] = {savage_bci_cmdbuf, 1, 0},
+       [DRM_IOCTL_NR(DRM_SAVAGE_BCI_EVENT_EMIT)] = {savage_bci_event_emit, 1, 0},
+       [DRM_IOCTL_NR(DRM_SAVAGE_BCI_EVENT_WAIT)] = {savage_bci_event_wait, 1, 0},
+};
+
+int savage_max_ioctl = DRM_ARRAY_SIZE(savage_ioctls);
diff --git a/drivers/char/drm/savage_drm.h b/drivers/char/drm/savage_drm.h
new file mode 100644 (file)
index 0000000..6526c9a
--- /dev/null
@@ -0,0 +1,209 @@
+/* savage_drm.h -- Public header for the savage driver
+ *
+ * Copyright 2004  Felix Kuehling
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT. IN NO EVENT SHALL FELIX KUEHLING BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __SAVAGE_DRM_H__
+#define __SAVAGE_DRM_H__
+
+#ifndef __SAVAGE_SAREA_DEFINES__
+#define __SAVAGE_SAREA_DEFINES__
+
+/* 2 heaps (1 for card, 1 for agp), each divided into upto 128
+ * regions, subject to a minimum region size of (1<<16) == 64k.
+ *
+ * Clients may subdivide regions internally, but when sharing between
+ * clients, the region size is the minimum granularity.
+ */
+
+#define SAVAGE_CARD_HEAP               0
+#define SAVAGE_AGP_HEAP                        1
+#define SAVAGE_NR_TEX_HEAPS            2
+#define SAVAGE_NR_TEX_REGIONS          16
+#define SAVAGE_LOG_MIN_TEX_REGION_SIZE 16
+
+#endif /* __SAVAGE_SAREA_DEFINES__ */
+
+typedef struct _drm_savage_sarea {
+       /* LRU lists for texture memory in agp space and on the card.
+        */
+       drm_tex_region_t texList[SAVAGE_NR_TEX_HEAPS][SAVAGE_NR_TEX_REGIONS+1];
+       unsigned int texAge[SAVAGE_NR_TEX_HEAPS];
+
+       /* Mechanism to validate card state.
+        */
+       int ctxOwner;
+} drm_savage_sarea_t, *drm_savage_sarea_ptr;
+
+/* Savage-specific ioctls
+ */
+#define DRM_SAVAGE_BCI_INIT            0x00
+#define DRM_SAVAGE_BCI_CMDBUF           0x01
+#define DRM_SAVAGE_BCI_EVENT_EMIT      0x02
+#define DRM_SAVAGE_BCI_EVENT_WAIT      0x03
+
+#define DRM_IOCTL_SAVAGE_INIT          DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_INIT, drm_savage_init_t)
+#define DRM_IOCTL_SAVAGE_CMDBUF                DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_CMDBUF, drm_savage_cmdbuf_t)
+#define DRM_IOCTL_SAVAGE_EVENT_EMIT    DRM_IOWR(DRM_COMMAND_BASE + DRM_SAVAGE_BCI_EVENT_EMIT, drm_savage_event_emit_t)
+#define DRM_IOCTL_SAVAGE_EVENT_WAIT    DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_EVENT_WAIT, drm_savage_event_wait_t)
+
+#define SAVAGE_DMA_PCI 1
+#define SAVAGE_DMA_AGP 3
+typedef struct drm_savage_init {
+       enum {
+               SAVAGE_INIT_BCI = 1,
+               SAVAGE_CLEANUP_BCI = 2
+       } func;
+       unsigned int sarea_priv_offset;
+
+       /* some parameters */
+       unsigned int cob_size;
+       unsigned int bci_threshold_lo, bci_threshold_hi;
+       unsigned int dma_type;
+
+       /* frame buffer layout */
+       unsigned int fb_bpp;
+       unsigned int front_offset, front_pitch;
+       unsigned int back_offset, back_pitch;
+       unsigned int depth_bpp;
+       unsigned int depth_offset, depth_pitch;
+
+       /* local textures */
+       unsigned int texture_offset;
+       unsigned int texture_size;
+
+       /* physical locations of non-permanent maps */
+       unsigned long status_offset;
+       unsigned long buffers_offset;
+       unsigned long agp_textures_offset;
+       unsigned long cmd_dma_offset;
+} drm_savage_init_t;
+
+typedef union drm_savage_cmd_header drm_savage_cmd_header_t;
+typedef struct drm_savage_cmdbuf {
+                               /* command buffer in client's address space */
+       drm_savage_cmd_header_t __user *cmd_addr;
+       unsigned int size;      /* size of the command buffer in 64bit units */
+
+       unsigned int dma_idx;   /* DMA buffer index to use */
+       int discard;            /* discard DMA buffer when done */
+                               /* vertex buffer in client's address space */
+       unsigned int __user *vb_addr;
+       unsigned int vb_size;   /* size of client vertex buffer in bytes */
+       unsigned int vb_stride; /* stride of vertices in 32bit words */
+                               /* boxes in client's address space */
+       drm_clip_rect_t __user *box_addr;
+       unsigned int nbox;      /* number of clipping boxes */
+} drm_savage_cmdbuf_t;
+
+#define SAVAGE_WAIT_2D  0x1 /* wait for 2D idle before updating event tag */
+#define SAVAGE_WAIT_3D  0x2 /* wait for 3D idle before updating event tag */
+#define SAVAGE_WAIT_IRQ 0x4 /* emit or wait for IRQ, not implemented yet */
+typedef struct drm_savage_event {
+       unsigned int count;
+       unsigned int flags;
+} drm_savage_event_emit_t, drm_savage_event_wait_t;
+
+/* Commands for the cmdbuf ioctl
+ */
+#define SAVAGE_CMD_STATE       0  /* a range of state registers */
+#define SAVAGE_CMD_DMA_PRIM    1  /* vertices from DMA buffer */
+#define SAVAGE_CMD_VB_PRIM     2  /* vertices from client vertex buffer */
+#define SAVAGE_CMD_DMA_IDX     3  /* indexed vertices from DMA buffer */
+#define SAVAGE_CMD_VB_IDX      4  /* indexed vertices client vertex buffer */
+#define SAVAGE_CMD_CLEAR       5  /* clear buffers */
+#define SAVAGE_CMD_SWAP                6  /* swap buffers */
+
+/* Primitive types
+*/
+#define SAVAGE_PRIM_TRILIST    0  /* triangle list */
+#define SAVAGE_PRIM_TRISTRIP   1  /* triangle strip */
+#define SAVAGE_PRIM_TRIFAN     2  /* triangle fan */
+#define SAVAGE_PRIM_TRILIST_201        3  /* reorder verts for correct flat
+                                   * shading on s3d */
+
+/* Skip flags (vertex format)
+ */
+#define SAVAGE_SKIP_Z          0x01
+#define SAVAGE_SKIP_W          0x02
+#define SAVAGE_SKIP_C0         0x04
+#define SAVAGE_SKIP_C1         0x08
+#define SAVAGE_SKIP_S0         0x10
+#define SAVAGE_SKIP_T0         0x20
+#define SAVAGE_SKIP_ST0                0x30
+#define SAVAGE_SKIP_S1         0x40
+#define SAVAGE_SKIP_T1         0x80
+#define SAVAGE_SKIP_ST1                0xc0
+#define SAVAGE_SKIP_ALL_S3D    0x3f
+#define SAVAGE_SKIP_ALL_S4     0xff
+
+/* Buffer names for clear command
+ */
+#define SAVAGE_FRONT           0x1
+#define SAVAGE_BACK            0x2
+#define SAVAGE_DEPTH           0x4
+
+/* 64-bit command header
+ */
+union drm_savage_cmd_header {
+       struct {
+               unsigned char cmd;      /* command */
+               unsigned char pad0;
+               unsigned short pad1;
+               unsigned short pad2;
+               unsigned short pad3;
+       } cmd; /* generic */
+       struct {
+               unsigned char cmd;
+               unsigned char global;   /* need idle engine? */
+               unsigned short count;   /* number of consecutive registers */
+               unsigned short start;   /* first register */
+               unsigned short pad3;
+       } state; /* SAVAGE_CMD_STATE */
+       struct {
+               unsigned char cmd;
+               unsigned char prim;     /* primitive type */
+               unsigned short skip;    /* vertex format (skip flags) */
+               unsigned short count;   /* number of vertices */
+               unsigned short start;   /* first vertex in DMA/vertex buffer */
+       } prim; /* SAVAGE_CMD_DMA_PRIM, SAVAGE_CMD_VB_PRIM */
+       struct {
+               unsigned char cmd;
+               unsigned char prim;
+               unsigned short skip;
+               unsigned short count;   /* number of indices that follow */
+               unsigned short pad3;
+       } idx; /* SAVAGE_CMD_DMA_IDX, SAVAGE_CMD_VB_IDX */
+       struct {
+               unsigned char cmd;
+               unsigned char pad0;
+               unsigned short pad1;
+               unsigned int flags;
+       } clear0; /* SAVAGE_CMD_CLEAR */
+       struct {
+               unsigned int mask;
+               unsigned int value;
+       } clear1; /* SAVAGE_CMD_CLEAR data */
+};
+
+#endif
diff --git a/drivers/char/drm/savage_drv.c b/drivers/char/drm/savage_drv.c
new file mode 100644 (file)
index 0000000..ac8d270
--- /dev/null
@@ -0,0 +1,112 @@
+/* savage_drv.c -- Savage driver for Linux
+ *
+ * Copyright 2004  Felix Kuehling
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT. IN NO EVENT SHALL FELIX KUEHLING BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/config.h>
+#include "drmP.h"
+#include "savage_drm.h"
+#include "savage_drv.h"
+
+#include "drm_pciids.h"
+
+static int postinit( struct drm_device *dev, unsigned long flags )
+{
+       DRM_INFO( "Initialized %s %d.%d.%d %s on minor %d: %s\n",
+               DRIVER_NAME,
+               DRIVER_MAJOR,
+               DRIVER_MINOR,
+               DRIVER_PATCHLEVEL,
+               DRIVER_DATE,
+               dev->primary.minor,
+               pci_pretty_name(dev->pdev)
+               );
+       return 0;
+}
+
+static int version( drm_version_t *version )
+{
+       int len;
+
+       version->version_major = DRIVER_MAJOR;
+       version->version_minor = DRIVER_MINOR;
+       version->version_patchlevel = DRIVER_PATCHLEVEL;
+       DRM_COPY( version->name, DRIVER_NAME );
+       DRM_COPY( version->date, DRIVER_DATE );
+       DRM_COPY( version->desc, DRIVER_DESC );
+       return 0;
+}
+
+static struct pci_device_id pciidlist[] = {
+       savage_PCI_IDS
+};
+
+extern drm_ioctl_desc_t savage_ioctls[];
+extern int savage_max_ioctl;
+
+static struct drm_driver driver = {
+       .driver_features =
+           DRIVER_USE_AGP | DRIVER_USE_MTRR |
+           DRIVER_HAVE_DMA | DRIVER_PCI_DMA,
+       .dev_priv_size = sizeof(drm_savage_buf_priv_t),
+       .preinit = savage_preinit,
+       .postinit = postinit,
+       .postcleanup = savage_postcleanup,
+       .reclaim_buffers = savage_reclaim_buffers,
+       .get_map_ofs = drm_core_get_map_ofs,
+       .get_reg_ofs = drm_core_get_reg_ofs,
+       .version = version,
+       .ioctls = savage_ioctls,
+       .dma_ioctl = savage_bci_buffers,
+       .fops = {
+               .owner   = THIS_MODULE,
+               .open    = drm_open,
+               .release = drm_release,
+               .ioctl   = drm_ioctl,
+               .mmap    = drm_mmap,
+               .poll = drm_poll,
+               .fasync  = drm_fasync,
+       },
+       .pci_driver = {
+               .name          = DRIVER_NAME,
+               .id_table      = pciidlist,
+       }
+};
+
+static int __init savage_init(void)
+{
+       driver.num_ioctls = savage_max_ioctl;
+       return drm_init(&driver);
+}
+
+static void __exit savage_exit(void)
+{
+       drm_exit(&driver);
+}
+
+module_init(savage_init);
+module_exit(savage_exit);
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/char/drm/savage_drv.h b/drivers/char/drm/savage_drv.h
new file mode 100644 (file)
index 0000000..a454349
--- /dev/null
@@ -0,0 +1,579 @@
+/* savage_drv.h -- Private header for the savage driver
+ *
+ * Copyright 2004  Felix Kuehling
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT. IN NO EVENT SHALL FELIX KUEHLING BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __SAVAGE_DRV_H__
+#define __SAVAGE_DRV_H__
+
+#define DRIVER_AUTHOR  "Felix Kuehling"
+
+#define DRIVER_NAME    "savage"
+#define DRIVER_DESC    "Savage3D/MX/IX, Savage4, SuperSavage, Twister, ProSavage[DDR]"
+#define DRIVER_DATE    "20050313"
+
+#define DRIVER_MAJOR           2
+#define DRIVER_MINOR           4
+#define DRIVER_PATCHLEVEL      1
+/* Interface history:
+ *
+ * 1.x   The DRM driver from the VIA/S3 code drop, basically a dummy
+ * 2.0   The first real DRM
+ * 2.1   Scissors registers managed by the DRM, 3D operations clipped by
+ *       cliprects of the cmdbuf ioctl
+ * 2.2   Implemented SAVAGE_CMD_DMA_IDX and SAVAGE_CMD_VB_IDX
+ * 2.3   Event counters used by BCI_EVENT_EMIT/WAIT ioctls are now 32 bits
+ *       wide and thus very long lived (unlikely to ever wrap). The size
+ *       in the struct was 32 bits before, but only 16 bits were used
+ * 2.4   Implemented command DMA. Now drm_savage_init_t.cmd_dma_offset is
+ *       actually used
+ */
+
+typedef struct drm_savage_age {
+       uint16_t event;
+       unsigned int wrap;
+} drm_savage_age_t;
+
+typedef struct drm_savage_buf_priv {
+       struct drm_savage_buf_priv *next;
+       struct drm_savage_buf_priv *prev;
+       drm_savage_age_t age;
+       drm_buf_t *buf;
+} drm_savage_buf_priv_t;
+
+typedef struct drm_savage_dma_page {
+       drm_savage_age_t age;
+       unsigned int used, flushed;
+} drm_savage_dma_page_t;
+#define SAVAGE_DMA_PAGE_SIZE 1024 /* in dwords */
+/* Fake DMA buffer size in bytes. 4 pages. Allows a maximum command
+ * size of 16kbytes or 4k entries. Minimum requirement would be
+ * 10kbytes for 255 40-byte vertices in one drawing command. */
+#define SAVAGE_FAKE_DMA_SIZE (SAVAGE_DMA_PAGE_SIZE*4*4)
+
+/* interesting bits of hardware state that are saved in dev_priv */
+typedef union {
+       struct drm_savage_common_state {
+               uint32_t vbaddr;
+       } common;
+       struct {
+               unsigned char pad[sizeof(struct drm_savage_common_state)];
+               uint32_t texctrl, texaddr;
+               uint32_t scstart, new_scstart;
+               uint32_t scend, new_scend;
+       } s3d;
+       struct {
+               unsigned char pad[sizeof(struct drm_savage_common_state)];
+               uint32_t texdescr, texaddr0, texaddr1;
+               uint32_t drawctrl0, new_drawctrl0;
+               uint32_t drawctrl1, new_drawctrl1;
+       } s4;
+} drm_savage_state_t;
+
+/* these chip tags should match the ones in the 2D driver in savage_regs.h. */
+enum savage_family {
+       S3_UNKNOWN = 0,
+       S3_SAVAGE3D,
+       S3_SAVAGE_MX,
+       S3_SAVAGE4,
+       S3_PROSAVAGE,
+       S3_TWISTER,
+       S3_PROSAVAGEDDR,
+       S3_SUPERSAVAGE,
+       S3_SAVAGE2000,
+       S3_LAST
+};
+
+#define S3_SAVAGE3D_SERIES(chip)  ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE_MX))
+
+#define S3_SAVAGE4_SERIES(chip)  ((chip==S3_SAVAGE4)            \
+                                  || (chip==S3_PROSAVAGE)       \
+                                  || (chip==S3_TWISTER)         \
+                                  || (chip==S3_PROSAVAGEDDR))
+
+#define        S3_SAVAGE_MOBILE_SERIES(chip)   ((chip==S3_SAVAGE_MX) || (chip==S3_SUPERSAVAGE))
+
+#define S3_SAVAGE_SERIES(chip)    ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE2000))
+
+#define S3_MOBILE_TWISTER_SERIES(chip)   ((chip==S3_TWISTER)    \
+                                          ||(chip==S3_PROSAVAGEDDR))
+
+/* flags */
+#define SAVAGE_IS_AGP 1
+
+typedef struct drm_savage_private {
+       drm_savage_sarea_t *sarea_priv;
+
+       drm_savage_buf_priv_t head, tail;
+
+       /* who am I? */
+       enum savage_family chipset;
+
+       unsigned int cob_size;
+       unsigned int bci_threshold_lo, bci_threshold_hi;
+       unsigned int dma_type;
+
+       /* frame buffer layout */
+       unsigned int fb_bpp;
+       unsigned int front_offset, front_pitch;
+       unsigned int back_offset, back_pitch;
+       unsigned int depth_bpp;
+       unsigned int depth_offset, depth_pitch;
+
+       /* bitmap descriptors for swap and clear */
+       unsigned int front_bd, back_bd, depth_bd;
+
+       /* local textures */
+       unsigned int texture_offset;
+       unsigned int texture_size;
+
+       /* memory regions in physical memory */
+       drm_local_map_t *sarea;
+       drm_local_map_t *mmio;
+       drm_local_map_t *fb;
+       drm_local_map_t *aperture;
+       drm_local_map_t *status;
+       drm_local_map_t *agp_textures;
+       drm_local_map_t *cmd_dma;
+       drm_local_map_t fake_dma;
+
+       struct {
+               int handle;
+               unsigned long base, size;
+       } mtrr[3];
+
+       /* BCI and status-related stuff */
+       volatile uint32_t *status_ptr, *bci_ptr;
+       uint32_t status_used_mask;
+       uint16_t event_counter;
+       unsigned int event_wrap;
+
+       /* Savage4 command DMA */
+       drm_savage_dma_page_t *dma_pages;
+       unsigned int nr_dma_pages, first_dma_page, current_dma_page;
+       drm_savage_age_t last_dma_age;
+
+       /* saved hw state for global/local check on S3D */
+       uint32_t hw_draw_ctrl, hw_zbuf_ctrl;
+       /* and for scissors (global, so don't emit if not changed) */
+       uint32_t hw_scissors_start, hw_scissors_end;
+
+       drm_savage_state_t state;
+
+       /* after emitting a wait cmd Savage3D needs 63 nops before next DMA */
+       unsigned int waiting;
+
+       /* config/hardware-dependent function pointers */
+       int (*wait_fifo)(struct drm_savage_private *dev_priv, unsigned int n);
+       int (*wait_evnt)(struct drm_savage_private *dev_priv, uint16_t e);
+       /* Err, there is a macro wait_event in include/linux/wait.h.
+        * Avoid unwanted macro expansion. */
+       void (*emit_clip_rect)(struct drm_savage_private *dev_priv,
+                              drm_clip_rect_t *pbox);
+       void (*dma_flush)(struct drm_savage_private *dev_priv);
+} drm_savage_private_t;
+
+/* ioctls */
+extern int savage_bci_cmdbuf(DRM_IOCTL_ARGS);
+extern int savage_bci_buffers(DRM_IOCTL_ARGS);
+
+/* BCI functions */
+extern uint16_t savage_bci_emit_event(drm_savage_private_t *dev_priv,
+                                     unsigned int flags);
+extern void savage_freelist_put(drm_device_t *dev, drm_buf_t *buf);
+extern void savage_dma_reset(drm_savage_private_t *dev_priv);
+extern void savage_dma_wait(drm_savage_private_t *dev_priv, unsigned int page);
+extern uint32_t *savage_dma_alloc(drm_savage_private_t *dev_priv,
+                                 unsigned int n);
+extern int savage_preinit(drm_device_t *dev, unsigned long chipset);
+extern int savage_postcleanup(drm_device_t *dev);
+extern int savage_do_cleanup_bci(drm_device_t *dev);
+extern void savage_reclaim_buffers(drm_device_t *dev, DRMFILE filp);
+
+/* state functions */
+extern void savage_emit_clip_rect_s3d(drm_savage_private_t *dev_priv,
+                                     drm_clip_rect_t *pbox);
+extern void savage_emit_clip_rect_s4(drm_savage_private_t *dev_priv,
+                                    drm_clip_rect_t *pbox);
+
+#define SAVAGE_FB_SIZE_S3      0x01000000      /*  16MB */
+#define SAVAGE_FB_SIZE_S4      0x02000000      /*  32MB */
+#define SAVAGE_MMIO_SIZE        0x00080000     /* 512kB */
+#define SAVAGE_APERTURE_OFFSET  0x02000000     /*  32MB */
+#define SAVAGE_APERTURE_SIZE    0x05000000     /* 5 tiled surfaces, 16MB each */
+
+#define SAVAGE_BCI_OFFSET       0x00010000      /* offset of the BCI region
+                                                * inside the MMIO region */
+#define SAVAGE_BCI_FIFO_SIZE   32              /* number of entries in on-chip
+                                                * BCI FIFO */
+
+/*
+ * MMIO registers
+ */
+#define SAVAGE_STATUS_WORD0            0x48C00
+#define SAVAGE_STATUS_WORD1            0x48C04
+#define SAVAGE_ALT_STATUS_WORD0        0x48C60
+
+#define SAVAGE_FIFO_USED_MASK_S3D      0x0001ffff
+#define SAVAGE_FIFO_USED_MASK_S4       0x001fffff
+
+/* Copied from savage_bci.h in the 2D driver with some renaming. */
+
+/* Bitmap descriptors */
+#define SAVAGE_BD_STRIDE_SHIFT 0
+#define SAVAGE_BD_BPP_SHIFT   16
+#define SAVAGE_BD_TILE_SHIFT  24
+#define SAVAGE_BD_BW_DISABLE  (1<<28)
+/* common: */
+#define        SAVAGE_BD_TILE_LINEAR           0
+/* savage4, MX, IX, 3D */
+#define        SAVAGE_BD_TILE_16BPP            2
+#define        SAVAGE_BD_TILE_32BPP            3
+/* twister, prosavage, DDR, supersavage, 2000 */
+#define        SAVAGE_BD_TILE_DEST             1
+#define        SAVAGE_BD_TILE_TEXTURE          2
+/* GBD - BCI enable */
+/* savage4, MX, IX, 3D */
+#define SAVAGE_GBD_BCI_ENABLE                    8
+/* twister, prosavage, DDR, supersavage, 2000 */
+#define SAVAGE_GBD_BCI_ENABLE_TWISTER            0
+
+#define SAVAGE_GBD_BIG_ENDIAN                    4
+#define SAVAGE_GBD_LITTLE_ENDIAN                 0
+#define SAVAGE_GBD_64                            1
+
+/*  Global Bitmap Descriptor */
+#define SAVAGE_BCI_GLB_BD_LOW             0x8168
+#define SAVAGE_BCI_GLB_BD_HIGH            0x816C
+
+/*
+ * BCI registers
+ */
+/* Savage4/Twister/ProSavage 3D registers */
+#define SAVAGE_DRAWLOCALCTRL_S4                0x1e
+#define SAVAGE_TEXPALADDR_S4           0x1f
+#define SAVAGE_TEXCTRL0_S4             0x20
+#define SAVAGE_TEXCTRL1_S4             0x21
+#define SAVAGE_TEXADDR0_S4             0x22
+#define SAVAGE_TEXADDR1_S4             0x23
+#define SAVAGE_TEXBLEND0_S4            0x24
+#define SAVAGE_TEXBLEND1_S4            0x25
+#define SAVAGE_TEXXPRCLR_S4            0x26 /* never used */
+#define SAVAGE_TEXDESCR_S4             0x27
+#define SAVAGE_FOGTABLE_S4             0x28
+#define SAVAGE_FOGCTRL_S4              0x30
+#define SAVAGE_STENCILCTRL_S4          0x31
+#define SAVAGE_ZBUFCTRL_S4             0x32
+#define SAVAGE_ZBUFOFF_S4              0x33
+#define SAVAGE_DESTCTRL_S4             0x34
+#define SAVAGE_DRAWCTRL0_S4            0x35
+#define SAVAGE_DRAWCTRL1_S4            0x36
+#define SAVAGE_ZWATERMARK_S4           0x37
+#define SAVAGE_DESTTEXRWWATERMARK_S4   0x38
+#define SAVAGE_TEXBLENDCOLOR_S4                0x39
+/* Savage3D/MX/IX 3D registers */
+#define SAVAGE_TEXPALADDR_S3D          0x18
+#define SAVAGE_TEXXPRCLR_S3D           0x19 /* never used */
+#define SAVAGE_TEXADDR_S3D             0x1A
+#define SAVAGE_TEXDESCR_S3D            0x1B
+#define SAVAGE_TEXCTRL_S3D             0x1C
+#define SAVAGE_FOGTABLE_S3D            0x20
+#define SAVAGE_FOGCTRL_S3D             0x30
+#define SAVAGE_DRAWCTRL_S3D            0x31
+#define SAVAGE_ZBUFCTRL_S3D            0x32
+#define SAVAGE_ZBUFOFF_S3D             0x33
+#define SAVAGE_DESTCTRL_S3D            0x34
+#define SAVAGE_SCSTART_S3D             0x35
+#define SAVAGE_SCEND_S3D               0x36
+#define SAVAGE_ZWATERMARK_S3D          0x37 
+#define SAVAGE_DESTTEXRWWATERMARK_S3D  0x38
+/* common stuff */
+#define SAVAGE_VERTBUFADDR             0x3e
+#define SAVAGE_BITPLANEWTMASK          0xd7
+#define SAVAGE_DMABUFADDR              0x51
+
+/* texture enable bits (needed for tex addr checking) */
+#define SAVAGE_TEXCTRL_TEXEN_MASK      0x00010000 /* S3D */
+#define SAVAGE_TEXDESCR_TEX0EN_MASK    0x02000000 /* S4 */
+#define SAVAGE_TEXDESCR_TEX1EN_MASK    0x04000000 /* S4 */
+
+/* Global fields in Savage4/Twister/ProSavage 3D registers:
+ *
+ * All texture registers and DrawLocalCtrl are local. All other
+ * registers are global. */
+
+/* Global fields in Savage3D/MX/IX 3D registers:
+ *
+ * All texture registers are local. DrawCtrl and ZBufCtrl are
+ * partially local. All other registers are global.
+ *
+ * DrawCtrl global fields: cullMode, alphaTestCmpFunc, alphaTestEn, alphaRefVal
+ * ZBufCtrl global fields: zCmpFunc, zBufEn
+ */
+#define SAVAGE_DRAWCTRL_S3D_GLOBAL     0x03f3c00c
+#define SAVAGE_ZBUFCTRL_S3D_GLOBAL     0x00000027
+
+/* Masks for scissor bits (drawCtrl[01] on s4, scissorStart/End on s3d)
+ */
+#define SAVAGE_SCISSOR_MASK_S4         0x00fff7ff
+#define SAVAGE_SCISSOR_MASK_S3D                0x07ff07ff
+
+/*
+ * BCI commands
+ */
+#define BCI_CMD_NOP                  0x40000000
+#define BCI_CMD_RECT                 0x48000000
+#define BCI_CMD_RECT_XP              0x01000000
+#define BCI_CMD_RECT_YP              0x02000000
+#define BCI_CMD_SCANLINE             0x50000000
+#define BCI_CMD_LINE                 0x5C000000
+#define BCI_CMD_LINE_LAST_PIXEL      0x58000000
+#define BCI_CMD_BYTE_TEXT            0x63000000
+#define BCI_CMD_NT_BYTE_TEXT         0x67000000
+#define BCI_CMD_BIT_TEXT             0x6C000000
+#define BCI_CMD_GET_ROP(cmd)         (((cmd) >> 16) & 0xFF)
+#define BCI_CMD_SET_ROP(cmd, rop)    ((cmd) |= ((rop & 0xFF) << 16))
+#define BCI_CMD_SEND_COLOR           0x00008000
+
+#define BCI_CMD_CLIP_NONE            0x00000000
+#define BCI_CMD_CLIP_CURRENT         0x00002000
+#define BCI_CMD_CLIP_LR              0x00004000
+#define BCI_CMD_CLIP_NEW             0x00006000
+
+#define BCI_CMD_DEST_GBD             0x00000000
+#define BCI_CMD_DEST_PBD             0x00000800
+#define BCI_CMD_DEST_PBD_NEW         0x00000C00
+#define BCI_CMD_DEST_SBD             0x00001000
+#define BCI_CMD_DEST_SBD_NEW         0x00001400
+
+#define BCI_CMD_SRC_TRANSPARENT      0x00000200
+#define BCI_CMD_SRC_SOLID            0x00000000
+#define BCI_CMD_SRC_GBD              0x00000020
+#define BCI_CMD_SRC_COLOR            0x00000040
+#define BCI_CMD_SRC_MONO             0x00000060
+#define BCI_CMD_SRC_PBD_COLOR        0x00000080
+#define BCI_CMD_SRC_PBD_MONO         0x000000A0
+#define BCI_CMD_SRC_PBD_COLOR_NEW    0x000000C0
+#define BCI_CMD_SRC_PBD_MONO_NEW     0x000000E0
+#define BCI_CMD_SRC_SBD_COLOR        0x00000100
+#define BCI_CMD_SRC_SBD_MONO         0x00000120
+#define BCI_CMD_SRC_SBD_COLOR_NEW    0x00000140
+#define BCI_CMD_SRC_SBD_MONO_NEW     0x00000160
+
+#define BCI_CMD_PAT_TRANSPARENT      0x00000010
+#define BCI_CMD_PAT_NONE             0x00000000
+#define BCI_CMD_PAT_COLOR            0x00000002
+#define BCI_CMD_PAT_MONO             0x00000003
+#define BCI_CMD_PAT_PBD_COLOR        0x00000004
+#define BCI_CMD_PAT_PBD_MONO         0x00000005
+#define BCI_CMD_PAT_PBD_COLOR_NEW    0x00000006
+#define BCI_CMD_PAT_PBD_MONO_NEW     0x00000007
+#define BCI_CMD_PAT_SBD_COLOR        0x00000008
+#define BCI_CMD_PAT_SBD_MONO         0x00000009
+#define BCI_CMD_PAT_SBD_COLOR_NEW    0x0000000A
+#define BCI_CMD_PAT_SBD_MONO_NEW     0x0000000B
+
+#define BCI_BD_BW_DISABLE            0x10000000
+#define BCI_BD_TILE_MASK             0x03000000
+#define BCI_BD_TILE_NONE             0x00000000
+#define BCI_BD_TILE_16               0x02000000
+#define BCI_BD_TILE_32               0x03000000
+#define BCI_BD_GET_BPP(bd)           (((bd) >> 16) & 0xFF)
+#define BCI_BD_SET_BPP(bd, bpp)      ((bd) |= (((bpp) & 0xFF) << 16))
+#define BCI_BD_GET_STRIDE(bd)        ((bd) & 0xFFFF)
+#define BCI_BD_SET_STRIDE(bd, st)    ((bd) |= ((st) & 0xFFFF))
+
+#define BCI_CMD_SET_REGISTER            0x96000000
+
+#define BCI_CMD_WAIT                    0xC0000000
+#define BCI_CMD_WAIT_3D                 0x00010000
+#define BCI_CMD_WAIT_2D                 0x00020000
+
+#define BCI_CMD_UPDATE_EVENT_TAG        0x98000000
+
+#define BCI_CMD_DRAW_PRIM               0x80000000
+#define BCI_CMD_DRAW_INDEXED_PRIM       0x88000000
+#define BCI_CMD_DRAW_CONT               0x01000000
+#define BCI_CMD_DRAW_TRILIST            0x00000000
+#define BCI_CMD_DRAW_TRISTRIP           0x02000000
+#define BCI_CMD_DRAW_TRIFAN             0x04000000
+#define BCI_CMD_DRAW_SKIPFLAGS          0x000000ff
+#define BCI_CMD_DRAW_NO_Z              0x00000001
+#define BCI_CMD_DRAW_NO_W              0x00000002
+#define BCI_CMD_DRAW_NO_CD             0x00000004
+#define BCI_CMD_DRAW_NO_CS             0x00000008
+#define BCI_CMD_DRAW_NO_U0             0x00000010
+#define BCI_CMD_DRAW_NO_V0             0x00000020
+#define BCI_CMD_DRAW_NO_UV0            0x00000030
+#define BCI_CMD_DRAW_NO_U1             0x00000040
+#define BCI_CMD_DRAW_NO_V1             0x00000080
+#define BCI_CMD_DRAW_NO_UV1            0x000000c0
+
+#define BCI_CMD_DMA                    0xa8000000
+
+#define BCI_W_H(w, h)                ((((h) << 16) | (w)) & 0x0FFF0FFF)
+#define BCI_X_Y(x, y)                ((((y) << 16) | (x)) & 0x0FFF0FFF)
+#define BCI_X_W(x, y)                ((((w) << 16) | (x)) & 0x0FFF0FFF)
+#define BCI_CLIP_LR(l, r)            ((((r) << 16) | (l)) & 0x0FFF0FFF)
+#define BCI_CLIP_TL(t, l)            ((((t) << 16) | (l)) & 0x0FFF0FFF)
+#define BCI_CLIP_BR(b, r)            ((((b) << 16) | (r)) & 0x0FFF0FFF)
+
+#define BCI_LINE_X_Y(x, y)           (((y) << 16) | ((x) & 0xFFFF))
+#define BCI_LINE_STEPS(diag, axi)    (((axi) << 16) | ((diag) & 0xFFFF))
+#define BCI_LINE_MISC(maj, ym, xp, yp, err) \
+       (((maj) & 0x1FFF) | \
+       ((ym) ? 1<<13 : 0) | \
+       ((xp) ? 1<<14 : 0) | \
+       ((yp) ? 1<<15 : 0) | \
+       ((err) << 16))
+
+/*
+ * common commands
+ */
+#define BCI_SET_REGISTERS( first, n )                  \
+       BCI_WRITE(BCI_CMD_SET_REGISTER |                \
+                 ((uint32_t)(n) & 0xff) << 16 |        \
+                 ((uint32_t)(first) & 0xffff))
+#define DMA_SET_REGISTERS( first, n )                  \
+       DMA_WRITE(BCI_CMD_SET_REGISTER |                \
+                 ((uint32_t)(n) & 0xff) << 16 |        \
+                 ((uint32_t)(first) & 0xffff))
+
+#define BCI_DRAW_PRIMITIVE(n, type, skip)         \
+        BCI_WRITE(BCI_CMD_DRAW_PRIM | (type) | (skip) | \
+                 ((n) << 16))
+#define DMA_DRAW_PRIMITIVE(n, type, skip)         \
+        DMA_WRITE(BCI_CMD_DRAW_PRIM | (type) | (skip) | \
+                 ((n) << 16))
+
+#define BCI_DRAW_INDICES_S3D(n, type, i0)         \
+        BCI_WRITE(BCI_CMD_DRAW_INDEXED_PRIM | (type) |  \
+                 ((n) << 16) | (i0))
+
+#define BCI_DRAW_INDICES_S4(n, type, skip)        \
+        BCI_WRITE(BCI_CMD_DRAW_INDEXED_PRIM | (type) |  \
+                  (skip) | ((n) << 16))
+
+#define BCI_DMA(n)     \
+       BCI_WRITE(BCI_CMD_DMA | (((n) >> 1) - 1))
+
+/*
+ * access to MMIO
+ */
+#define SAVAGE_READ(reg)       DRM_READ32(  dev_priv->mmio, (reg) )
+#define SAVAGE_WRITE(reg)      DRM_WRITE32( dev_priv->mmio, (reg) )
+
+/*
+ * access to the burst command interface (BCI)
+ */
+#define SAVAGE_BCI_DEBUG 1
+
+#define BCI_LOCALS    volatile uint32_t *bci_ptr;
+
+#define BEGIN_BCI( n ) do {                    \
+       dev_priv->wait_fifo(dev_priv, (n));     \
+       bci_ptr = dev_priv->bci_ptr;            \
+} while(0)
+
+#define BCI_WRITE( val ) *bci_ptr++ = (uint32_t)(val)
+
+#define BCI_COPY_FROM_USER(src,n) do {                         \
+    unsigned int i;                                            \
+    for (i = 0; i < n; ++i) {                                  \
+       uint32_t val;                                           \
+       DRM_GET_USER_UNCHECKED(val, &((uint32_t*)(src))[i]);    \
+       BCI_WRITE(val);                                         \
+    }                                                          \
+} while(0)
+
+/*
+ * command DMA support
+ */
+#define SAVAGE_DMA_DEBUG 1
+
+#define DMA_LOCALS   uint32_t *dma_ptr;
+
+#define BEGIN_DMA( n ) do {                                            \
+       unsigned int cur = dev_priv->current_dma_page;                  \
+       unsigned int rest = SAVAGE_DMA_PAGE_SIZE -                      \
+               dev_priv->dma_pages[cur].used;                          \
+       if ((n) > rest) {                                               \
+               dma_ptr = savage_dma_alloc(dev_priv, (n));              \
+       } else { /* fast path for small allocations */                  \
+               dma_ptr = (uint32_t *)dev_priv->cmd_dma->handle +       \
+                       cur * SAVAGE_DMA_PAGE_SIZE +                    \
+                       dev_priv->dma_pages[cur].used;                  \
+               if (dev_priv->dma_pages[cur].used == 0)                 \
+                       savage_dma_wait(dev_priv, cur);                 \
+               dev_priv->dma_pages[cur].used += (n);                   \
+       }                                                               \
+} while(0)
+
+#define DMA_WRITE( val ) *dma_ptr++ = (uint32_t)(val)
+
+#define DMA_COPY_FROM_USER(src,n) do {                         \
+       DRM_COPY_FROM_USER_UNCHECKED(dma_ptr, (src), (n)*4);    \
+       dma_ptr += n;                                           \
+} while(0)
+
+#if SAVAGE_DMA_DEBUG
+#define DMA_COMMIT() do {                                              \
+       unsigned int cur = dev_priv->current_dma_page;                  \
+       uint32_t *expected = (uint32_t *)dev_priv->cmd_dma->handle +    \
+                       cur * SAVAGE_DMA_PAGE_SIZE +                    \
+                       dev_priv->dma_pages[cur].used;                  \
+       if (dma_ptr != expected) {                                      \
+               DRM_ERROR("DMA allocation and use don't match: "        \
+                         "%p != %p\n", expected, dma_ptr);             \
+               savage_dma_reset(dev_priv);                             \
+       }                                                               \
+} while(0)
+#else
+#define DMA_COMMIT() do {/* nothing */} while(0)
+#endif
+
+#define DMA_FLUSH() dev_priv->dma_flush(dev_priv)
+
+/* Buffer aging via event tag
+ */
+
+#define UPDATE_EVENT_COUNTER( ) do {                   \
+       if (dev_priv->status_ptr) {                     \
+               uint16_t count;                         \
+               /* coordinate with Xserver */           \
+               count = dev_priv->status_ptr[1023];     \
+               if (count < dev_priv->event_counter)    \
+                       dev_priv->event_wrap++;         \
+               dev_priv->event_counter = count;        \
+       }                                               \
+} while(0)
+
+#define SET_AGE( age, e, w ) do {      \
+       (age)->event = e;               \
+       (age)->wrap = w;                \
+} while(0)
+
+#define TEST_AGE( age, e, w )                          \
+       ( (age)->wrap < (w) || ( (age)->wrap == (w) && (age)->event <= (e) ) )
+
+#endif /* __SAVAGE_DRV_H__ */
diff --git a/drivers/char/drm/savage_state.c b/drivers/char/drm/savage_state.c
new file mode 100644 (file)
index 0000000..475695a
--- /dev/null
@@ -0,0 +1,1146 @@
+/* savage_state.c -- State and drawing support for Savage
+ *
+ * Copyright 2004  Felix Kuehling
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT. IN NO EVENT SHALL FELIX KUEHLING BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "drmP.h"
+#include "savage_drm.h"
+#include "savage_drv.h"
+
+void savage_emit_clip_rect_s3d(drm_savage_private_t *dev_priv,
+                              drm_clip_rect_t *pbox)
+{
+       uint32_t scstart = dev_priv->state.s3d.new_scstart;
+       uint32_t scend   = dev_priv->state.s3d.new_scend;
+       scstart = (scstart & ~SAVAGE_SCISSOR_MASK_S3D) |
+               ((uint32_t)pbox->x1 & 0x000007ff) | 
+               (((uint32_t)pbox->y1 << 16) & 0x07ff0000);
+       scend   = (scend   & ~SAVAGE_SCISSOR_MASK_S3D) |
+               (((uint32_t)pbox->x2-1) & 0x000007ff) |
+               ((((uint32_t)pbox->y2-1) << 16) & 0x07ff0000);
+       if (scstart != dev_priv->state.s3d.scstart ||
+           scend   != dev_priv->state.s3d.scend) {
+               DMA_LOCALS;
+               BEGIN_DMA(4);
+               DMA_WRITE(BCI_CMD_WAIT|BCI_CMD_WAIT_3D);
+               DMA_SET_REGISTERS(SAVAGE_SCSTART_S3D, 2);
+               DMA_WRITE(scstart);
+               DMA_WRITE(scend);
+               dev_priv->state.s3d.scstart = scstart;
+               dev_priv->state.s3d.scend   = scend;
+               dev_priv->waiting = 1;
+               DMA_COMMIT();
+       }
+}
+
+void savage_emit_clip_rect_s4(drm_savage_private_t *dev_priv,
+                             drm_clip_rect_t *pbox)
+{
+       uint32_t drawctrl0 = dev_priv->state.s4.new_drawctrl0;
+       uint32_t drawctrl1 = dev_priv->state.s4.new_drawctrl1;
+       drawctrl0 = (drawctrl0 & ~SAVAGE_SCISSOR_MASK_S4) |
+               ((uint32_t)pbox->x1 & 0x000007ff) |
+               (((uint32_t)pbox->y1 << 12) & 0x00fff000);
+       drawctrl1 = (drawctrl1 & ~SAVAGE_SCISSOR_MASK_S4) |
+               (((uint32_t)pbox->x2-1) & 0x000007ff) |
+               ((((uint32_t)pbox->y2-1) << 12) & 0x00fff000);
+       if (drawctrl0 != dev_priv->state.s4.drawctrl0 ||
+           drawctrl1 != dev_priv->state.s4.drawctrl1) {
+               DMA_LOCALS;
+               BEGIN_DMA(4);
+               DMA_WRITE(BCI_CMD_WAIT|BCI_CMD_WAIT_3D);
+               DMA_SET_REGISTERS(SAVAGE_DRAWCTRL0_S4, 2);
+               DMA_WRITE(drawctrl0);
+               DMA_WRITE(drawctrl1);
+               dev_priv->state.s4.drawctrl0 = drawctrl0;
+               dev_priv->state.s4.drawctrl1 = drawctrl1;
+               dev_priv->waiting = 1;
+               DMA_COMMIT();
+       }
+}
+
+static int savage_verify_texaddr(drm_savage_private_t *dev_priv, int unit,
+                                uint32_t addr)
+{
+       if ((addr & 6) != 2) { /* reserved bits */
+               DRM_ERROR("bad texAddr%d %08x (reserved bits)\n", unit, addr);
+               return DRM_ERR(EINVAL);
+       }
+       if (!(addr & 1)) { /* local */
+               addr &= ~7;
+               if (addr <  dev_priv->texture_offset ||
+                   addr >= dev_priv->texture_offset+dev_priv->texture_size) {
+                       DRM_ERROR("bad texAddr%d %08x (local addr out of range)\n",
+                                 unit, addr);
+                       return DRM_ERR(EINVAL);
+               }
+       } else { /* AGP */
+               if (!dev_priv->agp_textures) {
+                       DRM_ERROR("bad texAddr%d %08x (AGP not available)\n",
+                                 unit, addr);
+                       return DRM_ERR(EINVAL);
+               }
+               addr &= ~7;
+               if (addr < dev_priv->agp_textures->offset ||
+                   addr >= (dev_priv->agp_textures->offset +
+                            dev_priv->agp_textures->size)) {
+                       DRM_ERROR("bad texAddr%d %08x (AGP addr out of range)\n",
+                                 unit, addr);
+                       return DRM_ERR(EINVAL);
+               }
+       }
+       return 0;
+}
+
+#define SAVE_STATE(reg,where)                  \
+       if(start <= reg && start+count > reg)   \
+               DRM_GET_USER_UNCHECKED(dev_priv->state.where, &regs[reg-start])
+#define SAVE_STATE_MASK(reg,where,mask) do {                   \
+       if(start <= reg && start+count > reg) {                 \
+               uint32_t tmp;                                   \
+               DRM_GET_USER_UNCHECKED(tmp, &regs[reg-start]);  \
+               dev_priv->state.where = (tmp & (mask)) |        \
+                       (dev_priv->state.where & ~(mask));      \
+       }                                                       \
+} while (0)
+static int savage_verify_state_s3d(drm_savage_private_t *dev_priv,
+                                  unsigned int start, unsigned int count,
+                                  const uint32_t __user *regs)
+{
+       if (start < SAVAGE_TEXPALADDR_S3D ||
+           start+count-1 > SAVAGE_DESTTEXRWWATERMARK_S3D) {
+               DRM_ERROR("invalid register range (0x%04x-0x%04x)\n",
+                         start, start+count-1);
+               return DRM_ERR(EINVAL);
+       }
+
+       SAVE_STATE_MASK(SAVAGE_SCSTART_S3D, s3d.new_scstart,
+                       ~SAVAGE_SCISSOR_MASK_S3D);
+       SAVE_STATE_MASK(SAVAGE_SCEND_S3D, s3d.new_scend,
+                       ~SAVAGE_SCISSOR_MASK_S3D);
+
+       /* if any texture regs were changed ... */
+       if (start <= SAVAGE_TEXCTRL_S3D &&
+           start+count > SAVAGE_TEXPALADDR_S3D) {
+               /* ... check texture state */
+               SAVE_STATE(SAVAGE_TEXCTRL_S3D, s3d.texctrl);
+               SAVE_STATE(SAVAGE_TEXADDR_S3D, s3d.texaddr);
+               if (dev_priv->state.s3d.texctrl & SAVAGE_TEXCTRL_TEXEN_MASK)
+                       return savage_verify_texaddr(
+                               dev_priv, 0, dev_priv->state.s3d.texaddr);
+       }
+
+       return 0;
+}
+
+static int savage_verify_state_s4(drm_savage_private_t *dev_priv,
+                                 unsigned int start, unsigned int count,
+                                 const uint32_t __user *regs)
+{
+       int ret = 0;
+
+       if (start < SAVAGE_DRAWLOCALCTRL_S4 ||
+           start+count-1 > SAVAGE_TEXBLENDCOLOR_S4) {
+               DRM_ERROR("invalid register range (0x%04x-0x%04x)\n",
+                         start, start+count-1);
+               return DRM_ERR(EINVAL);
+       }
+
+       SAVE_STATE_MASK(SAVAGE_DRAWCTRL0_S4, s4.new_drawctrl0,
+                       ~SAVAGE_SCISSOR_MASK_S4);
+       SAVE_STATE_MASK(SAVAGE_DRAWCTRL1_S4, s4.new_drawctrl1,
+                       ~SAVAGE_SCISSOR_MASK_S4);
+
+       /* if any texture regs were changed ... */
+       if (start <= SAVAGE_TEXDESCR_S4 &&
+           start+count > SAVAGE_TEXPALADDR_S4) {
+               /* ... check texture state */
+               SAVE_STATE(SAVAGE_TEXDESCR_S4, s4.texdescr);
+               SAVE_STATE(SAVAGE_TEXADDR0_S4, s4.texaddr0);
+               SAVE_STATE(SAVAGE_TEXADDR1_S4, s4.texaddr1);
+               if (dev_priv->state.s4.texdescr & SAVAGE_TEXDESCR_TEX0EN_MASK)
+                       ret |= savage_verify_texaddr(
+                               dev_priv, 0, dev_priv->state.s4.texaddr0);
+               if (dev_priv->state.s4.texdescr & SAVAGE_TEXDESCR_TEX1EN_MASK)
+                       ret |= savage_verify_texaddr(
+                               dev_priv, 1, dev_priv->state.s4.texaddr1);
+       }
+
+       return ret;
+}
+#undef SAVE_STATE
+#undef SAVE_STATE_MASK
+
+static int savage_dispatch_state(drm_savage_private_t *dev_priv,
+                                const drm_savage_cmd_header_t *cmd_header,
+                                const uint32_t __user *regs)
+{
+       unsigned int count = cmd_header->state.count;
+       unsigned int start = cmd_header->state.start;
+       unsigned int count2 = 0;
+       unsigned int bci_size;
+       int ret;
+       DMA_LOCALS;
+
+       if (!count)
+               return 0;
+
+       if (DRM_VERIFYAREA_READ(regs, count*4))
+               return DRM_ERR(EFAULT);
+
+       if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
+               ret = savage_verify_state_s3d(dev_priv, start, count, regs);
+               if (ret != 0)
+                       return ret;
+               /* scissor regs are emitted in savage_dispatch_draw */
+               if (start < SAVAGE_SCSTART_S3D) {
+                       if (start+count > SAVAGE_SCEND_S3D+1)
+                               count2 = count - (SAVAGE_SCEND_S3D+1 - start);
+                       if (start+count > SAVAGE_SCSTART_S3D)
+                               count = SAVAGE_SCSTART_S3D - start;
+               } else if (start <= SAVAGE_SCEND_S3D) {
+                       if (start+count > SAVAGE_SCEND_S3D+1) {
+                               count -= SAVAGE_SCEND_S3D+1 - start;
+                               start = SAVAGE_SCEND_S3D+1;
+                       } else
+                               return 0;
+               }
+       } else {
+               ret = savage_verify_state_s4(dev_priv, start, count, regs);
+               if (ret != 0)
+                       return ret;
+               /* scissor regs are emitted in savage_dispatch_draw */
+               if (start < SAVAGE_DRAWCTRL0_S4) {
+                       if (start+count > SAVAGE_DRAWCTRL1_S4+1)
+                               count2 = count - (SAVAGE_DRAWCTRL1_S4+1 - start);
+                       if (start+count > SAVAGE_DRAWCTRL0_S4)
+                               count = SAVAGE_DRAWCTRL0_S4 - start;
+               } else if (start <= SAVAGE_DRAWCTRL1_S4) {
+                       if (start+count > SAVAGE_DRAWCTRL1_S4+1) {
+                               count -= SAVAGE_DRAWCTRL1_S4+1 - start;
+                               start = SAVAGE_DRAWCTRL1_S4+1;
+                       } else
+                               return 0;
+               }
+       }
+
+       bci_size = count + (count+254)/255 + count2 + (count2+254)/255;
+
+       if (cmd_header->state.global) {
+               BEGIN_DMA(bci_size+1);
+               DMA_WRITE(BCI_CMD_WAIT | BCI_CMD_WAIT_3D);
+               dev_priv->waiting = 1;
+       } else {
+               BEGIN_DMA(bci_size);
+       }
+
+       do {
+               while (count > 0) {
+                       unsigned int n = count < 255 ? count : 255;
+                       DMA_SET_REGISTERS(start, n);
+                       DMA_COPY_FROM_USER(regs, n);
+                       count -= n;
+                       start += n;
+                       regs += n;
+               }
+               start += 2;
+               regs += 2;
+               count = count2;
+               count2 = 0;
+       } while (count);
+
+       DMA_COMMIT();
+
+       return 0;
+}
+
+static int savage_dispatch_dma_prim(drm_savage_private_t *dev_priv,
+                                   const drm_savage_cmd_header_t *cmd_header,
+                                   const drm_buf_t *dmabuf)
+{
+       unsigned char reorder = 0;
+       unsigned int prim = cmd_header->prim.prim;
+       unsigned int skip = cmd_header->prim.skip;
+       unsigned int n = cmd_header->prim.count;
+       unsigned int start = cmd_header->prim.start;
+       unsigned int i;
+       BCI_LOCALS;
+
+       if (!dmabuf) {
+           DRM_ERROR("called without dma buffers!\n");
+           return DRM_ERR(EINVAL);
+       }
+
+       if (!n)
+               return 0;
+
+       switch (prim) {
+       case SAVAGE_PRIM_TRILIST_201:
+               reorder = 1;
+               prim = SAVAGE_PRIM_TRILIST;
+       case SAVAGE_PRIM_TRILIST:
+               if (n % 3 != 0) {
+                       DRM_ERROR("wrong number of vertices %u in TRILIST\n",
+                                 n);
+                       return DRM_ERR(EINVAL);
+               }
+               break;
+       case SAVAGE_PRIM_TRISTRIP:
+       case SAVAGE_PRIM_TRIFAN:
+               if (n < 3) {
+                       DRM_ERROR("wrong number of vertices %u in TRIFAN/STRIP\n",
+                                 n);
+                       return DRM_ERR(EINVAL);
+               }
+               break;
+       default:
+               DRM_ERROR("invalid primitive type %u\n", prim);
+               return DRM_ERR(EINVAL);
+       }
+
+       if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
+               if (skip != 0) {
+                       DRM_ERROR("invalid skip flags 0x%04x for DMA\n",
+                                 skip);
+                       return DRM_ERR(EINVAL);
+               }
+       } else {
+               unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) -
+                       (skip >> 2 & 1) - (skip >> 3 & 1) - (skip >> 4 & 1) -
+                       (skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1);
+               if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) {
+                       DRM_ERROR("invalid skip flags 0x%04x for DMA\n",
+                                 skip);
+                       return DRM_ERR(EINVAL);
+               }
+               if (reorder) {
+                       DRM_ERROR("TRILIST_201 used on Savage4 hardware\n");
+                       return DRM_ERR(EINVAL);
+               }
+       }
+
+       if (start + n > dmabuf->total/32) {
+               DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n",
+                         start, start + n - 1, dmabuf->total/32);
+               return DRM_ERR(EINVAL);
+       }
+
+       /* Vertex DMA doesn't work with command DMA at the same time,
+        * so we use BCI_... to submit commands here. Flush buffered
+        * faked DMA first. */
+       DMA_FLUSH();
+
+       if (dmabuf->bus_address != dev_priv->state.common.vbaddr) {
+               BEGIN_BCI(2);
+               BCI_SET_REGISTERS(SAVAGE_VERTBUFADDR, 1);
+               BCI_WRITE(dmabuf->bus_address | dev_priv->dma_type);
+               dev_priv->state.common.vbaddr = dmabuf->bus_address;
+       }
+       if (S3_SAVAGE3D_SERIES(dev_priv->chipset) && dev_priv->waiting) {
+               /* Workaround for what looks like a hardware bug. If a
+                * WAIT_3D_IDLE was emitted some time before the
+                * indexed drawing command then the engine will lock
+                * up. There are two known workarounds:
+                * WAIT_IDLE_EMPTY or emit at least 63 NOPs. */
+               BEGIN_BCI(63);
+               for (i = 0; i < 63; ++i)
+                       BCI_WRITE(BCI_CMD_WAIT);
+               dev_priv->waiting = 0;
+       }
+
+       prim <<= 25;
+       while (n != 0) {
+               /* Can emit up to 255 indices (85 triangles) at once. */
+               unsigned int count = n > 255 ? 255 : n;
+               if (reorder) {
+                       /* Need to reorder indices for correct flat
+                        * shading while preserving the clock sense
+                        * for correct culling. Only on Savage3D. */
+                       int reorder[3] = {-1, -1, -1};
+                       reorder[start%3] = 2;
+
+                       BEGIN_BCI((count+1+1)/2);
+                       BCI_DRAW_INDICES_S3D(count, prim, start+2);
+
+                       for (i = start+1; i+1 < start+count; i += 2)
+                               BCI_WRITE((i + reorder[i % 3]) |
+                                         ((i+1 + reorder[(i+1) % 3]) << 16));
+                       if (i < start+count)
+                               BCI_WRITE(i + reorder[i%3]);
+               } else if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
+                       BEGIN_BCI((count+1+1)/2);
+                       BCI_DRAW_INDICES_S3D(count, prim, start);
+
+                       for (i = start+1; i+1 < start+count; i += 2)
+                               BCI_WRITE(i | ((i+1) << 16));
+                       if (i < start+count)
+                               BCI_WRITE(i);
+               } else {
+                       BEGIN_BCI((count+2+1)/2);
+                       BCI_DRAW_INDICES_S4(count, prim, skip);
+
+                       for (i = start; i+1 < start+count; i += 2)
+                               BCI_WRITE(i | ((i+1) << 16));
+                       if (i < start+count)
+                               BCI_WRITE(i);
+               }
+
+               start += count;
+               n -= count;
+
+               prim |= BCI_CMD_DRAW_CONT;
+       }
+
+       return 0;
+}
+
+static int savage_dispatch_vb_prim(drm_savage_private_t *dev_priv,
+                                  const drm_savage_cmd_header_t *cmd_header,
+                                  const uint32_t __user *vtxbuf,
+                                  unsigned int vb_size,
+                                  unsigned int vb_stride)
+{
+       unsigned char reorder = 0;
+       unsigned int prim = cmd_header->prim.prim;
+       unsigned int skip = cmd_header->prim.skip;
+       unsigned int n = cmd_header->prim.count;
+       unsigned int start = cmd_header->prim.start;
+       unsigned int vtx_size;
+       unsigned int i;
+       DMA_LOCALS;
+
+       if (!n)
+               return 0;
+
+       switch (prim) {
+       case SAVAGE_PRIM_TRILIST_201:
+               reorder = 1;
+               prim = SAVAGE_PRIM_TRILIST;
+       case SAVAGE_PRIM_TRILIST:
+               if (n % 3 != 0) {
+                       DRM_ERROR("wrong number of vertices %u in TRILIST\n",
+                                 n);
+                       return DRM_ERR(EINVAL);
+               }
+               break;
+       case SAVAGE_PRIM_TRISTRIP:
+       case SAVAGE_PRIM_TRIFAN:
+               if (n < 3) {
+                       DRM_ERROR("wrong number of vertices %u in TRIFAN/STRIP\n",
+                                 n);
+                       return DRM_ERR(EINVAL);
+               }
+               break;
+       default:
+               DRM_ERROR("invalid primitive type %u\n", prim);
+               return DRM_ERR(EINVAL);
+       }
+
+       if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
+               if (skip > SAVAGE_SKIP_ALL_S3D) {
+                       DRM_ERROR("invalid skip flags 0x%04x\n", skip);
+                       return DRM_ERR(EINVAL);
+               }
+               vtx_size = 8; /* full vertex */
+       } else {
+               if (skip > SAVAGE_SKIP_ALL_S4) {
+                       DRM_ERROR("invalid skip flags 0x%04x\n", skip);
+                       return DRM_ERR(EINVAL);
+               }
+               vtx_size = 10; /* full vertex */
+       }
+
+       vtx_size -= (skip & 1) + (skip >> 1 & 1) +
+               (skip >> 2 & 1) + (skip >> 3 & 1) + (skip >> 4 & 1) +
+               (skip >> 5 & 1) + (skip >> 6 & 1) + (skip >> 7 & 1);
+
+       if (vtx_size > vb_stride) {
+               DRM_ERROR("vertex size greater than vb stride (%u > %u)\n",
+                         vtx_size, vb_stride);
+               return DRM_ERR(EINVAL);
+       }
+
+       if (start + n > vb_size / (vb_stride*4)) {
+               DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n",
+                         start, start + n - 1, vb_size / (vb_stride*4));
+               return DRM_ERR(EINVAL);
+       }
+
+       prim <<= 25;
+       while (n != 0) {
+               /* Can emit up to 255 vertices (85 triangles) at once. */
+               unsigned int count = n > 255 ? 255 : n;
+               if (reorder) {
+                       /* Need to reorder vertices for correct flat
+                        * shading while preserving the clock sense
+                        * for correct culling. Only on Savage3D. */
+                       int reorder[3] = {-1, -1, -1};
+                       reorder[start%3] = 2;
+
+                       BEGIN_DMA(count*vtx_size+1);
+                       DMA_DRAW_PRIMITIVE(count, prim, skip);
+
+                       for (i = start; i < start+count; ++i) {
+                               unsigned int j = i + reorder[i % 3];
+                               DMA_COPY_FROM_USER(&vtxbuf[vb_stride*j],
+                                                  vtx_size);
+                       }
+
+                       DMA_COMMIT();
+               } else {
+                       BEGIN_DMA(count*vtx_size+1);
+                       DMA_DRAW_PRIMITIVE(count, prim, skip);
+
+                       if (vb_stride == vtx_size) {
+                               DMA_COPY_FROM_USER(&vtxbuf[vb_stride*start],
+                                                  vtx_size*count);
+                       } else {
+                               for (i = start; i < start+count; ++i) {
+                                       DMA_COPY_FROM_USER(
+                                               &vtxbuf[vb_stride*i],
+                                               vtx_size);
+                               }
+                       }
+
+                       DMA_COMMIT();
+               }
+
+               start += count;
+               n -= count;
+
+               prim |= BCI_CMD_DRAW_CONT;
+       }
+
+       return 0;
+}
+
+static int savage_dispatch_dma_idx(drm_savage_private_t *dev_priv,
+                                  const drm_savage_cmd_header_t *cmd_header,
+                                  const uint16_t __user *usr_idx,
+                                  const drm_buf_t *dmabuf)
+{
+       unsigned char reorder = 0;
+       unsigned int prim = cmd_header->idx.prim;
+       unsigned int skip = cmd_header->idx.skip;
+       unsigned int n = cmd_header->idx.count;
+       unsigned int i;
+       BCI_LOCALS;
+
+       if (!dmabuf) {
+           DRM_ERROR("called without dma buffers!\n");
+           return DRM_ERR(EINVAL);
+       }
+
+       if (!n)
+               return 0;
+
+       switch (prim) {
+       case SAVAGE_PRIM_TRILIST_201:
+               reorder = 1;
+               prim = SAVAGE_PRIM_TRILIST;
+       case SAVAGE_PRIM_TRILIST:
+               if (n % 3 != 0) {
+                       DRM_ERROR("wrong number of indices %u in TRILIST\n",
+                                 n);
+                       return DRM_ERR(EINVAL);
+               }
+               break;
+       case SAVAGE_PRIM_TRISTRIP:
+       case SAVAGE_PRIM_TRIFAN:
+               if (n < 3) {
+                       DRM_ERROR("wrong number of indices %u in TRIFAN/STRIP\n",
+                                 n);
+                       return DRM_ERR(EINVAL);
+               }
+               break;
+       default:
+               DRM_ERROR("invalid primitive type %u\n", prim);
+               return DRM_ERR(EINVAL);
+       }
+
+       if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
+               if (skip != 0) {
+                       DRM_ERROR("invalid skip flags 0x%04x for DMA\n",
+                                 skip);
+                       return DRM_ERR(EINVAL);
+               }
+       } else {
+               unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) -
+                       (skip >> 2 & 1) - (skip >> 3 & 1) - (skip >> 4 & 1) -
+                       (skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1);
+               if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) {
+                       DRM_ERROR("invalid skip flags 0x%04x for DMA\n",
+                                 skip);
+                       return DRM_ERR(EINVAL);
+               }
+               if (reorder) {
+                       DRM_ERROR("TRILIST_201 used on Savage4 hardware\n");
+                       return DRM_ERR(EINVAL);
+               }
+       }
+
+       /* Vertex DMA doesn't work with command DMA at the same time,
+        * so we use BCI_... to submit commands here. Flush buffered
+        * faked DMA first. */
+       DMA_FLUSH();
+
+       if (dmabuf->bus_address != dev_priv->state.common.vbaddr) {
+               BEGIN_BCI(2);
+               BCI_SET_REGISTERS(SAVAGE_VERTBUFADDR, 1);
+               BCI_WRITE(dmabuf->bus_address | dev_priv->dma_type);
+               dev_priv->state.common.vbaddr = dmabuf->bus_address;
+       }
+       if (S3_SAVAGE3D_SERIES(dev_priv->chipset) && dev_priv->waiting) {
+               /* Workaround for what looks like a hardware bug. If a
+                * WAIT_3D_IDLE was emitted some time before the
+                * indexed drawing command then the engine will lock
+                * up. There are two known workarounds:
+                * WAIT_IDLE_EMPTY or emit at least 63 NOPs. */
+               BEGIN_BCI(63);
+               for (i = 0; i < 63; ++i)
+                       BCI_WRITE(BCI_CMD_WAIT);
+               dev_priv->waiting = 0;
+       }
+
+       prim <<= 25;
+       while (n != 0) {
+               /* Can emit up to 255 indices (85 triangles) at once. */
+               unsigned int count = n > 255 ? 255 : n;
+               /* Is it ok to allocate 510 bytes on the stack in an ioctl? */
+               uint16_t idx[255];
+
+               /* Copy and check indices */
+               DRM_COPY_FROM_USER_UNCHECKED(idx, usr_idx, count*2);
+               for (i = 0; i < count; ++i) {
+                       if (idx[i] > dmabuf->total/32) {
+                               DRM_ERROR("idx[%u]=%u out of range (0-%u)\n",
+                                         i, idx[i], dmabuf->total/32);
+                               return DRM_ERR(EINVAL);
+                       }
+               }
+
+               if (reorder) {
+                       /* Need to reorder indices for correct flat
+                        * shading while preserving the clock sense
+                        * for correct culling. Only on Savage3D. */
+                       int reorder[3] = {2, -1, -1};
+
+                       BEGIN_BCI((count+1+1)/2);
+                       BCI_DRAW_INDICES_S3D(count, prim, idx[2]);
+
+                       for (i = 1; i+1 < count; i += 2)
+                               BCI_WRITE(idx[i + reorder[i % 3]] |
+                                         (idx[i+1 + reorder[(i+1) % 3]] << 16));
+                       if (i < count)
+                               BCI_WRITE(idx[i + reorder[i%3]]);
+               } else if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
+                       BEGIN_BCI((count+1+1)/2);
+                       BCI_DRAW_INDICES_S3D(count, prim, idx[0]);
+
+                       for (i = 1; i+1 < count; i += 2)
+                               BCI_WRITE(idx[i] | (idx[i+1] << 16));
+                       if (i < count)
+                               BCI_WRITE(idx[i]);
+               } else {
+                       BEGIN_BCI((count+2+1)/2);
+                       BCI_DRAW_INDICES_S4(count, prim, skip);
+
+                       for (i = 0; i+1 < count; i += 2)
+                               BCI_WRITE(idx[i] | (idx[i+1] << 16));
+                       if (i < count)
+                               BCI_WRITE(idx[i]);
+               }
+
+               usr_idx += count;
+               n -= count;
+
+               prim |= BCI_CMD_DRAW_CONT;
+       }
+
+       return 0;
+}
+
+static int savage_dispatch_vb_idx(drm_savage_private_t *dev_priv,
+                                 const drm_savage_cmd_header_t *cmd_header,
+                                 const uint16_t __user *usr_idx,
+                                 const uint32_t __user *vtxbuf,
+                                 unsigned int vb_size,
+                                 unsigned int vb_stride)
+{
+       unsigned char reorder = 0;
+       unsigned int prim = cmd_header->idx.prim;
+       unsigned int skip = cmd_header->idx.skip;
+       unsigned int n = cmd_header->idx.count;
+       unsigned int vtx_size;
+       unsigned int i;
+       DMA_LOCALS;
+
+       if (!n)
+               return 0;
+
+       switch (prim) {
+       case SAVAGE_PRIM_TRILIST_201:
+               reorder = 1;
+               prim = SAVAGE_PRIM_TRILIST;
+       case SAVAGE_PRIM_TRILIST:
+               if (n % 3 != 0) {
+                       DRM_ERROR("wrong number of indices %u in TRILIST\n",
+                                 n);
+                       return DRM_ERR(EINVAL);
+               }
+               break;
+       case SAVAGE_PRIM_TRISTRIP:
+       case SAVAGE_PRIM_TRIFAN:
+               if (n < 3) {
+                       DRM_ERROR("wrong number of indices %u in TRIFAN/STRIP\n",
+                                 n);
+                       return DRM_ERR(EINVAL);
+               }
+               break;
+       default:
+               DRM_ERROR("invalid primitive type %u\n", prim);
+               return DRM_ERR(EINVAL);
+       }
+
+       if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
+               if (skip > SAVAGE_SKIP_ALL_S3D) {
+                       DRM_ERROR("invalid skip flags 0x%04x\n", skip);
+                       return DRM_ERR(EINVAL);
+               }
+               vtx_size = 8; /* full vertex */
+       } else {
+               if (skip > SAVAGE_SKIP_ALL_S4) {
+                       DRM_ERROR("invalid skip flags 0x%04x\n", skip);
+                       return DRM_ERR(EINVAL);
+               }
+               vtx_size = 10; /* full vertex */
+       }
+
+       vtx_size -= (skip & 1) + (skip >> 1 & 1) +
+               (skip >> 2 & 1) + (skip >> 3 & 1) + (skip >> 4 & 1) +
+               (skip >> 5 & 1) + (skip >> 6 & 1) + (skip >> 7 & 1);
+
+       if (vtx_size > vb_stride) {
+               DRM_ERROR("vertex size greater than vb stride (%u > %u)\n",
+                         vtx_size, vb_stride);
+               return DRM_ERR(EINVAL);
+       }
+
+       prim <<= 25;
+       while (n != 0) {
+               /* Can emit up to 255 vertices (85 triangles) at once. */
+               unsigned int count = n > 255 ? 255 : n;
+               /* Is it ok to allocate 510 bytes on the stack in an ioctl? */
+               uint16_t idx[255];
+
+               /* Copy and check indices */
+               DRM_COPY_FROM_USER_UNCHECKED(idx, usr_idx, count*2);
+               for (i = 0; i < count; ++i) {
+                       if (idx[i] > vb_size / (vb_stride*4)) {
+                               DRM_ERROR("idx[%u]=%u out of range (0-%u)\n",
+                                         i, idx[i],  vb_size / (vb_stride*4));
+                               return DRM_ERR(EINVAL);
+                       }
+               }
+
+               if (reorder) {
+                       /* Need to reorder vertices for correct flat
+                        * shading while preserving the clock sense
+                        * for correct culling. Only on Savage3D. */
+                       int reorder[3] = {2, -1, -1};
+
+                       BEGIN_DMA(count*vtx_size+1);
+                       DMA_DRAW_PRIMITIVE(count, prim, skip);
+
+                       for (i = 0; i < count; ++i) {
+                               unsigned int j = idx[i + reorder[i % 3]];
+                               DMA_COPY_FROM_USER(&vtxbuf[vb_stride*j],
+                                                  vtx_size);
+                       }
+
+                       DMA_COMMIT();
+               } else {
+                       BEGIN_DMA(count*vtx_size+1);
+                       DMA_DRAW_PRIMITIVE(count, prim, skip);
+
+                       for (i = 0; i < count; ++i) {
+                               unsigned int j = idx[i];
+                               DMA_COPY_FROM_USER(&vtxbuf[vb_stride*j],
+                                                  vtx_size);
+                       }
+
+                       DMA_COMMIT();
+               }
+
+               usr_idx += count;
+               n -= count;
+
+               prim |= BCI_CMD_DRAW_CONT;
+       }
+
+       return 0;
+}
+
+static int savage_dispatch_clear(drm_savage_private_t *dev_priv,
+                                const drm_savage_cmd_header_t *cmd_header,
+                                const drm_savage_cmd_header_t __user *data,
+                                unsigned int nbox,
+                                const drm_clip_rect_t __user *usr_boxes)
+{
+       unsigned int flags = cmd_header->clear0.flags, mask, value;
+       unsigned int clear_cmd;
+       unsigned int i, nbufs;
+       DMA_LOCALS;
+
+       if (nbox == 0)
+               return 0;
+
+       DRM_GET_USER_UNCHECKED(mask, &((const drm_savage_cmd_header_t*)data)
+                              ->clear1.mask);
+       DRM_GET_USER_UNCHECKED(value, &((const drm_savage_cmd_header_t*)data)
+                              ->clear1.value);
+
+       clear_cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP |
+               BCI_CMD_SEND_COLOR | BCI_CMD_DEST_PBD_NEW;
+       BCI_CMD_SET_ROP(clear_cmd,0xCC);
+
+       nbufs = ((flags & SAVAGE_FRONT) ? 1 : 0) +
+               ((flags & SAVAGE_BACK) ? 1 : 0) +
+               ((flags & SAVAGE_DEPTH) ? 1 : 0);
+       if (nbufs == 0)
+               return 0;
+
+       if (mask != 0xffffffff) {
+               /* set mask */
+               BEGIN_DMA(2);
+               DMA_SET_REGISTERS(SAVAGE_BITPLANEWTMASK, 1);
+               DMA_WRITE(mask);
+               DMA_COMMIT();
+       }
+       for (i = 0; i < nbox; ++i) {
+               drm_clip_rect_t box;
+               unsigned int x, y, w, h;
+               unsigned int buf;
+               DRM_COPY_FROM_USER_UNCHECKED(&box, &usr_boxes[i], sizeof(box));
+               x = box.x1, y = box.y1;
+               w = box.x2 - box.x1;
+               h = box.y2 - box.y1;
+               BEGIN_DMA(nbufs*6);
+               for (buf = SAVAGE_FRONT; buf <= SAVAGE_DEPTH; buf <<= 1) {
+                       if (!(flags & buf))
+                               continue;
+                       DMA_WRITE(clear_cmd);
+                       switch(buf) {
+                       case SAVAGE_FRONT:
+                               DMA_WRITE(dev_priv->front_offset);
+                               DMA_WRITE(dev_priv->front_bd);
+                               break;
+                       case SAVAGE_BACK:
+                               DMA_WRITE(dev_priv->back_offset);
+                               DMA_WRITE(dev_priv->back_bd);
+                               break;
+                       case SAVAGE_DEPTH:
+                               DMA_WRITE(dev_priv->depth_offset);
+                               DMA_WRITE(dev_priv->depth_bd);
+                               break;
+                       }
+                       DMA_WRITE(value);
+                       DMA_WRITE(BCI_X_Y(x, y));
+                       DMA_WRITE(BCI_W_H(w, h));
+               }
+               DMA_COMMIT();
+       }
+       if (mask != 0xffffffff) {
+               /* reset mask */
+               BEGIN_DMA(2);
+               DMA_SET_REGISTERS(SAVAGE_BITPLANEWTMASK, 1);
+               DMA_WRITE(0xffffffff);
+               DMA_COMMIT();
+       }
+
+       return 0;
+}
+
+static int savage_dispatch_swap(drm_savage_private_t *dev_priv,
+                               unsigned int nbox,
+                               const drm_clip_rect_t __user *usr_boxes)
+{
+       unsigned int swap_cmd;
+       unsigned int i;
+       DMA_LOCALS;
+
+       if (nbox == 0)
+               return 0;
+
+       swap_cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP |
+               BCI_CMD_SRC_PBD_COLOR_NEW | BCI_CMD_DEST_GBD;
+       BCI_CMD_SET_ROP(swap_cmd,0xCC);
+
+       for (i = 0; i < nbox; ++i) {
+               drm_clip_rect_t box;
+               DRM_COPY_FROM_USER_UNCHECKED(&box, &usr_boxes[i], sizeof(box));
+
+               BEGIN_DMA(6);
+               DMA_WRITE(swap_cmd);
+               DMA_WRITE(dev_priv->back_offset);
+               DMA_WRITE(dev_priv->back_bd);
+               DMA_WRITE(BCI_X_Y(box.x1, box.y1));
+               DMA_WRITE(BCI_X_Y(box.x1, box.y1));
+               DMA_WRITE(BCI_W_H(box.x2-box.x1, box.y2-box.y1));
+               DMA_COMMIT();
+       }
+
+       return 0;
+}
+
+static int savage_dispatch_draw(drm_savage_private_t *dev_priv,
+                               const drm_savage_cmd_header_t __user *start,
+                               const drm_savage_cmd_header_t __user *end,
+                               const drm_buf_t *dmabuf,
+                               const unsigned int __user *usr_vtxbuf,
+                               unsigned int vb_size, unsigned int vb_stride,
+                               unsigned int nbox,
+                               const drm_clip_rect_t __user *usr_boxes)
+{
+       unsigned int i, j;
+       int ret;
+
+       for (i = 0; i < nbox; ++i) {
+               drm_clip_rect_t box;
+               const drm_savage_cmd_header_t __user *usr_cmdbuf;
+               DRM_COPY_FROM_USER_UNCHECKED(&box, &usr_boxes[i], sizeof(box));
+               dev_priv->emit_clip_rect(dev_priv, &box);
+
+               usr_cmdbuf = start;
+               while (usr_cmdbuf < end) {
+                       drm_savage_cmd_header_t cmd_header;
+                       DRM_COPY_FROM_USER_UNCHECKED(&cmd_header, usr_cmdbuf,
+                                                    sizeof(cmd_header));
+                       usr_cmdbuf++;
+                       switch (cmd_header.cmd.cmd) {
+                       case SAVAGE_CMD_DMA_PRIM:
+                               ret = savage_dispatch_dma_prim(
+                                       dev_priv, &cmd_header, dmabuf);
+                               break;
+                       case SAVAGE_CMD_VB_PRIM:
+                               ret = savage_dispatch_vb_prim(
+                                       dev_priv, &cmd_header,
+                                       (const uint32_t __user *)usr_vtxbuf,
+                                       vb_size, vb_stride);
+                               break;
+                       case SAVAGE_CMD_DMA_IDX:
+                               j = (cmd_header.idx.count + 3) / 4;
+                               /* j was check in savage_bci_cmdbuf */
+                               ret = savage_dispatch_dma_idx(
+                                       dev_priv, &cmd_header,
+                                       (const uint16_t __user *)usr_cmdbuf,
+                                       dmabuf);
+                               usr_cmdbuf += j;
+                               break;
+                       case SAVAGE_CMD_VB_IDX:
+                               j = (cmd_header.idx.count + 3) / 4;
+                               /* j was check in savage_bci_cmdbuf */
+                               ret = savage_dispatch_vb_idx(
+                                       dev_priv, &cmd_header,
+                                       (const uint16_t __user *)usr_cmdbuf,
+                                       (const uint32_t __user *)usr_vtxbuf,
+                                       vb_size, vb_stride);
+                               usr_cmdbuf += j;
+                               break;
+                       default:
+                               /* What's the best return code? EFAULT? */
+                               DRM_ERROR("IMPLEMENTATION ERROR: "
+                                         "non-drawing-command %d\n",
+                                         cmd_header.cmd.cmd);
+                               return DRM_ERR(EINVAL);
+                       }
+
+                       if (ret != 0)
+                               return ret;
+               }
+       }
+
+       return 0;
+}
+
+int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_savage_private_t *dev_priv = dev->dev_private;
+       drm_device_dma_t *dma = dev->dma;
+       drm_buf_t *dmabuf;
+       drm_savage_cmdbuf_t cmdbuf;
+       drm_savage_cmd_header_t __user *usr_cmdbuf;
+       drm_savage_cmd_header_t __user *first_draw_cmd;
+       unsigned int __user *usr_vtxbuf;
+       drm_clip_rect_t __user *usr_boxes;
+       unsigned int i, j;
+       int ret = 0;
+
+       DRM_DEBUG("\n");
+       
+       LOCK_TEST_WITH_RETURN(dev, filp);
+
+       DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_savage_cmdbuf_t __user *)data,
+                                sizeof(cmdbuf));
+
+       if (dma && dma->buflist) {
+               if (cmdbuf.dma_idx > dma->buf_count) {
+                       DRM_ERROR("vertex buffer index %u out of range (0-%u)\n",
+                                 cmdbuf.dma_idx, dma->buf_count-1);
+                       return DRM_ERR(EINVAL);
+               }
+               dmabuf = dma->buflist[cmdbuf.dma_idx];
+       } else {
+               dmabuf = NULL;
+       }
+
+       usr_cmdbuf = (drm_savage_cmd_header_t __user *)cmdbuf.cmd_addr;
+       usr_vtxbuf = (unsigned int __user *)cmdbuf.vb_addr;
+       usr_boxes = (drm_clip_rect_t __user *)cmdbuf.box_addr;
+       if ((cmdbuf.size && DRM_VERIFYAREA_READ(usr_cmdbuf, cmdbuf.size*8)) ||
+           (cmdbuf.vb_size && DRM_VERIFYAREA_READ(
+                   usr_vtxbuf, cmdbuf.vb_size)) ||
+           (cmdbuf.nbox && DRM_VERIFYAREA_READ(
+                   usr_boxes, cmdbuf.nbox*sizeof(drm_clip_rect_t))))
+               return DRM_ERR(EFAULT);
+
+       /* Make sure writes to DMA buffers are finished before sending
+        * DMA commands to the graphics hardware. */
+       DRM_MEMORYBARRIER();
+
+       /* Coming from user space. Don't know if the Xserver has
+        * emitted wait commands. Assuming the worst. */
+       dev_priv->waiting = 1;
+
+       i = 0;
+       first_draw_cmd = NULL;
+       while (i < cmdbuf.size) {
+               drm_savage_cmd_header_t cmd_header;
+               DRM_COPY_FROM_USER_UNCHECKED(&cmd_header, usr_cmdbuf,
+                                            sizeof(cmd_header));
+               usr_cmdbuf++;
+               i++;
+
+               /* Group drawing commands with same state to minimize
+                * iterations over clip rects. */
+               j = 0;
+               switch (cmd_header.cmd.cmd) {
+               case SAVAGE_CMD_DMA_IDX:
+               case SAVAGE_CMD_VB_IDX:
+                       j = (cmd_header.idx.count + 3) / 4;
+                       if (i + j > cmdbuf.size) {
+                               DRM_ERROR("indexed drawing command extends "
+                                         "beyond end of command buffer\n");
+                               DMA_FLUSH();
+                               return DRM_ERR(EINVAL);
+                       }
+                       /* fall through */
+               case SAVAGE_CMD_DMA_PRIM:
+               case SAVAGE_CMD_VB_PRIM:
+                       if (!first_draw_cmd)
+                               first_draw_cmd = usr_cmdbuf-1;
+                       usr_cmdbuf += j;
+                       i += j;
+                       break;
+               default:
+                       if (first_draw_cmd) {
+                               ret = savage_dispatch_draw (
+                                       dev_priv, first_draw_cmd, usr_cmdbuf-1,
+                                       dmabuf, usr_vtxbuf, cmdbuf.vb_size,
+                                       cmdbuf.vb_stride,
+                                       cmdbuf.nbox, usr_boxes);
+                               if (ret != 0)
+                                       return ret;
+                               first_draw_cmd = NULL;
+                       }
+               }
+               if (first_draw_cmd)
+                       continue;
+
+               switch (cmd_header.cmd.cmd) {
+               case SAVAGE_CMD_STATE:
+                       j = (cmd_header.state.count + 1) / 2;
+                       if (i + j > cmdbuf.size) {
+                               DRM_ERROR("command SAVAGE_CMD_STATE extends "
+                                         "beyond end of command buffer\n");
+                               DMA_FLUSH();
+                               return DRM_ERR(EINVAL);
+                       }
+                       ret = savage_dispatch_state(
+                               dev_priv, &cmd_header,
+                               (uint32_t __user *)usr_cmdbuf);
+                       usr_cmdbuf += j;
+                       i += j;
+                       break;
+               case SAVAGE_CMD_CLEAR:
+                       if (i + 1 > cmdbuf.size) {
+                               DRM_ERROR("command SAVAGE_CMD_CLEAR extends "
+                                         "beyond end of command buffer\n");
+                               DMA_FLUSH();
+                               return DRM_ERR(EINVAL);
+                       }
+                       ret = savage_dispatch_clear(dev_priv, &cmd_header,
+                                                   usr_cmdbuf,
+                                                   cmdbuf.nbox, usr_boxes);
+                       usr_cmdbuf++;
+                       i++;
+                       break;
+               case SAVAGE_CMD_SWAP:
+                       ret = savage_dispatch_swap(dev_priv,
+                                                  cmdbuf.nbox, usr_boxes);
+                       break;
+               default:
+                       DRM_ERROR("invalid command 0x%x\n", cmd_header.cmd.cmd);
+                       DMA_FLUSH();
+                       return DRM_ERR(EINVAL);
+               }
+
+               if (ret != 0) {
+                       DMA_FLUSH();
+                       return ret;
+               }
+       }
+
+       if (first_draw_cmd) {
+               ret = savage_dispatch_draw (
+                       dev_priv, first_draw_cmd, usr_cmdbuf, dmabuf,
+                       usr_vtxbuf, cmdbuf.vb_size, cmdbuf.vb_stride,
+                       cmdbuf.nbox, usr_boxes);
+               if (ret != 0) {
+                       DMA_FLUSH();
+                       return ret;
+               }
+       }
+
+       DMA_FLUSH();
+
+       if (dmabuf && cmdbuf.discard) {
+               drm_savage_buf_priv_t *buf_priv = dmabuf->dev_private;
+               uint16_t event;
+               event = savage_bci_emit_event(dev_priv, SAVAGE_WAIT_3D);
+               SET_AGE(&buf_priv->age, event, dev_priv->event_wrap);
+               savage_freelist_put(dev, dmabuf);
+       }
+
+       return 0;
+}
index 6d864c502a1f71f7c1ce57ab14718bc81b11fe9c..6b0e6464eb391130d1751be13620ae38fd7d5635 100644 (file)
@@ -40,7 +40,7 @@
  * FIXME: IO should be max 256 bytes.  However, since we may
  * have a P2P bridge below a cardbus bridge, we need 4K.
  */
-#define CARDBUS_IO_SIZE                (256)
+#define CARDBUS_IO_SIZE                (4*1024)
 #define CARDBUS_MEM_SIZE       (32*1024*1024)
 
 static void __devinit
index 1cae14e741eb53b768d9ec2ca80d7f1b904cbad1..49ccde3937f97ec7d8bf4e28cb2955dea69b08d4 100644 (file)
@@ -1390,6 +1390,8 @@ static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struc
 
        jfs_info("jfs_lookup: name = %s", name);
 
+       if (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2)
+               dentry->d_op = &jfs_ci_dentry_operations;
 
        if ((name[0] == '.') && (len == 1))
                inum = dip->i_ino;
@@ -1417,9 +1419,6 @@ static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struc
                return ERR_PTR(-EACCES);
        }
 
-       if (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2)
-               dentry->d_op = &jfs_ci_dentry_operations;
-
        dentry = d_splice_alias(ip, dentry);
 
        if (dentry && (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2))
index 428f59794f4877e87455d49e9de7cb1779eb4334..72b9af4c3fd48e822fb28a8d3d025115fc82ff62 100644 (file)
@@ -29,7 +29,9 @@
  *     Sound core interface functions
  */
  
+struct device;
 extern int register_sound_special(struct file_operations *fops, int unit);
+extern int register_sound_special_device(struct file_operations *fops, int unit, struct device *dev);
 extern int register_sound_mixer(struct file_operations *fops, int dev);
 extern int register_sound_midi(struct file_operations *fops, int dev);
 extern int register_sound_dsp(struct file_operations *fops, int dev);
index 1309c12b8f71274faf024a944a8244abf17ed5e3..2857cf0472df02116ff7e1c82ddc4a8906752752 100644 (file)
@@ -26,6 +26,7 @@
  */
 
 #include <linux/bitops.h>
+#include <linux/device.h>
 #include "pcm.h"
 #include "control.h"
 #include "info.h"
 #define AC97_HAS_NO_PC_BEEP    (1<<12) /* no PC Beep volume */
 #define AC97_HAS_NO_VIDEO      (1<<13) /* no Video volume */
 #define AC97_HAS_NO_CD         (1<<14) /* no CD volume */
+#define AC97_HAS_NO_MIC        (1<<15) /* no MIC volume */
+#define AC97_HAS_NO_TONE       (1<<16) /* no Tone volume */
+#define AC97_HAS_NO_STD_PCM    (1<<17) /* no standard AC97 PCM volume and mute */
 
 /* rates indexes */
 #define AC97_RATES_FRONT_DAC   0
@@ -520,6 +524,7 @@ struct _snd_ac97 {
        /* jack-sharing info */
        unsigned char indep_surround;
        unsigned char channel_mode;
+       struct device dev;
 };
 
 /* conditions */
@@ -599,4 +604,8 @@ struct ac97_enum {
        unsigned short mask;
        const char **texts;
 };
+
+/* ad hoc AC97 device driver access */
+extern struct bus_type ac97_bus_type;
+
 #endif /* __SOUND_AC97_CODEC_H */
index 395978e375cf7caa870b106b9a0b53287a7002a2..ca2e0e4fa9375d866f3fb4866c515aa0481a173d 100644 (file)
@@ -138,6 +138,7 @@ struct _snd_ad1816a {
        spinlock_t lock;
 
        unsigned short mode;
+       unsigned int clock_freq;
 
        snd_card_t *card;
        snd_pcm_t *pcm;
index 9974f83cca440a88e6e9af4f30e0b7cc2bad767b..8e552d627fa58629dce85cf3408e077f99f132b2 100644 (file)
@@ -560,7 +560,7 @@ enum {
  *  Timer section - /dev/snd/timer
  */
 
-#define SNDRV_TIMER_VERSION            SNDRV_PROTOCOL_VERSION(2, 0, 4)
+#define SNDRV_TIMER_VERSION            SNDRV_PROTOCOL_VERSION(2, 0, 5)
 
 enum sndrv_timer_class {
        SNDRV_TIMER_CLASS_NONE = -1,
@@ -693,11 +693,15 @@ enum sndrv_timer_event {
        SNDRV_TIMER_EVENT_CONTINUE,             /* val = resolution in ns */
        SNDRV_TIMER_EVENT_PAUSE,                /* val = 0 */
        SNDRV_TIMER_EVENT_EARLY,                /* val = 0, early event */
+       SNDRV_TIMER_EVENT_SUSPEND,              /* val = 0 */
+       SNDRV_TIMER_EVENT_RESUME,               /* val = resolution in ns */
        /* master timer events for slave timer instances */
        SNDRV_TIMER_EVENT_MSTART = SNDRV_TIMER_EVENT_START + 10,
        SNDRV_TIMER_EVENT_MSTOP = SNDRV_TIMER_EVENT_STOP + 10,
        SNDRV_TIMER_EVENT_MCONTINUE = SNDRV_TIMER_EVENT_CONTINUE + 10,
        SNDRV_TIMER_EVENT_MPAUSE = SNDRV_TIMER_EVENT_PAUSE + 10,
+       SNDRV_TIMER_EVENT_MSUSPEND = SNDRV_TIMER_EVENT_SUSPEND + 10,
+       SNDRV_TIMER_EVENT_MRESUME = SNDRV_TIMER_EVENT_RESUME + 10,
 };
 
 struct sndrv_timer_tread {
index 182dd276ee74552f499de0fdaa08e165407658a3..9b94510eda60224f67d513e27ca1f1b4bd0596d6 100644 (file)
@@ -1748,7 +1748,7 @@ int snd_cs46xx_pcm(cs46xx_t *chip, int device, snd_pcm_t **rpcm);
 int snd_cs46xx_pcm_rear(cs46xx_t *chip, int device, snd_pcm_t **rpcm);
 int snd_cs46xx_pcm_iec958(cs46xx_t *chip, int device, snd_pcm_t **rpcm);
 int snd_cs46xx_pcm_center_lfe(cs46xx_t *chip, int device, snd_pcm_t **rpcm);
-int snd_cs46xx_mixer(cs46xx_t *chip);
+int snd_cs46xx_mixer(cs46xx_t *chip, int spdif_device);
 int snd_cs46xx_midi(cs46xx_t *chip, int device, snd_rawmidi_t **rmidi);
 int snd_cs46xx_start_dsp(cs46xx_t *chip);
 int snd_cs46xx_gameport(cs46xx_t *chip);
index c2ef3f02368793ffaddda2133b907653ab502320..4e3993dfcefef1a9301e0eee798c6554b42cc4cb 100644 (file)
@@ -1178,7 +1178,7 @@ int snd_p16v_free(emu10k1_t * emu);
 int snd_p16v_mixer(emu10k1_t * emu);
 int snd_emu10k1_pcm_multi(emu10k1_t * emu, int device, snd_pcm_t ** rpcm);
 int snd_emu10k1_fx8010_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm);
-int snd_emu10k1_mixer(emu10k1_t * emu);
+int snd_emu10k1_mixer(emu10k1_t * emu, int pcm_device, int multi_device);
 int snd_emu10k1_timer(emu10k1_t * emu, int device);
 int snd_emu10k1_fx8010_new(emu10k1_t *emu, int device, snd_hwdep_t ** rhwdep);
 
index b4b461ca173d6eb72a58ce7a1079b1c1e9417aaf..7000d9d9199d4575dab94b9726c711272122652c 100644 (file)
@@ -512,13 +512,13 @@ extern void snd_gf1_ctrl_stop(snd_gus_card_t * gus, unsigned char reg);
 
 extern void snd_gf1_write8(snd_gus_card_t * gus, unsigned char reg, unsigned char data);
 extern unsigned char snd_gf1_look8(snd_gus_card_t * gus, unsigned char reg);
-extern inline unsigned char snd_gf1_read8(snd_gus_card_t * gus, unsigned char reg)
+static inline unsigned char snd_gf1_read8(snd_gus_card_t * gus, unsigned char reg)
 {
        return snd_gf1_look8(gus, reg | 0x80);
 }
 extern void snd_gf1_write16(snd_gus_card_t * gus, unsigned char reg, unsigned int data);
 extern unsigned short snd_gf1_look16(snd_gus_card_t * gus, unsigned char reg);
-extern inline unsigned short snd_gf1_read16(snd_gus_card_t * gus, unsigned char reg)
+static inline unsigned short snd_gf1_read16(snd_gus_card_t * gus, unsigned char reg)
 {
        return snd_gf1_look16(gus, reg | 0x80);
 }
@@ -532,12 +532,12 @@ extern void snd_gf1_i_ctrl_stop(snd_gus_card_t * gus, unsigned char reg);
 extern void snd_gf1_i_write8(snd_gus_card_t * gus, unsigned char reg, unsigned char data);
 extern unsigned char snd_gf1_i_look8(snd_gus_card_t * gus, unsigned char reg);
 extern void snd_gf1_i_write16(snd_gus_card_t * gus, unsigned char reg, unsigned int data);
-extern inline unsigned char snd_gf1_i_read8(snd_gus_card_t * gus, unsigned char reg)
+static inline unsigned char snd_gf1_i_read8(snd_gus_card_t * gus, unsigned char reg)
 {
        return snd_gf1_i_look8(gus, reg | 0x80);
 }
 extern unsigned short snd_gf1_i_look16(snd_gus_card_t * gus, unsigned char reg);
-extern inline unsigned short snd_gf1_i_read16(snd_gus_card_t * gus, unsigned char reg)
+static inline unsigned short snd_gf1_i_read16(snd_gus_card_t * gus, unsigned char reg)
 {
        return snd_gf1_i_look16(gus, reg | 0x80);
 }
index d935417575b542bd94cc9ba1cff1dcc9c6fd4445..fa23ebfb857a8af771c12af6aa3fe51452e1c074 100644 (file)
@@ -379,7 +379,6 @@ struct _snd_pcm_substream {
        unsigned int dma_buf_id;
        size_t dma_max;
        /* -- hardware operations -- */
-       unsigned int open_flag: 1;      /* lowlevel device has been opened */
        snd_pcm_ops_t *ops;
        /* -- runtime information -- */
        snd_pcm_runtime_t *runtime;
index c085136f391f3be148c585ba150c9b927e7d2b19..8d19bfabb7e0812caf0963dfb763e92329fb1d82 100644 (file)
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated by configure.  */
-#define CONFIG_SND_VERSION "1.0.9b"
-#define CONFIG_SND_DATE " (Thu Jul 28 12:20:13 2005 UTC)"
+#define CONFIG_SND_VERSION "1.0.10rc1"
+#define CONFIG_SND_DATE " (Tue Aug 30 05:31:08 2005 UTC)"
index 4b570684a6aaeee45b75fd974d88f44a52e30bc4..9a3c1e6c820a2d28ddec0cffdaa83cfe7ba81d1f 100644 (file)
@@ -295,6 +295,7 @@ struct _snd_ymfpci_pcm {
        unsigned int running: 1;
        unsigned int output_front: 1;
        unsigned int output_rear: 1;
+       unsigned int update_pcm_vol;
        u32 period_size;                /* cached from runtime->period_size */
        u32 buffer_size;                /* cached from runtime->buffer_size */
        u32 period_pos;
@@ -367,6 +368,11 @@ struct _snd_ymfpci {
        int mode_dup4ch;
        int rear_opened;
        int spdif_opened;
+       struct {
+               u16 left;
+               u16 right;
+               snd_kcontrol_t *ctl;
+       } pcm_mixer[32];
 
        spinlock_t reg_lock;
        spinlock_t voice_lock;
index 46052304e2300dd5257716acdb4559150d8d2273..29450befb5da52b59680f7624d766897703d6d3c 100644 (file)
@@ -132,9 +132,9 @@ static void pxa2xx_ac97_reset(ac97_t *ac97)
                udelay(10);
                GCR |= GCR_WARM_RST;
                pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
-               udelay(50);
+               udelay(500);
 #else
-               GCR |= GCR_WARM_RST|GCR_PRIRDY_IEN|GCR_SECRDY_IEN;;
+               GCR |= GCR_WARM_RST|GCR_PRIRDY_IEN|GCR_SECRDY_IEN;
                wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
 #endif                 
 
@@ -261,7 +261,7 @@ static int pxa2xx_ac97_do_suspend(snd_card_t *card, unsigned int state)
        return 0;
 }
 
-static int pxa2xx_ac97_do_resume(snd_card_t *card, unsigned int state)
+static int pxa2xx_ac97_do_resume(snd_card_t *card)
 {
        if (card->power_state != SNDRV_CTL_POWER_D0) {
                pxa2xx_audio_ops_t *platform_ops = card->dev->platform_data;
@@ -275,13 +275,13 @@ static int pxa2xx_ac97_do_resume(snd_card_t *card, unsigned int state)
        return 0;
 }
 
-static int pxa2xx_ac97_suspend(struct device *_dev, u32 state, u32 level)
+static int pxa2xx_ac97_suspend(struct device *_dev, pm_message_t state, u32 level)
 {
        snd_card_t *card = dev_get_drvdata(_dev);
        int ret = 0;
 
        if (card && level == SUSPEND_DISABLE)
-               ret = pxa2xx_ac97_do_suspend(card, SNDRV_CTL_POWER_D3cold);
+               ret = pxa2xx_ac97_do_suspend(card, PMSG_SUSPEND);
 
        return ret;
 }
@@ -292,7 +292,7 @@ static int pxa2xx_ac97_resume(struct device *_dev, u32 level)
        int ret = 0;
 
        if (card && level == RESUME_ENABLE)
-               ret = pxa2xx_ac97_do_resume(card, SNDRV_CTL_POWER_D0);
+               ret = pxa2xx_ac97_do_resume(card);
 
        return ret;
 }
index 02132561c3f845d326f2bbf34a8870efab3439d5..39a54a415528080a01620e71d7a40efdcbac1e66 100644 (file)
@@ -512,7 +512,7 @@ static void free_all_reserved_pages(void)
  * proc file interface
  */
 #define SND_MEM_PROC_FILE      "driver/snd-page-alloc"
-struct proc_dir_entry *snd_mem_proc;
+static struct proc_dir_entry *snd_mem_proc;
 
 static int snd_mem_proc_read(char *page, char **start, off_t off,
                             int count, int *eof, void *data)
@@ -655,8 +655,7 @@ static int __init snd_mem_init(void)
 
 static void __exit snd_mem_exit(void)
 {
-       if (snd_mem_proc)
-               remove_proc_entry(SND_MEM_PROC_FILE, NULL);
+       remove_proc_entry(SND_MEM_PROC_FILE, NULL);
        free_all_reserved_pages();
        if (snd_allocated_pages > 0)
                printk(KERN_ERR "snd-malloc: Memory leak?  pages not freed = %li\n", snd_allocated_pages);
index f6895577bf864bb9b715508fde30774af1b8d4cc..1622893d00a228df4f1f46f17d4af8f875b82c25 100644 (file)
@@ -56,7 +56,7 @@ static DEFINE_SPINLOCK(snd_alloc_vmalloc_lock);
 #define VMALLOC_MAGIC 0x87654320
 static snd_info_entry_t *snd_memory_info_entry;
 
-void snd_memory_init(void)
+void __init snd_memory_init(void)
 {
        snd_alloc_kmalloc = 0;
        snd_alloc_vmalloc = 0;
index de7444c586f977e363833320cf7aa27d594c219d..a13bd7bb4c9f08cf6628ce8856f1c56896ba2e9c 100644 (file)
@@ -1705,13 +1705,12 @@ static int snd_pcm_oss_release_file(snd_pcm_oss_file_t *pcm_oss_file)
                if (snd_pcm_running(substream))
                        snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
                snd_pcm_stream_unlock_irq(substream);
-               if (substream->open_flag) {
+               if (substream->ffile != NULL) {
                        if (substream->ops->hw_free != NULL)
                                substream->ops->hw_free(substream);
                        substream->ops->close(substream);
-                       substream->open_flag = 0;
+                       substream->ffile = NULL;
                }
-               substream->ffile = NULL;
                snd_pcm_oss_release_substream(substream);
                snd_pcm_release_substream(substream);
        }
@@ -1778,14 +1777,13 @@ static int snd_pcm_oss_open_file(struct file *file,
                        snd_pcm_oss_release_file(pcm_oss_file);
                        return err;
                }
-               psubstream->open_flag = 1;
+               psubstream->ffile = file;
                err = snd_pcm_hw_constraints_complete(psubstream);
                if (err < 0) {
                        snd_printd("snd_pcm_hw_constraint_complete failed\n");
                        snd_pcm_oss_release_file(pcm_oss_file);
                        return err;
                }
-               psubstream->ffile = file;
                snd_pcm_oss_init_substream(psubstream, psetup, minor);
        }
        if (csubstream != NULL) {
@@ -1800,14 +1798,13 @@ static int snd_pcm_oss_open_file(struct file *file,
                        snd_pcm_oss_release_file(pcm_oss_file);
                        return err;
                }
-               csubstream->open_flag = 1;
+               csubstream->ffile = file;
                err = snd_pcm_hw_constraints_complete(csubstream);
                if (err < 0) {
                        snd_printd("snd_pcm_hw_constraint_complete failed\n");
                        snd_pcm_oss_release_file(pcm_oss_file);
                        return err;
                }
-               csubstream->ffile = file;
                snd_pcm_oss_init_substream(csubstream, csetup, minor);
        }
 
index 3920bf0eebbf20c98c2f31e1093385cb8efc56ff..4b6307df846d4c1f55c0c3b66913992061b6e128 100644 (file)
@@ -103,10 +103,24 @@ struct sndrv_pcm_sw_params32 {
        unsigned char reserved[64];
 };
 
+/* recalcuate the boundary within 32bit */
+static snd_pcm_uframes_t recalculate_boundary(snd_pcm_runtime_t *runtime)
+{
+       snd_pcm_uframes_t boundary;
+
+       if (! runtime->buffer_size)
+               return 0;
+       boundary = runtime->buffer_size;
+       while (boundary * 2 <= 0x7fffffffUL - runtime->buffer_size)
+               boundary *= 2;
+       return boundary;
+}
+
 static int snd_pcm_ioctl_sw_params_compat(snd_pcm_substream_t *substream,
                                          struct sndrv_pcm_sw_params32 __user *src)
 {
        snd_pcm_sw_params_t params;
+       snd_pcm_uframes_t boundary;
        int err;
 
        memset(&params, 0, sizeof(params));
@@ -120,10 +134,17 @@ static int snd_pcm_ioctl_sw_params_compat(snd_pcm_substream_t *substream,
            get_user(params.silence_threshold, &src->silence_threshold) ||
            get_user(params.silence_size, &src->silence_size))
                return -EFAULT;
+       /*
+        * Check silent_size parameter.  Since we have 64bit boundary,
+        * silence_size must be compared with the 32bit boundary.
+        */
+       boundary = recalculate_boundary(substream->runtime);
+       if (boundary && params.silence_size >= boundary)
+               params.silence_size = substream->runtime->boundary;
        err = snd_pcm_sw_params(substream, &params);
        if (err < 0)
                return err;
-       if (put_user(params.boundary, &src->boundary))
+       if (boundary && put_user(boundary, &src->boundary))
                return -EFAULT;
        return err;
 }
@@ -199,16 +220,6 @@ static int snd_pcm_status_user_compat(snd_pcm_substream_t *substream,
        return err;
 }
 
-/* recalcuate the boundary within 32bit */
-static void recalculate_boundary(snd_pcm_runtime_t *runtime)
-{
-       if (! runtime->buffer_size)
-               return;
-       runtime->boundary = runtime->buffer_size;
-       while (runtime->boundary * 2 <= 0x7fffffffUL - runtime->buffer_size)
-               runtime->boundary *= 2;
-}
-
 /* both for HW_PARAMS and HW_REFINE */
 static int snd_pcm_ioctl_hw_params_compat(snd_pcm_substream_t *substream,
                                          int refine, 
@@ -241,8 +252,11 @@ static int snd_pcm_ioctl_hw_params_compat(snd_pcm_substream_t *substream,
                goto error;
        }
 
-       if (! refine)
-               recalculate_boundary(runtime);
+       if (! refine) {
+               unsigned int new_boundary = recalculate_boundary(runtime);
+               if (new_boundary)
+                       runtime->boundary = new_boundary;
+       }
  error:
        kfree(data);
        return err;
@@ -380,6 +394,7 @@ static int snd_pcm_ioctl_sync_ptr_compat(snd_pcm_substream_t *substream,
        u32 sflags;
        struct sndrv_pcm_mmap_control scontrol;
        struct sndrv_pcm_mmap_status sstatus;
+       snd_pcm_uframes_t boundary;
        int err;
 
        snd_assert(runtime, return -EINVAL);
@@ -395,17 +410,21 @@ static int snd_pcm_ioctl_sync_ptr_compat(snd_pcm_substream_t *substream,
        }
        status = runtime->status;
        control = runtime->control;
+       boundary = recalculate_boundary(runtime);
+       if (! boundary)
+               boundary = 0x7fffffff;
        snd_pcm_stream_lock_irq(substream);
+       /* FIXME: we should consider the boundary for the sync from app */
        if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
                control->appl_ptr = scontrol.appl_ptr;
        else
-               scontrol.appl_ptr = control->appl_ptr;
+               scontrol.appl_ptr = control->appl_ptr % boundary;
        if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
                control->avail_min = scontrol.avail_min;
        else
                scontrol.avail_min = control->avail_min;
        sstatus.state = status->state;
-       sstatus.hw_ptr = status->hw_ptr;
+       sstatus.hw_ptr = status->hw_ptr % boundary;
        sstatus.tstamp = status->tstamp;
        sstatus.suspended_state = status->suspended_state;
        snd_pcm_stream_unlock_irq(substream);
index c5bfd0918cff9eba195d733355435580f27f8882..0082914a7e3331825b7a302dfe9dfe4035694971 100644 (file)
@@ -1584,8 +1584,8 @@ int snd_pcm_hw_param_set(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
        return snd_pcm_hw_param_value(params, var, NULL);
 }
 
-int _snd_pcm_hw_param_mask(snd_pcm_hw_params_t *params,
-                          snd_pcm_hw_param_t var, const snd_mask_t *val)
+static int _snd_pcm_hw_param_mask(snd_pcm_hw_params_t *params,
+                                 snd_pcm_hw_param_t var, const snd_mask_t *val)
 {
        int changed;
        assert(hw_is_mask(var));
@@ -2063,7 +2063,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(snd_pcm_substream_t *substream,
                if (((avail < runtime->control->avail_min && size > avail) ||
                   (size >= runtime->xfer_align && avail < runtime->xfer_align))) {
                        wait_queue_t wait;
-                       enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED } state;
+                       enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED, DROPPED } state;
                        long tout;
 
                        if (nonblock) {
@@ -2097,6 +2097,9 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(snd_pcm_substream_t *substream,
                                case SNDRV_PCM_STATE_SUSPENDED:
                                        state = SUSPENDED;
                                        goto _end_loop;
+                               case SNDRV_PCM_STATE_SETUP:
+                                       state = DROPPED;
+                                       goto _end_loop;
                                default:
                                        break;
                                }
@@ -2123,6 +2126,9 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(snd_pcm_substream_t *substream,
                                snd_printd("playback write error (DMA or IRQ trouble?)\n");
                                err = -EIO;
                                goto _end_unlock;
+                       case DROPPED:
+                               err = -EBADFD;
+                               goto _end_unlock;
                        default:
                                break;
                        }
@@ -2359,7 +2365,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(snd_pcm_substream_t *substream,
                } else if ((avail < runtime->control->avail_min && size > avail) ||
                           (size >= runtime->xfer_align && avail < runtime->xfer_align)) {
                        wait_queue_t wait;
-                       enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED } state;
+                       enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED, DROPPED } state;
                        long tout;
 
                        if (nonblock) {
@@ -2394,6 +2400,9 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(snd_pcm_substream_t *substream,
                                        goto _end_loop;
                                case SNDRV_PCM_STATE_DRAINING:
                                        goto __draining;
+                               case SNDRV_PCM_STATE_SETUP:
+                                       state = DROPPED;
+                                       goto _end_loop;
                                default:
                                        break;
                                }
@@ -2420,6 +2429,9 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(snd_pcm_substream_t *substream,
                                snd_printd("capture read error (DMA or IRQ trouble?)\n");
                                err = -EIO;
                                goto _end_unlock;
+                       case DROPPED:
+                               err = -EBADFD;
+                               goto _end_unlock;
                        default:
                                break;
                        }
index 10c2c98326497e6f0cb5fc0c453c1701daf5f8c4..03c17159dd8e0fe48f9625af9dfd979038a5adff 100644 (file)
@@ -1025,7 +1025,7 @@ static void snd_pcm_post_suspend(snd_pcm_substream_t *substream, int state)
        snd_pcm_runtime_t *runtime = substream->runtime;
        snd_pcm_trigger_tstamp(substream);
        if (substream->timer)
-               snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MPAUSE, &runtime->trigger_tstamp);
+               snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSUSPEND, &runtime->trigger_tstamp);
        runtime->status->suspended_state = runtime->status->state;
        runtime->status->state = SNDRV_PCM_STATE_SUSPENDED;
        snd_pcm_tick_set(substream, 0);
@@ -1115,7 +1115,7 @@ static void snd_pcm_post_resume(snd_pcm_substream_t *substream, int state)
        snd_pcm_runtime_t *runtime = substream->runtime;
        snd_pcm_trigger_tstamp(substream);
        if (substream->timer)
-               snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MCONTINUE, &runtime->trigger_tstamp);
+               snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MRESUME, &runtime->trigger_tstamp);
        runtime->status->state = runtime->status->suspended_state;
        if (runtime->sleep_min)
                snd_pcm_tick_prepare(substream);
@@ -1967,13 +1967,12 @@ static int snd_pcm_release_file(snd_pcm_file_t * pcm_file)
        runtime = substream->runtime;
        str = substream->pstr;
        snd_pcm_unlink(substream);
-       if (substream->open_flag) {
+       if (substream->ffile != NULL) {
                if (substream->ops->hw_free != NULL)
                        substream->ops->hw_free(substream);
                substream->ops->close(substream);
-               substream->open_flag = 0;
+               substream->ffile = NULL;
        }
-       substream->ffile = NULL;
        snd_pcm_remove_file(str, pcm_file);
        snd_pcm_release_substream(substream);
        kfree(pcm_file);
@@ -2022,18 +2021,15 @@ static int snd_pcm_open_file(struct file *file,
                snd_pcm_release_file(pcm_file);
                return err;
        }
-       substream->open_flag = 1;
+       substream->ffile = file;
 
        err = snd_pcm_hw_constraints_complete(substream);
        if (err < 0) {
                snd_printd("snd_pcm_hw_constraints_complete failed\n");
-               substream->ops->close(substream);
                snd_pcm_release_file(pcm_file);
                return err;
        }
 
-       substream->ffile = file;
-
        file->private_data = pcm_file;
        *rpcm_file = pcm_file;
        return 0;
index de39d212bc15189bbb1236f9519993b608ed8d15..e401c6703297c377196d9d1d12c2227b657eaae9 100644 (file)
@@ -98,6 +98,7 @@ int snd_register_oss_device(int type, snd_card_t * card, int dev, snd_minor_t *
        int cidx = SNDRV_MINOR_OSS_CARD(minor);
        int track2 = -1;
        int register1 = -1, register2 = -1;
+       struct device *carddev = NULL;
 
        if (minor < 0)
                return minor;
@@ -121,11 +122,13 @@ int snd_register_oss_device(int type, snd_card_t * card, int dev, snd_minor_t *
                track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_DMMIDI1);
                break;
        }
-       register1 = register_sound_special(reg->f_ops, minor);
+       if (card)
+               carddev = card->dev;
+       register1 = register_sound_special_device(reg->f_ops, minor, carddev);
        if (register1 != minor)
                goto __end;
        if (track2 >= 0) {
-               register2 = register_sound_special(reg->f_ops, track2);
+               register2 = register_sound_special_device(reg->f_ops, track2, carddev);
                if (register2 != track2)
                        goto __end;
        }
index cfaccd415b3b918cedc9cbdc6a9d4c89dd0a0861..4104f6e292e959ead04756ccd52d18ee52e49326 100644 (file)
@@ -799,13 +799,13 @@ static int snd_timer_free(snd_timer_t *timer)
        return 0;
 }
 
-int snd_timer_dev_free(snd_device_t *device)
+static int snd_timer_dev_free(snd_device_t *device)
 {
        snd_timer_t *timer = device->device_data;
        return snd_timer_free(timer);
 }
 
-int snd_timer_dev_register(snd_device_t *dev)
+static int snd_timer_dev_register(snd_device_t *dev)
 {
        snd_timer_t *timer = dev->device_data;
        snd_timer_t *timer1;
@@ -880,9 +880,11 @@ void snd_timer_notify(snd_timer_t *timer, enum sndrv_timer_event event, struct t
        struct list_head *p, *n;
 
        snd_runtime_check(timer->hw.flags & SNDRV_TIMER_HW_SLAVE, return);      
-       snd_assert(event >= SNDRV_TIMER_EVENT_MSTART && event <= SNDRV_TIMER_EVENT_MPAUSE, return);
+       snd_assert(event >= SNDRV_TIMER_EVENT_MSTART && event <= SNDRV_TIMER_EVENT_MRESUME, return);
        spin_lock_irqsave(&timer->lock, flags);
-       if (event == SNDRV_TIMER_EVENT_MSTART || event == SNDRV_TIMER_EVENT_MCONTINUE) {
+       if (event == SNDRV_TIMER_EVENT_MSTART ||
+           event == SNDRV_TIMER_EVENT_MCONTINUE ||
+           event == SNDRV_TIMER_EVENT_MRESUME) {
                if (timer->hw.c_resolution)
                        resolution = timer->hw.c_resolution(timer);
                else
@@ -1555,10 +1557,14 @@ static int snd_timer_user_params(struct file *file, snd_timer_params_t __user *_
                              (1<<SNDRV_TIMER_EVENT_STOP)|
                              (1<<SNDRV_TIMER_EVENT_CONTINUE)|
                              (1<<SNDRV_TIMER_EVENT_PAUSE)|
+                             (1<<SNDRV_TIMER_EVENT_SUSPEND)|
+                             (1<<SNDRV_TIMER_EVENT_RESUME)|
                              (1<<SNDRV_TIMER_EVENT_MSTART)|
                              (1<<SNDRV_TIMER_EVENT_MSTOP)|
                              (1<<SNDRV_TIMER_EVENT_MCONTINUE)|
-                             (1<<SNDRV_TIMER_EVENT_MPAUSE))) {
+                             (1<<SNDRV_TIMER_EVENT_MPAUSE)|
+                             (1<<SNDRV_TIMER_EVENT_MSUSPEND)|
+                             (1<<SNDRV_TIMER_EVENT_MRESUME))) {
                err = -EINVAL;
                goto _end;
        }
index f00c88886460c8b8dff9a3a5dc8e05c8549cd28d..19fc68c23378c039b4bc856b54997372bf0915c1 100644 (file)
@@ -796,14 +796,14 @@ static int vx_iec958_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontro
 
 static snd_kcontrol_new_t vx_control_iec958_mask = {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
        .info =         vx_iec958_info, /* shared */
        .get =          vx_iec958_mask_get,
 };
 
 static snd_kcontrol_new_t vx_control_iec958 = {
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
        .info =         vx_iec958_info,
        .get =          vx_iec958_get,
index af381b15fe5c4a813eb413ae04b0994b8ae67f38..d4becf44e24787ddc9743bb943da30f41c0e02ff 100644 (file)
@@ -549,8 +549,8 @@ static int vx_stop_stream(vx_core_t *chip, vx_pipe_t *pipe)
 
 static snd_pcm_hardware_t vx_pcm_playback_hw = {
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
-                                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID |
-                                SNDRV_PCM_INFO_RESUME),
+                                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID /*|*/
+                                /*SNDRV_PCM_INFO_RESUME*/),
        .formats =              /*SNDRV_PCM_FMTBIT_U8 |*/ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
        .rates =                SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
        .rate_min =             5000,
@@ -949,8 +949,8 @@ static snd_pcm_ops_t vx_pcm_playback_ops = {
 
 static snd_pcm_hardware_t vx_pcm_capture_hw = {
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
-                                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID |
-                                SNDRV_PCM_INFO_RESUME),
+                                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID /*|*/
+                                /*SNDRV_PCM_INFO_RESUME*/),
        .formats =              /*SNDRV_PCM_FMTBIT_U8 |*/ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
        .rates =                SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
        .rate_min =             5000,
index 563296d028941b53e211956fff89b54459640dce..0eb442ca23d6471e7abf63a730e1548c84dabfa9 100644 (file)
@@ -53,6 +53,7 @@ static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;      /* Pnp setup */
 static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;   /* Pnp setup */
 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;      /* PnP setup */
 static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;      /* PnP setup */
+static int clockfreq[SNDRV_CARDS];
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for ad1816a based soundcard.");
@@ -74,6 +75,8 @@ module_param_array(dma1, int, NULL, 0444);
 MODULE_PARM_DESC(dma1, "1st DMA # for ad1816a driver.");
 module_param_array(dma2, int, NULL, 0444);
 MODULE_PARM_DESC(dma2, "2nd DMA # for ad1816a driver.");
+module_param_array(clockfreq, int, NULL, 0444);
+MODULE_PARM_DESC(clockfreq, "Clock frequency for ad1816a driver (default = 0).");
 
 struct snd_card_ad1816a {
        struct pnp_dev *dev;
@@ -209,6 +212,8 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard
                snd_card_free(card);
                return error;
        }
+       if (clockfreq[dev] >= 5000 && clockfreq[dev] <= 100000)
+               chip->clock_freq = clockfreq[dev];
 
        strcpy(card->driver, "AD1816A");
        strcpy(card->shortname, "ADI SoundPort AD1816A");
index 625b2eff14a14d03f39c17902a448b974b3b8f13..ae860360ecf963a3620357e505b2d6025eb57800 100644 (file)
@@ -234,7 +234,7 @@ static int snd_ad1816a_playback_prepare(snd_pcm_substream_t *substream)
        ad1816a_t *chip = snd_pcm_substream_chip(substream);
        unsigned long flags;
        snd_pcm_runtime_t *runtime = substream->runtime;
-       unsigned int size;
+       unsigned int size, rate;
 
        spin_lock_irqsave(&chip->lock, flags);
 
@@ -245,7 +245,10 @@ static int snd_ad1816a_playback_prepare(snd_pcm_substream_t *substream)
        snd_dma_program(chip->dma1, runtime->dma_addr, size,
                        DMA_MODE_WRITE | DMA_AUTOINIT);
 
-       snd_ad1816a_write(chip, AD1816A_PLAYBACK_SAMPLE_RATE, runtime->rate);
+       rate = runtime->rate;
+       if (chip->clock_freq)
+               rate = (rate * 33000) / chip->clock_freq;
+       snd_ad1816a_write(chip, AD1816A_PLAYBACK_SAMPLE_RATE, rate);
        snd_ad1816a_out_mask(chip, AD1816A_PLAYBACK_CONFIG,
                AD1816A_FMT_ALL | AD1816A_FMT_STEREO,
                snd_ad1816a_get_format(chip, runtime->format,
@@ -263,7 +266,7 @@ static int snd_ad1816a_capture_prepare(snd_pcm_substream_t *substream)
        ad1816a_t *chip = snd_pcm_substream_chip(substream);
        unsigned long flags;
        snd_pcm_runtime_t *runtime = substream->runtime;
-       unsigned int size;
+       unsigned int size, rate;
 
        spin_lock_irqsave(&chip->lock, flags);
 
@@ -274,7 +277,10 @@ static int snd_ad1816a_capture_prepare(snd_pcm_substream_t *substream)
        snd_dma_program(chip->dma2, runtime->dma_addr, size,
                        DMA_MODE_READ | DMA_AUTOINIT);
 
-       snd_ad1816a_write(chip, AD1816A_CAPTURE_SAMPLE_RATE, runtime->rate);
+       rate = runtime->rate;
+       if (chip->clock_freq)
+               rate = (rate * 33000) / chip->clock_freq;
+       snd_ad1816a_write(chip, AD1816A_CAPTURE_SAMPLE_RATE, rate);
        snd_ad1816a_out_mask(chip, AD1816A_CAPTURE_CONFIG,
                AD1816A_FMT_ALL | AD1816A_FMT_STEREO,
                snd_ad1816a_get_format(chip, runtime->format,
index 8fb3db103e485e698420dd18b587ca497a0a0907..bc642dc94547b5cea97570988571a9a506070cb2 100644 (file)
@@ -1196,6 +1196,7 @@ int snd_ad1848_add_ctl(ad1848_t *chip, const char *name, int index, int type, un
                        .put = snd_ad1848_put_double,
                },
                [AD1848_MIX_CAPTURE] = {
+                       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                        .info = snd_ad1848_info_mux,
                        .get = snd_ad1848_get_mux,
                        .put = snd_ad1848_put_mux,
index 46776cc0c1578b369ed678905905f3ebe2ad4e69..1fce8b9f37cf88de82991392a12ced9aa363443e 100644 (file)
@@ -194,8 +194,8 @@ AD1848_DOUBLE("Wavetable Capture Volume", 0, CMI8330_WAVGAIN, CMI8330_WAVGAIN, 4
 AD1848_SINGLE("3D Control - Switch", 0, CMI8330_RMUX3D, 5, 1, 1),
 AD1848_SINGLE("PC Speaker Playback Volume", 0, CMI8330_OUTPUTVOL, 3, 3, 0),
 AD1848_SINGLE("FM Playback Switch", 0, CMI8330_RECMUX, 3, 1, 1),
-AD1848_SINGLE("IEC958 Input Capture Switch", 0, CMI8330_RMUX3D, 7, 1, 1),
-AD1848_SINGLE("IEC958 Input Playback Switch", 0, CMI8330_MUTEMUX, 7, 1, 1),
+AD1848_SINGLE(SNDRV_CTL_NAME_IEC958("Input ",CAPTURE,SWITCH), 0, CMI8330_RMUX3D, 7, 1, 1),
+AD1848_SINGLE(SNDRV_CTL_NAME_IEC958("Input ",PLAYBACK,SWITCH), 0, CMI8330_MUTEMUX, 7, 1, 1),
 };
 
 #ifdef ENABLE_SB_MIXER
index 3e7a2a33a5cad3a2dbf8f05f8add115a868634aa..3199941edd9bafd67de441b6bbde50f18f343338 100644 (file)
@@ -1346,6 +1346,8 @@ static void snd_cs4231_suspend(cs4231_t *chip)
        int reg;
        unsigned long flags;
        
+       if (chip->pcm)
+               snd_pcm_suspend_all(chip->pcm);
        spin_lock_irqsave(&chip->reg_lock, flags);
        for (reg = 0; reg < 32; reg++)
                chip->image[reg] = snd_cs4231_in(chip, reg);
index 337b0e2a8a36905a6b996587043699caf0c6c9ac..23e1b5f19e1ab78f24ba8ff48614ba15876f0f25 100644 (file)
@@ -269,8 +269,9 @@ void snd_gf1_i_write_addr(snd_gus_card_t * gus, unsigned char reg,
 
 #endif  /*  0  */
 
-unsigned int snd_gf1_i_read_addr(snd_gus_card_t * gus,
-                                unsigned char reg, short w_16bit)
+#ifdef CONFIG_SND_DEBUG
+static unsigned int snd_gf1_i_read_addr(snd_gus_card_t * gus,
+                                       unsigned char reg, short w_16bit)
 {
        unsigned int res;
        unsigned long flags;
@@ -280,6 +281,7 @@ unsigned int snd_gf1_i_read_addr(snd_gus_card_t * gus,
        spin_unlock_irqrestore(&gus->reg_lock, flags);
        return res;
 }
+#endif
 
 /*
 
index 95c7b3e53407fecbeadf461bf4ad9f9729e68487..75bd6eca63e741ed8545f86543a97884a8130eb7 100644 (file)
@@ -145,6 +145,14 @@ static snd_card_t *snd_opl3sa2_legacy[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
 
 #ifdef CONFIG_PNP
 
+static struct pnp_device_id snd_opl3sa2_pnpbiosids[] = {
+       { .id = "YMH0021" },
+       { .id = "NMX2210" },    /* Gateway Solo 2500 */
+       { .id = "" }            /* end */
+};
+
+MODULE_DEVICE_TABLE(pnp, snd_opl3sa2_pnpbiosids);
+
 static struct pnp_card_device_id snd_opl3sa2_pnpids[] = {
        /* Yamaha YMF719E-S (Genius Sound Maker 3DX) */
        { .id = "YMH0020", .devs = { { "YMH0021" } } },
@@ -568,20 +576,18 @@ static int snd_opl3sa2_resume(snd_card_t *card)
 
 #ifdef CONFIG_PNP
 static int __init snd_opl3sa2_pnp(int dev, opl3sa2_t *chip,
-                                 struct pnp_card_link *card,
-                                 const struct pnp_card_device_id *id)
+                                 struct pnp_dev *pdev,
+                                 int isapnp)
 {
-       struct pnp_dev *pdev;
-       struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
+       struct pnp_resource_table * cfg;
        int err;
 
+       if (!isapnp && pnp_device_is_isapnp(pdev))
+               return -ENOENT; /* we have another procedure - card */
+
+       cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
        if (!cfg)
                return -ENOMEM;
-       pdev = chip->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
-       if (chip->dev == NULL) {
-               kfree(cfg);
-               return -EBUSY;
-       }
        /* PnP initialization */
        pnp_init_resource_table(cfg);
        if (sb_port[dev] != SNDRV_AUTO_PORT)
@@ -601,7 +607,7 @@ static int __init snd_opl3sa2_pnp(int dev, opl3sa2_t *chip,
        if (irq[dev] != SNDRV_AUTO_IRQ)
                pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
        err = pnp_manual_config_dev(pdev, cfg, 0);
-       if (err < 0)
+       if (err < 0 && isapnp)
                snd_printk(KERN_ERR "PnP manual resources are invalid, using auto config\n");
        err = pnp_activate_dev(pdev);
        if (err < 0) {
@@ -617,13 +623,31 @@ static int __init snd_opl3sa2_pnp(int dev, opl3sa2_t *chip,
        dma1[dev] = pnp_dma(pdev, 0);
        dma2[dev] = pnp_dma(pdev, 1);
        irq[dev] = pnp_irq(pdev, 0);
-       snd_printdd("PnP OPL3-SA: sb port=0x%lx, wss port=0x%lx, fm port=0x%lx, midi port=0x%lx\n",
-               sb_port[dev], wss_port[dev], fm_port[dev], midi_port[dev]);
-       snd_printdd("PnP OPL3-SA: control port=0x%lx, dma1=%i, dma2=%i, irq=%i\n",
-               port[dev], dma1[dev], dma2[dev], irq[dev]);
+       snd_printdd("%sPnP OPL3-SA: sb port=0x%lx, wss port=0x%lx, fm port=0x%lx, midi port=0x%lx\n",
+               pnp_device_is_pnpbios(pdev) ? "BIOS" : "ISA", sb_port[dev], wss_port[dev], fm_port[dev], midi_port[dev]);
+       snd_printdd("%sPnP OPL3-SA: control port=0x%lx, dma1=%i, dma2=%i, irq=%i\n",
+               pnp_device_is_pnpbios(pdev) ? "BIOS" : "ISA", port[dev], dma1[dev], dma2[dev], irq[dev]);
        kfree(cfg);
+       chip->dev = pdev;
        return 0;
 }
+
+static int __init snd_opl3sa2_cpnp(int dev, opl3sa2_t *chip,
+                                  struct pnp_card_link *card,
+                                  const struct pnp_card_device_id *id)
+{
+       struct pnp_dev *pdev;
+       struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
+
+       if (!cfg)
+               return -ENOMEM;
+       pdev = pnp_request_card_device(card, id->devs[0].id, NULL);
+       if (pdev == NULL) {
+               kfree(cfg);
+               return -EBUSY;
+       }
+       return snd_opl3sa2_pnp(dev, chip, pdev, 1);
+}
 #endif /* CONFIG_PNP */
 
 static int snd_opl3sa2_free(opl3sa2_t *chip)
@@ -645,6 +669,7 @@ static int snd_opl3sa2_dev_free(snd_device_t *device)
 }
 
 static int __devinit snd_opl3sa2_probe(int dev,
+                                      struct pnp_dev *pdev,
                                       struct pnp_card_link *pcard,
                                       const struct pnp_card_device_id *pid)
 {
@@ -695,8 +720,13 @@ static int __devinit snd_opl3sa2_probe(int dev,
        if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0)
                goto __error;
 #ifdef CONFIG_PNP
-       if (isapnp[dev]) {
-               if ((err = snd_opl3sa2_pnp(dev, chip, pcard, pid)) < 0)
+       if (pdev) {
+               if ((err = snd_opl3sa2_pnp(dev, chip, pdev, 0)) < 0)
+                       goto __error;
+               snd_card_set_dev(card, &pdev->dev);
+       }
+       if (pcard) {
+               if ((err = snd_opl3sa2_cpnp(dev, chip, pcard, pid)) < 0)
                        goto __error;
                snd_card_set_dev(card, &pcard->card->dev);
        }
@@ -768,7 +798,9 @@ static int __devinit snd_opl3sa2_probe(int dev,
        if ((err = snd_card_register(card)) < 0)
                goto __error;
 
-       if (pcard)
+       if (pdev)
+               pnp_set_drvdata(pdev, card);
+       else if (pcard)
                pnp_set_card_drvdata(pcard, card);
        else
                snd_opl3sa2_legacy[dev] = card;
@@ -780,8 +812,8 @@ static int __devinit snd_opl3sa2_probe(int dev,
 }
 
 #ifdef CONFIG_PNP
-static int __devinit snd_opl3sa2_pnp_detect(struct pnp_card_link *card,
-                                           const struct pnp_card_device_id *id)
+static int __devinit snd_opl3sa2_pnp_detect(struct pnp_dev *pdev,
+                                           const struct pnp_device_id *id)
 {
         static int dev;
         int res;
@@ -789,7 +821,7 @@ static int __devinit snd_opl3sa2_pnp_detect(struct pnp_card_link *card,
         for ( ; dev < SNDRV_CARDS; dev++) {
                 if (!enable[dev] || !isapnp[dev])
                         continue;
-                res = snd_opl3sa2_probe(dev, card, id);
+                res = snd_opl3sa2_probe(dev, pdev, NULL, NULL);
                 if (res < 0)
                         return res;
                 dev++;
@@ -798,7 +830,40 @@ static int __devinit snd_opl3sa2_pnp_detect(struct pnp_card_link *card,
         return -ENODEV;
 }
 
-static void __devexit snd_opl3sa2_pnp_remove(struct pnp_card_link * pcard)
+static void __devexit snd_opl3sa2_pnp_remove(struct pnp_dev * pdev)
+{
+       snd_card_t *card = (snd_card_t *) pnp_get_drvdata(pdev);
+        
+       snd_card_disconnect(card);
+       snd_card_free_in_thread(card);
+}
+
+static struct pnp_driver opl3sa2_pnp_driver = {
+       .name = "opl3sa2-pnpbios",
+       .id_table = snd_opl3sa2_pnpbiosids,
+       .probe = snd_opl3sa2_pnp_detect,
+       .remove = __devexit_p(snd_opl3sa2_pnp_remove),
+};
+
+static int __devinit snd_opl3sa2_pnp_cdetect(struct pnp_card_link *card,
+                                            const struct pnp_card_device_id *id)
+{
+        static int dev;
+        int res;
+
+        for ( ; dev < SNDRV_CARDS; dev++) {
+                if (!enable[dev] || !isapnp[dev])
+                        continue;
+                res = snd_opl3sa2_probe(dev, NULL, card, id);
+                if (res < 0)
+                        return res;
+                dev++;
+                return 0;
+        }
+        return -ENODEV;
+}
+
+static void __devexit snd_opl3sa2_pnp_cremove(struct pnp_card_link * pcard)
 {
        snd_card_t *card = (snd_card_t *) pnp_get_card_drvdata(pcard);
         
@@ -810,8 +875,8 @@ static struct pnp_card_driver opl3sa2_pnpc_driver = {
        .flags = PNP_DRIVER_RES_DISABLE,
        .name = "opl3sa2",
        .id_table = snd_opl3sa2_pnpids,
-       .probe = snd_opl3sa2_pnp_detect,
-       .remove = __devexit_p(snd_opl3sa2_pnp_remove),
+       .probe = snd_opl3sa2_pnp_cdetect,
+       .remove = __devexit_p(snd_opl3sa2_pnp_cremove),
 };
 #endif /* CONFIG_PNP */
 
@@ -826,10 +891,11 @@ static int __init alsa_card_opl3sa2_init(void)
                if (isapnp[dev])
                        continue;
 #endif
-               if (snd_opl3sa2_probe(dev, NULL, NULL) >= 0)
+               if (snd_opl3sa2_probe(dev, NULL, NULL, NULL) >= 0)
                        cards++;
        }
 #ifdef CONFIG_PNP
+       cards += pnp_register_driver(&opl3sa2_pnp_driver);
        cards += pnp_register_card_driver(&opl3sa2_pnpc_driver);
 #endif
        if (!cards) {
index a6a0fa51626840fd741a4532535f57a96a3dadb1..a99e642a68b590d9be7a3e53d3dbfaf75a814907 100644 (file)
@@ -729,7 +729,7 @@ static int snd_sb16_dma_control_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_valu
 }
 
 static snd_kcontrol_new_t snd_sb16_dma_control = {
-       .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+       .iface = SNDRV_CTL_ELEM_IFACE_CARD,
        .name = "16-bit DMA Allocation",
        .info = snd_sb16_dma_control_info,
        .get = snd_sb16_dma_control_get,
index 26b42bb20a0a180f0493e670be5ee218a09f4c17..1e458919cce6dfbc97822c95b383baac9eac041f 100644 (file)
@@ -1,11 +1,15 @@
 # ALSA PCI drivers
 
-menu "PCI devices"
-       depends on SND!=n && PCI
-
 config SND_AC97_CODEC
        tristate
        select SND_PCM
+       select SND_AC97_BUS
+
+config SND_AC97_BUS
+       tristate
+
+menu "PCI devices"
+       depends on SND!=n && PCI
 
 config SND_ALI5451
        tristate "ALi M5451 PCI Audio Controller"
index 3c3222122d8b0acda0e1a4389ee8fa452da0409d..77b3482cb1332fe29f92ec9d9c249f5ec1f0d6df 100644 (file)
@@ -10,9 +10,11 @@ snd-ac97-codec-objs += ac97_proc.o
 endif
 
 snd-ak4531-codec-objs := ak4531_codec.o
+snd-ac97-bus-objs := ac97_bus.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_AC97_CODEC) += snd-ac97-codec.o
 obj-$(CONFIG_SND_ENS1370) += snd-ak4531-codec.o
+obj-$(CONFIG_SND_AC97_BUS) += snd-ac97-bus.o
 
 obj-m := $(sort $(obj-m))
diff --git a/sound/pci/ac97/ac97_bus.c b/sound/pci/ac97/ac97_bus.c
new file mode 100644 (file)
index 0000000..227f8b9
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Linux driver model AC97 bus interface
+ *
+ * Author:     Nicolas Pitre
+ * Created:    Jan 14, 2005
+ * Copyright:  (C) MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/string.h>
+
+/*
+ * Codec families have names seperated by commas, so we search for an
+ * individual codec name within the family string. 
+ */
+static int ac97_bus_match(struct device *dev, struct device_driver *drv)
+{
+       return (strstr(dev->bus_id, drv->name) != NULL);
+}
+
+static int ac97_bus_suspend(struct device *dev, pm_message_t state)
+{
+       int ret = 0;
+
+       if (dev->driver && dev->driver->suspend) {
+               ret = dev->driver->suspend(dev, state, SUSPEND_DISABLE);
+               if (ret == 0)
+                       ret = dev->driver->suspend(dev, state, SUSPEND_SAVE_STATE);
+               if (ret == 0)
+                       ret = dev->driver->suspend(dev, state, SUSPEND_POWER_DOWN);
+       }
+       return ret;
+}
+
+static int ac97_bus_resume(struct device *dev)
+{
+       int ret = 0;
+
+       if (dev->driver && dev->driver->resume) {
+               ret = dev->driver->resume(dev, RESUME_POWER_ON);
+               if (ret == 0)
+                       ret = dev->driver->resume(dev, RESUME_RESTORE_STATE);
+               if (ret == 0)
+                       ret = dev->driver->resume(dev, RESUME_ENABLE);
+       }
+       return ret;
+}
+
+struct bus_type ac97_bus_type = {
+       .name           = "ac97",
+       .match          = ac97_bus_match,
+       .suspend        = ac97_bus_suspend,
+       .resume         = ac97_bus_resume,
+};
+
+static int __init ac97_bus_init(void)
+{
+       return bus_register(&ac97_bus_type);
+}
+
+subsys_initcall(ac97_bus_init);
+
+static void __exit ac97_bus_exit(void)
+{
+       bus_unregister(&ac97_bus_type);
+}
+
+module_exit(ac97_bus_exit);
+
+EXPORT_SYMBOL(ac97_bus_type);
+
+MODULE_LICENSE("GPL");
index 6983eea226da2fa227a8f3b0df205bb68ba6d861..5501f4440c9223439f476788ecfe6211052d948b 100644 (file)
@@ -157,6 +157,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
 { 0x54524123, 0xffffffff, "TR28602",           NULL,           NULL }, // only guess --jk [TR28023 = eMicro EM28023 (new CT1297)]
 { 0x54584e20, 0xffffffff, "TLC320AD9xC",       NULL,           NULL },
 { 0x56494161, 0xffffffff, "VIA1612A",          NULL,           NULL }, // modified ICE1232 with S/PDIF
+{ 0x56494170, 0xffffffff, "VIA1617A",          patch_vt1617a,  NULL }, // modified VT1616 with S/PDIF
 { 0x57454301, 0xffffffff, "W83971D",           NULL,           NULL },
 { 0x574d4c00, 0xffffffff, "WM9701A",           NULL,           NULL },
 { 0x574d4C03, 0xffffffff, "WM9703,WM9707,WM9708,WM9717", patch_wolfson03, NULL},
@@ -1307,16 +1308,18 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
        }
        
        /* build master tone controls */
-       if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_TONE)) {
-               for (idx = 0; idx < 2; idx++) {
-                       if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_tone[idx], ac97))) < 0)
-                               return err;
-                       if (ac97->id == AC97_ID_YMF753) {
-                               kctl->private_value &= ~(0xff << 16);
-                               kctl->private_value |= 7 << 16;
+       if (!(ac97->flags & AC97_HAS_NO_TONE)) {
+               if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_TONE)) {
+                       for (idx = 0; idx < 2; idx++) {
+                               if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_tone[idx], ac97))) < 0)
+                                       return err;
+                               if (ac97->id == AC97_ID_YMF753) {
+                                       kctl->private_value &= ~(0xff << 16);
+                                       kctl->private_value |= 7 << 16;
+                               }
                        }
+                       snd_ac97_write_cache(ac97, AC97_MASTER_TONE, 0x0f0f);
                }
-               snd_ac97_write_cache(ac97, AC97_MASTER_TONE, 0x0f0f);
        }
        
        /* build PC Speaker controls */
@@ -1339,11 +1342,13 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
        }
        
        /* build MIC controls */
-       if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) {
-               if ((err = snd_ac97_cmix_new(card, "Mic Playback", AC97_MIC, ac97)) < 0)
-                       return err;
-               if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0)
-                       return err;
+       if (!(ac97->flags & AC97_HAS_NO_MIC)) {
+               if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) {
+                       if ((err = snd_ac97_cmix_new(card, "Mic Playback", AC97_MIC, ac97)) < 0)
+                               return err;
+                       if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0)
+                               return err;
+               }
        }
 
        /* build Line controls */
@@ -1402,12 +1407,14 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
                }
                snd_ac97_write_cache(ac97, AC97_PCM, init_val);
        } else {
-               if (ac97->flags & AC97_HAS_NO_PCM_VOL)
-                       err = snd_ac97_cmute_new(card, "PCM Playback Switch", AC97_PCM, ac97);
-               else
-                       err = snd_ac97_cmix_new(card, "PCM Playback", AC97_PCM, ac97);
-               if (err < 0)
-                       return err;
+               if (!(ac97->flags & AC97_HAS_NO_STD_PCM)) {
+                       if (ac97->flags & AC97_HAS_NO_PCM_VOL)
+                               err = snd_ac97_cmute_new(card, "PCM Playback Switch", AC97_PCM, ac97);
+                       else
+                               err = snd_ac97_cmix_new(card, "PCM Playback", AC97_PCM, ac97);
+                       if (err < 0)
+                               return err;
+               }
        }
 
        /* build Capture controls */
@@ -1807,6 +1814,39 @@ int snd_ac97_bus(snd_card_t *card, int num, ac97_bus_ops_t *ops,
        return 0;
 }
 
+/* stop no dev release warning */
+static void ac97_device_release(struct device * dev)
+{
+}
+
+/* register ac97 codec to bus */
+static int snd_ac97_dev_register(snd_device_t *device)
+{
+       ac97_t *ac97 = device->device_data;
+       int err;
+
+       ac97->dev.bus = &ac97_bus_type;
+       ac97->dev.parent = ac97->bus->card->dev;
+       ac97->dev.platform_data = ac97;
+       ac97->dev.release = ac97_device_release;
+       snprintf(ac97->dev.bus_id, BUS_ID_SIZE, "card%d-%d", ac97->bus->card->number, ac97->num);
+       if ((err = device_register(&ac97->dev)) < 0) {
+               snd_printk(KERN_ERR "Can't register ac97 bus\n");
+               ac97->dev.bus = NULL;
+               return err;
+       }
+       return 0;
+}
+
+/* unregister ac97 codec */
+static int snd_ac97_dev_unregister(snd_device_t *device)
+{
+       ac97_t *ac97 = device->device_data;
+       if (ac97->dev.bus)
+               device_unregister(&ac97->dev);
+       return snd_ac97_free(ac97);
+}
+
 /* build_ops to do nothing */
 static struct snd_ac97_build_ops null_build_ops;
 
@@ -1840,6 +1880,8 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97)
        const ac97_codec_id_t *pid;
        static snd_device_ops_t ops = {
                .dev_free =     snd_ac97_dev_free,
+               .dev_register = snd_ac97_dev_register,
+               .dev_unregister =       snd_ac97_dev_unregister,
        };
 
        snd_assert(rac97 != NULL, return -EINVAL);
@@ -2539,8 +2581,6 @@ int snd_ac97_tune_hardware(ac97_t *ac97, struct ac97_quirk *quirk, const char *o
 {
        int result;
 
-       snd_assert(quirk, return -EINVAL);
-
        /* quirk overriden? */
        if (override && strcmp(override, "-1") && strcmp(override, "default")) {
                result = apply_quirk_str(ac97, override);
@@ -2549,6 +2589,9 @@ int snd_ac97_tune_hardware(ac97_t *ac97, struct ac97_quirk *quirk, const char *o
                return result;
        }
 
+       if (! quirk)
+               return -EINVAL;
+
        for (; quirk->subvendor; quirk++) {
                if (quirk->subvendor != ac97->subsystem_vendor)
                        continue;
index 66edc857d3e632cb133bb65d72bcdf09eab49912..b584172c1104d55c470a9f810ee0eb9e14f79f49 100644 (file)
@@ -370,141 +370,387 @@ int patch_yamaha_ymf753(ac97_t * ac97)
  *  added support for WM9705,WM9708,WM9709,WM9710,WM9711,WM9712 and WM9717.
  */
 
-int patch_wolfson03(ac97_t * ac97)
+static const snd_kcontrol_new_t wm97xx_snd_ac97_controls[] = {
+AC97_DOUBLE("Front Playback Volume", AC97_WM97XX_FMIXER_VOL, 8, 0, 31, 1),
+AC97_SINGLE("Front Playback Switch", AC97_WM97XX_FMIXER_VOL, 15, 1, 1),
+};
+
+static int patch_wolfson_wm9703_specific(ac97_t * ac97)
 {
        /* This is known to work for the ViewSonic ViewPad 1000
-          Randolph Bentson <bentson@holmsjoen.com> */
+        * Randolph Bentson <bentson@holmsjoen.com>
+        * WM9703/9707/9708/9717 
+        */
+       int err, i;
+       
+       for (i = 0; i < ARRAY_SIZE(wm97xx_snd_ac97_controls); i++) {
+               if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm97xx_snd_ac97_controls[i], ac97))) < 0)
+                       return err;
+       }
+       snd_ac97_write_cache(ac97,  AC97_WM97XX_FMIXER_VOL, 0x0808);
+       return 0;
+}
+
+static struct snd_ac97_build_ops patch_wolfson_wm9703_ops = {
+       .build_specific = patch_wolfson_wm9703_specific,
+};
 
-       // WM9703/9707/9708/9717
-       snd_ac97_write_cache(ac97, AC97_WM97XX_FMIXER_VOL, 0x0808);
-       snd_ac97_write_cache(ac97, AC97_GENERAL_PURPOSE, 0x8000);
+int patch_wolfson03(ac97_t * ac97)
+{
+       ac97->build_ops = &patch_wolfson_wm9703_ops;
        return 0;
 }
-  
-int patch_wolfson04(ac97_t * ac97)
+
+static const snd_kcontrol_new_t wm9704_snd_ac97_controls[] = {
+AC97_DOUBLE("Front Playback Volume", AC97_WM97XX_FMIXER_VOL, 8, 0, 31, 1),
+AC97_SINGLE("Front Playback Switch", AC97_WM97XX_FMIXER_VOL, 15, 1, 1),
+AC97_DOUBLE("Rear Playback Volume", AC97_WM9704_RMIXER_VOL, 8, 0, 31, 1),
+AC97_SINGLE("Rear Playback Switch", AC97_WM9704_RMIXER_VOL, 15, 1, 1),
+AC97_DOUBLE("Rear DAC Volume", AC97_WM9704_RPCM_VOL, 8, 0, 31, 1),
+AC97_DOUBLE("Surround Volume", AC97_SURROUND_MASTER, 8, 0, 31, 1),
+};
+
+static int patch_wolfson_wm9704_specific(ac97_t * ac97)
 {
-       // WM9704M/9704Q
-       // set front and rear mixer volume
-       snd_ac97_write_cache(ac97, AC97_WM97XX_FMIXER_VOL, 0x0808);
-       snd_ac97_write_cache(ac97, AC97_WM9704_RMIXER_VOL, 0x0808);
-       
-       // patch for DVD noise
+       int err, i;
+       for (i = 0; i < ARRAY_SIZE(wm9704_snd_ac97_controls); i++) {
+               if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm9704_snd_ac97_controls[i], ac97))) < 0)
+                       return err;
+       }
+       /* patch for DVD noise */
        snd_ac97_write_cache(ac97, AC97_WM9704_TEST, 0x0200);
-       // init vol
-       snd_ac97_write_cache(ac97, AC97_WM9704_RPCM_VOL, 0x0808);
-       // set rear surround volume
-       snd_ac97_write_cache(ac97, AC97_SURROUND_MASTER, 0x0000);
        return 0;
 }
-  
+
+static struct snd_ac97_build_ops patch_wolfson_wm9704_ops = {
+       .build_specific = patch_wolfson_wm9704_specific,
+};
+
+int patch_wolfson04(ac97_t * ac97)
+{
+       /* WM9704M/9704Q */
+       ac97->build_ops = &patch_wolfson_wm9704_ops;
+       return 0;
+}
+
+static int patch_wolfson_wm9705_specific(ac97_t * ac97)
+{
+       int err, i;
+       for (i = 0; i < ARRAY_SIZE(wm97xx_snd_ac97_controls); i++) {
+               if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm97xx_snd_ac97_controls[i], ac97))) < 0)
+                       return err;
+       }
+       snd_ac97_write_cache(ac97,  0x72, 0x0808);
+       return 0;
+}
+
+static struct snd_ac97_build_ops patch_wolfson_wm9705_ops = {
+       .build_specific = patch_wolfson_wm9705_specific,
+};
+
 int patch_wolfson05(ac97_t * ac97)
 {
-       // WM9705, WM9710
-       // set front mixer volume
-       snd_ac97_write_cache(ac97, AC97_WM97XX_FMIXER_VOL, 0x0808);
+       /* WM9705, WM9710 */
+       ac97->build_ops = &patch_wolfson_wm9705_ops;
+       return 0;
+}
+
+static const char* wm9711_alc_select[] = {"None", "Left", "Right", "Stereo"};
+static const char* wm9711_alc_mix[] = {"Stereo", "Right", "Left", "None"};
+static const char* wm9711_out3_src[] = {"Left", "VREF", "Left + Right", "Mono"};
+static const char* wm9711_out3_lrsrc[] = {"Master Mix", "Headphone Mix"};
+static const char* wm9711_rec_adc[] = {"Stereo", "Left", "Right", "Mute"};
+static const char* wm9711_base[] = {"Linear Control", "Adaptive Boost"};
+static const char* wm9711_rec_gain[] = {"+1.5dB Steps", "+0.75dB Steps"};
+static const char* wm9711_mic[] = {"Mic 1", "Differential", "Mic 2", "Stereo"};
+static const char* wm9711_rec_sel[] = 
+       {"Mic 1", "NC", "NC", "Master Mix", "Line", "Headphone Mix", "Phone Mix", "Phone"};
+static const char* wm9711_ng_type[] = {"Constant Gain", "Mute"};
+
+static const struct ac97_enum wm9711_enum[] = {
+AC97_ENUM_SINGLE(AC97_PCI_SVID, 14, 4, wm9711_alc_select),
+AC97_ENUM_SINGLE(AC97_VIDEO, 10, 4, wm9711_alc_mix),
+AC97_ENUM_SINGLE(AC97_AUX, 9, 4, wm9711_out3_src),
+AC97_ENUM_SINGLE(AC97_AUX, 8, 2, wm9711_out3_lrsrc),
+AC97_ENUM_SINGLE(AC97_REC_SEL, 12, 4, wm9711_rec_adc),
+AC97_ENUM_SINGLE(AC97_MASTER_TONE, 15, 2, wm9711_base),
+AC97_ENUM_DOUBLE(AC97_REC_GAIN, 14, 6, 2, wm9711_rec_gain),
+AC97_ENUM_SINGLE(AC97_MIC, 5, 4, wm9711_mic),
+AC97_ENUM_DOUBLE(AC97_REC_SEL, 8, 0, 8, wm9711_rec_sel),
+AC97_ENUM_SINGLE(AC97_PCI_SVID, 5, 2, wm9711_ng_type),
+};
+
+static const snd_kcontrol_new_t wm9711_snd_ac97_controls[] = {
+AC97_SINGLE("ALC Target Volume", AC97_CODEC_CLASS_REV, 12, 15, 0),
+AC97_SINGLE("ALC Hold Time", AC97_CODEC_CLASS_REV, 8, 15, 0),
+AC97_SINGLE("ALC Decay Time", AC97_CODEC_CLASS_REV, 4, 15, 0),
+AC97_SINGLE("ALC Attack Time", AC97_CODEC_CLASS_REV, 0, 15, 0),
+AC97_ENUM("ALC Function", wm9711_enum[0]),
+AC97_SINGLE("ALC Max Volume", AC97_PCI_SVID, 11, 7, 1),
+AC97_SINGLE("ALC ZC Timeout", AC97_PCI_SVID, 9, 3, 1),
+AC97_SINGLE("ALC ZC Switch", AC97_PCI_SVID, 8, 1, 0),
+AC97_SINGLE("ALC NG Switch", AC97_PCI_SVID, 7, 1, 0),
+AC97_ENUM("ALC NG Type", wm9711_enum[9]),
+AC97_SINGLE("ALC NG Threshold", AC97_PCI_SVID, 0, 31, 1),
+
+AC97_SINGLE("Side Tone Switch", AC97_VIDEO, 15, 1, 1),
+AC97_SINGLE("Side Tone Volume", AC97_VIDEO, 12, 7, 1),
+AC97_ENUM("ALC Headphone Mux", wm9711_enum[1]),
+AC97_SINGLE("ALC Headphone Volume", AC97_VIDEO, 7, 7, 1),
+
+AC97_SINGLE("Out3 Switch", AC97_AUX, 15, 1, 1),
+AC97_SINGLE("Out3 ZC Switch", AC97_AUX, 7, 1, 1),
+AC97_ENUM("Out3 Mux", wm9711_enum[2]),
+AC97_ENUM("Out3 LR Mux", wm9711_enum[3]),
+AC97_SINGLE("Out3 Volume", AC97_AUX, 0, 31, 1),
+
+AC97_SINGLE("Beep to Headphone Switch", AC97_PC_BEEP, 15, 1, 1),
+AC97_SINGLE("Beep to Headphone Volume", AC97_PC_BEEP, 12, 7, 1),
+AC97_SINGLE("Beep to Side Tone Switch", AC97_PC_BEEP, 11, 1, 1),
+AC97_SINGLE("Beep to Side Tone Volume", AC97_PC_BEEP, 8, 7, 1),
+AC97_SINGLE("Beep to Phone Switch", AC97_PC_BEEP, 7, 1, 1),
+AC97_SINGLE("Beep to Phone Volume", AC97_PC_BEEP, 4, 7, 1),
+
+AC97_SINGLE("Aux to Headphone Switch", AC97_CD, 15, 1, 1),
+AC97_SINGLE("Aux to Headphone Volume", AC97_CD, 12, 7, 1),
+AC97_SINGLE("Aux to Side Tone Switch", AC97_CD, 11, 1, 1),
+AC97_SINGLE("Aux to Side Tone Volume", AC97_CD, 8, 7, 1),
+AC97_SINGLE("Aux to Phone Switch", AC97_CD, 7, 1, 1),
+AC97_SINGLE("Aux to Phone Volume", AC97_CD, 4, 7, 1),
+
+AC97_SINGLE("Phone to Headphone Switch", AC97_PHONE, 15, 1, 1),
+AC97_SINGLE("Phone to Master Switch", AC97_PHONE, 14, 1, 1),
+
+AC97_SINGLE("Line to Headphone Switch", AC97_LINE, 15, 1, 1),
+AC97_SINGLE("Line to Master Switch", AC97_LINE, 14, 1, 1),
+AC97_SINGLE("Line to Phone Switch", AC97_LINE, 13, 1, 1),
+
+AC97_SINGLE("PCM Playback to Headphone Switch", AC97_PCM, 15, 1, 1),
+AC97_SINGLE("PCM Playback to Master Switch", AC97_PCM, 14, 1, 1),
+AC97_SINGLE("PCM Playback to Phone Switch", AC97_PCM, 13, 1, 1),
+
+AC97_SINGLE("Capture 20dB Boost Switch", AC97_REC_SEL, 14, 1, 0),
+AC97_ENUM("Capture to Phone Mux", wm9711_enum[4]),
+AC97_SINGLE("Capture to Phone 20dB Boost Switch", AC97_REC_SEL, 11, 1, 1),
+AC97_ENUM("Capture Select", wm9711_enum[8]),
+
+AC97_SINGLE("3D Upper Cut-off Switch", AC97_3D_CONTROL, 5, 1, 1),
+AC97_SINGLE("3D Lower Cut-off Switch", AC97_3D_CONTROL, 4, 1, 1),
+
+AC97_ENUM("Bass Control", wm9711_enum[5]),
+AC97_SINGLE("Bass Cut-off Switch", AC97_MASTER_TONE, 12, 1, 1),
+AC97_SINGLE("Tone Cut-off Switch", AC97_MASTER_TONE, 4, 1, 1),
+AC97_SINGLE("Playback Attenuate (-6dB) Switch", AC97_MASTER_TONE, 6, 1, 0),
+
+AC97_SINGLE("ADC Switch", AC97_REC_GAIN, 15, 1, 1),
+AC97_ENUM("Capture Volume Steps", wm9711_enum[6]),
+AC97_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 15, 1),
+AC97_SINGLE("Capture ZC Switch", AC97_REC_GAIN, 7, 1, 0),
+
+AC97_SINGLE("Mic 1 to Phone Switch", AC97_MIC, 14, 1, 1),
+AC97_SINGLE("Mic 2 to Phone Switch", AC97_MIC, 13, 1, 1),
+AC97_ENUM("Mic Select Source", wm9711_enum[7]),
+AC97_SINGLE("Mic 1 Volume", AC97_MIC, 8, 32, 1),
+AC97_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 7, 1, 0),
+
+AC97_SINGLE("Master ZC Switch", AC97_MASTER, 7, 1, 0),
+AC97_SINGLE("Headphone ZC Switch", AC97_HEADPHONE, 7, 1, 0),
+AC97_SINGLE("Mono ZC Switch", AC97_MASTER_MONO, 7, 1, 0),
+};
+
+static int patch_wolfson_wm9711_specific(ac97_t * ac97)
+{
+       int err, i;
+       
+       for (i = 0; i < ARRAY_SIZE(wm9711_snd_ac97_controls); i++) {
+               if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm9711_snd_ac97_controls[i], ac97))) < 0)
+                       return err;
+       }
+       snd_ac97_write_cache(ac97,  AC97_CODEC_CLASS_REV, 0x0808);
+       snd_ac97_write_cache(ac97,  AC97_PCI_SVID, 0x0808);
+       snd_ac97_write_cache(ac97,  AC97_VIDEO, 0x0808);
+       snd_ac97_write_cache(ac97,  AC97_AUX, 0x0808);
+       snd_ac97_write_cache(ac97,  AC97_PC_BEEP, 0x0808);
+       snd_ac97_write_cache(ac97,  AC97_CD, 0x0000);
        return 0;
 }
 
+static struct snd_ac97_build_ops patch_wolfson_wm9711_ops = {
+       .build_specific = patch_wolfson_wm9711_specific,
+};
+
 int patch_wolfson11(ac97_t * ac97)
 {
-       // WM9711, WM9712
-       // set out3 volume
-       snd_ac97_write_cache(ac97, AC97_WM9711_OUT3VOL, 0x0808);
+       /* WM9711, WM9712 */
+       ac97->build_ops = &patch_wolfson_wm9711_ops;
+
+       ac97->flags |= AC97_HAS_NO_REC_GAIN | AC97_STEREO_MUTES | AC97_HAS_NO_MIC |
+               AC97_HAS_NO_PC_BEEP | AC97_HAS_NO_VIDEO | AC97_HAS_NO_CD;
+       
        return 0;
 }
 
-static const char* wm9713_mic_mixer[] = {"Stereo", "Mic1", "Mic2", "Mute"};
+static const char* wm9713_mic_mixer[] = {"Stereo", "Mic 1", "Mic 2", "Mute"};
 static const char* wm9713_rec_mux[] = {"Stereo", "Left", "Right", "Mute"};
-static const char* wm9713_rec_src_l[] = {"Mic1", "Mic2", "Line L", "Mono In", "HP Mix L", "Spk Mix", "Mono Mix", "Zh"};
-static const char* wm9713_rec_src_r[] = {"Mic1", "Mic2", "Line R", "Mono In", "HP Mix R", "Spk Mix", "Mono Mix", "Zh"};
+static const char* wm9713_rec_src[] = 
+       {"Mic 1", "Mic 2", "Line", "Mono In", "Headphone Mix", "Master Mix", 
+       "Mono Mix", "Zh"};
+static const char* wm9713_rec_gain[] = {"+1.5dB Steps", "+0.75dB Steps"};
+static const char* wm9713_alc_select[] = {"None", "Left", "Right", "Stereo"};
+static const char* wm9713_mono_pga[] = {"Vmid", "Zh", "Mono Mix", "Inv 1"};
+static const char* wm9713_spk_pga[] = 
+       {"Vmid", "Zh", "Headphone Mix", "Master Mix", "Inv", "NC", "NC", "NC"};
+static const char* wm9713_hp_pga[] = {"Vmid", "Zh", "Headphone Mix", "NC"};
+static const char* wm9713_out3_pga[] = {"Vmid", "Zh", "Inv 1", "NC"};
+static const char* wm9713_out4_pga[] = {"Vmid", "Zh", "Inv 2", "NC"};
+static const char* wm9713_dac_inv[] = 
+       {"Off", "Mono Mix", "Master Mix", "Headphone Mix L", "Headphone Mix R", 
+       "Headphone Mix Mono", "NC", "Vmid"};
+static const char* wm9713_base[] = {"Linear Control", "Adaptive Boost"};
+static const char* wm9713_ng_type[] = {"Constant Gain", "Mute"};
 
 static const struct ac97_enum wm9713_enum[] = {
 AC97_ENUM_SINGLE(AC97_LINE, 3, 4, wm9713_mic_mixer),
 AC97_ENUM_SINGLE(AC97_VIDEO, 14, 4, wm9713_rec_mux),
 AC97_ENUM_SINGLE(AC97_VIDEO, 9, 4, wm9713_rec_mux),
-AC97_ENUM_SINGLE(AC97_VIDEO, 3, 8, wm9713_rec_src_l),
-AC97_ENUM_SINGLE(AC97_VIDEO, 0, 8, wm9713_rec_src_r),
+AC97_ENUM_DOUBLE(AC97_VIDEO, 3, 0, 8, wm9713_rec_src),
+AC97_ENUM_DOUBLE(AC97_CD, 14, 6, 2, wm9713_rec_gain),
+AC97_ENUM_SINGLE(AC97_PCI_SVID, 14, 4, wm9713_alc_select),
+AC97_ENUM_SINGLE(AC97_REC_GAIN, 14, 4, wm9713_mono_pga),
+AC97_ENUM_DOUBLE(AC97_REC_GAIN, 11, 8, 8, wm9713_spk_pga),
+AC97_ENUM_DOUBLE(AC97_REC_GAIN, 6, 4, 4, wm9713_hp_pga),
+AC97_ENUM_SINGLE(AC97_REC_GAIN, 2, 4, wm9713_out3_pga),
+AC97_ENUM_SINGLE(AC97_REC_GAIN, 0, 4, wm9713_out4_pga),
+AC97_ENUM_DOUBLE(AC97_REC_GAIN_MIC, 13, 10, 8, wm9713_dac_inv),
+AC97_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 15, 2, wm9713_base),
+AC97_ENUM_SINGLE(AC97_PCI_SVID, 5, 2, wm9713_ng_type),
 };
 
-static const snd_kcontrol_new_t wm13_snd_ac97_controls_line_in[] = {
+static const snd_kcontrol_new_t wm13_snd_ac97_controls[] = {
 AC97_DOUBLE("Line In Volume", AC97_PC_BEEP, 8, 0, 31, 1),
-AC97_SINGLE("Line In to Headphone Mute", AC97_PC_BEEP, 15, 1, 1),
-AC97_SINGLE("Line In to Speaker Mute", AC97_PC_BEEP, 14, 1, 1),
-AC97_SINGLE("Line In to Mono Mute", AC97_PC_BEEP, 13, 1, 1),
+AC97_SINGLE("Line In to Headphone Switch", AC97_PC_BEEP, 15, 1, 1),
+AC97_SINGLE("Line In to Master Switch", AC97_PC_BEEP, 14, 1, 1),
+AC97_SINGLE("Line In to Mono Switch", AC97_PC_BEEP, 13, 1, 1),
+
+AC97_DOUBLE("PCM Playback Volume", AC97_PHONE, 8, 0, 31, 1),
+AC97_SINGLE("PCM Playback to Headphone Switch", AC97_PHONE, 15, 1, 1),
+AC97_SINGLE("PCM Playback to Master Switch", AC97_PHONE, 14, 1, 1),
+AC97_SINGLE("PCM Playback to Mono Switch", AC97_PHONE, 13, 1, 1),
+
+AC97_SINGLE("Mic 1 Volume", AC97_MIC, 8, 31, 1),
+AC97_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1),
+AC97_SINGLE("Mic 1 to Mono Switch", AC97_LINE, 7, 1, 1),
+AC97_SINGLE("Mic 2 to Mono Switch", AC97_LINE, 6, 1, 1),
+AC97_SINGLE("Mic Boost (+20dB) Switch", AC97_LINE, 5, 1, 0),
+AC97_ENUM("Mic to Headphone Mux", wm9713_enum[0]),
+AC97_SINGLE("Mic Headphone Mixer Volume", AC97_LINE, 0, 7, 1),
+
+AC97_SINGLE("Capture Switch", AC97_CD, 15, 1, 1),
+AC97_ENUM("Capture Volume Steps", wm9713_enum[4]),
+AC97_DOUBLE("Capture Volume", AC97_CD, 8, 0, 15, 0),
+AC97_SINGLE("Capture ZC Switch", AC97_CD, 7, 1, 0),
+
+AC97_ENUM("Capture to Headphone Mux", wm9713_enum[1]),
+AC97_SINGLE("Capture to Headphone Volume", AC97_VIDEO, 11, 7, 1),
+AC97_ENUM("Capture to Mono Mux", wm9713_enum[2]),
+AC97_SINGLE("Capture to Mono Boost (+20dB) Switch", AC97_VIDEO, 8, 1, 0),
+AC97_SINGLE("Capture ADC Boost (+20dB) Switch", AC97_VIDEO, 6, 1, 0),
+AC97_ENUM("Capture Select", wm9713_enum[3]),
+
+AC97_SINGLE("ALC Target Volume", AC97_CODEC_CLASS_REV, 12, 15, 0),
+AC97_SINGLE("ALC Hold Time", AC97_CODEC_CLASS_REV, 8, 15, 0),
+AC97_SINGLE("ALC Decay Time ", AC97_CODEC_CLASS_REV, 4, 15, 0),
+AC97_SINGLE("ALC Attack Time", AC97_CODEC_CLASS_REV, 0, 15, 0),
+AC97_ENUM("ALC Function", wm9713_enum[5]),
+AC97_SINGLE("ALC Max Volume", AC97_PCI_SVID, 11, 7, 0),
+AC97_SINGLE("ALC ZC Timeout", AC97_PCI_SVID, 9, 3, 0),
+AC97_SINGLE("ALC ZC Switch", AC97_PCI_SVID, 8, 1, 0),
+AC97_SINGLE("ALC NG Switch", AC97_PCI_SVID, 7, 1, 0),
+AC97_ENUM("ALC NG Type", wm9713_enum[13]),
+AC97_SINGLE("ALC NG Threshold", AC97_PCI_SVID, 0, 31, 0),
+
+AC97_DOUBLE("Master ZC Switch", AC97_MASTER, 14, 6, 1, 0),
+AC97_DOUBLE("Headphone ZC Switch", AC97_HEADPHONE, 14, 6, 1, 0),
+AC97_DOUBLE("Out3/4 ZC Switch", AC97_MASTER_MONO, 14, 6, 1, 0),
+AC97_SINGLE("Master Right Switch", AC97_MASTER, 7, 1, 1),
+AC97_SINGLE("Headphone Right Switch", AC97_HEADPHONE, 7, 1, 1),
+AC97_SINGLE("Out3/4 Right Switch", AC97_MASTER_MONO, 7, 1, 1),
+
+AC97_SINGLE("Mono In to Headphone Switch", AC97_MASTER_TONE, 15, 1, 1),
+AC97_SINGLE("Mono In to Master Switch", AC97_MASTER_TONE, 14, 1, 1),
+AC97_SINGLE("Mono In Volume", AC97_MASTER_TONE, 8, 31, 1),
+AC97_SINGLE("Mono Switch", AC97_MASTER_TONE, 7, 1, 1),
+AC97_SINGLE("Mono ZC Switch", AC97_MASTER_TONE, 6, 1, 0),
+AC97_SINGLE("Mono Volume", AC97_MASTER_TONE, 0, 31, 1),
+
+AC97_SINGLE("PC Beep to Headphone Switch", AC97_AUX, 15, 1, 1),
+AC97_SINGLE("PC Beep to Headphone Volume", AC97_AUX, 12, 7, 1),
+AC97_SINGLE("PC Beep to Master Switch", AC97_AUX, 11, 1, 1),
+AC97_SINGLE("PC Beep to Master Volume", AC97_AUX, 8, 7, 1),
+AC97_SINGLE("PC Beep to Mono Switch", AC97_AUX, 7, 1, 1),
+AC97_SINGLE("PC Beep to Mono Volume", AC97_AUX, 4, 7, 1),
+
+AC97_SINGLE("Voice to Headphone Switch", AC97_PCM, 15, 1, 1),
+AC97_SINGLE("Voice to Headphone Volume", AC97_PCM, 12, 7, 1),
+AC97_SINGLE("Voice to Master Switch", AC97_PCM, 11, 1, 1),
+AC97_SINGLE("Voice to Master Volume", AC97_PCM, 8, 7, 1),
+AC97_SINGLE("Voice to Mono Switch", AC97_PCM, 7, 1, 1),
+AC97_SINGLE("Voice to Mono Volume", AC97_PCM, 4, 7, 1),
+
+AC97_SINGLE("Aux to Headphone Switch", AC97_REC_SEL, 15, 1, 1),
+AC97_SINGLE("Aux to Headphone Volume", AC97_REC_SEL, 12, 7, 1),
+AC97_SINGLE("Aux to Master Switch", AC97_REC_SEL, 11, 1, 1),
+AC97_SINGLE("Aux to Master Volume", AC97_REC_SEL, 8, 7, 1),
+AC97_SINGLE("Aux to Mono Switch", AC97_REC_SEL, 7, 1, 1),
+AC97_SINGLE("Aux to Mono Volume", AC97_REC_SEL, 4, 7, 1),
+
+AC97_ENUM("Mono Input Mux", wm9713_enum[6]),
+AC97_ENUM("Master Input Mux", wm9713_enum[7]),
+AC97_ENUM("Headphone Input Mux", wm9713_enum[8]),
+AC97_ENUM("Out 3 Input Mux", wm9713_enum[9]),
+AC97_ENUM("Out 4 Input Mux", wm9713_enum[10]),
+
+AC97_ENUM("Bass Control", wm9713_enum[12]),
+AC97_SINGLE("Bass Cut-off Switch", AC97_GENERAL_PURPOSE, 12, 1, 1),
+AC97_SINGLE("Tone Cut-off Switch", AC97_GENERAL_PURPOSE, 4, 1, 1),
+AC97_SINGLE("Playback Attenuate (-6dB) Switch", AC97_GENERAL_PURPOSE, 6, 1, 0),
+AC97_SINGLE("Bass Volume", AC97_GENERAL_PURPOSE, 8, 15, 1),
+AC97_SINGLE("Tone Volume", AC97_GENERAL_PURPOSE, 0, 15, 1),
 };
 
-static const snd_kcontrol_new_t wm13_snd_ac97_controls_dac[] = {
-AC97_DOUBLE("DAC Volume", AC97_PHONE, 8, 0, 31, 1),
-AC97_SINGLE("DAC to Headphone Mute", AC97_PHONE, 15, 1, 1),
-AC97_SINGLE("DAC to Speaker Mute", AC97_PHONE, 14, 1, 1),
-AC97_SINGLE("DAC to Mono Mute", AC97_PHONE, 13, 1, 1),
+static const snd_kcontrol_new_t wm13_snd_ac97_controls_3d[] = {
+AC97_ENUM("Inv Input Mux", wm9713_enum[11]),
+AC97_SINGLE("3D Upper Cut-off Switch", AC97_REC_GAIN_MIC, 5, 1, 0),
+AC97_SINGLE("3D Lower Cut-off Switch", AC97_REC_GAIN_MIC, 4, 1, 0),
+AC97_SINGLE("3D Depth", AC97_REC_GAIN_MIC, 0, 15, 1),
 };
 
-static const snd_kcontrol_new_t wm13_snd_ac97_controls_mic[] = {
-AC97_SINGLE("MICA Volume", AC97_MIC, 8, 31, 1),
-AC97_SINGLE("MICB Volume", AC97_MIC, 0, 31, 1),
-AC97_SINGLE("MICA to Mono Mute", AC97_LINE, 7, 1, 1),
-AC97_SINGLE("MICB to Mono Mute", AC97_LINE, 6, 1, 1),
-AC97_SINGLE("MIC Boost (+20dB)", AC97_LINE, 5, 1, 1),
-AC97_ENUM("MIC Headphone Routing", wm9713_enum[0]),
-AC97_SINGLE("MIC Headphone Mixer Volume", AC97_LINE, 0, 7, 1)
-};
-
-static const snd_kcontrol_new_t wm13_snd_ac97_controls_adc[] = {
-AC97_SINGLE("ADC Mute", AC97_CD, 15, 1, 1),
-AC97_DOUBLE("Gain Step Size (1.5dB/0.75dB)", AC97_CD, 14, 6, 1, 1),
-AC97_DOUBLE("ADC Volume",AC97_CD, 8, 0, 15, 0),
-AC97_SINGLE("ADC Zero Cross", AC97_CD, 7, 1, 1),
-};
-
-static const snd_kcontrol_new_t wm13_snd_ac97_controls_recsel[] = {
-AC97_ENUM("Record to Headphone Path", wm9713_enum[1]),
-AC97_SINGLE("Record to Headphone Volume", AC97_VIDEO, 11, 7, 0),
-AC97_ENUM("Record to Mono Path", wm9713_enum[2]),
-AC97_SINGLE("Record to Mono Boost (+20dB)", AC97_VIDEO, 8, 1, 0),
-AC97_SINGLE("Record ADC Boost (+20dB)", AC97_VIDEO, 6, 1, 0),
-AC97_ENUM("Record Select Left", wm9713_enum[3]),
-AC97_ENUM("Record Select Right", wm9713_enum[4]),
-};
+static int patch_wolfson_wm9713_3d (ac97_t * ac97)
+{
+       int err, i;
+    
+       for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_3d); i++) {
+               if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_3d[i], ac97))) < 0)
+                       return err;
+       }
+       return 0;
+}
 
 static int patch_wolfson_wm9713_specific(ac97_t * ac97)
 {
        int err, i;
        
-       for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_line_in); i++) {
-               if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_line_in[i], ac97))) < 0)
+       for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls); i++) {
+               if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls[i], ac97))) < 0)
                        return err;
        }
        snd_ac97_write_cache(ac97, AC97_PC_BEEP, 0x0808);
-       
-       for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_dac); i++) {
-               if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_dac[i], ac97))) < 0)
-                       return err;
-       }
        snd_ac97_write_cache(ac97, AC97_PHONE, 0x0808);
-       
-       for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_mic); i++) {
-               if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_mic[i], ac97))) < 0)
-                       return err;
-       }
        snd_ac97_write_cache(ac97, AC97_MIC, 0x0808);
        snd_ac97_write_cache(ac97, AC97_LINE, 0x00da);
-       
-       for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_adc); i++) {
-               if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_adc[i], ac97))) < 0)
-                       return err;
-       }
        snd_ac97_write_cache(ac97, AC97_CD, 0x0808);
-       
-       for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_recsel); i++) {
-               if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_recsel[i], ac97))) < 0)
-                       return err;
-       }
        snd_ac97_write_cache(ac97, AC97_VIDEO, 0xd612);
        snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x1ba0);
-       
        return 0;
 }
 
@@ -525,6 +771,7 @@ static void patch_wolfson_wm9713_resume (ac97_t * ac97)
 
 static struct snd_ac97_build_ops patch_wolfson_wm9713_ops = {
        .build_specific = patch_wolfson_wm9713_specific,
+       .build_3d = patch_wolfson_wm9713_3d,
 #ifdef CONFIG_PM       
        .suspend = patch_wolfson_wm9713_suspend,
        .resume = patch_wolfson_wm9713_resume
@@ -533,10 +780,13 @@ static struct snd_ac97_build_ops patch_wolfson_wm9713_ops = {
 
 int patch_wolfson13(ac97_t * ac97)
 {
+       /* WM9713, WM9714 */
        ac97->build_ops = &patch_wolfson_wm9713_ops;
 
        ac97->flags |= AC97_HAS_NO_REC_GAIN | AC97_STEREO_MUTES | AC97_HAS_NO_PHONE |
-               AC97_HAS_NO_PC_BEEP | AC97_HAS_NO_VIDEO | AC97_HAS_NO_CD;
+               AC97_HAS_NO_PC_BEEP | AC97_HAS_NO_VIDEO | AC97_HAS_NO_CD | AC97_HAS_NO_TONE |
+               AC97_HAS_NO_STD_PCM;
+       ac97->scaps &= ~AC97_SCAP_MODEM;
 
        snd_ac97_write_cache(ac97, AC97_EXTENDED_MID, 0xda00);
        snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0x3810);
@@ -1379,6 +1629,7 @@ static void check_ad1981_hp_jack_sense(ac97_t *ac97)
        u32 subid = ((u32)ac97->subsystem_vendor << 16) | ac97->subsystem_device;
        switch (subid) {
        case 0x103c0890: /* HP nc6000 */
+       case 0x103c099c: /* HP nx6110 */
        case 0x103c006d: /* HP nx9105 */
        case 0x17340088: /* FSC Scenic-W */
                /* enable headphone jack sense */
@@ -1706,7 +1957,7 @@ static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = {
 };
 
 static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc650[] = {
-        AC97_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0),
+        AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), AC97_ALC650_MULTICH, 11, 1, 0),
         AC97_SINGLE("Analog to IEC958 Output", AC97_ALC650_MULTICH, 12, 1, 0),
        /* disable this controls since it doesn't work as expected */
        /* AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0), */
@@ -1849,12 +2100,12 @@ static int alc655_iec958_route_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_
 }
 
 static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc655[] = {
-        AC97_PAGE_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0, 0),
+        AC97_PAGE_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), AC97_ALC650_MULTICH, 11, 1, 0, 0),
        /* disable this controls since it doesn't work as expected */
         /* AC97_PAGE_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 14, 1, 0, 0), */
        {
                .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name   = "IEC958 Playback Route",
+               .name   = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
                .info   = alc655_iec958_route_info,
                .get    = alc655_iec958_route_get,
                .put    = alc655_iec958_route_put,
@@ -2415,6 +2666,16 @@ int patch_vt1616(ac97_t * ac97)
        return 0;
 }
 
+/*
+ * VT1617A codec
+ */
+int patch_vt1617a(ac97_t * ac97)
+{
+       ac97->ext_id |= AC97_EI_SPDIF;  /* force the detection of spdif */
+       ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000;
+       return 0;
+}
+
 /*
  */
 static void it2646_update_jacks(ac97_t *ac97)
@@ -2433,7 +2694,7 @@ static const snd_kcontrol_new_t snd_ac97_controls_it2646[] = {
 };
 
 static const snd_kcontrol_new_t snd_ac97_spdif_controls_it2646[] = {
-       AC97_SINGLE("IEC958 Capture Switch", 0x76, 11, 1, 0),
+       AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), 0x76, 11, 1, 0),
        AC97_SINGLE("Analog to IEC958 Output", 0x76, 12, 1, 0),
        AC97_SINGLE("IEC958 Input Monitor", 0x76, 13, 1, 0),
 };
index 7b7377d0f2ae4d3926e3cd7e379be16d488d3027..ec181132010660e2d3015124b98b6b7923132c3b 100644 (file)
@@ -56,5 +56,6 @@ int patch_cm9739(ac97_t * ac97);
 int patch_cm9761(ac97_t * ac97);
 int patch_cm9780(ac97_t * ac97);
 int patch_vt1616(ac97_t * ac97);
+int patch_vt1617a(ac97_t * ac97);
 int patch_it2646(ac97_t * ac97);
 int mpatch_si3036(ac97_t * ac97);
index f08ae71f902da108b4312e75e759a6f672c48ef3..ce6c9fadb5948b57c185dbf44d91e783bb969de0 100644 (file)
@@ -1842,7 +1842,7 @@ static int __devinit snd_ali_pcm(ali_t * codec, int device, struct ali_pcm_descr
        return 0;
 }
 
-struct ali_pcm_description ali_pcms[] = {
+static struct ali_pcm_description ali_pcms[] = {
        { "ALI 5451", ALI_CHANNELS, 1, &snd_ali_playback_ops, &snd_ali_capture_ops },
        { "ALI 5451 modem", 1, 1, &snd_ali_modem_playback_ops, &snd_ali_modem_capture_ops }
 };
@@ -1959,9 +1959,9 @@ static int snd_ali5451_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
 static snd_kcontrol_new_t snd_ali5451_mixer_spdif[] __devinitdata = {
        /* spdif aplayback switch */
        /* FIXME: "IEC958 Playback Switch" may conflict with one on ac97_codec */
-       ALI5451_SPDIF("IEC958 Output switch", 0, 0),
+       ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH), 0, 0),
        /* spdif out to spdif channel */
-       ALI5451_SPDIF("IEC958 Channel Output Switch", 0, 1),
+       ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("Channel Output ",NONE,SWITCH), 0, 1),
        /* spdif in from spdif channel */
        ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), 0, 2)
 };
index cafab4af5c571752765ad1a4b552c9013f4e4aad..904d17394e1c595593f0a60beec7a4f41c493e31 100644 (file)
@@ -248,6 +248,7 @@ struct snd_atiixp_dma {
        unsigned int period_bytes, periods;
        int opened;
        int running;
+       int suspended;
        int pcm_open_flag;
        int ac97_pcm_type;      /* index # of ac97_pcm to access, -1 = not used */
        unsigned int saved_curptr;
@@ -699,12 +700,18 @@ static int snd_atiixp_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
        spin_lock(&chip->reg_lock);
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+       case SNDRV_PCM_TRIGGER_RESUME:
                dma->ops->enable_transfer(chip, 1);
                dma->running = 1;
+               dma->suspended = 0;
                break;
        case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
                dma->ops->enable_transfer(chip, 0);
                dma->running = 0;
+               dma->suspended = cmd == SNDRV_PCM_TRIGGER_SUSPEND;
                break;
        default:
                err = -EINVAL;
@@ -975,6 +982,7 @@ static snd_pcm_hardware_t snd_atiixp_pcm_hw =
 {
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                                SNDRV_PCM_INFO_PAUSE |
                                 SNDRV_PCM_INFO_RESUME |
                                 SNDRV_PCM_INFO_MMAP_VALID),
        .formats =              SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
@@ -1443,7 +1451,7 @@ static int snd_atiixp_resume(snd_card_t *card)
        for (i = 0; i < NUM_ATI_PCMDEVS; i++)
                if (chip->pcmdevs[i]) {
                        atiixp_dma_t *dma = &chip->dmas[i];
-                       if (dma->substream && dma->running) {
+                       if (dma->substream && dma->suspended) {
                                dma->ops->enable_dma(chip, 1);
                                writel((u32)dma->desc_buf.addr | ATI_REG_LINKPTR_EN,
                                       chip->remap_addr + dma->ops->llp_offset);
index 04dcefd8b8ff01eea95c4118db15c20fca490f32..38bd2b5dd434a00c63b4a6dcdfe6c9124bc77c91 100644 (file)
@@ -33,7 +33,7 @@
 /* hardware definition */
 static snd_pcm_hardware_t snd_vortex_playback_hw_adb = {
        .info =
-           (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_RESUME |
+           (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */
             SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
             SNDRV_PCM_INFO_MMAP_VALID),
        .formats =
@@ -58,7 +58,7 @@ static snd_pcm_hardware_t snd_vortex_playback_hw_adb = {
 #ifndef CHIP_AU8820
 static snd_pcm_hardware_t snd_vortex_playback_hw_a3d = {
        .info =
-           (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_RESUME |
+           (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */
             SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
             SNDRV_PCM_INFO_MMAP_VALID),
        .formats =
@@ -78,7 +78,7 @@ static snd_pcm_hardware_t snd_vortex_playback_hw_a3d = {
 #endif
 static snd_pcm_hardware_t snd_vortex_playback_hw_spdif = {
        .info =
-           (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_RESUME |
+           (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */
             SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
             SNDRV_PCM_INFO_MMAP_VALID),
        .formats =
@@ -220,8 +220,10 @@ snd_vortex_pcm_hw_params(snd_pcm_substream_t * substream,
                    vortex_adb_allocroute(chip, -1,
                                          params_channels(hw_params),
                                          substream->stream, type);
-               if (dma < 0)
+               if (dma < 0) {
+                       spin_unlock_irq(&chip->lock);
                        return dma;
+               }
                stream = substream->runtime->private_data = &chip->dma_adb[dma];
                stream->substream = substream;
                /* Setup Buffers. */
index 95c289284267fdf0a33edfd507e5b7277826eac9..7e27bfc3743985d06a4c1fee9a62a86061143b0b 100644 (file)
@@ -188,6 +188,14 @@ static ca0106_details_t ca0106_chip_details[] = {
           .name   = "MSI K8N Diamond MB [SB0438]",
           .gpio_type = 1,
           .i2c_adc = 1 } ,
+        /* Shuttle XPC SD31P which has an onboard Creative Labs Sound Blaster Live! 24-bit EAX
+         * high-definition 7.1 audio processor".
+         * Added using info from andrewvegan in alsa bug #1298
+         */
+        { .serial = 0x30381297,
+          .name   = "Shuttle XPC SD31P [SD31P]",
+          .gpio_type = 1,
+          .i2c_adc = 1 } ,
         { .serial = 0,
           .name   = "AudigyLS [Unknown]" }
 };
index 0e5e9ce0ff28be76943cf8d9809a0028cbaa9bfe..b6b8882ce704fb3bd70dd11b5d380f97f64bcc8d 100644 (file)
@@ -297,7 +297,7 @@ static int snd_ca0106_spdif_put(snd_kcontrol_t * kcontrol,
 static snd_kcontrol_new_t snd_ca0106_spdif_mask_control =
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-        .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+        .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
         .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
        .count =        4,
         .info =         snd_ca0106_spdif_info,
@@ -306,7 +306,7 @@ static snd_kcontrol_new_t snd_ca0106_spdif_mask_control =
 
 static snd_kcontrol_new_t snd_ca0106_spdif_control =
 {
-        .iface =       SNDRV_CTL_ELEM_IFACE_MIXER,
+        .iface =       SNDRV_CTL_ELEM_IFACE_PCM,
         .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
        .count =        4,
         .info =         snd_ca0106_spdif_info,
index f5a4ac1ceef917303423927584d92f3017b41e1a..b098b51099c2ddbccac84f9ebf2ebae629837b90 100644 (file)
@@ -1029,7 +1029,7 @@ static int snd_cmipci_spdif_mask_get(snd_kcontrol_t * kcontrol,
 static snd_kcontrol_new_t snd_cmipci_spdif_mask __devinitdata =
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
        .info =         snd_cmipci_spdif_mask_info,
        .get =          snd_cmipci_spdif_mask_get,
index db212ecd792aac6080700f44b365c16290d6286b..b9fff4ee6f9dc789db6285c08cf18bf2332b6260 100644 (file)
@@ -113,7 +113,7 @@ static int __devinit snd_card_cs46xx_probe(struct pci_dev *pci,
                return err;
        }
 #endif
-       if ((err = snd_cs46xx_mixer(chip)) < 0) {
+       if ((err = snd_cs46xx_mixer(chip, 2)) < 0) {
                snd_card_free(card);
                return err;
        }
index ff28af1f658ebf6964535119c1794f6bd3d978d8..4b052158ee3378bb32ec9c3670903a1f8350e6fb 100644 (file)
@@ -1243,8 +1243,8 @@ static snd_pcm_hardware_t snd_cs46xx_playback =
 {
        .info =                 (SNDRV_PCM_INFO_MMAP |
                                 SNDRV_PCM_INFO_INTERLEAVED | 
-                                SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                                SNDRV_PCM_INFO_RESUME),
+                                SNDRV_PCM_INFO_BLOCK_TRANSFER /*|*/
+                                /*SNDRV_PCM_INFO_RESUME*/),
        .formats =              (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |
                                 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
                                 SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE),
@@ -1265,8 +1265,8 @@ static snd_pcm_hardware_t snd_cs46xx_capture =
 {
        .info =                 (SNDRV_PCM_INFO_MMAP |
                                 SNDRV_PCM_INFO_INTERLEAVED |
-                                SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                                SNDRV_PCM_INFO_RESUME),
+                                SNDRV_PCM_INFO_BLOCK_TRANSFER /*|*/
+                                /*SNDRV_PCM_INFO_RESUME*/),
        .formats =              SNDRV_PCM_FMTBIT_S16_LE,
        .rates =                SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
        .rate_min =             5500,
@@ -2231,7 +2231,7 @@ static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = {
 },
 {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "IEC958 Output Switch",
+       .name = SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH),
        .info = snd_mixer_boolean_info,
        .get = snd_cs46xx_iec958_get,
        .put = snd_cs46xx_iec958_put,
@@ -2239,7 +2239,7 @@ static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = {
 },
 {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "IEC958 Input Switch",
+       .name = SNDRV_CTL_NAME_IEC958("Input ",NONE,SWITCH),
        .info = snd_mixer_boolean_info,
        .get = snd_cs46xx_iec958_get,
        .put = snd_cs46xx_iec958_put,
@@ -2249,7 +2249,7 @@ static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = {
 /* Input IEC958 volume does not work for the moment. (Benny) */
 {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "IEC958 Input Volume",
+       .name = SNDRV_CTL_NAME_IEC958("Input ",NONE,VOLUME),
        .info = snd_cs46xx_vol_info,
        .get = snd_cs46xx_vol_iec958_get,
        .put = snd_cs46xx_vol_iec958_put,
@@ -2440,7 +2440,7 @@ static int __devinit cs46xx_detect_codec(cs46xx_t *chip, int codec)
        return -ENXIO;
 }
 
-int __devinit snd_cs46xx_mixer(cs46xx_t *chip)
+int __devinit snd_cs46xx_mixer(cs46xx_t *chip, int spdif_device)
 {
        snd_card_t *card = chip->card;
        snd_ctl_elem_id_t id;
@@ -2476,6 +2476,8 @@ int __devinit snd_cs46xx_mixer(cs46xx_t *chip)
        for (idx = 0; idx < ARRAY_SIZE(snd_cs46xx_controls); idx++) {
                snd_kcontrol_t *kctl;
                kctl = snd_ctl_new1(&snd_cs46xx_controls[idx], chip);
+               if (kctl && kctl->id.iface == SNDRV_CTL_ELEM_IFACE_PCM)
+                       kctl->id.device = spdif_device;
                if ((err = snd_ctl_add(card, kctl)) < 0)
                        return err;
        }
index b17142cabeadf0ead22487452012f820529a8abd..fc377c4b666c6d2d7846a3c13b12b50e144bd288 100644 (file)
@@ -149,7 +149,7 @@ static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci,
                }
        }
 
-       if ((err = snd_emu10k1_mixer(emu)) < 0) {
+       if ((err = snd_emu10k1_mixer(emu, 0, 3)) < 0) {
                snd_card_free(card);
                return err;
        }
index 746b51ef39663e263d290e66805ca69dcfebb653..e69d5b739e802f84c92029d9afdd51b8456c6a9b 100644 (file)
@@ -741,12 +741,20 @@ static emu_chip_details_t emu_chip_details[] = {
         .emu10k1_chip = 1,
         .ac97_chip = 1,
         .sblive51 = 1} ,
+       /* Tested by Thomas Zehetbauer 27th Aug 2005 */
+       {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80651102,
+        .driver = "EMU10K1", .name = "SB Live 5.1 [SB0220]", 
+        .id = "Live",
+        .emu10k1_chip = 1,
+        .ac97_chip = 1,
+        .sblive51 = 1} ,
        {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80641102,
         .driver = "EMU10K1", .name = "SB Live 5.1", 
         .id = "Live",
         .emu10k1_chip = 1,
         .ac97_chip = 1,
         .sblive51 = 1} ,
+       /* Tested by alsa bugtrack user "hus" 12th Sept 2005 */
        {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80611102,
         .driver = "EMU10K1", .name = "SBLive! Player 5.1 [SB0060]", 
         .id = "Live",
index e90c5ddd1d17ef0451e87010040c72bb71966ac7..52c7826df4402ee0e71629ff425bc5ab1f284d9a 100644 (file)
@@ -1183,7 +1183,7 @@ static int snd_emu10k1x_spdif_put(snd_kcontrol_t * kcontrol,
 static snd_kcontrol_new_t snd_emu10k1x_spdif_mask_control =
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
        .count =        3,
        .info =         snd_emu10k1x_spdif_info,
@@ -1192,7 +1192,7 @@ static snd_kcontrol_new_t snd_emu10k1x_spdif_mask_control =
 
 static snd_kcontrol_new_t snd_emu10k1x_spdif_control =
 {
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
        .count =        3,
        .info =         snd_emu10k1x_spdif_info,
index 0529fb281125cf949d2de4ebd2163fbe71fb9d67..637c555cfdb1f42b4a3be06e98dc806fe20ff839 100644 (file)
@@ -1159,12 +1159,12 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
        /* Optical SPDIF Playback Volume */
        A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_OPT_SPDIF_L);
        A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
-       snd_emu10k1_init_stereo_control(&controls[nctl++], "IEC958 Optical Playback Volume", gpr, 0);
+       snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",PLAYBACK,VOLUME), gpr, 0);
        gpr += 2;
        /* Optical SPDIF Capture Volume */
        A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_OPT_SPDIF_L);
        A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
-       snd_emu10k1_init_stereo_control(&controls[nctl++], "IEC958 Optical Capture Volume", gpr, 0);
+       snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",CAPTURE,VOLUME), gpr, 0);
        gpr += 2;
 
        /* Line2 Playback Volume */
@@ -1389,7 +1389,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
                        A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
                }
        }
-       snd_emu10k1_init_stereo_onoff_control(controls + nctl++, "IEC958 Optical Raw Playback Switch", gpr, 0);
+       snd_emu10k1_init_stereo_onoff_control(controls + nctl++, SNDRV_CTL_NAME_IEC958("Optical Raw ",PLAYBACK,SWITCH), gpr, 0);
        gpr += 2;
        
        A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
@@ -1716,7 +1716,7 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
                /* IEC958 TTL Playback Volume */
                for (z = 0; z < 2; z++)
                        VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_SPDIF_CD_L + z, gpr + z);
-               snd_emu10k1_init_stereo_control(controls + i++, "IEC958 TTL Playback Volume", gpr, 0);
+               snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",PLAYBACK,VOLUME), gpr, 0);
                gpr += 2;
        
                /* IEC958 TTL Capture Volume + Switch */
@@ -1724,8 +1724,8 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
                        SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_SPDIF_CD_L + z, gpr + 2 + z);
                        VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
                }
-               snd_emu10k1_init_stereo_control(controls + i++, "IEC958 TTL Capture Volume", gpr, 0);
-               snd_emu10k1_init_stereo_onoff_control(controls + i++, "IEC958 TTL Capture Switch", gpr + 2, 0);
+               snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",CAPTURE,VOLUME), gpr, 0);
+               snd_emu10k1_init_stereo_onoff_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",CAPTURE,SWITCH), gpr + 2, 0);
                gpr += 4;
        }
        
@@ -1750,7 +1750,7 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
                /* IEC958 Optical Playback Volume */
                for (z = 0; z < 2; z++)
                        VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_TOSLINK_L + z, gpr + z);
-               snd_emu10k1_init_stereo_control(controls + i++, "IEC958 LiveDrive Playback Volume", gpr, 0);
+               snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",PLAYBACK,VOLUME), gpr, 0);
                gpr += 2;
        
                /* IEC958 Optical Capture Volume */
@@ -1758,8 +1758,8 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
                        SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_TOSLINK_L + z, gpr + 2 + z);
                        VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
                }
-               snd_emu10k1_init_stereo_control(controls + i++, "IEC958 LiveDrive Capture Volume", gpr, 0);
-               snd_emu10k1_init_stereo_onoff_control(controls + i++, "IEC958 LiveDrive Capture Switch", gpr + 2, 0);
+               snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",CAPTURE,VOLUME), gpr, 0);
+               snd_emu10k1_init_stereo_onoff_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",CAPTURE,SWITCH), gpr + 2, 0);
                gpr += 4;
        }
        
@@ -1784,7 +1784,7 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
                /* IEC958 Coax Playback Volume */
                for (z = 0; z < 2; z++)
                        VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_COAX_SPDIF_L + z, gpr + z);
-               snd_emu10k1_init_stereo_control(controls + i++, "IEC958 Coaxial Playback Volume", gpr, 0);
+               snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",PLAYBACK,VOLUME), gpr, 0);
                gpr += 2;
        
                /* IEC958 Coax Capture Volume + Switch */
@@ -1792,8 +1792,8 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
                        SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_COAX_SPDIF_L + z, gpr + 2 + z);
                        VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
                }
-               snd_emu10k1_init_stereo_control(controls + i++, "IEC958 Coaxial Capture Volume", gpr, 0);
-               snd_emu10k1_init_stereo_onoff_control(controls + i++, "IEC958 Coaxial Capture Switch", gpr + 2, 0);
+               snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",CAPTURE,VOLUME), gpr, 0);
+               snd_emu10k1_init_stereo_onoff_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",CAPTURE,SWITCH), gpr + 2, 0);
                gpr += 4;
        }
        
@@ -1920,7 +1920,7 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
 #endif
                }
 
-               snd_emu10k1_init_stereo_onoff_control(controls + i++, "IEC958 Optical Raw Playback Switch", gpr, 0);
+               snd_emu10k1_init_stereo_onoff_control(controls + i++, SNDRV_CTL_NAME_IEC958("Optical Raw ",PLAYBACK,SWITCH), gpr, 0);
                gpr += 2;
        }
 
index 6be82c5fe138089363749889afbda70fa118b8fe..d71a72e84bcc9181a7c2f23c31b14fd864c9cfe9 100644 (file)
@@ -181,7 +181,7 @@ static int snd_emu10k1_spdif_put(snd_kcontrol_t * kcontrol,
 static snd_kcontrol_new_t snd_emu10k1_spdif_mask_control =
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
        .count =        4,
        .info =         snd_emu10k1_spdif_info,
@@ -190,7 +190,7 @@ static snd_kcontrol_new_t snd_emu10k1_spdif_mask_control =
 
 static snd_kcontrol_new_t snd_emu10k1_spdif_control =
 {
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
        .count =        4,
        .info =         snd_emu10k1_spdif_info,
@@ -295,7 +295,7 @@ static int snd_emu10k1_send_routing_put(snd_kcontrol_t * kcontrol,
 static snd_kcontrol_new_t snd_emu10k1_send_routing_control =
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         "EMU10K1 PCM Send Routing",
        .count =        32,
        .info =         snd_emu10k1_send_routing_info,
@@ -364,7 +364,7 @@ static int snd_emu10k1_send_volume_put(snd_kcontrol_t * kcontrol,
 static snd_kcontrol_new_t snd_emu10k1_send_volume_control =
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         "EMU10K1 PCM Send Volume",
        .count =        32,
        .info =         snd_emu10k1_send_volume_info,
@@ -427,7 +427,7 @@ static int snd_emu10k1_attn_put(snd_kcontrol_t * kcontrol,
 static snd_kcontrol_new_t snd_emu10k1_attn_control =
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         "EMU10K1 PCM Volume",
        .count =        32,
        .info =         snd_emu10k1_attn_info,
@@ -737,7 +737,8 @@ static int rename_ctl(snd_card_t *card, const char *src, const char *dst)
        return -ENOENT;
 }
 
-int __devinit snd_emu10k1_mixer(emu10k1_t *emu)
+int __devinit snd_emu10k1_mixer(emu10k1_t *emu,
+                               int pcm_device, int multi_device)
 {
        int err, pcm;
        snd_kcontrol_t *kctl;
@@ -852,29 +853,35 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu)
 
        if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL)
                return -ENOMEM;
+       kctl->id.device = pcm_device;
        if ((err = snd_ctl_add(card, kctl)))
                return err;
        if ((kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu)) == NULL)
                return -ENOMEM;
+       kctl->id.device = pcm_device;
        if ((err = snd_ctl_add(card, kctl)))
                return err;
        if ((kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu)) == NULL)
                return -ENOMEM;
+       kctl->id.device = pcm_device;
        if ((err = snd_ctl_add(card, kctl)))
                return err;
 
        if ((kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu)) == NULL)
                return -ENOMEM;
+       kctl->id.device = multi_device;
        if ((err = snd_ctl_add(card, kctl)))
                return err;
        
        if ((kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu)) == NULL)
                return -ENOMEM;
+       kctl->id.device = multi_device;
        if ((err = snd_ctl_add(card, kctl)))
                return err;
        
        if ((kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu)) == NULL)
                return -ENOMEM;
+       kctl->id.device = multi_device;
        if ((err = snd_ctl_add(card, kctl)))
                return err;
 
@@ -924,10 +931,14 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu)
                /* sb live! and audigy */
                if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL)
                        return -ENOMEM;
+               if (!emu->audigy)
+                       kctl->id.device = emu->pcm_efx->device;
                if ((err = snd_ctl_add(card, kctl)))
                        return err;
                if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL)
                        return -ENOMEM;
+               if (!emu->audigy)
+                       kctl->id.device = emu->pcm_efx->device;
                if ((err = snd_ctl_add(card, kctl)))
                        return err;
        }
index 520b99af5f550d0429ef030c8c90c0d8027c0171..9c35f6dde1b5a49ccbb4f73f44ac723a21315b77 100644 (file)
@@ -1682,6 +1682,7 @@ static void snd_emu10k1_pcm_efx_free(snd_pcm_t *pcm)
 int __devinit snd_emu10k1_pcm_efx(emu10k1_t * emu, int device, snd_pcm_t ** rpcm)
 {
        snd_pcm_t *pcm;
+       snd_kcontrol_t *kctl;
        int err;
 
        if (rpcm)
@@ -1714,7 +1715,11 @@ int __devinit snd_emu10k1_pcm_efx(emu10k1_t * emu, int device, snd_pcm_t ** rpcm
                emu->efx_voices_mask[0] = 0xffff0000;
                emu->efx_voices_mask[1] = 0;
        }
-       snd_ctl_add(emu->card, snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu));
+       kctl = snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu);
+       if (!kctl)
+               return -ENOMEM;
+       kctl->id.device = device;
+       snd_ctl_add(emu->card, kctl);
 
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024);
 
index 78a81f3912a1ac35c756d2bfb992d6101bde6533..f06b95f41a1de5daa5e73fad55d9b7d7829bd271 100644 (file)
@@ -1444,7 +1444,7 @@ static int snd_es1371_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
 
 /* spdif controls */
 static snd_kcontrol_new_t snd_es1371_mixer_spdif[] __devinitdata = {
-       ES1371_SPDIF("IEC958 Playback Switch"),
+       ES1371_SPDIF(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH)),
        {
                .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
                .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
index ff10e637a95e0ffb1b5d2882e59765ea1b557efb..36b2f62e857385ace4b567b846ac31edd4b0c679 100644 (file)
@@ -1155,10 +1155,10 @@ FM801_SINGLE("FM Playback Switch", FM801_FM_VOL, 15, 1, 1),
 static snd_kcontrol_new_t snd_fm801_controls_multi[] __devinitdata = {
 FM801_SINGLE("AC97 2ch->4ch Copy Switch", FM801_CODEC_CTRL, 7, 1, 0),
 FM801_SINGLE("AC97 18-bit Switch", FM801_CODEC_CTRL, 10, 1, 0),
-FM801_SINGLE("IEC958 Capture Switch", FM801_I2S_MODE, 8, 1, 0),
-FM801_SINGLE("IEC958 Raw Data Playback Switch", FM801_I2S_MODE, 9, 1, 0),
-FM801_SINGLE("IEC958 Raw Data Capture Switch", FM801_I2S_MODE, 10, 1, 0),
-FM801_SINGLE("IEC958 Playback Switch", FM801_GEN_CTRL, 2, 1, 0),
+FM801_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), FM801_I2S_MODE, 8, 1, 0),
+FM801_SINGLE(SNDRV_CTL_NAME_IEC958("Raw Data ",PLAYBACK,SWITCH), FM801_I2S_MODE, 9, 1, 0),
+FM801_SINGLE(SNDRV_CTL_NAME_IEC958("Raw Data ",CAPTURE,SWITCH), FM801_I2S_MODE, 10, 1, 0),
+FM801_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), FM801_GEN_CTRL, 2, 1, 0),
 };
 
 static void snd_fm801_mixer_free_ac97_bus(ac97_bus_t *bus)
index bd8cb33c4fb492fa4d2a198b3cfbe60b6983d96f..ddfb5ff7fb8f804fd6b24af953364c4bede877fd 100644 (file)
@@ -1,5 +1,5 @@
 snd-hda-intel-objs := hda_intel.o
-snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o
+snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o patch_si3054.o
 ifdef CONFIG_PROC_FS
 snd-hda-codec-objs += hda_proc.o
 endif
index e2cf0238728925bef2183adeb72bf9cb8abadb1b..20f7762f714444a8ed5e516977cb0ac4bd4487bd 100644 (file)
@@ -432,22 +432,26 @@ void snd_hda_get_codec_name(struct hda_codec *codec,
 }
 
 /*
- * look for an AFG node
- *
- * return 0 if not found
+ * look for an AFG and MFG nodes
  */
-static int look_for_afg_node(struct hda_codec *codec)
+static void setup_fg_nodes(struct hda_codec *codec)
 {
        int i, total_nodes;
        hda_nid_t nid;
 
        total_nodes = snd_hda_get_sub_nodes(codec, AC_NODE_ROOT, &nid);
        for (i = 0; i < total_nodes; i++, nid++) {
-               if ((snd_hda_param_read(codec, nid, AC_PAR_FUNCTION_TYPE) & 0xff) ==
-                   AC_GRP_AUDIO_FUNCTION)
-                       return nid;
+               switch((snd_hda_param_read(codec, nid, AC_PAR_FUNCTION_TYPE) & 0xff)) {
+               case AC_GRP_AUDIO_FUNCTION:
+                       codec->afg = nid;
+                       break;
+               case AC_GRP_MODEM_FUNCTION:
+                       codec->mfg = nid;
+                       break;
+               default:
+                       break;
+               }
        }
-       return 0;
 }
 
 /*
@@ -507,10 +511,9 @@ int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
        codec->subsystem_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_SUBSYSTEM_ID);
        codec->revision_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_REV_ID);
 
-       /* FIXME: support for multiple AFGs? */
-       codec->afg = look_for_afg_node(codec);
-       if (! codec->afg) {
-               snd_printdd("hda_codec: no AFG node found\n");
+       setup_fg_nodes(codec);
+       if (! codec->afg && ! codec->mfg) {
+               snd_printdd("hda_codec: no AFG or MFG node found\n");
                snd_hda_codec_free(codec);
                return -ENODEV;
        }
@@ -749,12 +752,14 @@ int snd_hda_mixer_amp_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
        long *valp = ucontrol->value.integer.value;
        int change = 0;
 
-       if (chs & 1)
+       if (chs & 1) {
                change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
                                                  0x7f, *valp);
+               valp++;
+       }
        if (chs & 2)
                change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
-                                                  0x7f, valp[1]);
+                                                  0x7f, *valp);
        return change;
 }
 
@@ -796,12 +801,15 @@ int snd_hda_mixer_amp_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
        long *valp = ucontrol->value.integer.value;
        int change = 0;
 
-       if (chs & 1)
+       if (chs & 1) {
                change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
                                                  0x80, *valp ? 0 : 0x80);
+               valp++;
+       }
        if (chs & 2)
                change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
-                                                  0x80, valp[1] ? 0 : 0x80);
+                                                  0x80, *valp ? 0 : 0x80);
+       
        return change;
 }
 
@@ -1155,8 +1163,16 @@ int snd_hda_build_controls(struct hda_bus *bus)
 /*
  * stream formats
  */
-static unsigned int rate_bits[][3] = {
+struct hda_rate_tbl {
+       unsigned int hz;
+       unsigned int alsa_bits;
+       unsigned int hda_fmt;
+};
+
+static struct hda_rate_tbl rate_bits[] = {
        /* rate in Hz, ALSA rate bitmask, HDA format value */
+
+       /* autodetected value used in snd_hda_query_supported_pcm */
        { 8000, SNDRV_PCM_RATE_8000, 0x0500 }, /* 1/6 x 48 */
        { 11025, SNDRV_PCM_RATE_11025, 0x4300 }, /* 1/4 x 44 */
        { 16000, SNDRV_PCM_RATE_16000, 0x0200 }, /* 1/3 x 48 */
@@ -1168,7 +1184,11 @@ static unsigned int rate_bits[][3] = {
        { 96000, SNDRV_PCM_RATE_96000, 0x0800 }, /* 2 x 48 */
        { 176400, SNDRV_PCM_RATE_176400, 0x5800 },/* 4 x 44 */
        { 192000, SNDRV_PCM_RATE_192000, 0x1800 }, /* 4 x 48 */
-       { 0 }
+
+       /* not autodetected value */
+       { 9600, SNDRV_PCM_RATE_KNOT, 0x0400 }, /* 1/5 x 48 */
+
+       { 0 } /* terminator */
 };
 
 /**
@@ -1190,12 +1210,12 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
        int i;
        unsigned int val = 0;
 
-       for (i = 0; rate_bits[i][0]; i++)
-               if (rate_bits[i][0] == rate) {
-                       val = rate_bits[i][2];
+       for (i = 0; rate_bits[i].hz; i++)
+               if (rate_bits[i].hz == rate) {
+                       val = rate_bits[i].hda_fmt;
                        break;
                }
-       if (! rate_bits[i][0]) {
+       if (! rate_bits[i].hz) {
                snd_printdd("invalid rate %d\n", rate);
                return 0;
        }
@@ -1258,9 +1278,9 @@ int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
 
        if (ratesp) {
                u32 rates = 0;
-               for (i = 0; rate_bits[i][0]; i++) {
+               for (i = 0; rate_bits[i].hz; i++) {
                        if (val & (1 << i))
-                               rates |= rate_bits[i][1];
+                               rates |= rate_bits[i].alsa_bits;
                }
                *ratesp = rates;
        }
@@ -1352,13 +1372,13 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
        }
 
        rate = format & 0xff00;
-       for (i = 0; rate_bits[i][0]; i++)
-               if (rate_bits[i][2] == rate) {
+       for (i = 0; rate_bits[i].hz; i++)
+               if (rate_bits[i].hda_fmt == rate) {
                        if (val & (1 << i))
                                break;
                        return 0;
                }
-       if (! rate_bits[i][0])
+       if (! rate_bits[i].hz)
                return 0;
 
        stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
@@ -1541,8 +1561,11 @@ int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_c
                for (c = tbl; c->modelname || c->pci_subvendor; c++) {
                        if (c->pci_subvendor == subsystem_vendor &&
                            (! c->pci_subdevice /* all match */||
-                            (c->pci_subdevice == subsystem_device)))
+                            (c->pci_subdevice == subsystem_device))) {
+                               snd_printdd(KERN_INFO "hda_codec: PCI %x:%x, codec config %d is selected\n",
+                                           subsystem_vendor, subsystem_device, c->config);
                                return c->config;
+                       }
                }
        }
        return -1;
@@ -1803,11 +1826,25 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c
                                cfg->line_out_pins[j] = nid;
                        }
 
-       /* Swap surround and CLFE: the association order is front/CLFE/surr/back */
-       if (cfg->line_outs >= 3) {
+       /* Reorder the surround channels
+        * ALSA sequence is front/surr/clfe/side
+        * HDA sequence is:
+        *    4-ch: front/surr  =>  OK as it is
+        *    6-ch: front/clfe/surr
+        *    8-ch: front/clfe/side/surr
+        */
+       switch (cfg->line_outs) {
+       case 3:
                nid = cfg->line_out_pins[1];
                cfg->line_out_pins[1] = cfg->line_out_pins[2];
                cfg->line_out_pins[2] = nid;
+               break;
+       case 4:
+               nid = cfg->line_out_pins[1];
+               cfg->line_out_pins[1] = cfg->line_out_pins[3];
+               cfg->line_out_pins[3] = cfg->line_out_pins[2];
+               cfg->line_out_pins[2] = nid;
+               break;
        }
 
        return 0;
index dd0d99d2ad2724e937337c4e79720362fab11436..63a29a8a2860e34e092f852f92e86b81511abc65 100644 (file)
@@ -514,6 +514,7 @@ struct hda_codec {
        struct list_head list;  /* list point */
 
        hda_nid_t afg;  /* AFG node id */
+       hda_nid_t mfg;  /* MFG node id */
 
        /* ids */
        u32 vendor_id;
index 2d046abb591108bc9033be2f5ce16b6a4ab95c6b..1229227af5b5f4c98bfa2e1a998817cfb27c5471 100644 (file)
@@ -881,6 +881,11 @@ int snd_hda_parse_generic_codec(struct hda_codec *codec)
        struct hda_gspec *spec;
        int err;
 
+       if(!codec->afg) {
+               snd_printdd("hda_generic: no generic modem yet\n");
+               return -ENODEV;
+       }
+
        spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
        if (spec == NULL) {
                printk(KERN_ERR "hda_generic: can't allocate spec\n");
index 288ab07648305576a4f2b754c6102e55a76502f5..15107df1f490808ebc52dfc5e1a977ee7dc83d08 100644 (file)
@@ -71,7 +71,9 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
                         "{Intel, ESB2},"
                         "{ATI, SB450},"
                         "{VIA, VT8251},"
-                        "{VIA, VT8237A}}");
+                        "{VIA, VT8237A},"
+                        "{SiS, SIS966},"
+                        "{ULI, M5461}}");
 MODULE_DESCRIPTION("Intel HDA driver");
 
 #define SFX    "hda-intel: "
@@ -141,9 +143,24 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
  */
 
 /* max number of SDs */
-#define MAX_ICH6_DEV           8
+/* ICH, ATI and VIA have 4 playback and 4 capture */
+#define ICH6_CAPTURE_INDEX     0
+#define ICH6_NUM_CAPTURE       4
+#define ICH6_PLAYBACK_INDEX    4
+#define ICH6_NUM_PLAYBACK      4
+
+/* ULI has 6 playback and 5 capture */
+#define ULI_CAPTURE_INDEX      0
+#define ULI_NUM_CAPTURE                5
+#define ULI_PLAYBACK_INDEX     5
+#define ULI_NUM_PLAYBACK       6
+
+/* this number is statically defined for simplicity */
+#define MAX_AZX_DEV            16
+
 /* max number of fragments - we may use more if allocating more pages for BDL */
-#define AZX_MAX_FRAG           (PAGE_SIZE / (MAX_ICH6_DEV * 16))
+#define BDL_SIZE               PAGE_ALIGN(8192)
+#define AZX_MAX_FRAG           (BDL_SIZE / (MAX_AZX_DEV * 16))
 /* max buffer size - no h/w limit, you can increase as you like */
 #define AZX_MAX_BUF_SIZE       (1024*1024*1024)
 /* max number of PCM devics per card */
@@ -200,7 +217,6 @@ enum {
 };
 
 /* Defines for ATI HD Audio support in SB450 south bridge */
-#define ATI_SB450_HDAUDIO_PCI_DEVICE_ID     0x437b
 #define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR   0x42
 #define ATI_SB450_HDAUDIO_ENABLE_SNOOP      0x02
 
@@ -258,6 +274,14 @@ struct snd_azx {
        snd_card_t *card;
        struct pci_dev *pci;
 
+       /* chip type specific */
+       int driver_type;
+       int playback_streams;
+       int playback_index_offset;
+       int capture_streams;
+       int capture_index_offset;
+       int num_streams;
+
        /* pci resources */
        unsigned long addr;
        void __iomem *remap_addr;
@@ -267,8 +291,8 @@ struct snd_azx {
        spinlock_t reg_lock;
        struct semaphore open_mutex;
 
-       /* streams */
-       azx_dev_t azx_dev[MAX_ICH6_DEV];
+       /* streams (x num_streams) */
+       azx_dev_t *azx_dev;
 
        /* PCM */
        unsigned int pcm_devs;
@@ -292,6 +316,23 @@ struct snd_azx {
        unsigned int initialized: 1;
 };
 
+/* driver types */
+enum {
+       AZX_DRIVER_ICH,
+       AZX_DRIVER_ATI,
+       AZX_DRIVER_VIA,
+       AZX_DRIVER_SIS,
+       AZX_DRIVER_ULI,
+};
+
+static char *driver_short_names[] __devinitdata = {
+       [AZX_DRIVER_ICH] = "HDA Intel",
+       [AZX_DRIVER_ATI] = "HDA ATI SB",
+       [AZX_DRIVER_VIA] = "HDA VIA VT82xx",
+       [AZX_DRIVER_SIS] = "HDA SIS966",
+       [AZX_DRIVER_ULI] = "HDA ULI M5461"
+};
+
 /*
  * macros for easy use
  */
@@ -360,6 +401,8 @@ static void azx_init_cmd_io(azx_t *chip)
        azx_writel(chip, CORBLBASE, (u32)chip->corb.addr);
        azx_writel(chip, CORBUBASE, upper_32bit(chip->corb.addr));
 
+       /* set the corb size to 256 entries (ULI requires explicitly) */
+       azx_writeb(chip, CORBSIZE, 0x02);
        /* set the corb write pointer to 0 */
        azx_writew(chip, CORBWP, 0);
        /* reset the corb hw read pointer */
@@ -373,6 +416,8 @@ static void azx_init_cmd_io(azx_t *chip)
        azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr);
        azx_writel(chip, RIRBUBASE, upper_32bit(chip->rirb.addr));
 
+       /* set the rirb size to 256 entries (ULI requires explicitly) */
+       azx_writeb(chip, RIRBSIZE, 0x02);
        /* reset the rirb hw write pointer */
        azx_writew(chip, RIRBWP, ICH6_RBRWP_CLR);
        /* set N=1, get RIRB response interrupt for new entry */
@@ -596,7 +641,7 @@ static void azx_int_disable(azx_t *chip)
        int i;
 
        /* disable interrupts in stream descriptor */
-       for (i = 0; i < MAX_ICH6_DEV; i++) {
+       for (i = 0; i < chip->num_streams; i++) {
                azx_dev_t *azx_dev = &chip->azx_dev[i];
                azx_sd_writeb(azx_dev, SD_CTL,
                              azx_sd_readb(azx_dev, SD_CTL) & ~SD_INT_MASK);
@@ -616,7 +661,7 @@ static void azx_int_clear(azx_t *chip)
        int i;
 
        /* clear stream status */
-       for (i = 0; i < MAX_ICH6_DEV; i++) {
+       for (i = 0; i < chip->num_streams; i++) {
                azx_dev_t *azx_dev = &chip->azx_dev[i];
                azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
        }
@@ -686,8 +731,7 @@ static void azx_init_chip(azx_t *chip)
        }
 
        /* For ATI SB450 azalia HD audio, we need to enable snoop */
-       if (chip->pci->vendor == PCI_VENDOR_ID_ATI && 
-           chip->pci->device == ATI_SB450_HDAUDIO_PCI_DEVICE_ID) {
+       if (chip->driver_type == AZX_DRIVER_ATI) {
                pci_read_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, 
                                     &ati_misc_cntl2);
                pci_write_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, 
@@ -714,7 +758,7 @@ static irqreturn_t azx_interrupt(int irq, void* dev_id, struct pt_regs *regs)
                return IRQ_NONE;
        }
        
-       for (i = 0; i < MAX_ICH6_DEV; i++) {
+       for (i = 0; i < chip->num_streams; i++) {
                azx_dev = &chip->azx_dev[i];
                if (status & azx_dev->sd_int_sta_mask) {
                        azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
@@ -879,9 +923,15 @@ static int __devinit azx_codec_create(azx_t *chip, const char *model)
 /* assign a stream for the PCM */
 static inline azx_dev_t *azx_assign_device(azx_t *chip, int stream)
 {
-       int dev, i;
-       dev = stream == SNDRV_PCM_STREAM_PLAYBACK ? 4 : 0;
-       for (i = 0; i < 4; i++, dev++)
+       int dev, i, nums;
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               dev = chip->playback_index_offset;
+               nums = chip->playback_streams;
+       } else {
+               dev = chip->capture_index_offset;
+               nums = chip->capture_streams;
+       }
+       for (i = 0; i < nums; i++, dev++)
                if (! chip->azx_dev[dev].opened) {
                        chip->azx_dev[dev].opened = 1;
                        return &chip->azx_dev[dev];
@@ -899,8 +949,8 @@ static snd_pcm_hardware_t azx_pcm_hw = {
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID |
-                                SNDRV_PCM_INFO_PAUSE |
-                                SNDRV_PCM_INFO_RESUME),
+                                SNDRV_PCM_INFO_PAUSE /*|*/
+                                /*SNDRV_PCM_INFO_RESUME*/),
        .formats =              SNDRV_PCM_FMTBIT_S16_LE,
        .rates =                SNDRV_PCM_RATE_48000,
        .rate_min =             48000,
@@ -1049,6 +1099,7 @@ static int azx_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
                azx_dev->running = 1;
                break;
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_STOP:
                azx_stream_stop(chip, azx_dev);
                azx_dev->running = 0;
@@ -1058,6 +1109,7 @@ static int azx_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
        }
        spin_unlock(&chip->reg_lock);
        if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH ||
+           cmd == SNDRV_PCM_TRIGGER_SUSPEND ||
            cmd == SNDRV_PCM_TRIGGER_STOP) {
                int timeout = 5000;
                while (azx_sd_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START && --timeout)
@@ -1136,6 +1188,7 @@ static int __devinit create_codec_pcm(azx_t *chip, struct hda_codec *codec,
                                              snd_dma_pci_data(chip->pci),
                                              1024 * 64, 1024 * 128);
        chip->pcm[pcm_dev] = pcm;
+       chip->pcm_devs = pcm_dev + 1;
 
        return 0;
 }
@@ -1186,7 +1239,7 @@ static int __devinit azx_init_stream(azx_t *chip)
        /* initialize each stream (aka device)
         * assign the starting bdl address to each stream (device) and initialize
         */
-       for (i = 0; i < MAX_ICH6_DEV; i++) {
+       for (i = 0; i < chip->num_streams; i++) {
                unsigned int off = sizeof(u32) * (i * AZX_MAX_FRAG * 4);
                azx_dev_t *azx_dev = &chip->azx_dev[i];
                azx_dev->bdl = (u32 *)(chip->bdl.area + off);
@@ -1245,7 +1298,7 @@ static int azx_free(azx_t *chip)
        if (chip->initialized) {
                int i;
 
-               for (i = 0; i < MAX_ICH6_DEV; i++)
+               for (i = 0; i < chip->num_streams; i++)
                        azx_stream_stop(chip, &chip->azx_dev[i]);
 
                /* disable interrupts */
@@ -1261,10 +1314,10 @@ static int azx_free(azx_t *chip)
 
                /* wait a little for interrupts to finish */
                msleep(1);
-
-               iounmap(chip->remap_addr);
        }
 
+       if (chip->remap_addr)
+               iounmap(chip->remap_addr);
        if (chip->irq >= 0)
                free_irq(chip->irq, (void*)chip);
 
@@ -1276,6 +1329,7 @@ static int azx_free(azx_t *chip)
                snd_dma_free_pages(&chip->posbuf);
        pci_release_regions(chip->pci);
        pci_disable_device(chip->pci);
+       kfree(chip->azx_dev);
        kfree(chip);
 
        return 0;
@@ -1290,7 +1344,8 @@ static int azx_dev_free(snd_device_t *device)
  * constructor
  */
 static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci,
-                               int posfix, azx_t **rchip)
+                               int posfix, int driver_type,
+                               azx_t **rchip)
 {
        azx_t *chip;
        int err = 0;
@@ -1316,9 +1371,20 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci,
        chip->card = card;
        chip->pci = pci;
        chip->irq = -1;
+       chip->driver_type = driver_type;
 
        chip->position_fix = posfix;
 
+#if BITS_PER_LONG != 64
+       /* Fix up base address on ULI M5461 */
+       if (chip->driver_type == AZX_DRIVER_ULI) {
+               u16 tmp3;
+               pci_read_config_word(pci, 0x40, &tmp3);
+               pci_write_config_word(pci, 0x40, tmp3 | 0x10);
+               pci_write_config_dword(pci, PCI_BASE_ADDRESS_1, 0);
+       }
+#endif
+
        if ((err = pci_request_regions(pci, "ICH HD audio")) < 0) {
                kfree(chip);
                pci_disable_device(pci);
@@ -1344,16 +1410,37 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci,
        pci_set_master(pci);
        synchronize_irq(chip->irq);
 
+       switch (chip->driver_type) {
+       case AZX_DRIVER_ULI:
+               chip->playback_streams = ULI_NUM_PLAYBACK;
+               chip->capture_streams = ULI_NUM_CAPTURE;
+               chip->playback_index_offset = ULI_PLAYBACK_INDEX;
+               chip->capture_index_offset = ULI_CAPTURE_INDEX;
+               break;
+       default:
+               chip->playback_streams = ICH6_NUM_PLAYBACK;
+               chip->capture_streams = ICH6_NUM_CAPTURE;
+               chip->playback_index_offset = ICH6_PLAYBACK_INDEX;
+               chip->capture_index_offset = ICH6_CAPTURE_INDEX;
+               break;
+       }
+       chip->num_streams = chip->playback_streams + chip->capture_streams;
+       chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), GFP_KERNEL);
+       if (! chip->azx_dev) {
+               snd_printk(KERN_ERR "cannot malloc azx_dev\n");
+               goto errout;
+       }
+
        /* allocate memory for the BDL for each stream */
        if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
-                                      PAGE_SIZE, &chip->bdl)) < 0) {
+                                      BDL_SIZE, &chip->bdl)) < 0) {
                snd_printk(KERN_ERR SFX "cannot allocate BDL\n");
                goto errout;
        }
        if (chip->position_fix == POS_FIX_POSBUF) {
                /* allocate memory for the position buffer */
                if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
-                                              MAX_ICH6_DEV * 8, &chip->posbuf)) < 0) {
+                                              chip->num_streams * 8, &chip->posbuf)) < 0) {
                        snd_printk(KERN_ERR SFX "cannot allocate posbuf\n");
                        goto errout;
                }
@@ -1382,6 +1469,10 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci,
                goto errout;
        }
 
+       strcpy(card->driver, "HDA-Intel");
+       strcpy(card->shortname, driver_short_names[chip->driver_type]);
+       sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->addr, chip->irq);
+
        *rchip = chip;
        return 0;
 
@@ -1410,15 +1501,12 @@ static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id *
                return -ENOMEM;
        }
 
-       if ((err = azx_create(card, pci, position_fix[dev], &chip)) < 0) {
+       if ((err = azx_create(card, pci, position_fix[dev], pci_id->driver_data,
+                             &chip)) < 0) {
                snd_card_free(card);
                return err;
        }
 
-       strcpy(card->driver, "HDA-Intel");
-       strcpy(card->shortname, "HDA Intel");
-       sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->addr, chip->irq);
-
        /* create codec instances */
        if ((err = azx_codec_create(chip, model[dev])) < 0) {
                snd_card_free(card);
@@ -1459,12 +1547,13 @@ static void __devexit azx_remove(struct pci_dev *pci)
 
 /* PCI IDs */
 static struct pci_device_id azx_ids[] = {
-       { 0x8086, 0x2668, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH6 */
-       { 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH7 */
-       { 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ESB2 */
-       { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ATI SB450 */
-       { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* VIA VT8251/VT8237A */
-       { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ALI 5461? */
+       { 0x8086, 0x2668, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH6 */
+       { 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH7 */
+       { 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ESB2 */
+       { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */
+       { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */
+       { 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */
+       { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, azx_ids);
index a5de684b69446a6c958324ba566d91794f5313a9..acaef3c811b8c4791271f2250603d8cce6160e32 100644 (file)
@@ -10,11 +10,14 @@ extern struct hda_codec_preset snd_hda_preset_cmedia[];
 extern struct hda_codec_preset snd_hda_preset_analog[];
 /* SigmaTel codecs */
 extern struct hda_codec_preset snd_hda_preset_sigmatel[];
+/* SiLabs 3054/3055 modem codecs */
+extern struct hda_codec_preset snd_hda_preset_si3054[];
 
 static const struct hda_codec_preset *hda_preset_tables[] = {
        snd_hda_preset_realtek,
        snd_hda_preset_cmedia,
        snd_hda_preset_analog,
        snd_hda_preset_sigmatel,
+       snd_hda_preset_si3054,
        NULL
 };
index 2fd05bb841365ee67ebc5f8639307e133c4e0d0a..bceb83a42a38d50705c8eeb91d6af1e72df63013 100644 (file)
@@ -572,7 +572,7 @@ static snd_kcontrol_new_t ad1983_mixers[] = {
        },
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "IEC958 Playback Route",
+               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
                .info = ad1983_spdif_route_info,
                .get = ad1983_spdif_route_get,
                .put = ad1983_spdif_route_put,
@@ -705,7 +705,7 @@ static snd_kcontrol_new_t ad1981_mixers[] = {
        /* identical with AD1983 */
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "IEC958 Playback Route",
+               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
                .info = ad1983_spdif_route_info,
                .get = ad1983_spdif_route_get,
                .put = ad1983_spdif_route_put,
index 86f195f19eef0e64a9d12ffb7dd11f06ded9223c..07fb4f5a54b36558c65575acf630ec6951f5b559 100644 (file)
@@ -647,6 +647,7 @@ static struct hda_board_config cmi9880_cfg_tbl[] = {
        { .modelname = "min_fp", .config = CMI_MIN_FP },
        { .modelname = "full", .config = CMI_FULL },
        { .modelname = "full_dig", .config = CMI_FULL_DIG },
+       { .pci_subvendor = 0x1043, .pci_subdevice = 0x813d, .config = CMI_FULL_DIG }, /* ASUS P5AD2 */
        { .modelname = "allout", .config = CMI_ALLOUT },
        { .modelname = "auto", .config = CMI_AUTO },
        {} /* terminator */
index 9b85699007872a9edc91a2124388ac22ba1d3140..eeb900ab79afdbb677e255a96b0fa62f3308d27e 100644 (file)
@@ -687,6 +687,12 @@ static snd_kcontrol_new_t alc880_asus_w1v_mixer[] = {
        { } /* end */
 };
 
+/* additional mixers to alc880_asus_mixer */
+static snd_kcontrol_new_t alc880_pcbeep_mixer[] = {
+       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+       { } /* end */
+};
 
 /*
  * build control elements
@@ -1524,6 +1530,7 @@ static struct hda_board_config alc880_cfg_tbl[] = {
        /* Back 3 jack plus 1 SPDIF out jack, front 2 jack */
        { .modelname = "3stack-digout", .config = ALC880_3ST_DIG },
        { .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG },
+       { .pci_subvendor = 0x1025, .pci_subdevice = 0x0070, .config = ALC880_3ST_DIG },
 
        /* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/
        { .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG },
@@ -1734,7 +1741,7 @@ static struct alc_config_preset alc880_presets[] = {
                .input_mux = &alc880_capture_source,
        },
        [ALC880_UNIWILL_DIG] = {
-               .mixers = { alc880_asus_mixer },
+               .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer },
                .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs },
                .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
                .dac_nids = alc880_asus_dac_nids,
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c
new file mode 100644 (file)
index 0000000..b0270d1
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * HD audio interface patch for Silicon Labs 3054/5 modem codec
+ *
+ * Copyright (c) 2005 Sasha Khapyorsky <sashak@smlink.com>
+ *                    Takashi Iwai <tiwai@suse.de>
+ *
+ *
+ *  This driver is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This driver is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <sound/driver.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+
+/* si3054 verbs */
+#define SI3054_VERB_READ_NODE  0x900
+#define SI3054_VERB_WRITE_NODE 0x100
+
+/* si3054 nodes (registers) */
+#define SI3054_EXTENDED_MID    2
+#define SI3054_LINE_RATE       3
+#define SI3054_LINE_LEVEL      4
+#define SI3054_GPIO_CFG        5
+#define SI3054_GPIO_POLARITY   6
+#define SI3054_GPIO_STICKY     7
+#define SI3054_GPIO_WAKEUP     8
+#define SI3054_GPIO_STATUS     9
+#define SI3054_GPIO_CONTROL   10
+#define SI3054_MISC_AFE       11
+#define SI3054_CHIPID         12
+#define SI3054_LINE_CFG1      13
+#define SI3054_LINE_STATUS    14
+#define SI3054_DC_TERMINATION 15
+#define SI3054_LINE_CONFIG    16
+#define SI3054_CALLPROG_ATT   17
+#define SI3054_SQ_CONTROL     18
+#define SI3054_MISC_CONTROL   19
+#define SI3054_RING_CTRL1     20
+#define SI3054_RING_CTRL2     21
+
+/* extended MID */
+#define SI3054_MEI_READY 0xf
+
+/* line level */
+#define SI3054_ATAG_MASK 0x00f0
+#define SI3054_DTAG_MASK 0xf000
+
+/* GPIO bits */
+#define SI3054_GPIO_OH    0x0001
+#define SI3054_GPIO_CID   0x0002
+
+/* chipid and revisions */
+#define SI3054_CHIPID_CODEC_REV_MASK 0x000f
+#define SI3054_CHIPID_DAA_REV_MASK   0x00f0
+#define SI3054_CHIPID_INTERNATIONAL  0x0100
+#define SI3054_CHIPID_DAA_ID         0x0f00
+#define SI3054_CHIPID_CODEC_ID      (1<<12)
+
+/* si3054 codec registers (nodes) access macros */
+#define GET_REG(codec,reg) (snd_hda_codec_read(codec,reg,0,SI3054_VERB_READ_NODE,0))
+#define SET_REG(codec,reg,val) (snd_hda_codec_write(codec,reg,0,SI3054_VERB_WRITE_NODE,val))
+
+
+struct si3054_spec {
+       unsigned international;
+       struct hda_pcm pcm;
+};
+
+
+/*
+ * Modem mixer
+ */
+
+#define PRIVATE_VALUE(reg,mask) ((reg<<16)|(mask&0xffff))
+#define PRIVATE_REG(val) ((val>>16)&0xffff)
+#define PRIVATE_MASK(val) (val&0xffff)
+
+static int si3054_switch_info(snd_kcontrol_t *kcontrol,
+                              snd_ctl_elem_info_t *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int si3054_switch_get(snd_kcontrol_t *kcontrol,
+                              snd_ctl_elem_value_t *uvalue)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       u16 reg  = PRIVATE_REG(kcontrol->private_value);
+       u16 mask = PRIVATE_MASK(kcontrol->private_value);
+       uvalue->value.integer.value[0] = (GET_REG(codec, reg)) & mask ? 1 : 0 ;
+       return 0;
+}
+
+static int si3054_switch_put(snd_kcontrol_t *kcontrol,
+                              snd_ctl_elem_value_t *uvalue)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       u16 reg  = PRIVATE_REG(kcontrol->private_value);
+       u16 mask = PRIVATE_MASK(kcontrol->private_value);
+       if (uvalue->value.integer.value[0])
+               SET_REG(codec, reg, (GET_REG(codec, reg)) | mask);
+       else
+               SET_REG(codec, reg, (GET_REG(codec, reg)) & ~mask);
+       return 0;
+}
+
+#define SI3054_KCONTROL(kname,reg,mask) { \
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = kname, \
+       .info = si3054_switch_info, \
+       .get  = si3054_switch_get, \
+       .put  = si3054_switch_put, \
+       .private_value = PRIVATE_VALUE(reg,mask), \
+}
+               
+
+static snd_kcontrol_new_t si3054_modem_mixer[] = {
+       SI3054_KCONTROL("Off-hook Switch", SI3054_GPIO_CONTROL, SI3054_GPIO_OH),
+       SI3054_KCONTROL("Caller ID Switch", SI3054_GPIO_CONTROL, SI3054_GPIO_CID),
+       {}
+};
+
+static int si3054_build_controls(struct hda_codec *codec)
+{
+       return snd_hda_add_new_ctls(codec, si3054_modem_mixer);
+}
+
+
+/*
+ * PCM callbacks
+ */
+
+static int si3054_pcm_prepare(struct hda_pcm_stream *hinfo,
+                             struct hda_codec *codec,
+                             unsigned int stream_tag,
+                             unsigned int format,
+                             snd_pcm_substream_t *substream)
+{
+       u16 val;
+
+       SET_REG(codec, SI3054_LINE_RATE, substream->runtime->rate);
+       val = GET_REG(codec, SI3054_LINE_LEVEL);
+       val &= 0xff << (8 * (substream->stream != SNDRV_PCM_STREAM_PLAYBACK));
+       val |= ((stream_tag & 0xf) << 4) << (8 * (substream->stream == SNDRV_PCM_STREAM_PLAYBACK));
+       SET_REG(codec, SI3054_LINE_LEVEL, val);
+
+       snd_hda_codec_setup_stream(codec, hinfo->nid,
+                                  stream_tag, 0, format);
+       return 0;
+}
+
+static int si3054_pcm_open(struct hda_pcm_stream *hinfo,
+                          struct hda_codec *codec,
+                           snd_pcm_substream_t *substream)
+{
+       static unsigned int rates[] = { 8000, 9600, 16000 };
+       static snd_pcm_hw_constraint_list_t hw_constraints_rates = {
+               .count = ARRAY_SIZE(rates),
+               .list = rates,
+               .mask = 0,
+       };
+       substream->runtime->hw.period_bytes_min = 80;
+       return snd_pcm_hw_constraint_list(substream->runtime, 0,
+                       SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
+}
+
+
+static struct hda_pcm_stream si3054_pcm = {
+       .substreams = 1,
+       .channels_min = 1,
+       .channels_max = 1,
+       .nid = 0x1,
+       .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_KNOT,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       .maxbps = 16,
+       .ops = {
+               .open = si3054_pcm_open,
+               .prepare = si3054_pcm_prepare,
+       },
+};
+
+
+static int si3054_build_pcms(struct hda_codec *codec)
+{
+       struct si3054_spec *spec = codec->spec;
+       struct hda_pcm *info = &spec->pcm;
+       si3054_pcm.nid = codec->mfg;
+       codec->num_pcms = 1;
+       codec->pcm_info = info;
+       info->name = "Si3054 Modem";
+       info->stream[SNDRV_PCM_STREAM_PLAYBACK] = si3054_pcm;
+       info->stream[SNDRV_PCM_STREAM_CAPTURE]  = si3054_pcm;
+       return 0;
+}
+
+
+/*
+ * Init part
+ */
+
+static int si3054_init(struct hda_codec *codec)
+{
+       struct si3054_spec *spec = codec->spec;
+       unsigned wait_count;
+       u16 val;
+
+       snd_hda_codec_write(codec, AC_NODE_ROOT, 0, AC_VERB_SET_CODEC_RESET, 0);
+       snd_hda_codec_write(codec, codec->mfg, 0, AC_VERB_SET_STREAM_FORMAT, 0);
+       SET_REG(codec, SI3054_LINE_RATE, 9600);
+       SET_REG(codec, SI3054_LINE_LEVEL, SI3054_DTAG_MASK|SI3054_ATAG_MASK);
+       SET_REG(codec, SI3054_EXTENDED_MID, 0);
+
+       wait_count = 10;
+       do {
+               msleep(2);
+               val = GET_REG(codec, SI3054_EXTENDED_MID);
+       } while ((val & SI3054_MEI_READY) != SI3054_MEI_READY && wait_count--);
+
+       if((val&SI3054_MEI_READY) != SI3054_MEI_READY) {
+               snd_printk(KERN_ERR "si3054: cannot initialize. EXT MID = %04x\n", val);
+               return -EACCES;
+       }
+
+       SET_REG(codec, SI3054_GPIO_POLARITY, 0xffff);
+       SET_REG(codec, SI3054_GPIO_CFG, 0x0);
+       SET_REG(codec, SI3054_MISC_AFE, 0);
+       SET_REG(codec, SI3054_LINE_CFG1,0x200);
+
+       if((GET_REG(codec,SI3054_LINE_STATUS) & (1<<6)) == 0) {
+               snd_printd("Link Frame Detect(FDT) is not ready (line status: %04x)\n",
+                               GET_REG(codec,SI3054_LINE_STATUS));
+       }
+
+       spec->international = GET_REG(codec, SI3054_CHIPID) & SI3054_CHIPID_INTERNATIONAL;
+
+       return 0;
+}
+
+static void si3054_free(struct hda_codec *codec)
+{
+       kfree(codec->spec);
+}
+
+
+/*
+ */
+
+static struct hda_codec_ops si3054_patch_ops = {
+       .build_controls = si3054_build_controls,
+       .build_pcms = si3054_build_pcms,
+       .init = si3054_init,
+       .free = si3054_free,
+#ifdef CONFIG_PM
+       //.suspend = si3054_suspend,
+       .resume = si3054_init,
+#endif
+};
+
+static int patch_si3054(struct hda_codec *codec)
+{
+       struct si3054_spec *spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+       codec->spec = spec;
+       codec->patch_ops = si3054_patch_ops;
+       return 0;
+}
+
+/*
+ * patch entries
+ */
+struct hda_codec_preset snd_hda_preset_si3054[] = {
+       { .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 },
+       {}
+};
+
index eb20f73be61a68682c91f3294c7d26720b1ac546..39fbe662965d85246ed16eec5cd15bf8f1c0ce63 100644 (file)
@@ -618,15 +618,15 @@ static int __devinit snd_ice1712_delta_init(ice1712_t *ice)
  */
 
 static snd_kcontrol_new_t snd_ice1712_delta1010_wordclock_select __devinitdata =
-ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_PCM, "Word Clock Sync", 0, ICE1712_DELTA_WORD_CLOCK_SELECT, 1, 0);
+ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_WORD_CLOCK_SELECT, 1, 0);
 static snd_kcontrol_new_t snd_ice1712_delta1010lt_wordclock_select __devinitdata =
-ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_PCM, "Word Clock Sync", 0, ICE1712_DELTA_1010LT_WORDCLOCK, 1, 0);
+ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_1010LT_WORDCLOCK, 1, 0);
 static snd_kcontrol_new_t snd_ice1712_delta1010_wordclock_status __devinitdata =
-ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_PCM, "Word Clock Status", 0, ICE1712_DELTA_WORD_CLOCK_STATUS, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE);
+ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Status", 0, ICE1712_DELTA_WORD_CLOCK_STATUS, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE);
 static snd_kcontrol_new_t snd_ice1712_deltadio2496_spdif_in_select __devinitdata =
-ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_PCM, "IEC958 Input Optical", 0, ICE1712_DELTA_SPDIF_INPUT_SELECT, 0, 0);
+ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "IEC958 Input Optical", 0, ICE1712_DELTA_SPDIF_INPUT_SELECT, 0, 0);
 static snd_kcontrol_new_t snd_ice1712_delta_spdif_in_status __devinitdata =
-ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_PCM, "Delta IEC958 Input Status", 0, ICE1712_DELTA_SPDIF_IN_STAT, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE);
+ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Delta IEC958 Input Status", 0, ICE1712_DELTA_SPDIF_IN_STAT, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE);
 
 
 static int __devinit snd_ice1712_delta_add_controls(ice1712_t *ice)
index a2545a5b26c48b1546ea9d35b6a0c31cbeff069b..b97f50d10ba308cd532bac7285c45b9107fbcbbc 100644 (file)
@@ -1422,7 +1422,7 @@ static snd_kcontrol_new_t snd_ice1712_multi_capture_analog_switch __devinitdata
 
 static snd_kcontrol_new_t snd_ice1712_multi_capture_spdif_switch __devinitdata = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "IEC958 Multi Capture Switch",
+       .name = SNDRV_CTL_NAME_IEC958("Multi ",CAPTURE,SWITCH),
        .info = snd_ice1712_pro_mixer_switch_info,
        .get = snd_ice1712_pro_mixer_switch_get,
        .put = snd_ice1712_pro_mixer_switch_put,
@@ -1441,7 +1441,7 @@ static snd_kcontrol_new_t snd_ice1712_multi_capture_analog_volume __devinitdata
 
 static snd_kcontrol_new_t snd_ice1712_multi_capture_spdif_volume __devinitdata = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "IEC958 Multi Capture Volume",
+       .name = SNDRV_CTL_NAME_IEC958("Multi ",CAPTURE,VOLUME),
        .info = snd_ice1712_pro_mixer_volume_info,
        .get = snd_ice1712_pro_mixer_volume_get,
        .put = snd_ice1712_pro_mixer_volume_put,
@@ -1715,7 +1715,7 @@ static int snd_ice1712_spdif_maskp_get(snd_kcontrol_t * kcontrol,
 static snd_kcontrol_new_t snd_ice1712_spdif_maskc __devinitdata =
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
        .info =         snd_ice1712_spdif_info,
        .get =          snd_ice1712_spdif_maskc_get,
@@ -1724,7 +1724,7 @@ static snd_kcontrol_new_t snd_ice1712_spdif_maskc __devinitdata =
 static snd_kcontrol_new_t snd_ice1712_spdif_maskp __devinitdata =
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
        .info =         snd_ice1712_spdif_info,
        .get =          snd_ice1712_spdif_maskp_get,
@@ -2203,7 +2203,7 @@ static snd_kcontrol_new_t snd_ice1712_mixer_pro_analog_route __devinitdata = {
 
 static snd_kcontrol_new_t snd_ice1712_mixer_pro_spdif_route __devinitdata = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "IEC958 Playback Route",
+       .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
        .info = snd_ice1712_pro_route_info,
        .get = snd_ice1712_pro_route_spdif_get,
        .put = snd_ice1712_pro_route_spdif_put,
index 79b5f12e06fc4afba100a65e8eacefbefa697b52..c7af5e5fee13e1f2d318ae32b5d2ba5d7781e487 100644 (file)
@@ -1414,7 +1414,7 @@ static int snd_vt1724_spdif_maskp_get(snd_kcontrol_t * kcontrol,
 static snd_kcontrol_new_t snd_vt1724_spdif_maskc __devinitdata =
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
        .info =         snd_vt1724_spdif_info,
        .get =          snd_vt1724_spdif_maskc_get,
@@ -1423,7 +1423,7 @@ static snd_kcontrol_new_t snd_vt1724_spdif_maskc __devinitdata =
 static snd_kcontrol_new_t snd_vt1724_spdif_maskp __devinitdata =
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
        .info =         snd_vt1724_spdif_info,
        .get =          snd_vt1724_spdif_maskp_get,
@@ -1466,7 +1466,7 @@ static snd_kcontrol_new_t snd_vt1724_spdif_switch __devinitdata =
        .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
        /* FIXME: the following conflict with IEC958 Playback Route */
        // .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH),
-       .name =         "IEC958 Output Switch",
+       .name =         SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH),
        .info =         snd_vt1724_spdif_sw_info,
        .get =          snd_vt1724_spdif_sw_get,
        .put =          snd_vt1724_spdif_sw_put
index d7af3e47443263810fc075e1b7e9e513c01996fc..7b548416dcefc086295511b6845359975bb8dda8 100644 (file)
@@ -389,6 +389,7 @@ typedef struct {
        struct ac97_pcm *pcm;
        int pcm_open_flag;
        unsigned int page_attr_changed: 1;
+       unsigned int suspended: 1;
 } ichdev_t;
 
 typedef struct _snd_intel8x0 intel8x0_t;
@@ -862,12 +863,16 @@ static int snd_intel8x0_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
        unsigned long port = ichdev->reg_offset;
 
        switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
+               ichdev->suspended = 0;
+               /* fallthru */
+       case SNDRV_PCM_TRIGGER_START:
                val = ICH_IOCE | ICH_STARTBM;
                break;
-       case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
+               ichdev->suspended = 1;
+               /* fallthru */
+       case SNDRV_PCM_TRIGGER_STOP:
                val = 0;
                break;
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
@@ -899,9 +904,11 @@ static int snd_intel8x0_ali_trigger(snd_pcm_substream_t *substream, int cmd)
 
        val = igetdword(chip, ICHREG(ALI_DMACR));
        switch (cmd) {
+       case SNDRV_PCM_TRIGGER_RESUME:
+               ichdev->suspended = 0;
+               /* fallthru */
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-       case SNDRV_PCM_TRIGGER_RESUME:
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                        /* clear FIFO for synchronization of channels */
                        fifo = igetdword(chip, fiforeg[ichdev->ali_slot / 4]);
@@ -913,9 +920,11 @@ static int snd_intel8x0_ali_trigger(snd_pcm_substream_t *substream, int cmd)
                val &= ~(1 << (ichdev->ali_slot + 16)); /* clear PAUSE flag */
                iputdword(chip, ICHREG(ALI_DMACR), val | (1 << ichdev->ali_slot)); /* start DMA */
                break;
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               ichdev->suspended = 1;
+               /* fallthru */
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
                iputdword(chip, ICHREG(ALI_DMACR), val | (1 << (ichdev->ali_slot + 16))); /* pause */
                iputbyte(chip, port + ICH_REG_OFF_CR, 0);
                while (igetbyte(chip, port + ICH_REG_OFF_CR))
@@ -994,6 +1003,8 @@ static void snd_intel8x0_setup_pcm_out(intel8x0_t *chip,
 {
        unsigned int cnt;
        int dbl = runtime->rate > 48000;
+
+       spin_lock_irq(&chip->reg_lock);
        switch (chip->device_type) {
        case DEVICE_ALI:
                cnt = igetdword(chip, ICHREG(ALI_SCR));
@@ -1037,6 +1048,7 @@ static void snd_intel8x0_setup_pcm_out(intel8x0_t *chip,
                iputdword(chip, ICHREG(GLOB_CNT), cnt);
                break;
        }
+       spin_unlock_irq(&chip->reg_lock);
 }
 
 static int snd_intel8x0_pcm_prepare(snd_pcm_substream_t * substream)
@@ -1048,15 +1060,12 @@ static int snd_intel8x0_pcm_prepare(snd_pcm_substream_t * substream)
        ichdev->physbuf = runtime->dma_addr;
        ichdev->size = snd_pcm_lib_buffer_bytes(substream);
        ichdev->fragsize = snd_pcm_lib_period_bytes(substream);
-       spin_lock_irq(&chip->reg_lock);
        if (ichdev->ichd == ICHD_PCMOUT) {
                snd_intel8x0_setup_pcm_out(chip, runtime);
-               if (chip->device_type == DEVICE_INTEL_ICH4) {
+               if (chip->device_type == DEVICE_INTEL_ICH4)
                        ichdev->pos_shift = (runtime->sample_bits > 16) ? 2 : 1;
-               }
        }
        snd_intel8x0_setup_periods(chip, ichdev);
-       spin_unlock_irq(&chip->reg_lock);
        return 0;
 }
 
@@ -1815,6 +1824,18 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
                .name = "HP nc6000",
                .type = AC97_TUNE_MUTE_LED
        },
+       {
+               .subvendor = 0x103c,
+               .subdevice = 0x0934,
+               .name = "HP nx8220",
+               .type = AC97_TUNE_MUTE_LED
+       },
+       {
+               .subvendor = 0x103c,
+               .subdevice = 0x099c,
+               .name = "HP nx6110",    /* AD1981B */
+               .type = AC97_TUNE_HP_ONLY
+       },
        {
                .subvendor = 0x103c,
                .subdevice = 0x129d,
@@ -1869,6 +1890,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
                .name = "Fujitsu S6210",        /* STAC9750/51 */
                .type = AC97_TUNE_HP_ONLY
        },
+       {
+               .subvendor = 0x10cf,
+               .subdevice = 0x12ec,
+               .name = "Fujitsu-Siemens 4010",
+               .type = AC97_TUNE_HP_ONLY
+       },
        {
                .subvendor = 0x10f1,
                .subdevice = 0x2665,
@@ -2424,6 +2451,20 @@ static int intel8x0_resume(snd_card_t *card)
                }
        }
 
+       /* resume status */
+       for (i = 0; i < chip->bdbars_count; i++) {
+               ichdev_t *ichdev = &chip->ichd[i];
+               unsigned long port = ichdev->reg_offset;
+               if (! ichdev->substream || ! ichdev->suspended)
+                       continue;
+               if (ichdev->ichd == ICHD_PCMOUT)
+                       snd_intel8x0_setup_pcm_out(chip, ichdev->substream->runtime);
+               iputdword(chip, port + ICH_REG_OFF_BDBAR, ichdev->bdbar_addr);
+               iputbyte(chip, port + ICH_REG_OFF_LVI, ichdev->lvi);
+               iputbyte(chip, port + ICH_REG_OFF_CIV, ichdev->civ);
+               iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI);
+       }
+
        return 0;
 }
 #endif /* CONFIG_PM */
index 79d8eda54f0d48dfa60690db217f7251d451bcfd..d2aa9c82d41e44029d737e370cb8155e899a3c56 100644 (file)
@@ -2067,7 +2067,7 @@ static int snd_korg1212_control_sync_put(snd_kcontrol_t * kcontrol, snd_ctl_elem
         },                                                                                      \
         {                                                                                      \
                 .access =      SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE,       \
-                .iface =        SNDRV_CTL_ELEM_IFACE_PCM,                                      \
+                .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,                                    \
                 .name =                c_name " Monitor Phase Invert",                                 \
                 .info =                snd_korg1212_control_phase_info,                                \
                 .get =         snd_korg1212_control_phase_get,                                 \
@@ -2082,7 +2082,7 @@ static snd_kcontrol_new_t snd_korg1212_controls[] = {
         MON_MIXER(4, "ADAT-5"), MON_MIXER(5, "ADAT-6"), MON_MIXER(6, "ADAT-7"), MON_MIXER(7, "ADAT-8"),
        {
                 .access =      SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE,
-                .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+                .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
                 .name =                "Sync Source",
                 .info =                snd_korg1212_control_sync_info,
                 .get =         snd_korg1212_control_sync_get,
index 7eb20b8f89f62c160d27f97965b3067e2fd86502..2bbeb10ff7c4a0c3aa182a98176a0dde05cf461d 100644 (file)
@@ -189,6 +189,7 @@ struct snd_nm256_stream {
        nm256_t *chip;
        snd_pcm_substream_t *substream;
        int running;
+       int suspended;
        
        u32 buf;        /* offset from chip->buffer */
        int bufsize;    /* buffer size in bytes */
@@ -231,8 +232,10 @@ struct snd_nm256 {
        int mixer_status_mask;          /* bit mask to test the mixer status */
 
        int irq;
+       int irq_acks;
        irqreturn_t (*interrupt)(int, void *, struct pt_regs *);
        int badintrcount;               /* counter to check bogus interrupts */
+       struct semaphore irq_mutex;
 
        nm256_stream_t streams[2];
 
@@ -464,6 +467,37 @@ snd_nm256_set_format(nm256_t *chip, nm256_stream_t *s, snd_pcm_substream_t *subs
        }
 }
 
+/* acquire interrupt */
+static int snd_nm256_acquire_irq(nm256_t *chip)
+{
+       down(&chip->irq_mutex);
+       if (chip->irq < 0) {
+               if (request_irq(chip->pci->irq, chip->interrupt, SA_INTERRUPT|SA_SHIRQ,
+                               chip->card->driver, (void*)chip)) {
+                       snd_printk("unable to grab IRQ %d\n", chip->pci->irq);
+                       up(&chip->irq_mutex);
+                       return -EBUSY;
+               }
+               chip->irq = chip->pci->irq;
+       }
+       chip->irq_acks++;
+       up(&chip->irq_mutex);
+       return 0;
+}
+
+/* release interrupt */
+static void snd_nm256_release_irq(nm256_t *chip)
+{
+       down(&chip->irq_mutex);
+       if (chip->irq_acks > 0)
+               chip->irq_acks--;
+       if (chip->irq_acks == 0 && chip->irq >= 0) {
+               free_irq(chip->irq, (void*)chip);
+               chip->irq = -1;
+       }
+       up(&chip->irq_mutex);
+}
+
 /*
  * start / stop
  */
@@ -538,15 +572,19 @@ snd_nm256_playback_trigger(snd_pcm_substream_t *substream, int cmd)
 
        spin_lock(&chip->reg_lock);
        switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
+               s->suspended = 0;
+               /* fallthru */
+       case SNDRV_PCM_TRIGGER_START:
                if (! s->running) {
                        snd_nm256_playback_start(chip, s, substream);
                        s->running = 1;
                }
                break;
-       case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
+               s->suspended = 1;
+               /* fallthru */
+       case SNDRV_PCM_TRIGGER_STOP:
                if (s->running) {
                        snd_nm256_playback_stop(chip);
                        s->running = 0;
@@ -818,6 +856,8 @@ snd_nm256_playback_open(snd_pcm_substream_t *substream)
 {
        nm256_t *chip = snd_pcm_substream_chip(substream);
 
+       if (snd_nm256_acquire_irq(chip) < 0)
+               return -EBUSY;
        snd_nm256_setup_stream(chip, &chip->streams[SNDRV_PCM_STREAM_PLAYBACK],
                               substream, &snd_nm256_playback);
        return 0;
@@ -828,6 +868,8 @@ snd_nm256_capture_open(snd_pcm_substream_t *substream)
 {
        nm256_t *chip = snd_pcm_substream_chip(substream);
 
+       if (snd_nm256_acquire_irq(chip) < 0)
+               return -EBUSY;
        snd_nm256_setup_stream(chip, &chip->streams[SNDRV_PCM_STREAM_CAPTURE],
                               substream, &snd_nm256_capture);
        return 0;
@@ -839,6 +881,9 @@ snd_nm256_capture_open(snd_pcm_substream_t *substream)
 static int
 snd_nm256_playback_close(snd_pcm_substream_t *substream)
 {
+       nm256_t *chip = snd_pcm_substream_chip(substream);
+
+       snd_nm256_release_irq(chip);
        return 0;
 }
 
@@ -846,6 +891,9 @@ snd_nm256_playback_close(snd_pcm_substream_t *substream)
 static int
 snd_nm256_capture_close(snd_pcm_substream_t *substream)
 {
+       nm256_t *chip = snd_pcm_substream_chip(substream);
+
+       snd_nm256_release_irq(chip);
        return 0;
 }
 
@@ -915,18 +963,16 @@ snd_nm256_pcm(nm256_t *chip, int device)
 static void
 snd_nm256_init_chip(nm256_t *chip)
 {
-       spin_lock_irq(&chip->reg_lock);
        /* Reset everything. */
        snd_nm256_writeb(chip, 0x0, 0x11);
        snd_nm256_writew(chip, 0x214, 0);
        /* stop sounds.. */
        //snd_nm256_playback_stop(chip);
        //snd_nm256_capture_stop(chip);
-       spin_unlock_irq(&chip->reg_lock);
 }
 
 
-static inline void
+static irqreturn_t
 snd_nm256_intr_check(nm256_t *chip)
 {
        if (chip->badintrcount++ > 1000) {
@@ -947,7 +993,9 @@ snd_nm256_intr_check(nm256_t *chip)
                if (chip->streams[SNDRV_PCM_STREAM_CAPTURE].running)
                        snd_nm256_capture_stop(chip);
                chip->badintrcount = 0;
+               return IRQ_HANDLED;
        }
+       return IRQ_NONE;
 }
 
 /* 
@@ -969,10 +1017,8 @@ snd_nm256_interrupt(int irq, void *dev_id, struct pt_regs *dummy)
        status = snd_nm256_readw(chip, NM_INT_REG);
 
        /* Not ours. */
-       if (status == 0) {
-               snd_nm256_intr_check(chip);
-               return IRQ_NONE;
-       }
+       if (status == 0)
+               return snd_nm256_intr_check(chip);
 
        chip->badintrcount = 0;
 
@@ -1036,10 +1082,8 @@ snd_nm256_interrupt_zx(int irq, void *dev_id, struct pt_regs *dummy)
        status = snd_nm256_readl(chip, NM_INT_REG);
 
        /* Not ours. */
-       if (status == 0) {
-               snd_nm256_intr_check(chip);
-               return IRQ_NONE;
-       }
+       if (status == 0)
+               return snd_nm256_intr_check(chip);
 
        chip->badintrcount = 0;
 
@@ -1192,7 +1236,7 @@ snd_nm256_mixer(nm256_t *chip)
                AC97_PC_BEEP, AC97_PHONE, AC97_MIC, AC97_LINE, AC97_CD,
                AC97_VIDEO, AC97_AUX, AC97_PCM, AC97_REC_SEL,
                AC97_REC_GAIN, AC97_GENERAL_PURPOSE, AC97_3D_CONTROL,
-               AC97_EXTENDED_ID,
+               /*AC97_EXTENDED_ID,*/
                AC97_VENDOR_ID1, AC97_VENDOR_ID2,
                -1
        };
@@ -1206,6 +1250,7 @@ snd_nm256_mixer(nm256_t *chip)
        for (i = 0; mixer_regs[i] >= 0; i++)
                set_bit(mixer_regs[i], ac97.reg_accessed);
        ac97.private_data = chip;
+       pbus->no_vra = 1;
        err = snd_ac97_mixer(pbus, &ac97, &chip->ac97);
        if (err < 0)
                return err;
@@ -1281,6 +1326,7 @@ static int nm256_suspend(snd_card_t *card, pm_message_t state)
 static int nm256_resume(snd_card_t *card)
 {
        nm256_t *chip = card->pm_private_data;
+       int i;
 
        /* Perform a full reset on the hardware */
        pci_enable_device(chip->pci);
@@ -1289,6 +1335,15 @@ static int nm256_resume(snd_card_t *card)
        /* restore ac97 */
        snd_ac97_resume(chip->ac97);
 
+       for (i = 0; i < 2; i++) {
+               nm256_stream_t *s = &chip->streams[i];
+               if (s->substream && s->suspended) {
+                       spin_lock_irq(&chip->reg_lock);
+                       snd_nm256_set_format(chip, s, s->substream);
+                       spin_unlock_irq(&chip->reg_lock);
+               }
+       }
+
        return 0;
 }
 #endif /* CONFIG_PM */
@@ -1360,6 +1415,7 @@ snd_nm256_create(snd_card_t *card, struct pci_dev *pci,
        chip->use_cache = usecache;
        spin_lock_init(&chip->reg_lock);
        chip->irq = -1;
+       init_MUTEX(&chip->irq_mutex);
 
        chip->streams[SNDRV_PCM_STREAM_PLAYBACK].bufsize = play_bufsize;
        chip->streams[SNDRV_PCM_STREAM_CAPTURE].bufsize = capt_bufsize;
@@ -1470,15 +1526,6 @@ snd_nm256_create(snd_card_t *card, struct pci_dev *pci,
                chip->coeff_buf[SNDRV_PCM_STREAM_CAPTURE] = addr;
        }
 
-       /* acquire interrupt */
-       if (request_irq(pci->irq, chip->interrupt, SA_INTERRUPT|SA_SHIRQ,
-                       card->driver, (void*)chip)) {
-               err = -EBUSY;
-               snd_printk("unable to grab IRQ %d\n", pci->irq);
-               goto __error;
-       }
-       chip->irq = pci->irq;
-
        /* Fixed setting. */
        chip->mixer_base = NM_MIXER_OFFSET;
 
index b7b554df6705b368e4610e71ad9552dc6e79965e..456be39e8e4a1171f296e2eab71513b0efb4d490 100644 (file)
@@ -1900,7 +1900,7 @@ static snd_kcontrol_new_t snd_rme32_controls[] = {
        },
        {
                .access = SNDRV_CTL_ELEM_ACCESS_READ,
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
                .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
                .info = snd_rme32_control_spdif_mask_info,
                .get =  snd_rme32_control_spdif_mask_get,
@@ -1908,7 +1908,7 @@ static snd_kcontrol_new_t snd_rme32_controls[] = {
        },
        {
                .access = SNDRV_CTL_ELEM_ACCESS_READ,
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
                .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PRO_MASK),
                .info = snd_rme32_control_spdif_mask_info,
                .get =  snd_rme32_control_spdif_mask_get,
index 10c4f45a913c7bc449c8403d03edb3f7f987cfac..9645e9004a48e49550e7e26d08c091595a52df80 100644 (file)
@@ -2266,7 +2266,7 @@ static snd_kcontrol_new_t snd_rme96_controls[] = {
 },
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
        .info =         snd_rme96_control_spdif_mask_info,
        .get =          snd_rme96_control_spdif_mask_get,
@@ -2276,7 +2276,7 @@ static snd_kcontrol_new_t snd_rme96_controls[] = {
 },
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
        .info =         snd_rme96_control_spdif_mask_info,
        .get =          snd_rme96_control_spdif_mask_get,
index 796621de5009bfa3f82284093edc526364def850..6694866089b5cd8061e088a1c27490d1109bbbe4 100644 (file)
@@ -1524,7 +1524,7 @@ static int snd_hdsp_control_spdif_mask_get(snd_kcontrol_t * kcontrol, snd_ctl_el
 }
 
 #define HDSP_SPDIF_IN(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM,  \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdsp_info_spdif_in, \
@@ -1584,7 +1584,7 @@ static int snd_hdsp_put_spdif_in(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
 }
 
 #define HDSP_SPDIF_OUT(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .info = snd_hdsp_info_spdif_bits, \
   .get = snd_hdsp_get_spdif_out, .put = snd_hdsp_put_spdif_out }
 
@@ -1638,7 +1638,7 @@ static int snd_hdsp_put_spdif_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_
 }
 
 #define HDSP_SPDIF_PROFESSIONAL(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .info = snd_hdsp_info_spdif_bits, \
   .get = snd_hdsp_get_spdif_professional, .put = snd_hdsp_put_spdif_professional }
 
@@ -1683,7 +1683,7 @@ static int snd_hdsp_put_spdif_professional(snd_kcontrol_t * kcontrol, snd_ctl_el
 }
 
 #define HDSP_SPDIF_EMPHASIS(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .info = snd_hdsp_info_spdif_bits, \
   .get = snd_hdsp_get_spdif_emphasis, .put = snd_hdsp_put_spdif_emphasis }
 
@@ -1728,7 +1728,7 @@ static int snd_hdsp_put_spdif_emphasis(snd_kcontrol_t * kcontrol, snd_ctl_elem_v
 }
 
 #define HDSP_SPDIF_NON_AUDIO(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .info = snd_hdsp_info_spdif_bits, \
   .get = snd_hdsp_get_spdif_nonaudio, .put = snd_hdsp_put_spdif_nonaudio }
 
@@ -1773,7 +1773,7 @@ static int snd_hdsp_put_spdif_nonaudio(snd_kcontrol_t * kcontrol, snd_ctl_elem_v
 }
 
 #define HDSP_SPDIF_SAMPLE_RATE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ, \
@@ -1834,7 +1834,7 @@ static int snd_hdsp_get_spdif_sample_rate(snd_kcontrol_t * kcontrol, snd_ctl_ele
 }
 
 #define HDSP_SYSTEM_SAMPLE_RATE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ, \
@@ -1858,7 +1858,7 @@ static int snd_hdsp_get_system_sample_rate(snd_kcontrol_t * kcontrol, snd_ctl_el
 }
 
 #define HDSP_AUTOSYNC_SAMPLE_RATE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ, \
@@ -1918,7 +1918,7 @@ static int snd_hdsp_get_autosync_sample_rate(snd_kcontrol_t * kcontrol, snd_ctl_
 }
 
 #define HDSP_SYSTEM_CLOCK_MODE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ, \
@@ -1958,7 +1958,7 @@ static int snd_hdsp_get_system_clock_mode(snd_kcontrol_t * kcontrol, snd_ctl_ele
 }
 
 #define HDSP_CLOCK_SOURCE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdsp_info_clock_source, \
@@ -2124,7 +2124,7 @@ static int snd_hdsp_put_clock_source_lock(snd_kcontrol_t * kcontrol, snd_ctl_ele
 }
 
 #define HDSP_DA_GAIN(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdsp_info_da_gain, \
@@ -2210,7 +2210,7 @@ static int snd_hdsp_put_da_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
 }
 
 #define HDSP_AD_GAIN(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdsp_info_ad_gain, \
@@ -2296,7 +2296,7 @@ static int snd_hdsp_put_ad_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
 }
 
 #define HDSP_PHONE_GAIN(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdsp_info_phone_gain, \
@@ -2382,7 +2382,7 @@ static int snd_hdsp_put_phone_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value
 }
 
 #define HDSP_XLR_BREAKOUT_CABLE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdsp_info_xlr_breakout_cable, \
@@ -2447,7 +2447,7 @@ static int snd_hdsp_put_xlr_breakout_cable(snd_kcontrol_t * kcontrol, snd_ctl_el
    Switching this on desactivates external ADAT
 */
 #define HDSP_AEB(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdsp_info_aeb, \
@@ -2508,7 +2508,7 @@ static int snd_hdsp_put_aeb(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * uc
 }
 
 #define HDSP_PREF_SYNC_REF(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdsp_info_pref_sync_ref, \
@@ -2641,7 +2641,7 @@ static int snd_hdsp_put_pref_sync_ref(snd_kcontrol_t * kcontrol, snd_ctl_elem_va
 }
 
 #define HDSP_AUTOSYNC_REF(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ, \
@@ -2697,7 +2697,7 @@ static int snd_hdsp_get_autosync_ref(snd_kcontrol_t * kcontrol, snd_ctl_elem_val
 }
 
 #define HDSP_LINE_OUT(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdsp_info_line_out, \
@@ -2757,7 +2757,7 @@ static int snd_hdsp_put_line_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
 }
 
 #define HDSP_PRECISE_POINTER(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_CARD, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdsp_info_precise_pointer, \
@@ -2811,7 +2811,7 @@ static int snd_hdsp_put_precise_pointer(snd_kcontrol_t * kcontrol, snd_ctl_elem_
 }
 
 #define HDSP_USE_MIDI_TASKLET(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_CARD, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdsp_info_use_midi_tasklet, \
@@ -2868,6 +2868,7 @@ static int snd_hdsp_put_use_midi_tasklet(snd_kcontrol_t * kcontrol, snd_ctl_elem
 { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
   .name = xname, \
   .index = xindex, \
+  .device = 0, \
   .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
                 SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
   .info = snd_hdsp_info_mixer, \
@@ -2939,7 +2940,7 @@ static int snd_hdsp_put_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *
 }
 
 #define HDSP_WC_SYNC_CHECK(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
@@ -2983,7 +2984,7 @@ static int snd_hdsp_get_wc_sync_check(snd_kcontrol_t * kcontrol, snd_ctl_elem_va
 }
 
 #define HDSP_SPDIF_SYNC_CHECK(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
@@ -3015,7 +3016,7 @@ static int snd_hdsp_get_spdif_sync_check(snd_kcontrol_t * kcontrol, snd_ctl_elem
 }
 
 #define HDSP_ADATSYNC_SYNC_CHECK(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
@@ -3046,7 +3047,7 @@ static int snd_hdsp_get_adatsync_sync_check(snd_kcontrol_t * kcontrol, snd_ctl_e
 }
 
 #define HDSP_ADAT_SYNC_CHECK \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
   .info = snd_hdsp_info_sync_check, \
   .get = snd_hdsp_get_adat_sync_check \
@@ -3119,7 +3120,7 @@ static snd_kcontrol_new_t snd_hdsp_controls[] = {
 },
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
        .info =         snd_hdsp_control_spdif_mask_info,
        .get =          snd_hdsp_control_spdif_mask_get,
@@ -3129,7 +3130,7 @@ static snd_kcontrol_new_t snd_hdsp_controls[] = {
 },
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
        .info =         snd_hdsp_control_spdif_mask_info,
        .get =          snd_hdsp_control_spdif_mask_get,
@@ -3146,8 +3147,6 @@ HDSP_SPDIF_NON_AUDIO("IEC958 Non-audio Bit", 0),
 /* 'Sample Clock Source' complies with the alsa control naming scheme */ 
 HDSP_CLOCK_SOURCE("Sample Clock Source", 0),
 {
-       /* FIXME: should be PCM or MIXER? */
-       /* .iface = SNDRV_CTL_ELEM_IFACE_PCM, */
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "Sample Clock Source Locking",
        .info = snd_hdsp_info_clock_source_lock,
index 9e86d0eb41ce600561928d6561bb6d6a91644b3f..5d786d113b254422e1aa7d8aecbc31f330e8294f 100644 (file)
@@ -65,7 +65,7 @@ module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable/disable specific HDSPM soundcards.");
 
 module_param_array(precise_ptr, bool, NULL, 0444);
-MODULE_PARM_DESC(precise_ptr, "Enable precise pointer, or disable.");
+MODULE_PARM_DESC(precise_ptr, "Enable or disable precise pointer.");
 
 module_param_array(line_outs_monitor, bool, NULL, 0444);
 MODULE_PARM_DESC(line_outs_monitor,
@@ -1104,14 +1104,14 @@ static int snd_hdspm_midi_output_close(snd_rawmidi_substream_t * substream)
        return 0;
 }
 
-snd_rawmidi_ops_t snd_hdspm_midi_output =
+static snd_rawmidi_ops_t snd_hdspm_midi_output =
 {
        .open =         snd_hdspm_midi_output_open,
        .close =        snd_hdspm_midi_output_close,
        .trigger =      snd_hdspm_midi_output_trigger,
 };
 
-snd_rawmidi_ops_t snd_hdspm_midi_input =
+static snd_rawmidi_ops_t snd_hdspm_midi_input =
 {
        .open =         snd_hdspm_midi_input_open,
        .close =        snd_hdspm_midi_input_close,
@@ -1168,7 +1168,7 @@ static void hdspm_midi_tasklet(unsigned long arg)
 /* get the system sample rate which is set */
 
 #define HDSPM_SYSTEM_SAMPLE_RATE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ, \
@@ -1195,7 +1195,7 @@ static int snd_hdspm_get_system_sample_rate(snd_kcontrol_t * kcontrol,
 }
 
 #define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ, \
@@ -1264,7 +1264,7 @@ static int snd_hdspm_get_autosync_sample_rate(snd_kcontrol_t * kcontrol,
 }
 
 #define HDSPM_SYSTEM_CLOCK_MODE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ, \
@@ -1310,7 +1310,7 @@ static int snd_hdspm_get_system_clock_mode(snd_kcontrol_t * kcontrol,
 }
 
 #define HDSPM_CLOCK_SOURCE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdspm_info_clock_source, \
@@ -1457,7 +1457,7 @@ static int snd_hdspm_put_clock_source(snd_kcontrol_t * kcontrol,
 }
 
 #define HDSPM_PREF_SYNC_REF(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdspm_info_pref_sync_ref, \
@@ -1547,7 +1547,7 @@ static int snd_hdspm_put_pref_sync_ref(snd_kcontrol_t * kcontrol,
 }
 
 #define HDSPM_AUTOSYNC_REF(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ, \
@@ -1604,7 +1604,7 @@ static int snd_hdspm_get_autosync_ref(snd_kcontrol_t * kcontrol,
 }
 
 #define HDSPM_LINE_OUT(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdspm_info_line_out, \
@@ -1668,7 +1668,7 @@ static int snd_hdspm_put_line_out(snd_kcontrol_t * kcontrol,
 }
 
 #define HDSPM_TX_64(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdspm_info_tx_64, \
@@ -1731,7 +1731,7 @@ static int snd_hdspm_put_tx_64(snd_kcontrol_t * kcontrol,
 }
 
 #define HDSPM_C_TMS(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdspm_info_c_tms, \
@@ -1794,7 +1794,7 @@ static int snd_hdspm_put_c_tms(snd_kcontrol_t * kcontrol,
 }
 
 #define HDSPM_SAFE_MODE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdspm_info_safe_mode, \
@@ -1857,7 +1857,7 @@ static int snd_hdspm_put_safe_mode(snd_kcontrol_t * kcontrol,
 }
 
 #define HDSPM_INPUT_SELECT(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdspm_info_input_select, \
@@ -1941,6 +1941,7 @@ static int snd_hdspm_put_input_select(snd_kcontrol_t * kcontrol,
 { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
   .name = xname, \
   .index = xindex, \
+  .device = 0, \
   .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
                 SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
   .info = snd_hdspm_info_mixer, \
@@ -2124,7 +2125,7 @@ static int snd_hdspm_put_playback_mixer(snd_kcontrol_t * kcontrol,
 }
 
 #define HDSPM_WC_SYNC_CHECK(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
@@ -2170,7 +2171,7 @@ static int snd_hdspm_get_wc_sync_check(snd_kcontrol_t * kcontrol,
 
 
 #define HDSPM_MADI_SYNC_CHECK(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
index 1bc9d0df8516e27b2a338b6859c1fa0ec63088dc..8ee4d6fd6ea789e20b3c2b1e0180efc7cbcfe051 100644 (file)
@@ -893,7 +893,7 @@ static int snd_rme9652_control_spdif_mask_get(snd_kcontrol_t * kcontrol, snd_ctl
 }
 
 #define RME9652_ADAT1_IN(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .info = snd_rme9652_info_adat1_in, \
   .get = snd_rme9652_get_adat1_in, \
   .put = snd_rme9652_put_adat1_in }
@@ -971,7 +971,7 @@ static int snd_rme9652_put_adat1_in(snd_kcontrol_t * kcontrol, snd_ctl_elem_valu
 }
 
 #define RME9652_SPDIF_IN(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .info = snd_rme9652_info_spdif_in, \
   .get = snd_rme9652_get_spdif_in, .put = snd_rme9652_put_spdif_in }
 
@@ -1042,7 +1042,7 @@ static int snd_rme9652_put_spdif_in(snd_kcontrol_t * kcontrol, snd_ctl_elem_valu
 }
 
 #define RME9652_SPDIF_OUT(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .info = snd_rme9652_info_spdif_out, \
   .get = snd_rme9652_get_spdif_out, .put = snd_rme9652_put_spdif_out }
 
@@ -1110,7 +1110,7 @@ static int snd_rme9652_put_spdif_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_val
 }
 
 #define RME9652_SYNC_MODE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .info = snd_rme9652_info_sync_mode, \
   .get = snd_rme9652_get_sync_mode, .put = snd_rme9652_put_sync_mode }
 
@@ -1195,7 +1195,7 @@ static int snd_rme9652_put_sync_mode(snd_kcontrol_t * kcontrol, snd_ctl_elem_val
 }
 
 #define RME9652_SYNC_PREF(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .info = snd_rme9652_info_sync_pref, \
   .get = snd_rme9652_get_sync_pref, .put = snd_rme9652_put_sync_pref }
 
@@ -1340,7 +1340,7 @@ static int snd_rme9652_put_thru(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
 }
 
 #define RME9652_PASSTHRU(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .info = snd_rme9652_info_passthru, \
   .put = snd_rme9652_put_passthru, \
   .get = snd_rme9652_get_passthru }
@@ -1386,7 +1386,7 @@ static int snd_rme9652_put_passthru(snd_kcontrol_t * kcontrol, snd_ctl_elem_valu
 /* Read-only switches */
 
 #define RME9652_SPDIF_RATE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
   .info = snd_rme9652_info_spdif_rate, \
   .get = snd_rme9652_get_spdif_rate }
@@ -1411,7 +1411,7 @@ static int snd_rme9652_get_spdif_rate(snd_kcontrol_t * kcontrol, snd_ctl_elem_va
 }
 
 #define RME9652_ADAT_SYNC(xname, xindex, xidx) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
   .info = snd_rme9652_info_adat_sync, \
   .get = snd_rme9652_get_adat_sync, .private_value = xidx }
@@ -1447,7 +1447,7 @@ static int snd_rme9652_get_adat_sync(snd_kcontrol_t * kcontrol, snd_ctl_elem_val
 }
 
 #define RME9652_TC_VALID(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
   .info = snd_rme9652_info_tc_valid, \
   .get = snd_rme9652_get_tc_valid }
@@ -1545,7 +1545,7 @@ static snd_kcontrol_new_t snd_rme9652_controls[] = {
 },
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
        .info =         snd_rme9652_control_spdif_mask_info,
        .get =          snd_rme9652_control_spdif_mask_get,
@@ -1555,7 +1555,7 @@ static snd_kcontrol_new_t snd_rme9652_controls[] = {
 },
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
        .info =         snd_rme9652_control_spdif_mask_info,
        .get =          snd_rme9652_control_spdif_mask_get,
@@ -1568,7 +1568,7 @@ RME9652_SPDIF_OUT("IEC958 Output also on ADAT1", 0),
 RME9652_SYNC_MODE("Sync Mode", 0),
 RME9652_SYNC_PREF("Preferred Sync Source", 0),
 {
-       .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "Channels Thru",
        .index = 0,
        .info = snd_rme9652_info_thru,
index 29d89bfba0a48b67f1b7d601161c3427c5f51366..f30d9d9478629f07f39441e7dfd8043a41d70f51 100644 (file)
@@ -1689,7 +1689,7 @@ static snd_pcm_hardware_t snd_trident_playback =
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
-                                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+                                SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */),
        .formats =              (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |
                                 SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE),
        .rates =                SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
@@ -1714,7 +1714,7 @@ static snd_pcm_hardware_t snd_trident_capture =
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
-                                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+                                SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */),
        .formats =              (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |
                                 SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE),
        .rates =                SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
@@ -1739,7 +1739,7 @@ static snd_pcm_hardware_t snd_trident_foldback =
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
-                                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+                                SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */),
        .formats =              SNDRV_PCM_FMTBIT_S16_LE,
        .rates =                SNDRV_PCM_RATE_48000,
        .rate_min =             48000,
@@ -1763,7 +1763,7 @@ static snd_pcm_hardware_t snd_trident_spdif =
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
-                                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+                                SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */),
        .formats =              SNDRV_PCM_FMTBIT_S16_LE,
        .rates =                (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
                                 SNDRV_PCM_RATE_48000),
@@ -1784,7 +1784,7 @@ static snd_pcm_hardware_t snd_trident_spdif_7018 =
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
-                                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+                                SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */),
        .formats =              SNDRV_PCM_FMTBIT_S16_LE,
        .rates =                SNDRV_PCM_RATE_48000,
        .rate_min =             48000,
index 4889600387c8fe7a408525c598276b06690795d4..56c6e52d7264228e965a3055db1de0219e70c2ae 100644 (file)
@@ -663,10 +663,12 @@ static int snd_via82xx_pcm_trigger(snd_pcm_substream_t * substream, int cmd)
                val = 0;
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
                val |= VIA_REG_CTRL_START;
                viadev->running = 1;
                break;
        case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
                val = VIA_REG_CTRL_TERMINATE;
                viadev->running = 0;
                break;
@@ -929,12 +931,12 @@ static int snd_via8233_playback_prepare(snd_pcm_substream_t *substream)
 
        if ((rate_changed = via_lock_rate(&chip->rates[0], ac97_rate)) < 0)
                return rate_changed;
-       if (rate_changed) {
+       if (rate_changed)
                snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE,
                                  chip->no_vra ? 48000 : runtime->rate);
-               snd_ac97_set_rate(chip->ac97, AC97_SPDIF,
-                                 chip->no_vra ? 48000 : runtime->rate);
-       }
+       if (chip->spdif_on && viadev->reg_offset == 0x30)
+               snd_ac97_set_rate(chip->ac97, AC97_SPDIF, runtime->rate);
+
        if (runtime->rate == 48000)
                rbits = 0xfffff;
        else
@@ -1035,7 +1037,7 @@ static snd_pcm_hardware_t snd_via82xx_hw =
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID |
-                                SNDRV_PCM_INFO_RESUME |
+                                /* SNDRV_PCM_INFO_RESUME | */
                                 SNDRV_PCM_INFO_PAUSE),
        .formats =              SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
        .rates =                SNDRV_PCM_RATE_48000,
@@ -1484,7 +1486,7 @@ static int snd_via8233_dxs3_spdif_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_val
 }
 
 static snd_kcontrol_new_t snd_via8233_dxs3_spdif_control __devinitdata = {
-       .name = "IEC958 Output Switch",
+       .name = SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH),
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .info = snd_via8233_dxs3_spdif_info,
        .get = snd_via8233_dxs3_spdif_get,
@@ -2153,6 +2155,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci)
                { .subvendor = 0x1019, .subdevice = 0x0a81, .action = VIA_DXS_NO_VRA }, /* ECS K7VTA3 v8.0 */
                { .subvendor = 0x1019, .subdevice = 0x0a85, .action = VIA_DXS_NO_VRA }, /* ECS L7VMM2 */
                { .subvendor = 0x1025, .subdevice = 0x0033, .action = VIA_DXS_NO_VRA }, /* Acer Inspire 1353LM */
+               { .subvendor = 0x1025, .subdevice = 0x0046, .action = VIA_DXS_SRC }, /* Acer Aspire 1524 WLMi */
                { .subvendor = 0x1043, .subdevice = 0x8095, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8X (FIXME: possibly VIA_DXS_ENABLE?)*/
                { .subvendor = 0x1043, .subdevice = 0x80a1, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8-X */
                { .subvendor = 0x1043, .subdevice = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/ 
@@ -2168,10 +2171,12 @@ static int __devinit check_dxs_list(struct pci_dev *pci)
                { .subvendor = 0x1297, .subdevice = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */
                { .subvendor = 0x1458, .subdevice = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */
                { .subvendor = 0x1462, .subdevice = 0x0080, .action = VIA_DXS_SRC }, /* MSI K8T Neo-FIS2R */
+               { .subvendor = 0x1462, .subdevice = 0x0430, .action = VIA_DXS_SRC }, /* MSI 7142 (K8MM-V) */
                { .subvendor = 0x1462, .subdevice = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */
                { .subvendor = 0x1462, .subdevice = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */
                { .subvendor = 0x1462, .subdevice = 0x7023, .action = VIA_DXS_NO_VRA }, /* MSI K8T Neo2-FI */
                { .subvendor = 0x1462, .subdevice = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */
+               { .subvendor = 0x1462, .subdevice = 0x7142, .action = VIA_DXS_ENABLE }, /* MSI K8MM-V */
                { .subvendor = 0x147b, .subdevice = 0x1401, .action = VIA_DXS_ENABLE }, /* ABIT KD7(-RAID) */
                { .subvendor = 0x147b, .subdevice = 0x1411, .action = VIA_DXS_ENABLE }, /* ABIT VA-20 */
                { .subvendor = 0x147b, .subdevice = 0x1413, .action = VIA_DXS_ENABLE }, /* ABIT KV8 Pro */
index 4a9779cc97337e57ff77e63152f00cdbb36dcbef..5872d438a04a5f50f4f47aafe5ff3d4cabc9eb58 100644 (file)
@@ -521,6 +521,7 @@ static int snd_via82xx_pcm_trigger(snd_pcm_substream_t * substream, int cmd)
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
                val |= VIA_REG_CTRL_START;
                viadev->running = 1;
                break;
@@ -697,7 +698,7 @@ static snd_pcm_hardware_t snd_via82xx_hw =
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID |
-                                SNDRV_PCM_INFO_RESUME |
+                                /* SNDRV_PCM_INFO_RESUME | */
                                 SNDRV_PCM_INFO_PAUSE),
        .formats =              SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
        .rates =                SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_KNOT,
index d54f88a1b525b346b165cf1bd0f0ccb9819976f6..054836412dc4069b60c0af957058d902b49b1498 100644 (file)
@@ -321,6 +321,26 @@ static void snd_ymfpci_pcm_interrupt(ymfpci_t *chip, ymfpci_voice_t *voice)
                        snd_pcm_period_elapsed(ypcm->substream);
                        spin_lock(&chip->reg_lock);
                }
+
+               if (unlikely(ypcm->update_pcm_vol)) {
+                       unsigned int subs = ypcm->substream->number;
+                       unsigned int next_bank = 1 - chip->active_bank;
+                       snd_ymfpci_playback_bank_t *bank;
+                       u32 volume;
+                       
+                       bank = &voice->bank[next_bank];
+                       volume = cpu_to_le32(chip->pcm_mixer[subs].left << 15);
+                       bank->left_gain_end = volume;
+                       if (ypcm->output_rear)
+                               bank->eff2_gain_end = volume;
+                       if (ypcm->voices[1])
+                               bank = &ypcm->voices[1]->bank[next_bank];
+                       volume = cpu_to_le32(chip->pcm_mixer[subs].right << 15);
+                       bank->right_gain_end = volume;
+                       if (ypcm->output_rear)
+                               bank->eff3_gain_end = volume;
+                       ypcm->update_pcm_vol--;
+               }
        }
        spin_unlock(&chip->reg_lock);
 }
@@ -451,87 +471,74 @@ static int snd_ymfpci_pcm_voice_alloc(ymfpci_pcm_t *ypcm, int voices)
        return 0;
 }
 
-static void snd_ymfpci_pcm_init_voice(ymfpci_voice_t *voice, int stereo,
-                                     int rate, int w_16, unsigned long addr,
-                                     unsigned int end,
-                                     int output_front, int output_rear)
+static void snd_ymfpci_pcm_init_voice(ymfpci_pcm_t *ypcm, unsigned int voiceidx,
+                                     snd_pcm_runtime_t *runtime,
+                                     int has_pcm_volume)
 {
+       ymfpci_voice_t *voice = ypcm->voices[voiceidx];
        u32 format;
-       u32 delta = snd_ymfpci_calc_delta(rate);
-       u32 lpfQ = snd_ymfpci_calc_lpfQ(rate);
-       u32 lpfK = snd_ymfpci_calc_lpfK(rate);
+       u32 delta = snd_ymfpci_calc_delta(runtime->rate);
+       u32 lpfQ = snd_ymfpci_calc_lpfQ(runtime->rate);
+       u32 lpfK = snd_ymfpci_calc_lpfK(runtime->rate);
        snd_ymfpci_playback_bank_t *bank;
        unsigned int nbank;
+       u32 vol_left, vol_right;
+       u8 use_left, use_right;
 
        snd_assert(voice != NULL, return);
-       format = (stereo ? 0x00010000 : 0) | (w_16 ? 0 : 0x80000000);
+       if (runtime->channels == 1) {
+               use_left = 1;
+               use_right = 1;
+       } else {
+               use_left = (voiceidx & 1) == 0;
+               use_right = !use_left;
+       }
+       if (has_pcm_volume) {
+               vol_left = cpu_to_le32(ypcm->chip->pcm_mixer
+                                      [ypcm->substream->number].left << 15);
+               vol_right = cpu_to_le32(ypcm->chip->pcm_mixer
+                                       [ypcm->substream->number].right << 15);
+       } else {
+               vol_left = cpu_to_le32(0x40000000);
+               vol_right = cpu_to_le32(0x40000000);
+       }
+       format = runtime->channels == 2 ? 0x00010000 : 0;
+       if (snd_pcm_format_width(runtime->format) == 8)
+               format |= 0x80000000;
+       if (runtime->channels == 2 && (voiceidx & 1) != 0)
+               format |= 1;
        for (nbank = 0; nbank < 2; nbank++) {
                bank = &voice->bank[nbank];
+               memset(bank, 0, sizeof(*bank));
                bank->format = cpu_to_le32(format);
-               bank->loop_default = 0;
-               bank->base = cpu_to_le32(addr);
-               bank->loop_start = 0;
-               bank->loop_end = cpu_to_le32(end);
-               bank->loop_frac = 0;
-               bank->eg_gain_end = cpu_to_le32(0x40000000);
+               bank->base = cpu_to_le32(runtime->dma_addr);
+               bank->loop_end = cpu_to_le32(ypcm->buffer_size);
                bank->lpfQ = cpu_to_le32(lpfQ);
-               bank->status = 0;
-               bank->num_of_frames = 0;
-               bank->loop_count = 0;
-               bank->start = 0;
-               bank->start_frac = 0;
                bank->delta =
                bank->delta_end = cpu_to_le32(delta);
                bank->lpfK =
                bank->lpfK_end = cpu_to_le32(lpfK);
-               bank->eg_gain = cpu_to_le32(0x40000000);
-               bank->lpfD1 =
-               bank->lpfD2 = 0;
-
-               bank->left_gain = 
-               bank->right_gain =
-               bank->left_gain_end =
-               bank->right_gain_end =
-               bank->eff1_gain =
-               bank->eff2_gain =
-               bank->eff3_gain =
-               bank->eff1_gain_end =
-               bank->eff2_gain_end =
-               bank->eff3_gain_end = 0;
-
-               if (!stereo) {
-                       if (output_front) {
-                               bank->left_gain = 
+               bank->eg_gain =
+               bank->eg_gain_end = cpu_to_le32(0x40000000);
+
+               if (ypcm->output_front) {
+                       if (use_left) {
+                               bank->left_gain =
+                               bank->left_gain_end = vol_left;
+                       }
+                       if (use_right) {
                                bank->right_gain =
-                               bank->left_gain_end =
-                               bank->right_gain_end = cpu_to_le32(0x40000000);
+                               bank->right_gain_end = vol_right;
                        }
-                       if (output_rear) {
+               }
+               if (ypcm->output_rear) {
+                       if (use_left) {
                                bank->eff2_gain =
-                               bank->eff2_gain_end =
-                               bank->eff3_gain =
-                               bank->eff3_gain_end = cpu_to_le32(0x40000000);
-                       }
-               } else {
-                       if (output_front) {
-                               if ((voice->number & 1) == 0) {
-                                       bank->left_gain =
-                                       bank->left_gain_end = cpu_to_le32(0x40000000);
-                               } else {
-                                       bank->format |= cpu_to_le32(1);
-                                       bank->right_gain =
-                                       bank->right_gain_end = cpu_to_le32(0x40000000);
-                               }
+                               bank->eff2_gain_end = vol_left;
                        }
-                       if (output_rear) {
-                               if ((voice->number & 1) == 0) {
-                                       bank->eff3_gain =
-                                       bank->eff3_gain_end = cpu_to_le32(0x40000000);
-                               } else {
-                                       bank->format |= cpu_to_le32(1);
-                                       bank->eff2_gain =
-                                       bank->eff2_gain_end = cpu_to_le32(0x40000000);
-                               }
+                       if (use_right) {
+                               bank->eff3_gain =
+                               bank->eff3_gain_end = vol_right;
                        }
                }
        }
@@ -613,7 +620,7 @@ static int snd_ymfpci_playback_hw_free(snd_pcm_substream_t * substream)
 
 static int snd_ymfpci_playback_prepare(snd_pcm_substream_t * substream)
 {
-       // ymfpci_t *chip = snd_pcm_substream_chip(substream);
+       ymfpci_t *chip = snd_pcm_substream_chip(substream);
        snd_pcm_runtime_t *runtime = substream->runtime;
        ymfpci_pcm_t *ypcm = runtime->private_data;
        unsigned int nvoice;
@@ -623,14 +630,8 @@ static int snd_ymfpci_playback_prepare(snd_pcm_substream_t * substream)
        ypcm->period_pos = 0;
        ypcm->last_pos = 0;
        for (nvoice = 0; nvoice < runtime->channels; nvoice++)
-               snd_ymfpci_pcm_init_voice(ypcm->voices[nvoice],
-                                         runtime->channels == 2,
-                                         runtime->rate,
-                                         snd_pcm_format_width(runtime->format) == 16,
-                                         runtime->dma_addr,
-                                         ypcm->buffer_size,
-                                         ypcm->output_front,
-                                         ypcm->output_rear);
+               snd_ymfpci_pcm_init_voice(ypcm, nvoice, runtime,
+                                         substream->pcm == chip->pcm);
        return 0;
 }
 
@@ -882,6 +883,7 @@ static int snd_ymfpci_playback_open(snd_pcm_substream_t * substream)
        ymfpci_t *chip = snd_pcm_substream_chip(substream);
        snd_pcm_runtime_t *runtime = substream->runtime;
        ymfpci_pcm_t *ypcm;
+       snd_kcontrol_t *kctl;
        int err;
        
        if ((err = snd_ymfpci_playback_open_1(substream)) < 0)
@@ -895,6 +897,10 @@ static int snd_ymfpci_playback_open(snd_pcm_substream_t * substream)
                chip->rear_opened++;
        }
        spin_unlock_irq(&chip->reg_lock);
+
+       kctl = chip->pcm_mixer[substream->number].ctl;
+       kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+       snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id);
        return 0;
 }
 
@@ -987,6 +993,7 @@ static int snd_ymfpci_playback_close(snd_pcm_substream_t * substream)
 {
        ymfpci_t *chip = snd_pcm_substream_chip(substream);
        ymfpci_pcm_t *ypcm = substream->runtime->private_data;
+       snd_kcontrol_t *kctl;
 
        spin_lock_irq(&chip->reg_lock);
        if (ypcm->output_rear && chip->rear_opened > 0) {
@@ -994,6 +1001,9 @@ static int snd_ymfpci_playback_close(snd_pcm_substream_t * substream)
                ymfpci_close_extension(chip);
        }
        spin_unlock_irq(&chip->reg_lock);
+       kctl = chip->pcm_mixer[substream->number].ctl;
+       kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+       snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id);
        return snd_ymfpci_playback_close_1(substream);
 }
 
@@ -1665,6 +1675,66 @@ static snd_kcontrol_new_t snd_ymfpci_rear_shared __devinitdata = {
        .private_value = 2,
 };
 
+/*
+ * PCM voice volume
+ */
+
+static int snd_ymfpci_pcm_vol_info(snd_kcontrol_t *kcontrol,
+                                  snd_ctl_elem_info_t *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 0x8000;
+       return 0;
+}
+
+static int snd_ymfpci_pcm_vol_get(snd_kcontrol_t *kcontrol,
+                                 snd_ctl_elem_value_t *ucontrol)
+{
+       ymfpci_t *chip = snd_kcontrol_chip(kcontrol);
+       unsigned int subs = kcontrol->id.subdevice;
+
+       ucontrol->value.integer.value[0] = chip->pcm_mixer[subs].left;
+       ucontrol->value.integer.value[1] = chip->pcm_mixer[subs].right;
+       return 0;
+}
+
+static int snd_ymfpci_pcm_vol_put(snd_kcontrol_t *kcontrol,
+                                 snd_ctl_elem_value_t *ucontrol)
+{
+       ymfpci_t *chip = snd_kcontrol_chip(kcontrol);
+       unsigned int subs = kcontrol->id.subdevice;
+       snd_pcm_substream_t *substream;
+       unsigned long flags;
+
+       if (ucontrol->value.integer.value[0] != chip->pcm_mixer[subs].left ||
+           ucontrol->value.integer.value[1] != chip->pcm_mixer[subs].right) {
+               chip->pcm_mixer[subs].left = ucontrol->value.integer.value[0];
+               chip->pcm_mixer[subs].right = ucontrol->value.integer.value[1];
+
+               substream = (snd_pcm_substream_t *)kcontrol->private_value;
+               spin_lock_irqsave(&chip->voice_lock, flags);
+               if (substream->runtime && substream->runtime->private_data) {
+                       ymfpci_pcm_t *ypcm = substream->runtime->private_data;
+                       ypcm->update_pcm_vol = 2;
+               }
+               spin_unlock_irqrestore(&chip->voice_lock, flags);
+               return 1;
+       }
+       return 0;
+}
+
+static snd_kcontrol_new_t snd_ymfpci_pcm_volume __devinitdata = {
+       .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+       .name = "PCM Playback Volume",
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+               SNDRV_CTL_ELEM_ACCESS_INACTIVE,
+       .info = snd_ymfpci_pcm_vol_info,
+       .get = snd_ymfpci_pcm_vol_get,
+       .put = snd_ymfpci_pcm_vol_put,
+};
+
 
 /*
  *  Mixer routines
@@ -1686,6 +1756,7 @@ int __devinit snd_ymfpci_mixer(ymfpci_t *chip, int rear_switch)
 {
        ac97_template_t ac97;
        snd_kcontrol_t *kctl;
+       snd_pcm_substream_t *substream;
        unsigned int idx;
        int err;
        static ac97_bus_ops_t ops = {
@@ -1739,6 +1810,23 @@ int __devinit snd_ymfpci_mixer(ymfpci_t *chip, int rear_switch)
                        return err;
        }
 
+       /* per-voice volume */
+       substream = chip->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+       for (idx = 0; idx < 32; ++idx) {
+               kctl = snd_ctl_new1(&snd_ymfpci_pcm_volume, chip);
+               if (!kctl)
+                       return -ENOMEM;
+               kctl->id.device = chip->pcm->device;
+               kctl->id.subdevice = idx;
+               kctl->private_value = (unsigned long)substream;
+               if ((err = snd_ctl_add(chip->card, kctl)) < 0)
+                       return err;
+               chip->pcm_mixer[idx].left = 0x8000;
+               chip->pcm_mixer[idx].right = 0x8000;
+               chip->pcm_mixer[idx].ctl = kctl;
+               substream = substream->next;
+       }
+
        return 0;
 }
 
index 3a82161d3b24cd4e193af51b0b8a2b470e3edc5e..1e8f16b4c073a739f25223b409f910ad15853c0e 100644 (file)
@@ -297,6 +297,7 @@ static void vxpocket_config(dev_link_t *link)
        CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
 
        chip->dev = &handle_to_dev(link->handle);
+       snd_card_set_dev(chip->card, chip->dev);
 
        if (snd_vxpocket_assign_resources(chip, link->io.BasePort1, link->irq.AssignedIRQ) < 0)
                goto failed;
@@ -376,7 +377,7 @@ static int vxpocket_event(event_t event, int priority, event_callback_args_t *ar
 
 /*
  */
-static dev_link_t *vxp_attach(void)
+static dev_link_t *vxpocket_attach(void)
 {
        snd_card_t *card;
        struct snd_vxpocket *vxp;
@@ -407,7 +408,7 @@ static dev_link_t *vxp_attach(void)
                return NULL;
        }
 
-       vxp->index = index[i];
+       vxp->index = i;
        card_alloc |= 1 << i;
 
        /* Chain drivers */
@@ -417,7 +418,7 @@ static dev_link_t *vxp_attach(void)
        return &vxp->link;
 }
 
-static void vxp_detach(dev_link_t *link)
+static void vxpocket_detach(dev_link_t *link)
 {
        struct snd_vxpocket *vxp;
        vx_core_t *chip;
@@ -458,8 +459,9 @@ static struct pcmcia_driver vxp_cs_driver = {
        .drv            = {
                .name   = "snd-vxpocket",
        },
-       .attach         = vxp_attach,
-       .detach         = vxp_detach,
+       .attach         = vxpocket_attach,
+       .detach         = vxpocket_detach,
+       .event          = vxpocket_event,
        .id_table       = vxp_ids,
 };
 
index 21a69e096225bff839cfb59255d49e1a3b45abe2..954f994592ab3d7ff6b2f29a84816fbb38d1a039 100644 (file)
@@ -153,7 +153,7 @@ static DEFINE_SPINLOCK(sound_loader_lock);
  *     list. Acquires locks as needed
  */
 
-static int sound_insert_unit(struct sound_unit **list, struct file_operations *fops, int index, int low, int top, const char *name, umode_t mode)
+static int sound_insert_unit(struct sound_unit **list, struct file_operations *fops, int index, int low, int top, const char *name, umode_t mode, struct device *dev)
 {
        struct sound_unit *s = kmalloc(sizeof(*s), GFP_KERNEL);
        int r;
@@ -175,7 +175,7 @@ static int sound_insert_unit(struct sound_unit **list, struct file_operations *f
        devfs_mk_cdev(MKDEV(SOUND_MAJOR, s->unit_minor),
                        S_IFCHR | mode, s->name);
        class_device_create(sound_class, MKDEV(SOUND_MAJOR, s->unit_minor),
-                               NULL, s->name+6);
+                           dev, s->name+6);
        return r;
 
  fail:
@@ -227,16 +227,18 @@ static void sound_remove_unit(struct sound_unit **list, int unit)
 static struct sound_unit *chains[SOUND_STEP];
 
 /**
- *     register_sound_special - register a special sound node
+ *     register_sound_special_device - register a special sound node
  *     @fops: File operations for the driver
  *     @unit: Unit number to allocate
+ *      @dev: device pointer
  *
  *     Allocate a special sound device by minor number from the sound
  *     subsystem. The allocated number is returned on succes. On failure
  *     a negative error code is returned.
  */
  
-int register_sound_special(struct file_operations *fops, int unit)
+int register_sound_special_device(struct file_operations *fops, int unit,
+                                 struct device *dev)
 {
        const int chain = unit % SOUND_STEP;
        int max_unit = 128 + chain;
@@ -294,9 +296,16 @@ int register_sound_special(struct file_operations *fops, int unit)
                break;
        }
        return sound_insert_unit(&chains[chain], fops, -1, unit, max_unit,
-                                name, S_IRUSR | S_IWUSR);
+                                name, S_IRUSR | S_IWUSR, dev);
 }
  
+EXPORT_SYMBOL(register_sound_special_device);
+
+int register_sound_special(struct file_operations *fops, int unit)
+{
+       return register_sound_special_device(fops, unit, NULL);
+}
+
 EXPORT_SYMBOL(register_sound_special);
 
 /**
@@ -312,7 +321,7 @@ EXPORT_SYMBOL(register_sound_special);
 int register_sound_mixer(struct file_operations *fops, int dev)
 {
        return sound_insert_unit(&chains[0], fops, dev, 0, 128,
-                                "mixer", S_IRUSR | S_IWUSR);
+                                "mixer", S_IRUSR | S_IWUSR, NULL);
 }
 
 EXPORT_SYMBOL(register_sound_mixer);
@@ -330,7 +339,7 @@ EXPORT_SYMBOL(register_sound_mixer);
 int register_sound_midi(struct file_operations *fops, int dev)
 {
        return sound_insert_unit(&chains[2], fops, dev, 2, 130,
-                                "midi", S_IRUSR | S_IWUSR);
+                                "midi", S_IRUSR | S_IWUSR, NULL);
 }
 
 EXPORT_SYMBOL(register_sound_midi);
@@ -356,7 +365,7 @@ EXPORT_SYMBOL(register_sound_midi);
 int register_sound_dsp(struct file_operations *fops, int dev)
 {
        return sound_insert_unit(&chains[3], fops, dev, 3, 131,
-                                "dsp", S_IWUSR | S_IRUSR);
+                                "dsp", S_IWUSR | S_IRUSR, NULL);
 }
 
 EXPORT_SYMBOL(register_sound_dsp);
@@ -375,7 +384,7 @@ EXPORT_SYMBOL(register_sound_dsp);
 int register_sound_synth(struct file_operations *fops, int dev)
 {
        return sound_insert_unit(&chains[9], fops, dev, 9, 137,
-                                "synth", S_IRUSR | S_IWUSR);
+                                "synth", S_IRUSR | S_IWUSR, NULL);
 }
 
 EXPORT_SYMBOL(register_sound_synth);
index f13b038329ebfb29d5fad6728252484f162cb072..751bf1272af3bc77917d5ba3f66427ca76cdd09a 100644 (file)
@@ -98,7 +98,6 @@ snd_emux_note_on(void *p, int note, int vel, snd_midi_channel_t *chan)
                vp = emu->ops.get_voice(emu, port);
                if (vp == NULL || vp->ch < 0)
                        continue;
-               snd_assert(vp->emu != NULL && vp->hw != NULL, return);
                if (STATE_IS_PLAYING(vp->state))
                        emu->ops.terminate(vp);
 
index 8298c462c291c2a529cecf04f0cb18a0aa213a52..5aa5fe651a8aaac837e09335ecb1dfa31c073654 100644 (file)
 #include <sound/driver.h>
 #include <linux/bitops.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/list.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/usb.h>
+#include <linux/vmalloc.h>
 #include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/info.h>
@@ -79,7 +81,7 @@ module_param_array(vid, int, NULL, 0444);
 MODULE_PARM_DESC(vid, "Vendor ID for the USB audio device.");
 module_param_array(pid, int, NULL, 0444);
 MODULE_PARM_DESC(pid, "Product ID for the USB audio device.");
-module_param(nrpacks, int, 0444);
+module_param(nrpacks, int, 0644);
 MODULE_PARM_DESC(nrpacks, "Max. number of packets per URB.");
 module_param(async_unlink, bool, 0444);
 MODULE_PARM_DESC(async_unlink, "Use async unlink mode.");
@@ -97,7 +99,7 @@ MODULE_PARM_DESC(async_unlink, "Use async unlink mode.");
 
 #define MAX_PACKS      10
 #define MAX_PACKS_HS   (MAX_PACKS * 8) /* in high speed mode */
-#define MAX_URBS       5       /* max. 20ms long packets */
+#define MAX_URBS       8
 #define SYNC_URBS      4       /* always four urbs for sync */
 #define MIN_PACKS_URB  1       /* minimum 1 packet per urb */
 
@@ -126,11 +128,10 @@ struct audioformat {
 
 struct snd_urb_ctx {
        struct urb *urb;
+       unsigned int buffer_size;       /* size of data buffer, if data URB */
        snd_usb_substream_t *subs;
        int index;      /* index for urb array */
        int packets;    /* number of packets per urb */
-       int transfer;   /* transferred size */
-       char *buf;      /* buffer for capture */
 };
 
 struct snd_urb_ops {
@@ -165,12 +166,11 @@ struct snd_usb_substream {
        unsigned int curframesize;      /* current packet size in frames (for capture) */
        unsigned int fill_max: 1;       /* fill max packet size always */
        unsigned int fmt_type;          /* USB audio format type (1-3) */
+       unsigned int packs_per_ms;      /* packets per millisecond (for playback) */
 
        unsigned int running: 1;        /* running status */
 
-       unsigned int hwptr;                     /* free frame position in the buffer (only for playback) */
        unsigned int hwptr_done;                        /* processed frame position in the buffer */
-       unsigned int transfer_sched;            /* scheduled frames since last period (for playback) */
        unsigned int transfer_done;             /* processed frames since last period update */
        unsigned long active_mask;      /* bitmask of active urbs */
        unsigned long unlink_mask;      /* bitmask of unlinked urbs */
@@ -178,13 +178,14 @@ struct snd_usb_substream {
        unsigned int nurbs;                     /* # urbs */
        snd_urb_ctx_t dataurb[MAX_URBS];        /* data urb table */
        snd_urb_ctx_t syncurb[SYNC_URBS];       /* sync urb table */
-       char syncbuf[SYNC_URBS * 4];    /* sync buffer; it's so small - let's get static */
-       char *tmpbuf;                   /* temporary buffer for playback */
+       char *syncbuf;                          /* sync buffer for all sync URBs */
+       dma_addr_t sync_dma;                    /* DMA address of syncbuf */
 
        u64 formats;                    /* format bitmasks (all or'ed) */
        unsigned int num_formats;               /* number of supported audio formats (list) */
        struct list_head fmt_list;      /* format list */
        spinlock_t lock;
+       struct tasklet_struct start_period_elapsed;     /* for start trigger */
 
        struct snd_urb_ops ops;         /* callbacks (must be filled at init) */
 };
@@ -311,27 +312,17 @@ static int prepare_capture_urb(snd_usb_substream_t *subs,
                               struct urb *urb)
 {
        int i, offs;
-       unsigned long flags;
        snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
 
        offs = 0;
        urb->dev = ctx->subs->dev; /* we need to set this at each time */
-       urb->number_of_packets = 0;
-       spin_lock_irqsave(&subs->lock, flags);
        for (i = 0; i < ctx->packets; i++) {
                urb->iso_frame_desc[i].offset = offs;
                urb->iso_frame_desc[i].length = subs->curpacksize;
                offs += subs->curpacksize;
-               urb->number_of_packets++;
-               subs->transfer_sched += subs->curframesize;
-               if (subs->transfer_sched >= runtime->period_size) {
-                       subs->transfer_sched -= runtime->period_size;
-                       break;
-               }
        }
-       spin_unlock_irqrestore(&subs->lock, flags);
-       urb->transfer_buffer = ctx->buf;
        urb->transfer_buffer_length = offs;
+       urb->number_of_packets = ctx->packets;
 #if 0 // for check
        if (! urb->bandwidth) {
                int bustime;
@@ -359,6 +350,7 @@ static int retire_capture_urb(snd_usb_substream_t *subs,
        unsigned char *cp;
        int i;
        unsigned int stride, len, oldptr;
+       int period_elapsed = 0;
 
        stride = runtime->frame_bits >> 3;
 
@@ -378,6 +370,10 @@ static int retire_capture_urb(snd_usb_substream_t *subs,
                if (subs->hwptr_done >= runtime->buffer_size)
                        subs->hwptr_done -= runtime->buffer_size;
                subs->transfer_done += len;
+               if (subs->transfer_done >= runtime->period_size) {
+                       subs->transfer_done -= runtime->period_size;
+                       period_elapsed = 1;
+               }
                spin_unlock_irqrestore(&subs->lock, flags);
                /* copy a data chunk */
                if (oldptr + len > runtime->buffer_size) {
@@ -388,15 +384,9 @@ static int retire_capture_urb(snd_usb_substream_t *subs,
                } else {
                        memcpy(runtime->dma_area + oldptr * stride, cp, len * stride);
                }
-               /* update the pointer, call callback if necessary */
-               spin_lock_irqsave(&subs->lock, flags);
-               if (subs->transfer_done >= runtime->period_size) {
-                       subs->transfer_done -= runtime->period_size;
-                       spin_unlock_irqrestore(&subs->lock, flags);
-                       snd_pcm_period_elapsed(subs->pcm_substream);
-               } else
-                       spin_unlock_irqrestore(&subs->lock, flags);
        }
+       if (period_elapsed)
+               snd_pcm_period_elapsed(subs->pcm_substream);
        return 0;
 }
 
@@ -492,12 +482,10 @@ static int retire_playback_sync_urb_hs(snd_usb_substream_t *subs,
 /*
  * prepare urb for playback data pipe
  *
- * we copy the data directly from the pcm buffer.
- * the current position to be copied is held in hwptr field.
- * since a urb can handle only a single linear buffer, if the total
- * transferred area overflows the buffer boundary, we cannot send
- * it directly from the buffer.  thus the data is once copied to
- * a temporary buffer and urb points to that.
+ * Since a URB can handle only a single linear buffer, we must use double
+ * buffering when the data to be transferred overflows the buffer boundary.
+ * To avoid inconsistencies when updating hwptr_done, we use double buffering
+ * for all URBs.
  */
 static int prepare_playback_urb(snd_usb_substream_t *subs,
                                snd_pcm_runtime_t *runtime,
@@ -506,6 +494,7 @@ static int prepare_playback_urb(snd_usb_substream_t *subs,
        int i, stride, offs;
        unsigned int counts;
        unsigned long flags;
+       int period_elapsed = 0;
        snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
 
        stride = runtime->frame_bits >> 3;
@@ -530,80 +519,85 @@ static int prepare_playback_urb(snd_usb_substream_t *subs,
                urb->iso_frame_desc[i].length = counts * stride;
                offs += counts;
                urb->number_of_packets++;
-               subs->transfer_sched += counts;
-               if (subs->transfer_sched >= runtime->period_size) {
-                       subs->transfer_sched -= runtime->period_size;
+               subs->transfer_done += counts;
+               if (subs->transfer_done >= runtime->period_size) {
+                       subs->transfer_done -= runtime->period_size;
+                       period_elapsed = 1;
                        if (subs->fmt_type == USB_FORMAT_TYPE_II) {
-                               if (subs->transfer_sched > 0) {
-                                       /* FIXME: fill-max mode is not supported yet */
-                                       offs -= subs->transfer_sched;
-                                       counts -= subs->transfer_sched;
-                                       urb->iso_frame_desc[i].length = counts * stride;
-                                       subs->transfer_sched = 0;
+                               if (subs->transfer_done > 0) {
+                                       /* FIXME: fill-max mode is not
+                                        * supported yet */
+                                       offs -= subs->transfer_done;
+                                       counts -= subs->transfer_done;
+                                       urb->iso_frame_desc[i].length =
+                                               counts * stride;
+                                       subs->transfer_done = 0;
                                }
                                i++;
                                if (i < ctx->packets) {
                                        /* add a transfer delimiter */
-                                       urb->iso_frame_desc[i].offset = offs * stride;
+                                       urb->iso_frame_desc[i].offset =
+                                               offs * stride;
                                        urb->iso_frame_desc[i].length = 0;
                                        urb->number_of_packets++;
                                }
+                               break;
                        }
-                       break;
                }
+               /* finish at the frame boundary at/after the period boundary */
+               if (period_elapsed &&
+                   (i & (subs->packs_per_ms - 1)) == subs->packs_per_ms - 1)
+                       break;
        }
-       if (subs->hwptr + offs > runtime->buffer_size) {
-               /* err, the transferred area goes over buffer boundary.
-                * copy the data to the temp buffer.
-                */
-               int len;
-               len = runtime->buffer_size - subs->hwptr;
-               urb->transfer_buffer = subs->tmpbuf;
-               memcpy(subs->tmpbuf, runtime->dma_area + subs->hwptr * stride, len * stride);
-               memcpy(subs->tmpbuf + len * stride, runtime->dma_area, (offs - len) * stride);
-               subs->hwptr += offs;
-               subs->hwptr -= runtime->buffer_size;
+       if (subs->hwptr_done + offs > runtime->buffer_size) {
+               /* err, the transferred area goes over buffer boundary. */
+               unsigned int len = runtime->buffer_size - subs->hwptr_done;
+               memcpy(urb->transfer_buffer,
+                      runtime->dma_area + subs->hwptr_done * stride,
+                      len * stride);
+               memcpy(urb->transfer_buffer + len * stride,
+                      runtime->dma_area,
+                      (offs - len) * stride);
        } else {
-               /* set the buffer pointer */
-               urb->transfer_buffer = runtime->dma_area + subs->hwptr * stride;
-               subs->hwptr += offs;
-               if (subs->hwptr == runtime->buffer_size)
-                       subs->hwptr = 0;
+               memcpy(urb->transfer_buffer,
+                      runtime->dma_area + subs->hwptr_done * stride,
+                      offs * stride);
        }
+       subs->hwptr_done += offs;
+       if (subs->hwptr_done >= runtime->buffer_size)
+               subs->hwptr_done -= runtime->buffer_size;
        spin_unlock_irqrestore(&subs->lock, flags);
        urb->transfer_buffer_length = offs * stride;
-       ctx->transfer = offs;
-
+       if (period_elapsed) {
+               if (likely(subs->running))
+                       snd_pcm_period_elapsed(subs->pcm_substream);
+               else
+                       tasklet_hi_schedule(&subs->start_period_elapsed);
+       }
        return 0;
 }
 
 /*
  * process after playback data complete
- *
- * update the current position and call callback if a period is processed.
+ * - nothing to do
  */
 static int retire_playback_urb(snd_usb_substream_t *subs,
                               snd_pcm_runtime_t *runtime,
                               struct urb *urb)
 {
-       unsigned long flags;
-       snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
-
-       spin_lock_irqsave(&subs->lock, flags);
-       subs->transfer_done += ctx->transfer;
-       subs->hwptr_done += ctx->transfer;
-       ctx->transfer = 0;
-       if (subs->hwptr_done >= runtime->buffer_size)
-               subs->hwptr_done -= runtime->buffer_size;
-       if (subs->transfer_done >= runtime->period_size) {
-               subs->transfer_done -= runtime->period_size;
-               spin_unlock_irqrestore(&subs->lock, flags);
-               snd_pcm_period_elapsed(subs->pcm_substream);
-       } else
-               spin_unlock_irqrestore(&subs->lock, flags);
        return 0;
 }
 
+/*
+ * Delay the snd_pcm_period_elapsed() call until after the start trigger
+ * callback so that we're not longer in the substream's lock.
+ */
+static void start_period_elapsed(unsigned long data)
+{
+       snd_usb_substream_t *subs = (snd_usb_substream_t *)data;
+       snd_pcm_period_elapsed(subs->pcm_substream);
+}
+
 
 /*
  */
@@ -683,6 +677,42 @@ static void snd_complete_sync_urb(struct urb *urb, struct pt_regs *regs)
 }
 
 
+/* get the physical page pointer at the given offset */
+static struct page *snd_pcm_get_vmalloc_page(snd_pcm_substream_t *subs,
+                                            unsigned long offset)
+{
+       void *pageptr = subs->runtime->dma_area + offset;
+       return vmalloc_to_page(pageptr);
+}
+
+/* allocate virtual buffer; may be called more than once */
+static int snd_pcm_alloc_vmalloc_buffer(snd_pcm_substream_t *subs, size_t size)
+{
+       snd_pcm_runtime_t *runtime = subs->runtime;
+       if (runtime->dma_area) {
+               if (runtime->dma_bytes >= size)
+                       return 0; /* already large enough */
+               vfree_nocheck(runtime->dma_area);
+       }
+       runtime->dma_area = vmalloc_nocheck(size);
+       if (! runtime->dma_area)
+               return -ENOMEM;
+       runtime->dma_bytes = size;
+       return 0;
+}
+
+/* free virtual buffer; may be called more than once */
+static int snd_pcm_free_vmalloc_buffer(snd_pcm_substream_t *subs)
+{
+       snd_pcm_runtime_t *runtime = subs->runtime;
+       if (runtime->dma_area) {
+               vfree_nocheck(runtime->dma_area);
+               runtime->dma_area = NULL;
+       }
+       return 0;
+}
+
+
 /*
  * unlink active urbs.
  */
@@ -824,8 +854,14 @@ static int wait_clear_urbs(snd_usb_substream_t *subs)
  */
 static snd_pcm_uframes_t snd_usb_pcm_pointer(snd_pcm_substream_t *substream)
 {
-       snd_usb_substream_t *subs = (snd_usb_substream_t *)substream->runtime->private_data;
-       return subs->hwptr_done;
+       snd_usb_substream_t *subs;
+       snd_pcm_uframes_t hwptr_done;
+       
+       subs = (snd_usb_substream_t *)substream->runtime->private_data;
+       spin_lock(&subs->lock);
+       hwptr_done = subs->hwptr_done;
+       spin_unlock(&subs->lock);
+       return hwptr_done;
 }
 
 
@@ -858,11 +894,13 @@ static int snd_usb_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
 static void release_urb_ctx(snd_urb_ctx_t *u)
 {
        if (u->urb) {
+               if (u->buffer_size)
+                       usb_buffer_free(u->subs->dev, u->buffer_size,
+                                       u->urb->transfer_buffer,
+                                       u->urb->transfer_dma);
                usb_free_urb(u->urb);
                u->urb = NULL;
        }
-       kfree(u->buf);
-       u->buf = NULL;
 }
 
 /*
@@ -880,8 +918,9 @@ static void release_substream_urbs(snd_usb_substream_t *subs, int force)
                release_urb_ctx(&subs->dataurb[i]);
        for (i = 0; i < SYNC_URBS; i++)
                release_urb_ctx(&subs->syncurb[i]);
-       kfree(subs->tmpbuf);
-       subs->tmpbuf = NULL;
+       usb_buffer_free(subs->dev, SYNC_URBS * 4,
+                       subs->syncbuf, subs->sync_dma);
+       subs->syncbuf = NULL;
        subs->nurbs = 0;
 }
 
@@ -893,7 +932,7 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
 {
        unsigned int maxsize, n, i;
        int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
-       unsigned int npacks[MAX_URBS], urb_packs, total_packs;
+       unsigned int npacks[MAX_URBS], urb_packs, total_packs, packs_per_ms;
 
        /* calculate the frequency in 16.16 format */
        if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
@@ -920,24 +959,40 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
        else
                subs->curpacksize = maxsize;
 
-       if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
-               urb_packs = nrpacks;
+       if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH)
+               packs_per_ms = 8 >> subs->datainterval;
        else
-               urb_packs = (nrpacks * 8) >> subs->datainterval;
+               packs_per_ms = 1;
+       subs->packs_per_ms = packs_per_ms;
 
-       /* allocate a temporary buffer for playback */
        if (is_playback) {
-               subs->tmpbuf = kmalloc(maxsize * urb_packs, GFP_KERNEL);
-               if (! subs->tmpbuf) {
-                       snd_printk(KERN_ERR "cannot malloc tmpbuf\n");
-                       return -ENOMEM;
-               }
-       }
+               urb_packs = nrpacks;
+               urb_packs = max(urb_packs, (unsigned int)MIN_PACKS_URB);
+               urb_packs = min(urb_packs, (unsigned int)MAX_PACKS);
+       } else
+               urb_packs = 1;
+       urb_packs *= packs_per_ms;
 
        /* decide how many packets to be used */
-       total_packs = (period_bytes + maxsize - 1) / maxsize;
-       if (total_packs < 2 * MIN_PACKS_URB)
-               total_packs = 2 * MIN_PACKS_URB;
+       if (is_playback) {
+               unsigned int minsize;
+               /* determine how small a packet can be */
+               minsize = (subs->freqn >> (16 - subs->datainterval))
+                         * (frame_bits >> 3);
+               /* with sync from device, assume it can be 12% lower */
+               if (subs->syncpipe)
+                       minsize -= minsize >> 3;
+               minsize = max(minsize, 1u);
+               total_packs = (period_bytes + minsize - 1) / minsize;
+               /* round up to multiple of packs_per_ms */
+               total_packs = (total_packs + packs_per_ms - 1)
+                               & ~(packs_per_ms - 1);
+               /* we need at least two URBs for queueing */
+               if (total_packs < 2 * MIN_PACKS_URB * packs_per_ms)
+                       total_packs = 2 * MIN_PACKS_URB * packs_per_ms;
+       } else {
+               total_packs = MAX_URBS * urb_packs;
+       }
        subs->nurbs = (total_packs + urb_packs - 1) / urb_packs;
        if (subs->nurbs > MAX_URBS) {
                /* too much... */
@@ -956,7 +1011,7 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
                subs->nurbs = 2;
                npacks[0] = (total_packs + 1) / 2;
                npacks[1] = total_packs - npacks[0];
-       } else if (npacks[subs->nurbs-1] < MIN_PACKS_URB) {
+       } else if (npacks[subs->nurbs-1] < MIN_PACKS_URB * packs_per_ms) {
                /* the last packet is too small.. */
                if (subs->nurbs > 2) {
                        /* merge to the first one */
@@ -975,27 +1030,20 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
                snd_urb_ctx_t *u = &subs->dataurb[i];
                u->index = i;
                u->subs = subs;
-               u->transfer = 0;
                u->packets = npacks[i];
+               u->buffer_size = maxsize * u->packets;
                if (subs->fmt_type == USB_FORMAT_TYPE_II)
                        u->packets++; /* for transfer delimiter */
-               if (! is_playback) {
-                       /* allocate a capture buffer per urb */
-                       u->buf = kmalloc(maxsize * u->packets, GFP_KERNEL);
-                       if (! u->buf) {
-                               release_substream_urbs(subs, 0);
-                               return -ENOMEM;
-                       }
-               }
                u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
-               if (! u->urb) {
-                       release_substream_urbs(subs, 0);
-                       return -ENOMEM;
-               }
-               u->urb->dev = subs->dev;
+               if (! u->urb)
+                       goto out_of_memory;
+               u->urb->transfer_buffer =
+                       usb_buffer_alloc(subs->dev, u->buffer_size, GFP_KERNEL,
+                                        &u->urb->transfer_dma);
+               if (! u->urb->transfer_buffer)
+                       goto out_of_memory;
                u->urb->pipe = subs->datapipe;
-               u->urb->transfer_flags = URB_ISO_ASAP;
-               u->urb->number_of_packets = u->packets;
+               u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
                u->urb->interval = 1 << subs->datainterval;
                u->urb->context = u;
                u->urb->complete = snd_usb_complete_callback(snd_complete_urb);
@@ -1003,21 +1051,24 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
 
        if (subs->syncpipe) {
                /* allocate and initialize sync urbs */
+               subs->syncbuf = usb_buffer_alloc(subs->dev, SYNC_URBS * 4,
+                                                GFP_KERNEL, &subs->sync_dma);
+               if (! subs->syncbuf)
+                       goto out_of_memory;
                for (i = 0; i < SYNC_URBS; i++) {
                        snd_urb_ctx_t *u = &subs->syncurb[i];
                        u->index = i;
                        u->subs = subs;
                        u->packets = 1;
                        u->urb = usb_alloc_urb(1, GFP_KERNEL);
-                       if (! u->urb) {
-                               release_substream_urbs(subs, 0);
-                               return -ENOMEM;
-                       }
+                       if (! u->urb)
+                               goto out_of_memory;
                        u->urb->transfer_buffer = subs->syncbuf + i * 4;
+                       u->urb->transfer_dma = subs->sync_dma + i * 4;
                        u->urb->transfer_buffer_length = 4;
-                       u->urb->dev = subs->dev;
                        u->urb->pipe = subs->syncpipe;
-                       u->urb->transfer_flags = URB_ISO_ASAP;
+                       u->urb->transfer_flags = URB_ISO_ASAP |
+                                                URB_NO_TRANSFER_DMA_MAP;
                        u->urb->number_of_packets = 1;
                        u->urb->interval = 1 << subs->syncinterval;
                        u->urb->context = u;
@@ -1025,6 +1076,10 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
                }
        }
        return 0;
+
+out_of_memory:
+       release_substream_urbs(subs, 0);
+       return -ENOMEM;
 }
 
 
@@ -1293,7 +1348,8 @@ static int snd_usb_hw_params(snd_pcm_substream_t *substream,
        unsigned int channels, rate, format;
        int ret, changed;
 
-       ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+       ret = snd_pcm_alloc_vmalloc_buffer(substream,
+                                          params_buffer_bytes(hw_params));
        if (ret < 0)
                return ret;
 
@@ -1349,7 +1405,7 @@ static int snd_usb_hw_free(snd_pcm_substream_t *substream)
        subs->cur_rate = 0;
        subs->period_bytes = 0;
        release_substream_urbs(subs, 0);
-       return snd_pcm_lib_free_pages(substream);
+       return snd_pcm_free_vmalloc_buffer(substream);
 }
 
 /*
@@ -1372,9 +1428,7 @@ static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream)
        subs->curframesize = bytes_to_frames(runtime, subs->curpacksize);
 
        /* reset the pointer */
-       subs->hwptr = 0;
        subs->hwptr_done = 0;
-       subs->transfer_sched = 0;
        subs->transfer_done = 0;
        subs->phase = 0;
 
@@ -1390,7 +1444,7 @@ static snd_pcm_hardware_t snd_usb_playback =
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID),
-       .buffer_bytes_max =     (128*1024),
+       .buffer_bytes_max =     (256*1024),
        .period_bytes_min =     64,
        .period_bytes_max =     (128*1024),
        .periods_min =          2,
@@ -1402,7 +1456,7 @@ static snd_pcm_hardware_t snd_usb_capture =
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID),
-       .buffer_bytes_max =     (128*1024),
+       .buffer_bytes_max =     (256*1024),
        .period_bytes_min =     64,
        .period_bytes_max =     (128*1024),
        .periods_min =          2,
@@ -1794,6 +1848,7 @@ static snd_pcm_ops_t snd_usb_playback_ops = {
        .prepare =      snd_usb_pcm_prepare,
        .trigger =      snd_usb_pcm_trigger,
        .pointer =      snd_usb_pcm_pointer,
+       .page =         snd_pcm_get_vmalloc_page,
 };
 
 static snd_pcm_ops_t snd_usb_capture_ops = {
@@ -1805,6 +1860,7 @@ static snd_pcm_ops_t snd_usb_capture_ops = {
        .prepare =      snd_usb_pcm_prepare,
        .trigger =      snd_usb_pcm_trigger,
        .pointer =      snd_usb_pcm_pointer,
+       .page =         snd_pcm_get_vmalloc_page,
 };
 
 
@@ -2021,6 +2077,9 @@ static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat
 
        INIT_LIST_HEAD(&subs->fmt_list);
        spin_lock_init(&subs->lock);
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+               tasklet_init(&subs->start_period_elapsed, start_period_elapsed,
+                            (unsigned long)subs);
 
        subs->stream = as;
        subs->direction = stream;
@@ -2029,10 +2088,6 @@ static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat
                subs->ops = audio_urb_ops[stream];
        else
                subs->ops = audio_urb_ops_high_speed[stream];
-       snd_pcm_lib_preallocate_pages(as->pcm->streams[stream].substream,
-                                     SNDRV_DMA_TYPE_CONTINUOUS,
-                                     snd_dma_continuous_data(GFP_KERNEL),
-                                     64 * 1024, 128 * 1024);
        snd_pcm_set_ops(as->pcm, stream,
                        stream == SNDRV_PCM_STREAM_PLAYBACK ?
                        &snd_usb_playback_ops : &snd_usb_capture_ops);
@@ -2078,7 +2133,6 @@ static void snd_usb_audio_pcm_free(snd_pcm_t *pcm)
        snd_usb_stream_t *stream = pcm->private_data;
        if (stream) {
                stream->pcm = NULL;
-               snd_pcm_lib_preallocate_free_for_all(pcm);
                snd_usb_audio_stream_free(stream);
        }
 }
index 5778a9b725ec1eebbd03d1763861262500bf7315..93dedde3c42877137bded1e0d88f21f7ee98079e 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/timer.h>
 #include <linux/usb.h>
 #include <sound/core.h>
 #include <sound/minors.h>
  */
 /* #define DUMP_PACKETS */
 
+/*
+ * how long to wait after some USB errors, so that khubd can disconnect() us
+ * without too many spurious errors
+ */
+#define ERROR_DELAY_JIFFIES (HZ / 10)
+
 
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_DESCRIPTION("USB Audio/MIDI helper module");
@@ -100,6 +107,7 @@ struct snd_usb_midi {
        snd_rawmidi_t* rmidi;
        struct usb_protocol_ops* usb_protocol_ops;
        struct list_head list;
+       struct timer_list error_timer;
 
        struct snd_usb_midi_endpoint {
                snd_usb_midi_out_endpoint_t *out;
@@ -141,7 +149,8 @@ struct snd_usb_midi_in_endpoint {
        struct usbmidi_in_port {
                snd_rawmidi_substream_t* substream;
        } ports[0x10];
-       int seen_f5;
+       u8 seen_f5;
+       u8 error_resubmit;
        int current_port;
 };
 
@@ -167,14 +176,22 @@ static int snd_usbmidi_submit_urb(struct urb* urb, int flags)
  */
 static int snd_usbmidi_urb_error(int status)
 {
-       if (status == -ENOENT)
-               return status; /* killed */
-       if (status == -EILSEQ ||
-           status == -ECONNRESET ||
-           status == -ETIMEDOUT)
-               return -ENODEV; /* device removed/shutdown */
-       snd_printk(KERN_ERR "urb status %d\n", status);
-       return 0; /* continue */
+       switch (status) {
+       /* manually unlinked, or device gone */
+       case -ENOENT:
+       case -ECONNRESET:
+       case -ESHUTDOWN:
+       case -ENODEV:
+               return -ENODEV;
+       /* errors that might occur during unplugging */
+       case -EPROTO:    /* EHCI */
+       case -ETIMEDOUT: /* OHCI */
+       case -EILSEQ:    /* UHCI */
+               return -EIO;
+       default:
+               snd_printk(KERN_ERR "urb status %d\n", status);
+               return 0; /* continue */
+       }
 }
 
 /*
@@ -218,8 +235,15 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb, struct pt_regs *regs)
                ep->umidi->usb_protocol_ops->input(ep, urb->transfer_buffer,
                                                   urb->actual_length);
        } else {
-               if (snd_usbmidi_urb_error(urb->status) < 0)
+               int err = snd_usbmidi_urb_error(urb->status);
+               if (err < 0) {
+                       if (err != -ENODEV) {
+                               ep->error_resubmit = 1;
+                               mod_timer(&ep->umidi->error_timer,
+                                         jiffies + ERROR_DELAY_JIFFIES);
+                       }
                        return;
+               }
        }
 
        if (usb_pipe_needs_resubmit(urb->pipe)) {
@@ -236,8 +260,13 @@ static void snd_usbmidi_out_urb_complete(struct urb* urb, struct pt_regs *regs)
        ep->urb_active = 0;
        spin_unlock(&ep->buffer_lock);
        if (urb->status < 0) {
-               if (snd_usbmidi_urb_error(urb->status) < 0)
+               int err = snd_usbmidi_urb_error(urb->status);
+               if (err < 0) {
+                       if (err != -ENODEV)
+                               mod_timer(&ep->umidi->error_timer,
+                                         jiffies + ERROR_DELAY_JIFFIES);
                        return;
+               }
        }
        snd_usbmidi_do_output(ep);
 }
@@ -276,6 +305,24 @@ static void snd_usbmidi_out_tasklet(unsigned long data)
        snd_usbmidi_do_output(ep);
 }
 
+/* called after transfers had been interrupted due to some USB error */
+static void snd_usbmidi_error_timer(unsigned long data)
+{
+       snd_usb_midi_t *umidi = (snd_usb_midi_t *)data;
+       int i;
+
+       for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
+               snd_usb_midi_in_endpoint_t *in = umidi->endpoints[i].in;
+               if (in && in->error_resubmit) {
+                       in->error_resubmit = 0;
+                       in->urb->dev = umidi->chip->dev;
+                       snd_usbmidi_submit_urb(in->urb, GFP_ATOMIC);
+               }
+               if (umidi->endpoints[i].out)
+                       snd_usbmidi_do_output(umidi->endpoints[i].out);
+       }
+}
+
 /* helper function to send static data that may not DMA-able */
 static int send_bulk_static_data(snd_usb_midi_out_endpoint_t* ep,
                                 const void *data, int len)
@@ -594,17 +641,20 @@ static void snd_usbmidi_emagic_finish_out(snd_usb_midi_out_endpoint_t* ep)
 static void snd_usbmidi_emagic_input(snd_usb_midi_in_endpoint_t* ep,
                                     uint8_t* buffer, int buffer_length)
 {
-       /* ignore padding bytes at end of buffer */
-       while (buffer_length > 0 && buffer[buffer_length - 1] == 0xff)
-               --buffer_length;
+       int i;
+
+       /* FF indicates end of valid data */
+       for (i = 0; i < buffer_length; ++i)
+               if (buffer[i] == 0xff) {
+                       buffer_length = i;
+                       break;
+               }
 
        /* handle F5 at end of last buffer */
        if (ep->seen_f5)
                goto switch_port;
 
        while (buffer_length > 0) {
-               int i;
-
                /* determine size of data until next F5 */
                for (i = 0; i < buffer_length; ++i)
                        if (buffer[i] == 0xf5)
@@ -671,6 +721,10 @@ static void snd_usbmidi_emagic_output(snd_usb_midi_out_endpoint_t* ep)
                                break;
                }
        }
+       if (buf_free < ep->max_transfer && buf_free > 0) {
+               *buf = 0xff;
+               --buf_free;
+       }
        ep->urb->transfer_buffer_length = ep->max_transfer - buf_free;
 }
 
@@ -765,7 +819,10 @@ static snd_rawmidi_ops_t snd_usbmidi_input_ops = {
 static void snd_usbmidi_in_endpoint_delete(snd_usb_midi_in_endpoint_t* ep)
 {
        if (ep->urb) {
-               kfree(ep->urb->transfer_buffer);
+               usb_buffer_free(ep->umidi->chip->dev,
+                               ep->urb->transfer_buffer_length,
+                               ep->urb->transfer_buffer,
+                               ep->urb->transfer_dma);
                usb_free_urb(ep->urb);
        }
        kfree(ep);
@@ -799,7 +856,8 @@ static int snd_usbmidi_in_endpoint_create(snd_usb_midi_t* umidi,
        else
                pipe = usb_rcvbulkpipe(umidi->chip->dev, ep_info->in_ep);
        length = usb_maxpacket(umidi->chip->dev, pipe, 0);
-       buffer = kmalloc(length, GFP_KERNEL);
+       buffer = usb_buffer_alloc(umidi->chip->dev, length, GFP_KERNEL,
+                                 &ep->urb->transfer_dma);
        if (!buffer) {
                snd_usbmidi_in_endpoint_delete(ep);
                return -ENOMEM;
@@ -812,6 +870,7 @@ static int snd_usbmidi_in_endpoint_create(snd_usb_midi_t* umidi,
                usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe, buffer, length,
                                  snd_usb_complete_callback(snd_usbmidi_in_urb_complete),
                                  ep);
+       ep->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
 
        rep->in = ep;
        return 0;
@@ -832,10 +891,10 @@ static unsigned int snd_usbmidi_count_bits(unsigned int x)
  */
 static void snd_usbmidi_out_endpoint_delete(snd_usb_midi_out_endpoint_t* ep)
 {
-       if (ep->tasklet.func)
-               tasklet_kill(&ep->tasklet);
        if (ep->urb) {
-               kfree(ep->urb->transfer_buffer);
+               usb_buffer_free(ep->umidi->chip->dev, ep->max_transfer,
+                               ep->urb->transfer_buffer,
+                               ep->urb->transfer_dma);
                usb_free_urb(ep->urb);
        }
        kfree(ep);
@@ -867,7 +926,8 @@ static int snd_usbmidi_out_endpoint_create(snd_usb_midi_t* umidi,
        /* we never use interrupt output pipes */
        pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->out_ep);
        ep->max_transfer = usb_maxpacket(umidi->chip->dev, pipe, 1);
-       buffer = kmalloc(ep->max_transfer, GFP_KERNEL);
+       buffer = usb_buffer_alloc(umidi->chip->dev, ep->max_transfer,
+                                 GFP_KERNEL, &ep->urb->transfer_dma);
        if (!buffer) {
                snd_usbmidi_out_endpoint_delete(ep);
                return -ENOMEM;
@@ -875,6 +935,7 @@ static int snd_usbmidi_out_endpoint_create(snd_usb_midi_t* umidi,
        usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe, buffer,
                          ep->max_transfer,
                          snd_usb_complete_callback(snd_usbmidi_out_urb_complete), ep);
+       ep->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
 
        spin_lock_init(&ep->buffer_lock);
        tasklet_init(&ep->tasklet, snd_usbmidi_out_tasklet, (unsigned long)ep);
@@ -918,8 +979,11 @@ void snd_usbmidi_disconnect(struct list_head* p)
        int i;
 
        umidi = list_entry(p, snd_usb_midi_t, list);
+       del_timer_sync(&umidi->error_timer);
        for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
                snd_usb_midi_endpoint_t* ep = &umidi->endpoints[i];
+               if (ep->out)
+                       tasklet_kill(&ep->out->tasklet);
                if (ep->out && ep->out->urb) {
                        usb_kill_urb(ep->out->urb);
                        if (umidi->usb_protocol_ops->finish_out_endpoint)
@@ -1480,6 +1544,9 @@ int snd_usb_create_midi_interface(snd_usb_audio_t* chip,
        umidi->iface = iface;
        umidi->quirk = quirk;
        umidi->usb_protocol_ops = &snd_usbmidi_standard_ops;
+       init_timer(&umidi->error_timer);
+       umidi->error_timer.function = snd_usbmidi_error_timer;
+       umidi->error_timer.data = (unsigned long)umidi;
 
        /* detect the endpoint(s) to use */
        memset(endpoints, 0, sizeof(endpoints));
index ef28061287f200c7a6c07d0f841443c9b3388eec..d0199c4e55514dad367e3c51d7b1543180392f40 100644 (file)
@@ -624,7 +624,7 @@ static int usX2Y_pcms_lock_check(snd_card_t *card)
                for (s = 0; s < 2; ++s) {
                        snd_pcm_substream_t *substream;
                        substream = pcm->streams[s].substream;
-                       if (substream && substream->open_flag)
+                       if (substream && substream->ffile != NULL)
                                err = -EBUSY;
                }
        }