Merged ati-4-0-1
authorKevin E Martin <kem@kem.org>
Thu, 18 May 2000 06:14:27 +0000 (06:14 +0000)
committerKevin E Martin <kem@kem.org>
Thu, 18 May 2000 06:14:27 +0000 (06:14 +0000)
19 files changed:
libdrm/xf86drm.c
linux-core/Makefile.kernel
linux-core/drmP.h
linux-core/r128_drv.c [new file with mode: 0644]
linux/Makefile.kernel
linux/Makefile.linux
linux/agpsupport.c
linux/drm.h
linux/drmP.h
linux/proc.c
linux/r128_bufs.c [new file with mode: 0644]
linux/r128_context.c [new file with mode: 0644]
linux/r128_dma.c [new file with mode: 0644]
linux/r128_drm.h [new file with mode: 0644]
linux/r128_drv.c [new file with mode: 0644]
linux/r128_drv.h [new file with mode: 0644]
linux/vm.c
shared-core/drm.h
shared/drm.h

index 3b66c19..2e3c9b4 100644 (file)
@@ -1,8 +1,7 @@
 /* xf86drm.c -- User-level interface to DRM device
  * Created: Tue Jan  5 08:16:21 1999 by faith@precisioninsight.com
- * Revised: Sun Feb 13 23:43:32 2000 by kevin@precisioninsight.com
  *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -24,6 +23,8 @@
  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  * 
+ * Author: Rickard E. (Rik) Faith <faith@precisioninsight.com>
+ * 
  * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drm.c,v 1.10 2000/02/23 04:47:23 martin Exp $
  * 
  */
@@ -143,7 +144,7 @@ static int drm_open(const char *file)
     return -errno;
 }
 
-/* drmAvailable looks for /proc/drm, and returns 1 if it is present. */
+/* drmAvailable looks for /proc/dri, and returns 1 if it is present. */
 
 int drmAvailable(void)
 {
index 2ea6c72..a169473 100644 (file)
@@ -49,3 +49,5 @@ i810.o: i810_drv.o i810_context.o $(L_TARGET)
 mga.o: mga_drv.o mga_context.o mga_dma.o mga_bufs.o $(L_TARGET)
        $(LD) $(LD_RFLAG) -r -o $@ mga_drv.o mga_bufs.o mga_dma.o mga_context.o mga_state.o -L. -ldrm
 
+r128.o: r128_drv.o r128_context.o $(L_TARGET)
+       $(LD) $(LD_RFLAG) -r -o $@ r128_drv.o r128_context.o -L. -ldrm
index f8e78ea..43670e2 100644 (file)
@@ -1,8 +1,7 @@
 /* drmP.h -- Private header for Direct Rendering Manager -*- linux-c -*-
  * Created: Mon Jan  4 10:05:05 1999 by faith@precisioninsight.com
- * Revised: Sun Feb 13 23:34:30 2000 by kevin@precisioninsight.com
  *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
  * All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -228,8 +227,8 @@ typedef struct drm_magic_entry {
 } drm_magic_entry_t;
 
 typedef struct drm_magic_head {
-       struct drm_magic_entry *head;
-       struct drm_magic_entry *tail;
+       struct drm_magic_entry *head;
+       struct drm_magic_entry *tail;
 } drm_magic_head_t;
 
 typedef struct drm_vma_entry {
@@ -262,16 +261,15 @@ typedef struct drm_buf {
                DRM_LIST_RECLAIM = 5
        }                 list;        /* Which list we're on                */
 
-
-       void *dev_private;
-       int dev_priv_size;
-
 #if DRM_DMA_HISTOGRAM
        cycles_t          time_queued;     /* Queued to kernel DMA queue     */
        cycles_t          time_dispatched; /* Dispatched to hardware         */
        cycles_t          time_completed;  /* Completed by hardware          */
        cycles_t          time_freed;      /* Back on freelist               */
 #endif
+
+       int               dev_priv_size; /* Size of buffer private stoarge   */
+       void              *dev_private;  /* Per-buffer private storage       */
 } drm_buf_t;
 
 #if DRM_DMA_HISTOGRAM
diff --git a/linux-core/r128_drv.c b/linux-core/r128_drv.c
new file mode 100644 (file)
index 0000000..45ade1d
--- /dev/null
@@ -0,0 +1,737 @@
+/* r128_drv.c -- ATI Rage 128 driver -*- linux-c -*-
+ * Created: Mon Dec 13 09:47:27 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * 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@precisioninsight.com>
+ *          Kevin E. Martin <kevin@precisioninsight.com>
+ * 
+ * $XFree86$
+ *
+ */
+
+#define EXPORT_SYMTAB
+#include "drmP.h"
+#include "r128_drv.h"
+EXPORT_SYMBOL(r128_init);
+EXPORT_SYMBOL(r128_cleanup);
+
+#define R128_NAME       "r128"
+#define R128_DESC       "r128"
+#define R128_DATE       "20000422"
+#define R128_MAJOR      0
+#define R128_MINOR      0
+#define R128_PATCHLEVEL  5
+
+static drm_device_t          r128_device;
+drm_ctx_t                    r128_res_ctx;
+
+static struct file_operations r128_fops = {
+       open:    r128_open,
+       flush:   drm_flush,
+       release: r128_release,
+       ioctl:   r128_ioctl,
+       mmap:    drm_mmap,
+       read:    drm_read,
+       fasync:  drm_fasync,
+       poll:    drm_poll,
+};
+
+static struct miscdevice      r128_misc = {
+       minor: MISC_DYNAMIC_MINOR,
+       name:  R128_NAME,
+       fops:  &r128_fops,
+};
+
+static drm_ioctl_desc_t              r128_ioctls[] = {
+       [DRM_IOCTL_NR(DRM_IOCTL_VERSION)]     = { r128_version,    0, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)]  = { drm_getunique,   0, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)]   = { drm_getmagic,    0, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)]   = { drm_irq_busid,   0, 1 },
+
+       [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)]  = { drm_setunique,   1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)]       = { drm_block,       1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)]     = { drm_unblock,     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_ADD_BUFS)]    = { r128_addbufs,    1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)]   = { drm_markbufs,    1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)]   = { drm_infobufs,    1, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)]    = { r128_mapbufs,    1, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)]   = { drm_freebufs,    1, 0 },
+
+       [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)]     = { r128_addctx,     1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)]      = { r128_rmctx,      1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)]     = { r128_modctx,     1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)]     = { r128_getctx,     1, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)]  = { r128_switchctx,  1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)]     = { r128_newctx,     1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)]     = { r128_resctx,     1, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)]    = { drm_adddraw,     1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)]     = { drm_rmdraw,      1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_LOCK)]        = { r128_lock,       1, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)]      = { r128_unlock,     1, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_FINISH)]      = { drm_finish,      1, 0 },
+
+#ifdef DRM_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_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 },
+       [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)]  = { drm_agp_unbind,  1, 1 },
+#endif
+
+       [DRM_IOCTL_NR(DRM_IOCTL_R128_INIT)]   = { r128_init_cce,   1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_R128_RESET)]  = { r128_eng_reset,  1, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_R128_FLUSH)]  = { r128_eng_flush,  1, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_R128_PACKET)] = { r128_submit_pkt, 1, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_R128_CCEIDL)] = { r128_cce_idle,   1, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_R128_VERTEX)] = { r128_vertex_buf, 1, 0 },
+};
+#define R128_IOCTL_COUNT DRM_ARRAY_SIZE(r128_ioctls)
+
+#ifdef MODULE
+int                          init_module(void);
+void                         cleanup_module(void);
+static char                  *r128 = NULL;
+
+MODULE_AUTHOR("Precision Insight, Inc., Cedar Park, Texas.");
+MODULE_DESCRIPTION("r128");
+MODULE_PARM(r128, "s");
+
+/* init_module is called when insmod is used to load the module */
+
+int init_module(void)
+{
+       return r128_init();
+}
+
+/* cleanup_module is called when rmmod is used to unload the module */
+
+void cleanup_module(void)
+{
+       r128_cleanup();
+}
+#endif
+
+#ifndef MODULE
+/* r128_setup is called by the kernel to parse command-line options passed
+ * via the boot-loader (e.g., LILO).  It calls the insmod option routine,
+ * drm_parse_drm.
+ *
+ * This is not currently supported, since it requires changes to
+ * linux/init/main.c. */
+
+void __init r128_setup(char *str, int *ints)
+{
+       if (ints[0] != 0) {
+               DRM_ERROR("Illegal command line format, ignored\n");
+               return;
+       }
+       drm_parse_options(str);
+}
+#endif
+
+static int r128_setup(drm_device_t *dev)
+{
+       int i;
+       
+       atomic_set(&dev->ioctl_count, 0);
+       atomic_set(&dev->vma_count, 0);
+       dev->buf_use      = 0;
+       atomic_set(&dev->buf_alloc, 0);
+
+       drm_dma_setup(dev);
+
+       atomic_set(&dev->total_open, 0);
+       atomic_set(&dev->total_close, 0);
+       atomic_set(&dev->total_ioctl, 0);
+       atomic_set(&dev->total_irq, 0);
+       atomic_set(&dev->total_ctx, 0);
+       atomic_set(&dev->total_locks, 0);
+       atomic_set(&dev->total_unlocks, 0);
+       atomic_set(&dev->total_contends, 0);
+       atomic_set(&dev->total_sleeps, 0);
+
+       for (i = 0; i < DRM_HASH_SIZE; i++) {
+               dev->magiclist[i].head = NULL;
+               dev->magiclist[i].tail = NULL;
+       }
+       dev->maplist        = NULL;
+       dev->map_count      = 0;
+       dev->vmalist        = NULL;
+       dev->lock.hw_lock   = NULL;
+       init_waitqueue_head(&dev->lock.lock_queue);
+       dev->queue_count    = 0;
+       dev->queue_reserved = 0;
+       dev->queue_slots    = 0;
+       dev->queuelist      = NULL;
+       dev->irq            = 0;
+       dev->context_flag   = 0;
+       dev->interrupt_flag = 0;
+       dev->dma_flag       = 0;
+       dev->last_context   = 0;
+       dev->last_switch    = 0;
+       dev->last_checked   = 0;
+       init_timer(&dev->timer);
+       init_waitqueue_head(&dev->context_wait);
+
+       dev->ctx_start      = 0;
+       dev->lck_start      = 0;
+       
+       dev->buf_rp       = dev->buf;
+       dev->buf_wp       = dev->buf;
+       dev->buf_end      = dev->buf + DRM_BSZ;
+       dev->buf_async    = NULL;
+       init_waitqueue_head(&dev->buf_readers);
+       init_waitqueue_head(&dev->buf_writers);
+
+       r128_res_ctx.handle=-1;
+                       
+       DRM_DEBUG("\n");
+                       
+       /* The kernel's context could be created here, but is now created
+          in drm_dma_enqueue.  This is more resource-efficient for
+          hardware that does not do DMA, but may mean that
+          drm_select_queue fails between the time the interrupt is
+          initialized and the time the queues are initialized. */
+                       
+       return 0;
+}
+
+
+static int r128_takedown(drm_device_t *dev)
+{
+       int               i;
+       drm_magic_entry_t *pt, *next;
+       drm_map_t         *map;
+       drm_vma_entry_t   *vma, *vma_next;
+
+       DRM_DEBUG("\n");
+
+       down(&dev->struct_sem);
+       del_timer(&dev->timer);
+       
+       if (dev->devname) {
+               drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER);
+               dev->devname = NULL;
+       }
+       
+       if (dev->unique) {
+               drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER);
+               dev->unique = NULL;
+               dev->unique_len = 0;
+       }
+                               /* Clear pid list */
+       for (i = 0; i < DRM_HASH_SIZE; i++) {
+               for (pt = dev->magiclist[i].head; pt; pt = next) {
+                       next = pt->next;
+                       drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
+               }
+               dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
+       }
+
+#ifdef DRM_AGP
+                               /* Clear AGP information */
+       if (dev->agp) {
+               drm_agp_mem_t *entry;
+               drm_agp_mem_t *nexte;
+               
+                               /* Remove AGP resources, but leave dev->agp
+                                   intact until r128_cleanup is called. */
+               for (entry = dev->agp->memory; entry; entry = nexte) {
+                       nexte = entry->next;
+                       if (entry->bound) drm_unbind_agp(entry->memory);
+                       drm_free_agp(entry->memory, entry->pages);
+                       drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
+               }
+               dev->agp->memory = NULL;
+               
+               if (dev->agp->acquired && drm_agp.release)
+                       (*drm_agp.release)();
+               
+               dev->agp->acquired = 0;
+               dev->agp->enabled  = 0;
+       }
+#endif
+       
+                               /* Clear vma list (only built for debugging) */
+       if (dev->vmalist) {
+               for (vma = dev->vmalist; vma; vma = vma_next) {
+                       vma_next = vma->next;
+                       drm_free(vma, sizeof(*vma), DRM_MEM_VMAS);
+               }
+               dev->vmalist = NULL;
+       }
+       
+                               /* Clear map area and mtrr information */
+       if (dev->maplist) {
+               for (i = 0; i < dev->map_count; i++) {
+                       map = dev->maplist[i];
+                       switch (map->type) {
+                       case _DRM_REGISTERS:
+                       case _DRM_FRAME_BUFFER:
+#ifdef CONFIG_MTRR
+                               if (map->mtrr >= 0) {
+                                       int retcode;
+                                       retcode = mtrr_del(map->mtrr,
+                                                          map->offset,
+                                                          map->size);
+                                       DRM_DEBUG("mtrr_del = %d\n", retcode);
+                               }
+#endif
+                               drm_ioremapfree(map->handle, map->size);
+                               break;
+                       case _DRM_SHM:
+                               drm_free_pages((unsigned long)map->handle,
+                                              drm_order(map->size)
+                                              - PAGE_SHIFT,
+                                              DRM_MEM_SAREA);
+                               break;
+                       case _DRM_AGP:
+                               /* Do nothing here, because this is all
+                                   handled in the AGP/GART driver. */
+                               break;
+                       }
+                       drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+               }
+               drm_free(dev->maplist,
+                        dev->map_count * sizeof(*dev->maplist),
+                        DRM_MEM_MAPS);
+               dev->maplist   = NULL;
+               dev->map_count = 0;
+       }
+       
+       drm_dma_takedown(dev);
+
+       dev->queue_count     = 0;
+       if (dev->lock.hw_lock) {
+               dev->lock.hw_lock    = NULL; /* SHM removed */
+               dev->lock.pid        = 0;
+               wake_up_interruptible(&dev->lock.lock_queue);
+       }
+       up(&dev->struct_sem);
+       
+       return 0;
+}
+
+/* r128_init is called via init_module at module load time, or via
+ * linux/init/main.c (this is not currently supported). */
+
+int r128_init(void)
+{
+       int                   retcode;
+       drm_device_t          *dev = &r128_device;
+
+       DRM_DEBUG("\n");
+
+       memset((void *)dev, 0, sizeof(*dev));
+       dev->count_lock   = SPIN_LOCK_UNLOCKED;
+       sema_init(&dev->struct_sem, 1);
+       
+#ifdef MODULE
+       drm_parse_options(r128);
+#endif
+
+       if ((retcode = misc_register(&r128_misc))) {
+               DRM_ERROR("Cannot register \"%s\"\n", R128_NAME);
+               return retcode;
+       }
+       dev->device = MKDEV(MISC_MAJOR, r128_misc.minor);
+       dev->name   = R128_NAME;
+
+       drm_mem_init();
+       drm_proc_init(dev);
+
+#ifdef DRM_AGP
+       dev->agp    = drm_agp_init();
+
+#ifdef CONFIG_MTRR
+       dev->agp->agp_mtrr = mtrr_add(dev->agp->agp_info.aper_base,
+                                     dev->agp->agp_info.aper_size*1024*1024,
+                                     MTRR_TYPE_WRCOMB,
+                                     1);
+#endif
+#endif
+
+       if((retcode = drm_ctxbitmap_init(dev))) {
+               DRM_ERROR("Cannot allocate memory for context bitmap.\n");
+               drm_proc_cleanup();
+               misc_deregister(&r128_misc);
+               r128_takedown(dev);
+               return retcode;
+       }
+
+       DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
+                R128_NAME,
+                R128_MAJOR,
+                R128_MINOR,
+                R128_PATCHLEVEL,
+                R128_DATE,
+                r128_misc.minor);
+
+       return 0;
+}
+
+/* r128_cleanup is called via cleanup_module at module unload time. */
+
+void r128_cleanup(void)
+{
+       drm_device_t          *dev = &r128_device;
+
+       DRM_DEBUG("\n");
+       
+       drm_proc_cleanup();
+       if (misc_deregister(&r128_misc)) {
+               DRM_ERROR("Cannot unload module\n");
+       } else {
+               DRM_INFO("Module unloaded\n");
+       }
+       drm_ctxbitmap_cleanup(dev);
+       r128_takedown(dev);
+#ifdef DRM_AGP
+       if (dev->agp) {
+                               /* FIXME -- free other information, too */
+               drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS);
+               dev->agp = NULL;
+       }
+#endif
+}
+
+int r128_version(struct inode *inode, struct file *filp, unsigned int cmd,
+                 unsigned long arg)
+{
+       drm_version_t version;
+       int           len;
+
+       copy_from_user_ret(&version,
+                          (drm_version_t *)arg,
+                          sizeof(version),
+                          -EFAULT);
+
+#define DRM_COPY(name,value)                                \
+       len = strlen(value);                                 \
+       if (len > name##_len) len = name##_len;              \
+       name##_len = strlen(value);                          \
+       if (len && name) {                                   \
+               copy_to_user_ret(name, value, len, -EFAULT); \
+       }
+
+       version.version_major      = R128_MAJOR;
+       version.version_minor      = R128_MINOR;
+       version.version_patchlevel = R128_PATCHLEVEL;
+
+       DRM_COPY(version.name, R128_NAME);
+       DRM_COPY(version.date, R128_DATE);
+       DRM_COPY(version.desc, R128_DESC);
+
+       copy_to_user_ret((drm_version_t *)arg,
+                        &version,
+                        sizeof(version),
+                        -EFAULT);
+       return 0;
+}
+
+int r128_open(struct inode *inode, struct file *filp)
+{
+       drm_device_t  *dev    = &r128_device;
+       int           retcode = 0;
+       
+       DRM_DEBUG("open_count = %d\n", dev->open_count);
+       if (!(retcode = drm_open_helper(inode, filp, dev))) {
+               MOD_INC_USE_COUNT;
+               atomic_inc(&dev->total_open);
+               spin_lock(&dev->count_lock);
+               if (!dev->open_count++) {
+                       spin_unlock(&dev->count_lock);
+                       return r128_setup(dev);
+               }
+               spin_unlock(&dev->count_lock);
+       }
+       return retcode;
+}
+
+int r128_release(struct inode *inode, struct file *filp)
+{
+       drm_file_t    *priv   = filp->private_data;
+       drm_device_t  *dev    = priv->dev;
+       int           retcode = 0;
+
+       DRM_DEBUG("open_count = %d\n", dev->open_count);
+       if (!(retcode = drm_release(inode, filp))) {
+               MOD_DEC_USE_COUNT;
+               atomic_inc(&dev->total_close);
+               spin_lock(&dev->count_lock);
+               if (!--dev->open_count) {
+                       if (atomic_read(&dev->ioctl_count) || dev->blocked) {
+                               DRM_ERROR("Device busy: %d %d\n",
+                                         atomic_read(&dev->ioctl_count),
+                                         dev->blocked);
+                               spin_unlock(&dev->count_lock);
+                               return -EBUSY;
+                       }
+                       spin_unlock(&dev->count_lock);
+                       return r128_takedown(dev);
+               }
+               spin_unlock(&dev->count_lock);
+       }
+       return retcode;
+}
+
+/* r128_ioctl is called whenever a process performs an ioctl on /dev/drm. */
+
+int r128_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+               unsigned long arg)
+{
+       int              nr      = DRM_IOCTL_NR(cmd);
+       drm_file_t       *priv   = filp->private_data;
+       drm_device_t     *dev    = priv->dev;
+       int              retcode = 0;
+       drm_ioctl_desc_t *ioctl;
+       drm_ioctl_t      *func;
+
+       atomic_inc(&dev->ioctl_count);
+       atomic_inc(&dev->total_ioctl);
+       ++priv->ioctl_count;
+       
+       DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n",
+                 current->pid, cmd, nr, dev->device, priv->authenticated);
+
+       if (nr >= R128_IOCTL_COUNT) {
+               retcode = -EINVAL;
+       } else {
+               ioctl     = &r128_ioctls[nr];
+               func      = ioctl->func;
+
+               if (!func) {
+                       DRM_DEBUG("no function\n");
+                       retcode = -EINVAL;
+               } else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN))
+                           || (ioctl->auth_needed && !priv->authenticated)) {
+                       retcode = -EACCES;
+               } else {
+                       retcode = (func)(inode, filp, cmd, arg);
+               }
+       }
+       
+       atomic_dec(&dev->ioctl_count);
+       return retcode;
+}
+
+int r128_lock(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;
+        DECLARE_WAITQUEUE(entry, current);
+        int               ret   = 0;
+        drm_lock_t        lock;
+#if DRM_DMA_HISTOGRAM
+        cycles_t          start;
+
+        dev->lck_start = start = get_cycles();
+#endif
+
+        copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+
+        if (lock.context == DRM_KERNEL_CONTEXT) {
+                DRM_ERROR("Process %d using kernel context %d\n",
+                          current->pid, lock.context);
+                return -EINVAL;
+        }
+
+        DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
+                  lock.context, current->pid, dev->lock.hw_lock->lock,
+                  lock.flags);
+
+#if 0
+                               /* dev->queue_count == 0 right now for
+                                   r128.  FIXME? */
+        if (lock.context < 0 || lock.context >= dev->queue_count)
+                return -EINVAL;
+#endif
+        
+        if (!ret) {
+#if 0
+                if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)
+                    != lock.context) {
+                        long j = jiffies - dev->lock.lock_time;
+
+                        if (lock.context == r128_res_ctx.handle &&
+                               j >= 0 && j < DRM_LOCK_SLICE) {
+                                /* Can't take lock if we just had it and
+                                   there is contention. */
+                                DRM_DEBUG("%d (pid %d) delayed j=%d dev=%d jiffies=%d\n",
+                                       lock.context, current->pid, j, 
+                                       dev->lock.lock_time, jiffies);
+                                current->state = TASK_INTERRUPTIBLE;
+                               current->policy |= SCHED_YIELD;
+                                schedule_timeout(DRM_LOCK_SLICE-j);
+                               DRM_DEBUG("jiffies=%d\n", jiffies);
+                        }
+                }
+#endif
+                add_wait_queue(&dev->lock.lock_queue, &entry);
+                for (;;) {
+                        if (!dev->lock.hw_lock) {
+                                /* Device has been unregistered */
+                                ret = -EINTR;
+                                break;
+                        }
+                        if (drm_lock_take(&dev->lock.hw_lock->lock,
+                                          lock.context)) {
+                                dev->lock.pid       = current->pid;
+                                dev->lock.lock_time = jiffies;
+                                atomic_inc(&dev->total_locks);
+                                break;  /* Got lock */
+                        }
+                        
+                                /* Contention */
+                        atomic_inc(&dev->total_sleeps);
+                        current->state = TASK_INTERRUPTIBLE;
+#if 1
+                       current->policy |= SCHED_YIELD;
+#endif
+                        schedule();
+                        if (signal_pending(current)) {
+                                ret = -ERESTARTSYS;
+                                break;
+                        }
+                }
+                current->state = TASK_RUNNING;
+                remove_wait_queue(&dev->lock.lock_queue, &entry);
+        }
+
+#if 0
+       if (!ret && dev->last_context != lock.context &&
+               lock.context != r128_res_ctx.handle &&
+               dev->last_context != r128_res_ctx.handle) {
+               add_wait_queue(&dev->context_wait, &entry);
+               current->state = TASK_INTERRUPTIBLE;
+                /* PRE: dev->last_context != lock.context */
+               r128_context_switch(dev, dev->last_context, lock.context);
+               /* POST: we will wait for the context
+                   switch and will dispatch on a later call
+                   when dev->last_context == lock.context
+                   NOTE WE HOLD THE LOCK THROUGHOUT THIS
+                   TIME! */
+               current->policy |= SCHED_YIELD;
+               schedule();
+               current->state = TASK_RUNNING;
+               remove_wait_queue(&dev->context_wait, &entry);
+               if (signal_pending(current)) {
+                       ret = -EINTR;
+               } else if (dev->last_context != lock.context) {
+                       DRM_ERROR("Context mismatch: %d %d\n",
+                               dev->last_context, lock.context);
+               }
+       }
+#endif
+
+        if (!ret) {
+                if (lock.flags & _DRM_LOCK_READY) {
+                               /* Wait for space in DMA/FIFO */
+               }
+                if (lock.flags & _DRM_LOCK_QUIESCENT) {
+                               /* Make hardware quiescent */
+#if 0
+                        r128_quiescent(dev);
+#endif
+               }
+        }
+
+#if 0
+       DRM_ERROR("pid = %5d, old counter = %5ld\n", 
+               current->pid, current->counter);
+#endif
+       if (lock.context != r128_res_ctx.handle) {
+               current->counter = 5;
+               current->priority = DEF_PRIORITY/4;
+       }
+#if 0
+       while (current->counter > 25)
+               current->counter >>= 1; /* decrease time slice */
+       DRM_ERROR("pid = %5d, new counter = %5ld\n",
+                current->pid, current->counter);
+#endif
+        DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
+
+#if DRM_DMA_HISTOGRAM
+        atomic_inc(&dev->histo.lacq[drm_histogram_slot(get_cycles() - start)]);
+#endif
+        
+        return ret;
+}
+
+
+int r128_unlock(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_lock_t        lock;
+
+       copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+       
+       if (lock.context == DRM_KERNEL_CONTEXT) {
+               DRM_ERROR("Process %d using kernel context %d\n",
+                         current->pid, lock.context);
+               return -EINVAL;
+       }
+
+       DRM_DEBUG("%d frees lock (%d holds)\n",
+                 lock.context,
+                 _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+       atomic_inc(&dev->total_unlocks);
+       if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock))
+               atomic_inc(&dev->total_contends);
+       drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT);
+                               /* FIXME: Try to send data to card here */
+       if (!dev->context_flag) {
+               if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
+                                 DRM_KERNEL_CONTEXT)) {
+                       DRM_ERROR("\n");
+               }
+       }
+
+#if 0
+       current->policy |= SCHED_YIELD;
+       current->state = TASK_INTERRUPTIBLE;
+       schedule_timeout(1000);
+#endif
+
+       if (lock.context != r128_res_ctx.handle) {
+               current->counter = 5;
+               current->priority = DEF_PRIORITY;
+       }
+#if 0
+       current->state = TASK_INTERRUPTIBLE;
+       schedule_timeout(10);
+#endif
+       
+       return 0;
+}
index 2ea6c72..a169473 100644 (file)
@@ -49,3 +49,5 @@ i810.o: i810_drv.o i810_context.o $(L_TARGET)
 mga.o: mga_drv.o mga_context.o mga_dma.o mga_bufs.o $(L_TARGET)
        $(LD) $(LD_RFLAG) -r -o $@ mga_drv.o mga_bufs.o mga_dma.o mga_context.o mga_state.o -L. -ldrm
 
+r128.o: r128_drv.o r128_context.o $(L_TARGET)
+       $(LD) $(LD_RFLAG) -r -o $@ r128_drv.o r128_context.o -L. -ldrm
index 1db7a81..368c3c8 100644 (file)
@@ -1,8 +1,7 @@
 # Makefile -- For the Direct Rendering Manager module (drm)
 # Created: Mon Jan  4 09:26:53 1999 by faith@precisioninsight.com
-# Revised: Sun Feb 13 23:15:59 2000 by kevin@precisioninsight.com
 #
-# Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+# Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
 # All rights reserved.
 #
 # Permission is hereby granted, free of charge, to any person obtaining a
@@ -33,7 +32,7 @@
 
 # **** End of SMP/MODVERSIONS detection
 
-MODS=           gamma.o tdfx.o
+MODS=           gamma.o tdfx.o r128.o
 LIBS=           libdrm.a
 PROGS=         drmstat
 
@@ -47,6 +46,9 @@ GAMMAHEADERS=   gamma_drv.h $(DRMHEADERS)
 TDFXOBJS=       tdfx_drv.o tdfx_context.o
 TDFXHEADERS=    tdfx_drv.h $(DRMHEADERS)
 
+R128OBJS=      r128_drv.o r128_dma.o r128_bufs.o r128_context.o
+R128HEADERS=   r128_drv.h r128_drm.h $(DRMHEADERS)
+
 PROGOBJS=       drmstat.po xf86drm.po xf86drmHash.po xf86drmRandom.po sigio.po
 PROGHEADERS=    xf86drm.h $(DRMHEADERS)
 
@@ -153,6 +155,9 @@ gamma.o: $(GAMMAOBJS) $(LIBS)
 tdfx.o: $(TDFXOBJS) $(LIBS)
        $(LD) -r $^ -o $@
 
+r128.o: $(R128OBJS) $(LIBS)
+       $(LD) -r $^ -o $@
+
 ifeq ($(AGP),1)
 mga.o: $(MGAOBJS) $(LIBS)
        $(LD) -r $^ -o $@
@@ -182,6 +187,7 @@ ChangeLog:
 $(DRMOBJS): $(DRMHEADERS)
 $(GAMMAOBJS): $(GAMMAHEADERS)
 $(TDFXOBJS): $(TDFXHEADERS)
+$(R128OBJS): $(R128HEADERS)
 ifeq ($(AGP),1)
 $(MGAOBJS): $(MGAHEADERS)
 $(I810OBJS): $(I810HEADERS)
index c2da9ec..14fb8b5 100644 (file)
@@ -239,6 +239,8 @@ int drm_agp_bind(struct inode *inode, struct file *filp, unsigned int cmd,
        page = (request.offset + PAGE_SIZE - 1) / PAGE_SIZE;
        if ((retcode = drm_bind_agp(entry->memory, page))) return retcode;
        entry->bound = dev->agp->base + (page << PAGE_SHIFT);
+       DRM_DEBUG("base = 0x%lx entry->bound = 0x%lx\n", 
+                 dev->agp->base, entry->bound);
        return 0;
 }
 
index ae4c65c..25e4cce 100644 (file)
@@ -1,8 +1,7 @@
 /* drm.h -- Header for Direct Rendering Manager -*- linux-c -*-
  * Created: Mon Jan  4 10:05:05 1999 by faith@precisioninsight.com
- * Revised: Mon Feb 14 00:15:23 2000 by kevin@precisioninsight.com
  *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
  * All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -71,9 +70,10 @@ typedef struct drm_clip_rect {
            unsigned short y2;
 } drm_clip_rect_t;
 
-/* Seperate include files for the i810/mga specific structures */
+/* Seperate include files for the i810/mga/r128 specific structures */
 #include "mga_drm.h"
 #include "i810_drm.h"
+#include "r128_drm.h"
 
 typedef struct drm_version {
        int    version_major;     /* Major version                          */
@@ -349,4 +349,12 @@ typedef struct drm_agp_info {
 #define DRM_IOCTL_I810_FLUSH   DRM_IO ( 0x43)
 #define DRM_IOCTL_I810_GETAGE  DRM_IO ( 0x44)
 
+/* Rage 128 specific ioctls */
+#define DRM_IOCTL_R128_INIT    DRM_IOW( 0x40, drm_r128_init_t)
+#define DRM_IOCTL_R128_RESET   DRM_IO(  0x41)
+#define DRM_IOCTL_R128_FLUSH   DRM_IO(  0x42)
+#define DRM_IOCTL_R128_CCEIDL  DRM_IO(  0x43)
+#define DRM_IOCTL_R128_PACKET  DRM_IOW( 0x44, drm_r128_packet_t)
+#define DRM_IOCTL_R128_VERTEX  DRM_IOW( 0x45, drm_r128_vertex_t)
+
 #endif
index f8e78ea..43670e2 100644 (file)
@@ -1,8 +1,7 @@
 /* drmP.h -- Private header for Direct Rendering Manager -*- linux-c -*-
  * Created: Mon Jan  4 10:05:05 1999 by faith@precisioninsight.com
- * Revised: Sun Feb 13 23:34:30 2000 by kevin@precisioninsight.com
  *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
  * All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -228,8 +227,8 @@ typedef struct drm_magic_entry {
 } drm_magic_entry_t;
 
 typedef struct drm_magic_head {
-       struct drm_magic_entry *head;
-       struct drm_magic_entry *tail;
+       struct drm_magic_entry *head;
+       struct drm_magic_entry *tail;
 } drm_magic_head_t;
 
 typedef struct drm_vma_entry {
@@ -262,16 +261,15 @@ typedef struct drm_buf {
                DRM_LIST_RECLAIM = 5
        }                 list;        /* Which list we're on                */
 
-
-       void *dev_private;
-       int dev_priv_size;
-
 #if DRM_DMA_HISTOGRAM
        cycles_t          time_queued;     /* Queued to kernel DMA queue     */
        cycles_t          time_dispatched; /* Dispatched to hardware         */
        cycles_t          time_completed;  /* Completed by hardware          */
        cycles_t          time_freed;      /* Back on freelist               */
 #endif
+
+       int               dev_priv_size; /* Size of buffer private stoarge   */
+       void              *dev_private;  /* Per-buffer private storage       */
 } drm_buf_t;
 
 #if DRM_DMA_HISTOGRAM
index db98fd6..392abce 100644 (file)
@@ -1,8 +1,7 @@
 /* proc.c -- /proc support for DRM -*- linux-c -*-
  * Created: Mon Jan 11 09:48:47 1999 by faith@precisioninsight.com
- * Revised: Sun Feb 13 23:41:04 2000 by kevin@precisioninsight.com
  *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -400,6 +399,7 @@ static int _drm_vma_info(char *buf, char **start, off_t offset, int len,
                               pgprot & _PAGE_GLOBAL   ? 'g' : 'l' );
 #endif         
                DRM_PROC_PRINT("\n");
+#if 0
                for (i = vma->vm_start; i < vma->vm_end; i += PAGE_SIZE) {
                        pgd = pgd_offset(vma->vm_mm, i);
                        pmd = pmd_offset(pgd, i);
@@ -420,6 +420,7 @@ static int _drm_vma_info(char *buf, char **start, off_t offset, int len,
                                DRM_PROC_PRINT("      0x%08lx\n", i);
                        }
                }
+#endif
        }
        
        return len;
diff --git a/linux/r128_bufs.c b/linux/r128_bufs.c
new file mode 100644 (file)
index 0000000..bad6c57
--- /dev/null
@@ -0,0 +1,309 @@
+/* r128_bufs.c -- IOCTLs to manage buffers -*- linux-c -*-
+ * Created: Wed Apr 12 16:19:08 2000 by kevin@precisioninsight.com
+ *
+ * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * 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: Kevin E. Martin <kevin@precisioninsight.com>
+ *          Rickard E. (Rik) Faith <faith@precisioninsight.com>
+ *         Jeff Hartmann <jhartmann@precisioninsight.com>
+ * 
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include "r128_drv.h"
+#include "linux/un.h"
+
+
+#ifdef DRM_AGP
+int r128_addbufs_agp(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;
+       drm_buf_desc_t    request;
+       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;
+
+       if (!dma) return -EINVAL;
+
+       copy_from_user_ret(&request,
+                          (drm_buf_desc_t *)arg,
+                          sizeof(request),
+                          -EFAULT);
+
+       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 = dev->agp->base + 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: %ld\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 */
+       }
+   
+       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;
+
+       for (offset = 0;
+            entry->buf_count < count;
+            offset += alignment, ++entry->buf_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->address = (void *)(agp_offset + offset);
+               buf->next    = NULL;
+               buf->waiting = 0;
+               buf->pending = 0;
+               init_waitqueue_head(&buf->dma_wait);
+               buf->pid     = 0;
+
+               buf->dev_priv_size = sizeof(drm_r128_buf_priv_t);
+               buf->dev_private   = drm_alloc(sizeof(drm_r128_buf_priv_t),
+                                              DRM_MEM_BUFS);
+               memset(buf->dev_private, 0, buf->dev_priv_size);
+
+#if DRM_DMA_HISTOGRAM
+               buf->time_queued     = 0;
+               buf->time_dispatched = 0;
+               buf->time_completed  = 0;
+               buf->time_freed      = 0;
+#endif
+
+               byte_count += PAGE_SIZE << page_order;
+
+               DRM_DEBUG("buffer %d @ %p\n",
+                         entry->buf_count, buf->address);
+       }
+
+       DRM_DEBUG("byte_count: %d\n", byte_count);
+
+       dma->buflist = drm_realloc(dma->buflist,
+                                  dma->buf_count * sizeof(*dma->buflist),
+                                  (dma->buf_count + entry->buf_count)
+                                  * sizeof(*dma->buflist),
+                                  DRM_MEM_BUFS);
+       for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++)
+               dma->buflist[i] = &entry->buflist[i - dma->buf_count];
+
+       dma->buf_count  += entry->buf_count;
+       dma->byte_count += byte_count;
+
+       drm_freelist_create(&entry->freelist, entry->buf_count);
+       for (i = 0; i < entry->buf_count; i++) {
+               drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]);
+       }
+
+       up(&dev->struct_sem);
+
+       request.count = entry->buf_count;
+       request.size  = size;
+
+       copy_to_user_ret((drm_buf_desc_t *)arg,
+                        &request,
+                        sizeof(request),
+                        -EFAULT);
+
+       dma->flags = _DRM_DMA_USE_AGP;
+
+       atomic_dec(&dev->buf_alloc);
+       return 0;
+}
+#endif
+
+int r128_addbufs(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_r128_private_t      *dev_priv       = dev->dev_private;
+       drm_buf_desc_t          request;
+
+       if (!dev_priv || dev_priv->is_pci) return -EINVAL;
+
+       copy_from_user_ret(&request,
+                          (drm_buf_desc_t *)arg,
+                          sizeof(request),
+                          -EFAULT);
+
+#ifdef DRM_AGP
+       if (request.flags & _DRM_AGP_BUFFER)
+               return r128_addbufs_agp(inode, filp, cmd, arg);
+       else
+#endif
+               return -EINVAL;
+}
+
+int r128_mapbufs(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_r128_private_t      *dev_priv       = dev->dev_private;
+       drm_device_dma_t        *dma            = dev->dma;
+       int                      retcode        = 0;
+       const int                zero           = 0;
+       unsigned long            virtual;
+       unsigned long            address;
+       drm_buf_map_t            request;
+       int                      i;
+
+       if (!dma || !dev_priv || dev_priv->is_pci) return -EINVAL;
+
+       DRM_DEBUG("\n");
+
+       spin_lock(&dev->count_lock);
+       if (atomic_read(&dev->buf_alloc)) {
+               spin_unlock(&dev->count_lock);
+               return -EBUSY;
+       }
+       ++dev->buf_use;         /* Can't allocate more after this call */
+       spin_unlock(&dev->count_lock);
+
+       copy_from_user_ret(&request,
+                          (drm_buf_map_t *)arg,
+                          sizeof(request),
+                          -EFAULT);
+
+       if (request.count >= dma->buf_count) {
+               if (dma->flags & _DRM_DMA_USE_AGP) {
+                       drm_map_t *map;
+
+                       map = dev_priv->agp_vertbufs;
+                       if (!map) {
+                               retcode = -EINVAL;
+                               goto done;
+                       }
+
+                       down(&current->mm->mmap_sem);
+                       virtual = do_mmap(filp, 0, map->size, 
+                                         PROT_READ|PROT_WRITE,
+                                         MAP_SHARED, 
+                                         (unsigned long)map->offset);
+                       up(&current->mm->mmap_sem);
+               } else {
+                       down(&current->mm->mmap_sem);
+                       virtual = do_mmap(filp, 0, dma->byte_count,
+                                         PROT_READ|PROT_WRITE, MAP_SHARED, 0);
+                       up(&current->mm->mmap_sem);
+               }
+               if (virtual > -1024UL) {
+                       /* Real error */
+                       retcode = (signed long)virtual;
+                       goto done;
+               }
+               request.virtual = (void *)virtual;
+
+               for (i = 0; i < dma->buf_count; i++) {
+                       if (copy_to_user(&request.list[i].idx,
+                                        &dma->buflist[i]->idx,
+                                        sizeof(request.list[0].idx))) {
+                               retcode = -EFAULT;
+                               goto done;
+                       }
+                       if (copy_to_user(&request.list[i].total,
+                                        &dma->buflist[i]->total,
+                                        sizeof(request.list[0].total))) {
+                               retcode = -EFAULT;
+                               goto done;
+                       }
+                       if (copy_to_user(&request.list[i].used,
+                                        &zero,
+                                        sizeof(zero))) {
+                               retcode = -EFAULT;
+                               goto done;
+                       }
+                       address = virtual + dma->buflist[i]->offset;
+                       if (copy_to_user(&request.list[i].address,
+                                        &address,
+                                        sizeof(address))) {
+                               retcode = -EFAULT;
+                               goto done;
+                       }
+               }
+       }
+ done:
+       request.count = dma->buf_count;
+       DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode);
+
+       copy_to_user_ret((drm_buf_map_t *)arg,
+                        &request,
+                        sizeof(request),
+                        -EFAULT);
+
+       return retcode;
+}
diff --git a/linux/r128_context.c b/linux/r128_context.c
new file mode 100644 (file)
index 0000000..d288fd2
--- /dev/null
@@ -0,0 +1,214 @@
+/* r128_context.c -- IOCTLs for r128 contexts -*- linux-c -*-
+ * Created: Mon Dec 13 09:51:35 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * 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.
+ * 
+ * Author: Rickard E. (Rik) Faith <faith@precisioninsight.com>
+ *
+ * $XFree86$
+ *
+ */
+
+#include <linux/sched.h>
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include "r128_drv.h"
+
+extern drm_ctx_t r128_res_ctx;
+
+static int r128_alloc_queue(drm_device_t *dev)
+{
+#if 0
+       static int context = 0;
+#endif
+
+       return drm_ctxbitmap_next(dev);
+}
+
+int r128_context_switch(drm_device_t *dev, int old, int new)
+{
+        char        buf[64];
+
+        atomic_inc(&dev->total_ctx);
+
+        if (test_and_set_bit(0, &dev->context_flag)) {
+                DRM_ERROR("Reentering -- FIXME\n");
+                return -EBUSY;
+        }
+
+#if DRM_DMA_HISTOGRAM
+        dev->ctx_start = get_cycles();
+#endif
+        
+        DRM_DEBUG("Context switch from %d to %d\n", old, new);
+
+        if (new == dev->last_context) {
+                clear_bit(0, &dev->context_flag);
+                return 0;
+        }
+        
+        if (drm_flags & DRM_FLAG_NOCTX) {
+                r128_context_switch_complete(dev, new);
+        } else {
+                sprintf(buf, "C %d %d\n", old, new);
+                drm_write_string(dev, buf);
+        }
+        
+        return 0;
+}
+
+int r128_context_switch_complete(drm_device_t *dev, int new)
+{
+        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 a context switch is ever initiated
+                                   when the kernel holds the lock, release
+                                   that lock here. */
+#if DRM_DMA_HISTOGRAM
+        atomic_inc(&dev->histo.ctx[drm_histogram_slot(get_cycles()
+                                                      - dev->ctx_start)]);
+                   
+#endif
+        clear_bit(0, &dev->context_flag);
+        wake_up(&dev->context_wait);
+        
+        return 0;
+}
+
+
+int r128_resctx(struct inode *inode, struct file *filp, unsigned int cmd,
+              unsigned long arg)
+{
+       drm_ctx_res_t   res;
+       drm_ctx_t       ctx;
+       int             i;
+
+       DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS);
+       copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT);
+       if (res.count >= DRM_RESERVED_CONTEXTS) {
+               memset(&ctx, 0, sizeof(ctx));
+               for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
+                       ctx.handle = i;
+                       copy_to_user_ret(&res.contexts[i],
+                                        &i,
+                                        sizeof(i),
+                                        -EFAULT);
+               }
+       }
+       res.count = DRM_RESERVED_CONTEXTS;
+       copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT);
+       return 0;
+}
+
+
+int r128_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;
+
+       copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+       if ((ctx.handle = r128_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) {
+                               /* Skip kernel's context and get a new one. */
+               ctx.handle = r128_alloc_queue(dev);
+       }
+       DRM_DEBUG("%d\n", ctx.handle);
+       if (ctx.handle == -1) {
+               DRM_DEBUG("Not enough free contexts.\n");
+                               /* Should this return -EBUSY instead? */
+               return -ENOMEM;
+       }
+
+       copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT);
+       return 0;
+}
+
+int r128_modctx(struct inode *inode, struct file *filp, unsigned int cmd,
+       unsigned long arg)
+{
+       drm_ctx_t ctx;
+
+       copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT);
+       if (ctx.flags==_DRM_CONTEXT_PRESERVED)
+               r128_res_ctx.handle=ctx.handle;
+       return 0;
+}
+
+int r128_getctx(struct inode *inode, struct file *filp, unsigned int cmd,
+       unsigned long arg)
+{
+       drm_ctx_t ctx;
+
+       copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT);
+       /* This is 0, because we don't hanlde any context flags */
+       ctx.flags = 0;
+       copy_to_user_ret((drm_ctx_t*)arg, &ctx, sizeof(ctx), -EFAULT);
+       return 0;
+}
+
+int r128_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;
+
+       copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+       DRM_DEBUG("%d\n", ctx.handle);
+       return r128_context_switch(dev, dev->last_context, ctx.handle);
+}
+
+int r128_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;
+
+       copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+       DRM_DEBUG("%d\n", ctx.handle);
+       r128_context_switch_complete(dev, ctx.handle);
+
+       return 0;
+}
+
+int r128_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;
+
+       copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+       DRM_DEBUG("%d\n", ctx.handle);
+       drm_ctxbitmap_free(dev, ctx.handle);
+
+       return 0;
+}
diff --git a/linux/r128_dma.c b/linux/r128_dma.c
new file mode 100644 (file)
index 0000000..860c418
--- /dev/null
@@ -0,0 +1,908 @@
+/* r128_drv.c -- ATI Rage 128 driver -*- linux-c -*-
+ * Created: Wed Apr  5 19:24:19 2000 by kevin@precisioninsight.com
+ *
+ * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * 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: Kevin E. Martin <kevin@precisioninsight.com>
+ * 
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include "r128_drv.h"
+
+#include <linux/interrupt.h>   /* For task queue support */
+#include <linux/delay.h>
+
+
+
+#define DO_REMAP(_m) (_m)->handle = drm_ioremap((_m)->offset, (_m)->size)
+
+#define DO_REMAPFREE(_m)                                                    \
+       do {                                                                \
+               if ((_m)->handle && (_m)->size)                             \
+                       drm_ioremapfree((_m)->handle, (_m)->size);          \
+       } while (0)
+
+#define DO_FIND_MAP(_m, _o)                                                 \
+       do {                                                                \
+               int _i;                                                     \
+               for (_i = 0; _i < dev->map_count; _i++) {                   \
+                       if (dev->maplist[_i]->offset == _o) {               \
+                               _m = dev->maplist[_i];                      \
+                               break;                                      \
+                       }                                                   \
+               }                                                           \
+       } while (0)
+
+
+#define R128_MAX_VBUF_AGE      0x10000000
+#define R128_VB_AGE_REG                R128_GUI_SCRATCH_REG0
+
+int R128_READ_PLL(drm_device_t *dev, int addr)
+{
+       drm_r128_private_t *dev_priv = dev->dev_private;
+
+       R128_WRITE8(R128_CLOCK_CNTL_INDEX, addr & 0x1f);
+       return R128_READ(R128_CLOCK_CNTL_DATA);
+}
+
+static void r128_flush_write_combine(void)
+{
+       int xchangeDummy;
+
+       __asm__ volatile("push %%eax ;"
+                        "xchg %%eax, %0 ;"
+                        "pop %%eax" : : "m" (xchangeDummy));
+       __asm__ volatile("push %%eax ;"
+                        "push %%ebx ;"
+                        "push %%ecx ;"
+                        "push %%edx ;"
+                        "movl $0,%%eax ;"
+                        "cpuid ;"
+                        "pop %%edx ;"
+                        "pop %%ecx ;"
+                        "pop %%ebx ;"
+                        "pop %%eax" : /* no outputs */ :  /* no inputs */ );
+}
+
+static int r128_do_cleanup_cce(drm_device_t *dev)
+{
+       if (dev->dev_private) {
+               drm_r128_private_t *dev_priv = dev->dev_private;
+
+               if (!dev_priv->is_pci) {
+                       DO_REMAPFREE(dev_priv->agp_ring);
+                       DO_REMAPFREE(dev_priv->agp_read_ptr);
+                       DO_REMAPFREE(dev_priv->agp_vertbufs);
+                       DO_REMAPFREE(dev_priv->agp_indbufs);
+                       DO_REMAPFREE(dev_priv->agp_textures);
+               }
+
+               drm_free(dev->dev_private, sizeof(drm_r128_private_t),
+                        DRM_MEM_DRIVER);
+               dev->dev_private = NULL;
+       }
+
+       return 0;
+}
+
+static int r128_do_init_cce(drm_device_t *dev, drm_r128_init_t *init)
+{
+       drm_r128_private_t *dev_priv;
+        int                 i;
+
+       dev_priv = drm_alloc(sizeof(drm_r128_private_t), DRM_MEM_DRIVER);
+       if (dev_priv == NULL) return -ENOMEM;
+       dev->dev_private = (void *)dev_priv;
+
+       memset(dev_priv, 0, sizeof(drm_r128_private_t));
+
+       dev_priv->is_pci         = init->is_pci;
+
+       dev_priv->usec_timeout   = init->usec_timeout;
+       if (dev_priv->usec_timeout < 1 ||
+           dev_priv->usec_timeout > R128_MAX_USEC_TIMEOUT) {
+               drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER);
+               dev->dev_private = NULL;
+               return -EINVAL;
+       }
+
+       dev_priv->cce_mode       = init->cce_mode;
+       dev_priv->cce_fifo_size  = init->cce_fifo_size;
+       dev_priv->cce_is_bm_mode =
+               ((init->cce_mode == R128_PM4_192BM) ||
+                (init->cce_mode == R128_PM4_128BM_64INDBM) ||
+                (init->cce_mode == R128_PM4_64BM_128INDBM) ||
+                (init->cce_mode == R128_PM4_64BM_64VCBM_64INDBM));
+       dev_priv->cce_secure     = init->cce_secure;
+
+       if (dev_priv->cce_is_bm_mode && dev_priv->is_pci) {
+               drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER);
+               dev->dev_private = NULL;
+               return -EINVAL;
+       }
+
+       for (i = 0; i < dev->map_count; i++) {
+               if (dev->maplist[i]->type == _DRM_SHM) {
+                       dev_priv->sarea = dev->maplist[i];
+                       break;
+               }
+       }
+
+       DO_FIND_MAP(dev_priv->fb,           init->fb_offset);
+       if (!dev_priv->is_pci) {
+               DO_FIND_MAP(dev_priv->agp_ring,     init->agp_ring_offset);
+               DO_FIND_MAP(dev_priv->agp_read_ptr, init->agp_read_ptr_offset);
+               DO_FIND_MAP(dev_priv->agp_vertbufs, init->agp_vertbufs_offset);
+               DO_FIND_MAP(dev_priv->agp_indbufs,  init->agp_indbufs_offset);
+               DO_FIND_MAP(dev_priv->agp_textures, init->agp_textures_offset);
+       }
+       DO_FIND_MAP(dev_priv->mmio,         init->mmio_offset);
+
+       dev_priv->sarea_priv =
+               (drm_r128_sarea_t *)((u8 *)dev_priv->sarea->handle +
+                                    init->sarea_priv_offset);
+
+       if (!dev_priv->is_pci) {
+               DO_REMAP(dev_priv->agp_ring);
+               DO_REMAP(dev_priv->agp_read_ptr);
+               DO_REMAP(dev_priv->agp_vertbufs);
+#if 0
+               DO_REMAP(dev_priv->agp_indirectbufs);
+               DO_REMAP(dev_priv->agp_textures);
+#endif
+
+               dev_priv->ring_size     = init->ring_size;
+               dev_priv->ring_sizel2qw = drm_order(init->ring_size/8);
+               dev_priv->ring_entries  = init->ring_size/sizeof(u32);
+               dev_priv->ring_read_ptr = ((__volatile__ u32 *)
+                                          dev_priv->agp_read_ptr->handle);
+               dev_priv->ring_start    = (u32 *)dev_priv->agp_ring->handle;
+               dev_priv->ring_end      = ((u32 *)dev_priv->agp_ring->handle
+                                          + dev_priv->ring_entries);
+       }
+
+       dev_priv->submit_age    = 0;
+       R128_WRITE(R128_VB_AGE_REG, dev_priv->submit_age);
+
+       return 0;
+}
+
+int r128_init_cce(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_r128_init_t    init;
+
+       copy_from_user_ret(&init, (drm_r128_init_t *)arg, sizeof(init),
+                          -EFAULT);
+
+       switch (init.func) {
+       case R128_INIT_CCE:
+               return r128_do_init_cce(dev, &init);
+       case R128_CLEANUP_CCE:
+               return r128_do_cleanup_cce(dev);
+       }
+
+       return -EINVAL;
+}
+
+static void r128_mark_vertbufs_done(drm_device_t *dev)
+{
+       drm_device_dma_t   *dma      = dev->dma;
+       int                 i;
+
+       for (i = 0; i < dma->buf_count; i++) {
+               drm_buf_t           *buf      = dma->buflist[i];
+               drm_r128_buf_priv_t *buf_priv = buf->dev_private;
+               buf_priv->age = 0;
+       }
+}
+
+static int r128_do_pixcache_flush(drm_device_t *dev)
+{
+       drm_r128_private_t *dev_priv = dev->dev_private;
+       u32                 tmp;
+       int                 i;
+
+       tmp = R128_READ(R128_PC_NGUI_CTLSTAT) | R128_PC_FLUSH_ALL;
+       R128_WRITE(R128_PC_NGUI_CTLSTAT, tmp);
+
+       for (i = 0; i < dev_priv->usec_timeout; i++) {
+               if (!(R128_READ(R128_PC_NGUI_CTLSTAT) & R128_PC_BUSY))
+                       return 0;
+               udelay(1);
+       }
+
+       return -EBUSY;
+}
+
+static int r128_do_wait_for_fifo(drm_device_t *dev, int entries)
+{
+       drm_r128_private_t *dev_priv = dev->dev_private;
+       int                 i;
+
+       for (i = 0; i < dev_priv->usec_timeout; i++) {
+               int slots = R128_READ(R128_GUI_STAT) & R128_GUI_FIFOCNT_MASK;
+               if (slots >= entries) return 0;
+               udelay(1);
+       }
+       return -EBUSY;
+}
+
+static int r128_do_wait_for_idle(drm_device_t *dev)
+{
+       drm_r128_private_t *dev_priv = dev->dev_private;
+       int                 i, ret;
+
+       if (!(ret = r128_do_wait_for_fifo(dev, 64))) return ret;
+
+       for (i = 0; i < dev_priv->usec_timeout; i++) {
+               if (!(R128_READ(R128_GUI_STAT) & R128_GUI_ACTIVE)) {
+                       (void)r128_do_pixcache_flush(dev);
+                       return 0;
+               }
+               udelay(1);
+       }
+       return -EBUSY;
+}
+
+int r128_do_engine_reset(drm_device_t *dev)
+{
+       drm_r128_private_t *dev_priv = dev->dev_private;
+       u32                 clock_cntl_index, mclk_cntl, gen_reset_cntl;
+
+       (void)r128_do_pixcache_flush(dev);
+
+       clock_cntl_index = R128_READ(R128_CLOCK_CNTL_INDEX);
+       mclk_cntl        = R128_READ_PLL(dev, R128_MCLK_CNTL);
+
+       R128_WRITE_PLL(R128_MCLK_CNTL,
+                      mclk_cntl | R128_FORCE_GCP | R128_FORCE_PIPE3D_CPP);
+
+       gen_reset_cntl   = R128_READ(R128_GEN_RESET_CNTL);
+
+       R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl | R128_SOFT_RESET_GUI);
+       (void)R128_READ(R128_GEN_RESET_CNTL);
+       R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl & ~R128_SOFT_RESET_GUI);
+       (void)R128_READ(R128_GEN_RESET_CNTL);
+
+       R128_WRITE_PLL(R128_MCLK_CNTL,    mclk_cntl);
+       R128_WRITE(R128_CLOCK_CNTL_INDEX, clock_cntl_index);
+       R128_WRITE(R128_GEN_RESET_CNTL,   gen_reset_cntl);
+
+       /* For CCE ring buffer only */
+       if (dev_priv->cce_is_bm_mode) {
+               R128_WRITE(R128_PM4_BUFFER_DL_WPTR, 0);
+               R128_WRITE(R128_PM4_BUFFER_DL_RPTR, 0);
+               *dev_priv->ring_read_ptr = 0;
+               dev_priv->sarea_priv->ring_write = 0;
+       }
+
+       /* Reset the CCE mode */
+       (void)r128_do_wait_for_idle(dev);
+       R128_WRITE(R128_PM4_BUFFER_CNTL,
+                  dev_priv->cce_mode | dev_priv->ring_sizel2qw);
+       (void)R128_READ(R128_PM4_BUFFER_ADDR); /* as per the sample code */
+       R128_WRITE(R128_PM4_MICRO_CNTL, R128_PM4_MICRO_FREERUN);
+
+       r128_mark_vertbufs_done(dev);
+       return 0;
+}
+
+int r128_eng_reset(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;
+
+       if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) ||
+           dev->lock.pid != current->pid) {
+               DRM_ERROR("r128_eng_reset called without holding the lock\n");
+               return -EINVAL;
+       }
+
+       return r128_do_engine_reset(dev);
+}
+
+static int r128_do_engine_flush(drm_device_t *dev)
+{
+       drm_r128_private_t *dev_priv = dev->dev_private;
+       u32                 tmp;
+
+       tmp = R128_READ(R128_PM4_BUFFER_DL_WPTR);
+       R128_WRITE(R128_PM4_BUFFER_DL_WPTR, tmp | R128_PM4_BUFFER_DL_DONE);
+
+       return 0;
+}
+
+int r128_eng_flush(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;
+
+       if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) ||
+           dev->lock.pid != current->pid) {
+               DRM_ERROR("r128_eng_flush called without holding the lock\n");
+               return -EINVAL;
+       }
+
+       return r128_do_engine_flush(dev);
+}
+
+static int r128_do_cce_wait_for_fifo(drm_device_t *dev, int entries)
+{
+       drm_r128_private_t *dev_priv = dev->dev_private;
+       int                 i;
+
+       for (i = 0; i < dev_priv->usec_timeout; i++) {
+               int slots = R128_READ(R128_PM4_STAT) & R128_PM4_FIFOCNT_MASK;
+               if (slots >= entries) return 0;
+               udelay(1);
+       }
+       return -EBUSY;
+}
+
+int r128_do_cce_wait_for_idle(drm_device_t *dev)
+{
+       drm_r128_private_t *dev_priv = dev->dev_private;
+       int                 i;
+
+       if (dev_priv->cce_is_bm_mode) {
+               for (i = 0; i < dev_priv->usec_timeout; i++) {
+                       if (*dev_priv->ring_read_ptr == dev_priv->sarea_priv->ring_write) {
+                               int pm4stat = R128_READ(R128_PM4_STAT);
+                               if ((pm4stat & R128_PM4_FIFOCNT_MASK) >= dev_priv->cce_fifo_size &&
+                                   !(pm4stat & (R128_PM4_BUSY | R128_PM4_GUI_ACTIVE))) {
+                                       return r128_do_pixcache_flush(dev);
+                               }
+                       }
+                       udelay(1);
+               }
+               return -EBUSY;
+       } else {
+               int ret = r128_do_cce_wait_for_fifo(dev, dev_priv->cce_fifo_size);
+               if (ret < 0) return ret;
+
+               for (i = 0; i < dev_priv->usec_timeout; i++) {
+                       int pm4stat = R128_READ(R128_PM4_STAT);
+                       if (!(pm4stat & (R128_PM4_BUSY | R128_PM4_GUI_ACTIVE))) {
+                               return r128_do_pixcache_flush(dev);
+                       }
+                       udelay(1);
+               }
+               return -EBUSY;
+       }
+}
+
+int r128_cce_idle(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;
+
+       if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) ||
+           dev->lock.pid != current->pid) {
+               DRM_ERROR("r128_wait_idle called without holding the lock\n");
+               return -EINVAL;
+       }
+
+       return r128_do_cce_wait_for_idle(dev);
+}
+
+static int r128_submit_packets_ring_secure(drm_device_t *dev,
+                                          u32 *commands, int *count)
+{
+       drm_r128_private_t *dev_priv  = dev->dev_private;
+       int                 write     = dev_priv->sarea_priv->ring_write;
+       int                *write_ptr = dev_priv->ring_start + write;
+       int                 c         = *count;
+       u32                 tmp       = 0;
+       int                 psize     = 0;
+       int                 writing   = 1;
+       int                 timeout;
+
+       while (c > 0) {
+               tmp = *commands++;
+               if (!psize) {
+                       writing = 1;
+
+                       if ((tmp & R128_CCE_PACKET_MASK) == R128_CCE_PACKET0) {
+                               if ((tmp & R128_CCE_PACKET0_REG_MASK) <= (0x1004 >> 2)) {
+                                       if ((tmp & R128_CCE_PACKET0_REG_MASK) !=
+                                           (R128_PM4_VC_FPU_SETUP >> 2)) {
+                                               writing = 0;
+                                       }
+                               }
+                               psize = ((tmp & R128_CCE_PACKET_COUNT_MASK) >> 16) + 2;
+                       } else if ((tmp & R128_CCE_PACKET_MASK) == R128_CCE_PACKET1) {
+                               if ((tmp & R128_CCE_PACKET1_REG0_MASK) <= (0x1004 >> 2)) {
+                                       if ((tmp & R128_CCE_PACKET1_REG0_MASK) !=
+                                           (R128_PM4_VC_FPU_SETUP >> 2)) {
+                                               writing = 0;
+                                       }
+                               } else if ((tmp & R128_CCE_PACKET1_REG1_MASK) <=
+                                          (0x1004 << 9)) {
+                                       if ((tmp & R128_CCE_PACKET1_REG1_MASK) !=
+                                           (R128_PM4_VC_FPU_SETUP << 9)) {
+                                               writing = 0;
+                                       }
+                               }
+                               psize = 3;
+                       } else {
+                               psize = ((tmp & R128_CCE_PACKET_COUNT_MASK) >> 16) + 2;
+                       }
+               }
+               psize--;
+
+               if (writing) {
+                       write++;
+                       *write_ptr++ = tmp;
+               }
+               if (write >= dev_priv->ring_entries) {
+                       write     = 0;
+                       write_ptr = dev_priv->ring_start;
+               }
+               timeout = 0;
+               while (write == *dev_priv->ring_read_ptr) {
+                       (void)R128_READ(R128_PM4_BUFFER_DL_RPTR);
+                       if (timeout++ >= dev_priv->usec_timeout)
+                               return -EBUSY;
+                       udelay(1);
+               }
+               c--;
+       }
+
+       if (write < 32)
+           memcpy(dev_priv->ring_end,
+                  dev_priv->ring_start,
+                  write * sizeof(u32));
+
+       /* Make sure WC cache has been flushed */
+       r128_flush_write_combine();
+
+       dev_priv->sarea_priv->ring_write = write;
+       R128_WRITE(R128_PM4_BUFFER_DL_WPTR, write);
+
+       *count = 0;
+
+       return 0;
+}
+
+static int r128_submit_packets_pio_secure(drm_device_t *dev,
+                                         u32 *commands, int *count)
+{
+       drm_r128_private_t *dev_priv = dev->dev_private;
+       u32                 tmp      = 0;
+       int                 psize    = 0;
+       int                 writing  = 1;
+       int                 addr     = R128_PM4_FIFO_DATA_EVEN;
+       int                 ret;
+
+       while (*count > 0) {
+               tmp = *commands++;
+               if (!psize) {
+                       writing = 1;
+
+                       if ((tmp & R128_CCE_PACKET_MASK) == R128_CCE_PACKET0) {
+                               if ((tmp & R128_CCE_PACKET0_REG_MASK) <= (0x1004 >> 2)) {
+                                       if ((tmp & R128_CCE_PACKET0_REG_MASK) !=
+                                           (R128_PM4_VC_FPU_SETUP >> 2)) {
+                                               writing = 0;
+                                       }
+                               }
+                               psize = ((tmp & R128_CCE_PACKET_COUNT_MASK) >> 16) + 2;
+                       } else if ((tmp & R128_CCE_PACKET_MASK) == R128_CCE_PACKET1) {
+                               if ((tmp & R128_CCE_PACKET1_REG0_MASK) <= (0x1004 >> 2)) {
+                                       if ((tmp & R128_CCE_PACKET1_REG0_MASK) !=
+                                           (R128_PM4_VC_FPU_SETUP >> 2)) {
+                                               writing = 0;
+                                       }
+                               } else if ((tmp & R128_CCE_PACKET1_REG1_MASK) <=
+                                          (0x1004 << 9)) {
+                                       if ((tmp & R128_CCE_PACKET1_REG1_MASK) !=
+                                           (R128_PM4_VC_FPU_SETUP << 9)) {
+                                               writing = 0;
+                                       }
+                               }
+                               psize = 3;
+                       } else {
+                               psize = ((tmp & R128_CCE_PACKET_COUNT_MASK) >> 16) + 2;
+                       }
+               }
+               psize--;
+
+               if (writing) {
+                       if ((ret = r128_do_cce_wait_for_fifo(dev, 1)) < 0)
+                               return ret;
+                       R128_WRITE(addr, tmp);
+                       addr ^= 0x0004;
+               }
+
+               *count -= 1;
+       }
+
+       if (addr == R128_PM4_FIFO_DATA_ODD) {
+               if ((ret = r128_do_cce_wait_for_fifo(dev, 1)) < 0) return ret;
+               R128_WRITE(addr, R128_CCE_PACKET2);
+       }
+
+       return 0;
+}
+
+static int r128_submit_packets_ring(drm_device_t *dev,
+                                   u32 *commands, int *count)
+{
+       drm_r128_private_t *dev_priv  = dev->dev_private;
+       int                 write     = dev_priv->sarea_priv->ring_write;
+       int                *write_ptr = dev_priv->ring_start + write;
+       int                 c         = *count;
+       int                 timeout;
+
+       while (c > 0) {
+               write++;
+               *write_ptr++ = *commands++;
+               if (write >= dev_priv->ring_entries) {
+                       write     = 0;
+                       write_ptr = dev_priv->ring_start;
+               }
+               timeout = 0;
+               while (write == *dev_priv->ring_read_ptr) {
+                       (void)R128_READ(R128_PM4_BUFFER_DL_RPTR);
+                       if (timeout++ >= dev_priv->usec_timeout)
+                               return -EBUSY;
+                       udelay(1);
+               }
+               c--;
+       }
+
+       if (write < 32)
+           memcpy(dev_priv->ring_end,
+                  dev_priv->ring_start,
+                  write * sizeof(u32));
+
+       /* Make sure WC cache has been flushed */
+       r128_flush_write_combine();
+
+       dev_priv->sarea_priv->ring_write = write;
+       R128_WRITE(R128_PM4_BUFFER_DL_WPTR, write);
+
+       *count = 0;
+
+       return 0;
+}
+
+static int r128_submit_packets_pio(drm_device_t *dev,
+                                  u32 *commands, int *count)
+{
+       drm_r128_private_t *dev_priv = dev->dev_private;
+       int                 ret;
+
+       while (*count > 1) {
+               if ((ret = r128_do_cce_wait_for_fifo(dev, 2)) < 0) return ret;
+               R128_WRITE(R128_PM4_FIFO_DATA_EVEN, *commands++);
+               R128_WRITE(R128_PM4_FIFO_DATA_ODD,  *commands++);
+               *count -= 2;
+       }
+
+       if (*count) {
+               if ((ret = r128_do_cce_wait_for_fifo(dev, 2)) < 0) return ret;
+               R128_WRITE(R128_PM4_FIFO_DATA_EVEN, *commands++);
+               R128_WRITE(R128_PM4_FIFO_DATA_ODD,  R128_CCE_PACKET2);
+               *count = 0;
+       }
+
+       return 0;
+}
+
+static int r128_do_submit_packets(drm_device_t *dev, u32 *buffer, int count)
+{
+       drm_r128_private_t *dev_priv = dev->dev_private;
+       int                 c = count;
+       int                 ret;
+
+       if (dev_priv->cce_is_bm_mode) {
+               int left = 0;
+
+               if (c >= dev_priv->ring_entries) {
+                       c    = dev_priv->ring_entries-1;
+                       left = count - c;
+               }
+
+               /* Since this is only used by the kernel we can use the
+                   insecure ring buffer submit packet routine */
+               ret = r128_submit_packets_ring(dev, buffer, &c);
+
+               c += left;
+       } else {
+               /* Since this is only used by the kernel we can use the
+                   insecure PIO submit packet routine */
+               ret = r128_submit_packets_pio(dev, buffer, &c);
+       }
+
+       if (ret < 0) return ret;
+       else         return c;
+}
+
+int r128_submit_pkt(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_r128_private_t *dev_priv = dev->dev_private;
+       drm_r128_packet_t   packet;
+       u32                *buffer;
+       int                 c;
+       int                 size;
+       int                 ret = 0;
+
+       if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) ||
+           dev->lock.pid != current->pid) {
+               DRM_ERROR("r128_submit_pkt called without holding the lock\n");
+               return -EINVAL;
+       }
+
+       copy_from_user_ret(&packet, (drm_r128_packet_t *)arg, sizeof(packet),
+                          -EFAULT);
+
+       c    = packet.count;
+       size = c * sizeof(*buffer);
+
+       if (dev_priv->cce_is_bm_mode) {
+               int left = 0;
+
+               if (c >= dev_priv->ring_entries) {
+                       c    = dev_priv->ring_entries-1;
+                       size = c * sizeof(*buffer);
+                       left = packet.count - c;
+               }
+
+               if ((buffer = kmalloc(size, 0)) == NULL) return -ENOMEM;
+               copy_from_user_ret(buffer, packet.buffer, size, -EFAULT);
+
+               if (dev_priv->cce_secure)
+                       ret = r128_submit_packets_ring_secure(dev, buffer, &c);
+               else
+                       ret = r128_submit_packets_ring(dev, buffer, &c);
+
+               c += left;
+       } else {
+               if ((buffer = kmalloc(size, 0)) == NULL) return -ENOMEM;
+               copy_from_user_ret(buffer, packet.buffer, size, -EFAULT);
+
+               if (dev_priv->cce_secure)
+                       ret = r128_submit_packets_pio_secure(dev, buffer, &c);
+               else
+                       ret = r128_submit_packets_pio(dev, buffer, &c);
+       }
+
+       kfree(buffer);
+
+       packet.count = c;
+       copy_to_user_ret((drm_r128_packet_t *)arg, &packet, sizeof(packet),
+                        -EFAULT);
+
+       if (ret)        return ret;
+       else if (c > 0) return -EAGAIN;
+
+       return 0;
+}
+
+static int r128_send_vertbufs(drm_device_t *dev, drm_r128_vertex_t *v)
+{
+       drm_device_dma_t    *dma      = dev->dma;
+       drm_r128_private_t  *dev_priv = dev->dev_private;
+       drm_r128_buf_priv_t *buf_priv;
+       drm_buf_t           *buf;
+       int                  i, ret;
+       u32                  cce[2];
+
+       /* Make sure we have valid data */
+       for (i = 0; i < v->send_count; i++) {
+               int idx = v->send_indices[i];
+
+               if (idx < 0 || idx >= dma->buf_count) {
+                       DRM_ERROR("Index %d (of %d max)\n",
+                                 idx, dma->buf_count - 1);
+                       return -EINVAL;
+               }
+               buf = dma->buflist[idx];
+               if (buf->pid != current->pid) {
+                       DRM_ERROR("Process %d using buffer owned by %d\n",
+                                 current->pid, buf->pid);
+                       return -EINVAL;
+               }
+               if (buf->pending) {
+                       DRM_ERROR("Sending pending buffer:"
+                                 " buffer %d, offset %d\n",
+                                 v->send_indices[i], i);
+                       return -EINVAL;
+               }
+       }
+
+       /* Wait for idle, if we've wrapped to make sure that all pending
+           buffers have been processed */
+       if (dev_priv->submit_age == R128_MAX_VBUF_AGE) {
+               if ((ret = r128_do_cce_wait_for_idle(dev)) < 0) return ret;
+               dev_priv->submit_age = 0;
+               r128_mark_vertbufs_done(dev);
+       }
+
+       /* Make sure WC cache has been flushed (if in PIO mode) */
+       if (!dev_priv->cce_is_bm_mode) r128_flush_write_combine();
+
+       /* FIXME: Add support for sending vertex buffer to the CCE here
+          instead of in client code.  The v->prim holds the primitive
+          type that should be drawn.  Loop over the list buffers in
+          send_indices[] and submit a packet for each VB.
+
+          This will require us to loop over the clip rects here as
+          well, which implies that we extend the kernel driver to allow
+          cliprects to be stored here.  Note that the cliprects could
+          possibly come from the X server instead of the client, but
+          this will require additional changes to the DRI to allow for
+          this optimization. */
+
+       /* Submit a CCE packet that writes submit_age to R128_VB_AGE_REG */
+       cce[0] = R128CCE0(R128_CCE_PACKET0, R128_VB_AGE_REG, 0);
+       cce[1] = dev_priv->submit_age;
+       if ((ret = r128_do_submit_packets(dev, cce, 2)) < 0) {
+               /* Until we add support for sending VBs to the CCE in
+                  this routine, we can recover from this error.  After
+                  we add that support, we won't be able to easily
+                  recover, so we will probably have to implement
+                  another mechanism for handling timeouts from packets
+                  submitted directly by the kernel. */
+               return ret;
+       }
+
+       /* Now that the submit packet request has succeeded, we can mark
+           the buffers as pending */
+       for (i = 0; i < v->send_count; i++) {
+               buf = dma->buflist[v->send_indices[i]];
+               buf->pending = 1;
+
+               buf_priv      = buf->dev_private;
+               buf_priv->age = dev_priv->submit_age;
+       }
+
+       dev_priv->submit_age++;
+
+       return 0;
+}
+
+static drm_buf_t *r128_freelist_get(drm_device_t *dev)
+{
+       drm_device_dma_t    *dma      = dev->dma;
+       drm_r128_private_t  *dev_priv = dev->dev_private;
+       drm_r128_buf_priv_t *buf_priv;
+       drm_buf_t           *buf;
+       int                  i, t;
+
+       /* FIXME: Optimize -- use freelist code */
+
+       for (i = 0; i < dma->buf_count; i++) {
+               buf = dma->buflist[i];
+               buf_priv = buf->dev_private;
+               if (buf->pid == 0) return buf;
+       }
+
+       for (t = 0; t < dev_priv->usec_timeout; t++) {
+               u32 done_age = R128_READ(R128_VB_AGE_REG);
+
+               for (i = 0; i < dma->buf_count; i++) {
+                       buf = dma->buflist[i];
+                       buf_priv = buf->dev_private;
+                       if (buf->pending && buf_priv->age <= done_age) {
+                               /* The buffer has been processed, so it
+                                   can now be used */
+                               buf->pending = 0;
+                               return buf;
+                       }
+               }
+               udelay(1);
+       }
+
+       return NULL;
+}
+
+
+static int r128_get_vertbufs(drm_device_t *dev, drm_r128_vertex_t *v)
+{
+       drm_buf_t *buf;
+       int        i;
+
+       for (i = v->granted_count; i < v->request_count; i++) {
+               buf = r128_freelist_get(dev);
+               if (!buf) break;
+               buf->pid = current->pid;
+               copy_to_user_ret(&v->request_indices[i],
+                                &buf->idx,
+                                sizeof(buf->idx),
+                                -EFAULT);
+               copy_to_user_ret(&v->request_sizes[i],
+                                &buf->total,
+                                sizeof(buf->total),
+                                -EFAULT);
+               ++v->granted_count;
+       }
+       return 0;
+}
+
+int r128_vertex_buf(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_r128_private_t *dev_priv = dev->dev_private;
+       drm_device_dma_t   *dma      = dev->dma;
+       int                 retcode  = 0;
+       drm_r128_vertex_t   v;
+
+       if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) ||
+           dev->lock.pid != current->pid) {
+               DRM_ERROR("r128_vertex_buf called without holding the lock\n");
+               return -EINVAL;
+       }
+
+       if (!dev_priv || dev_priv->is_pci) {
+               DRM_ERROR("r128_vertex_buf called with a PCI card\n");
+               return -EINVAL;
+       }
+
+       copy_from_user_ret(&v, (drm_r128_vertex_t *)arg, sizeof(v), -EFAULT);
+       DRM_DEBUG("%d: %d send, %d req\n",
+                 current->pid, v.send_count, v.request_count);
+
+       if (v.send_count < 0 || v.send_count > dma->buf_count) {
+               DRM_ERROR("Process %d trying to send %d buffers (of %d max)\n",
+                         current->pid, v.send_count, dma->buf_count);
+               return -EINVAL;
+       }
+       if (v.request_count < 0 || v.request_count > dma->buf_count) {
+               DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
+                         current->pid, v.request_count, dma->buf_count);
+               return -EINVAL;
+       }
+
+       if (v.send_count) {
+               retcode = r128_send_vertbufs(dev, &v);
+       }
+
+       v.granted_count = 0;
+
+       if (!retcode && v.request_count) {
+               retcode = r128_get_vertbufs(dev, &v);
+       }
+
+       DRM_DEBUG("%d returning, granted = %d\n",
+                 current->pid, v.granted_count);
+       copy_to_user_ret((drm_r128_vertex_t *)arg, &v, sizeof(v), -EFAULT);
+
+       return retcode;
+}
diff --git a/linux/r128_drm.h b/linux/r128_drm.h
new file mode 100644 (file)
index 0000000..fa90d72
--- /dev/null
@@ -0,0 +1,111 @@
+/* r128_drm.h -- Public header for the r128 driver -*- linux-c -*-
+ * Created: Wed Apr  5 19:24:19 2000 by kevin@precisioninsight.com
+ *
+ * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * 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: Kevin E. Martin <kevin@precisioninsight.com>
+ *
+ * $XFree86$
+ */
+
+#ifndef _R128_DRM_H_
+#define _R128_DRM_H_
+
+/* WARNING: If you change any of these defines, make sure to change the
+ * defines in the Xserver file (xf86drmR128.h)
+ */
+typedef struct drm_r128_init {
+       enum { 
+               R128_INIT_CCE    = 0x01,
+               R128_CLEANUP_CCE = 0x02
+       } func;
+       int sarea_priv_offset;
+       int is_pci;
+       int cce_mode;
+       int cce_fifo_size;
+       int cce_secure;
+       int ring_size;
+       int usec_timeout;
+
+       int fb_offset;
+       int agp_ring_offset;
+       int agp_read_ptr_offset;
+       int agp_vertbufs_offset;
+       int agp_indbufs_offset;
+       int agp_textures_offset;
+       int mmio_offset;
+} drm_r128_init_t;
+
+typedef struct drm_r128_packet {
+       unsigned long *buffer;
+       int            count;
+       int            flags;
+} drm_r128_packet_t;
+
+typedef enum drm_r128_prim {
+       _DRM_R128_PRIM_NONE             = 0x0001,
+       _DRM_R128_PRIM_POINT            = 0x0002,
+       _DRM_R128_PRIM_LINE             = 0x0004,
+       _DRM_R128_PRIM_POLY_LINE        = 0x0008,
+       _DRM_R128_PRIM_TRI_LIST         = 0x0010,
+       _DRM_R128_PRIM_TRI_FAN          = 0x0020,
+       _DRM_R128_PRIM_TRI_STRIP        = 0x0040,
+       _DRM_R128_PRIM_TRI_TYPE2        = 0x0080
+} drm_r128_prim_t;
+
+typedef struct drm_r128_vertex {
+                               /* Indices here refer to the offset into
+                                  buflist in drm_buf_get_t.  */
+       int             send_count;       /* Number of buffers to send      */
+       int             *send_indices;    /* List of handles to buffers     */
+       int             *send_sizes;      /* Lengths of data to send        */
+       drm_r128_prim_t prim;             /* Primitive type                 */
+       int             request_count;    /* Number of buffers requested    */
+       int             *request_indices; /* Buffer information             */
+       int             *request_sizes;
+       int             granted_count;    /* Number of buffers granted      */
+} drm_r128_vertex_t;
+
+/* WARNING: If you change any of these defines, make sure to change the
+ * defines in the Xserver file (r128_sarea.h)
+ */
+#define R128_LOCAL_TEX_HEAP       0
+#define R128_AGP_TEX_HEAP         1
+#define R128_NR_TEX_HEAPS         2
+#define R128_NR_TEX_REGIONS      64
+#define R128_LOG_TEX_GRANULARITY 16
+
+typedef struct drm_tex_region {
+       unsigned char next, prev;       
+       unsigned char in_use;   
+       int age;                        
+} drm_tex_region_t;
+
+typedef struct drm_r128_sarea {
+       drm_tex_region_t tex_list[R128_NR_TEX_HEAPS][R128_NR_TEX_REGIONS+1];
+       int              tex_age[R128_NR_TEX_HEAPS];
+       int              ctx_owner;
+       int              ring_write;
+} drm_r128_sarea_t;
+
+#endif
diff --git a/linux/r128_drv.c b/linux/r128_drv.c
new file mode 100644 (file)
index 0000000..45ade1d
--- /dev/null
@@ -0,0 +1,737 @@
+/* r128_drv.c -- ATI Rage 128 driver -*- linux-c -*-
+ * Created: Mon Dec 13 09:47:27 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * 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@precisioninsight.com>
+ *          Kevin E. Martin <kevin@precisioninsight.com>
+ * 
+ * $XFree86$
+ *
+ */
+
+#define EXPORT_SYMTAB
+#include "drmP.h"
+#include "r128_drv.h"
+EXPORT_SYMBOL(r128_init);
+EXPORT_SYMBOL(r128_cleanup);
+
+#define R128_NAME       "r128"
+#define R128_DESC       "r128"
+#define R128_DATE       "20000422"
+#define R128_MAJOR      0
+#define R128_MINOR      0
+#define R128_PATCHLEVEL  5
+
+static drm_device_t          r128_device;
+drm_ctx_t                    r128_res_ctx;
+
+static struct file_operations r128_fops = {
+       open:    r128_open,
+       flush:   drm_flush,
+       release: r128_release,
+       ioctl:   r128_ioctl,
+       mmap:    drm_mmap,
+       read:    drm_read,
+       fasync:  drm_fasync,
+       poll:    drm_poll,
+};
+
+static struct miscdevice      r128_misc = {
+       minor: MISC_DYNAMIC_MINOR,
+       name:  R128_NAME,
+       fops:  &r128_fops,
+};
+
+static drm_ioctl_desc_t              r128_ioctls[] = {
+       [DRM_IOCTL_NR(DRM_IOCTL_VERSION)]     = { r128_version,    0, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)]  = { drm_getunique,   0, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)]   = { drm_getmagic,    0, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)]   = { drm_irq_busid,   0, 1 },
+
+       [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)]  = { drm_setunique,   1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)]       = { drm_block,       1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)]     = { drm_unblock,     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_ADD_BUFS)]    = { r128_addbufs,    1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)]   = { drm_markbufs,    1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)]   = { drm_infobufs,    1, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)]    = { r128_mapbufs,    1, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)]   = { drm_freebufs,    1, 0 },
+
+       [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)]     = { r128_addctx,     1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)]      = { r128_rmctx,      1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)]     = { r128_modctx,     1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)]     = { r128_getctx,     1, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)]  = { r128_switchctx,  1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)]     = { r128_newctx,     1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)]     = { r128_resctx,     1, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)]    = { drm_adddraw,     1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)]     = { drm_rmdraw,      1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_LOCK)]        = { r128_lock,       1, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)]      = { r128_unlock,     1, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_FINISH)]      = { drm_finish,      1, 0 },
+
+#ifdef DRM_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_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 },
+       [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)]  = { drm_agp_unbind,  1, 1 },
+#endif
+
+       [DRM_IOCTL_NR(DRM_IOCTL_R128_INIT)]   = { r128_init_cce,   1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_R128_RESET)]  = { r128_eng_reset,  1, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_R128_FLUSH)]  = { r128_eng_flush,  1, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_R128_PACKET)] = { r128_submit_pkt, 1, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_R128_CCEIDL)] = { r128_cce_idle,   1, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_R128_VERTEX)] = { r128_vertex_buf, 1, 0 },
+};
+#define R128_IOCTL_COUNT DRM_ARRAY_SIZE(r128_ioctls)
+
+#ifdef MODULE
+int                          init_module(void);
+void                         cleanup_module(void);
+static char                  *r128 = NULL;
+
+MODULE_AUTHOR("Precision Insight, Inc., Cedar Park, Texas.");
+MODULE_DESCRIPTION("r128");
+MODULE_PARM(r128, "s");
+
+/* init_module is called when insmod is used to load the module */
+
+int init_module(void)
+{
+       return r128_init();
+}
+
+/* cleanup_module is called when rmmod is used to unload the module */
+
+void cleanup_module(void)
+{
+       r128_cleanup();
+}
+#endif
+
+#ifndef MODULE
+/* r128_setup is called by the kernel to parse command-line options passed
+ * via the boot-loader (e.g., LILO).  It calls the insmod option routine,
+ * drm_parse_drm.
+ *
+ * This is not currently supported, since it requires changes to
+ * linux/init/main.c. */
+
+void __init r128_setup(char *str, int *ints)
+{
+       if (ints[0] != 0) {
+               DRM_ERROR("Illegal command line format, ignored\n");
+               return;
+       }
+       drm_parse_options(str);
+}
+#endif
+
+static int r128_setup(drm_device_t *dev)
+{
+       int i;
+       
+       atomic_set(&dev->ioctl_count, 0);
+       atomic_set(&dev->vma_count, 0);
+       dev->buf_use      = 0;
+       atomic_set(&dev->buf_alloc, 0);
+
+       drm_dma_setup(dev);
+
+       atomic_set(&dev->total_open, 0);
+       atomic_set(&dev->total_close, 0);
+       atomic_set(&dev->total_ioctl, 0);
+       atomic_set(&dev->total_irq, 0);
+       atomic_set(&dev->total_ctx, 0);
+       atomic_set(&dev->total_locks, 0);
+       atomic_set(&dev->total_unlocks, 0);
+       atomic_set(&dev->total_contends, 0);
+       atomic_set(&dev->total_sleeps, 0);
+
+       for (i = 0; i < DRM_HASH_SIZE; i++) {
+               dev->magiclist[i].head = NULL;
+               dev->magiclist[i].tail = NULL;
+       }
+       dev->maplist        = NULL;
+       dev->map_count      = 0;
+       dev->vmalist        = NULL;
+       dev->lock.hw_lock   = NULL;
+       init_waitqueue_head(&dev->lock.lock_queue);
+       dev->queue_count    = 0;
+       dev->queue_reserved = 0;
+       dev->queue_slots    = 0;
+       dev->queuelist      = NULL;
+       dev->irq            = 0;
+       dev->context_flag   = 0;
+       dev->interrupt_flag = 0;
+       dev->dma_flag       = 0;
+       dev->last_context   = 0;
+       dev->last_switch    = 0;
+       dev->last_checked   = 0;
+       init_timer(&dev->timer);
+       init_waitqueue_head(&dev->context_wait);
+
+       dev->ctx_start      = 0;
+       dev->lck_start      = 0;
+       
+       dev->buf_rp       = dev->buf;
+       dev->buf_wp       = dev->buf;
+       dev->buf_end      = dev->buf + DRM_BSZ;
+       dev->buf_async    = NULL;
+       init_waitqueue_head(&dev->buf_readers);
+       init_waitqueue_head(&dev->buf_writers);
+
+       r128_res_ctx.handle=-1;
+                       
+       DRM_DEBUG("\n");
+                       
+       /* The kernel's context could be created here, but is now created
+          in drm_dma_enqueue.  This is more resource-efficient for
+          hardware that does not do DMA, but may mean that
+          drm_select_queue fails between the time the interrupt is
+          initialized and the time the queues are initialized. */
+                       
+       return 0;
+}
+
+
+static int r128_takedown(drm_device_t *dev)
+{
+       int               i;
+       drm_magic_entry_t *pt, *next;
+       drm_map_t         *map;
+       drm_vma_entry_t   *vma, *vma_next;
+
+       DRM_DEBUG("\n");
+
+       down(&dev->struct_sem);
+       del_timer(&dev->timer);
+       
+       if (dev->devname) {
+               drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER);
+               dev->devname = NULL;
+       }
+       
+       if (dev->unique) {
+               drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER);
+               dev->unique = NULL;
+               dev->unique_len = 0;
+       }
+                               /* Clear pid list */
+       for (i = 0; i < DRM_HASH_SIZE; i++) {
+               for (pt = dev->magiclist[i].head; pt; pt = next) {
+                       next = pt->next;
+                       drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
+               }
+               dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
+       }
+
+#ifdef DRM_AGP
+                               /* Clear AGP information */
+       if (dev->agp) {
+               drm_agp_mem_t *entry;
+               drm_agp_mem_t *nexte;
+               
+                               /* Remove AGP resources, but leave dev->agp
+                                   intact until r128_cleanup is called. */
+               for (entry = dev->agp->memory; entry; entry = nexte) {
+                       nexte = entry->next;
+                       if (entry->bound) drm_unbind_agp(entry->memory);
+                       drm_free_agp(entry->memory, entry->pages);
+                       drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
+               }
+               dev->agp->memory = NULL;
+               
+               if (dev->agp->acquired && drm_agp.release)
+                       (*drm_agp.release)();
+               
+               dev->agp->acquired = 0;
+               dev->agp->enabled  = 0;
+       }
+#endif
+       
+                               /* Clear vma list (only built for debugging) */
+       if (dev->vmalist) {
+               for (vma = dev->vmalist; vma; vma = vma_next) {
+                       vma_next = vma->next;
+                       drm_free(vma, sizeof(*vma), DRM_MEM_VMAS);
+               }
+               dev->vmalist = NULL;
+       }
+       
+                               /* Clear map area and mtrr information */
+       if (dev->maplist) {
+               for (i = 0; i < dev->map_count; i++) {
+                       map = dev->maplist[i];
+                       switch (map->type) {
+                       case _DRM_REGISTERS:
+                       case _DRM_FRAME_BUFFER:
+#ifdef CONFIG_MTRR
+                               if (map->mtrr >= 0) {
+                                       int retcode;
+                                       retcode = mtrr_del(map->mtrr,
+                                                          map->offset,
+                                                          map->size);
+                                       DRM_DEBUG("mtrr_del = %d\n", retcode);
+                               }
+#endif
+                               drm_ioremapfree(map->handle, map->size);
+                               break;
+                       case _DRM_SHM:
+                               drm_free_pages((unsigned long)map->handle,
+                                              drm_order(map->size)
+                                              - PAGE_SHIFT,
+                                              DRM_MEM_SAREA);
+                               break;
+                       case _DRM_AGP:
+                               /* Do nothing here, because this is all
+                                   handled in the AGP/GART driver. */
+                               break;
+                       }
+                       drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+               }
+               drm_free(dev->maplist,
+                        dev->map_count * sizeof(*dev->maplist),
+                        DRM_MEM_MAPS);
+               dev->maplist   = NULL;
+               dev->map_count = 0;
+       }
+       
+       drm_dma_takedown(dev);
+
+       dev->queue_count     = 0;
+       if (dev->lock.hw_lock) {
+               dev->lock.hw_lock    = NULL; /* SHM removed */
+               dev->lock.pid        = 0;
+               wake_up_interruptible(&dev->lock.lock_queue);
+       }
+       up(&dev->struct_sem);
+       
+       return 0;
+}
+
+/* r128_init is called via init_module at module load time, or via
+ * linux/init/main.c (this is not currently supported). */
+
+int r128_init(void)
+{
+       int                   retcode;
+       drm_device_t          *dev = &r128_device;
+
+       DRM_DEBUG("\n");
+
+       memset((void *)dev, 0, sizeof(*dev));
+       dev->count_lock   = SPIN_LOCK_UNLOCKED;
+       sema_init(&dev->struct_sem, 1);
+       
+#ifdef MODULE
+       drm_parse_options(r128);
+#endif
+
+       if ((retcode = misc_register(&r128_misc))) {
+               DRM_ERROR("Cannot register \"%s\"\n", R128_NAME);
+               return retcode;
+       }
+       dev->device = MKDEV(MISC_MAJOR, r128_misc.minor);
+       dev->name   = R128_NAME;
+
+       drm_mem_init();
+       drm_proc_init(dev);
+
+#ifdef DRM_AGP
+       dev->agp    = drm_agp_init();
+
+#ifdef CONFIG_MTRR
+       dev->agp->agp_mtrr = mtrr_add(dev->agp->agp_info.aper_base,
+                                     dev->agp->agp_info.aper_size*1024*1024,
+                                     MTRR_TYPE_WRCOMB,
+                                     1);
+#endif
+#endif
+
+       if((retcode = drm_ctxbitmap_init(dev))) {
+               DRM_ERROR("Cannot allocate memory for context bitmap.\n");
+               drm_proc_cleanup();
+               misc_deregister(&r128_misc);
+               r128_takedown(dev);
+               return retcode;
+       }
+
+       DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
+                R128_NAME,
+                R128_MAJOR,
+                R128_MINOR,
+                R128_PATCHLEVEL,
+                R128_DATE,
+                r128_misc.minor);
+
+       return 0;
+}
+
+/* r128_cleanup is called via cleanup_module at module unload time. */
+
+void r128_cleanup(void)
+{
+       drm_device_t          *dev = &r128_device;
+
+       DRM_DEBUG("\n");
+       
+       drm_proc_cleanup();
+       if (misc_deregister(&r128_misc)) {
+               DRM_ERROR("Cannot unload module\n");
+       } else {
+               DRM_INFO("Module unloaded\n");
+       }
+       drm_ctxbitmap_cleanup(dev);
+       r128_takedown(dev);
+#ifdef DRM_AGP
+       if (dev->agp) {
+                               /* FIXME -- free other information, too */
+               drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS);
+               dev->agp = NULL;
+       }
+#endif
+}
+
+int r128_version(struct inode *inode, struct file *filp, unsigned int cmd,
+                 unsigned long arg)
+{
+       drm_version_t version;
+       int           len;
+
+       copy_from_user_ret(&version,
+                          (drm_version_t *)arg,
+                          sizeof(version),
+                          -EFAULT);
+
+#define DRM_COPY(name,value)                                \
+       len = strlen(value);                                 \
+       if (len > name##_len) len = name##_len;              \
+       name##_len = strlen(value);                          \
+       if (len && name) {                                   \
+               copy_to_user_ret(name, value, len, -EFAULT); \
+       }
+
+       version.version_major      = R128_MAJOR;
+       version.version_minor      = R128_MINOR;
+       version.version_patchlevel = R128_PATCHLEVEL;
+
+       DRM_COPY(version.name, R128_NAME);
+       DRM_COPY(version.date, R128_DATE);
+       DRM_COPY(version.desc, R128_DESC);
+
+       copy_to_user_ret((drm_version_t *)arg,
+                        &version,
+                        sizeof(version),
+                        -EFAULT);
+       return 0;
+}
+
+int r128_open(struct inode *inode, struct file *filp)
+{
+       drm_device_t  *dev    = &r128_device;
+       int           retcode = 0;
+       
+       DRM_DEBUG("open_count = %d\n", dev->open_count);
+       if (!(retcode = drm_open_helper(inode, filp, dev))) {
+               MOD_INC_USE_COUNT;
+               atomic_inc(&dev->total_open);
+               spin_lock(&dev->count_lock);
+               if (!dev->open_count++) {
+                       spin_unlock(&dev->count_lock);
+                       return r128_setup(dev);
+               }
+               spin_unlock(&dev->count_lock);
+       }
+       return retcode;
+}
+
+int r128_release(struct inode *inode, struct file *filp)
+{
+       drm_file_t    *priv   = filp->private_data;
+       drm_device_t  *dev    = priv->dev;
+       int           retcode = 0;
+
+       DRM_DEBUG("open_count = %d\n", dev->open_count);
+       if (!(retcode = drm_release(inode, filp))) {
+               MOD_DEC_USE_COUNT;
+               atomic_inc(&dev->total_close);
+               spin_lock(&dev->count_lock);
+               if (!--dev->open_count) {
+                       if (atomic_read(&dev->ioctl_count) || dev->blocked) {
+                               DRM_ERROR("Device busy: %d %d\n",
+                                         atomic_read(&dev->ioctl_count),
+                                         dev->blocked);
+                               spin_unlock(&dev->count_lock);
+                               return -EBUSY;
+                       }
+                       spin_unlock(&dev->count_lock);
+                       return r128_takedown(dev);
+               }
+               spin_unlock(&dev->count_lock);
+       }
+       return retcode;
+}
+
+/* r128_ioctl is called whenever a process performs an ioctl on /dev/drm. */
+
+int r128_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+               unsigned long arg)
+{
+       int              nr      = DRM_IOCTL_NR(cmd);
+       drm_file_t       *priv   = filp->private_data;
+       drm_device_t     *dev    = priv->dev;
+       int              retcode = 0;
+       drm_ioctl_desc_t *ioctl;
+       drm_ioctl_t      *func;
+
+       atomic_inc(&dev->ioctl_count);
+       atomic_inc(&dev->total_ioctl);
+       ++priv->ioctl_count;
+       
+       DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n",
+                 current->pid, cmd, nr, dev->device, priv->authenticated);
+
+       if (nr >= R128_IOCTL_COUNT) {
+               retcode = -EINVAL;
+       } else {
+               ioctl     = &r128_ioctls[nr];
+               func      = ioctl->func;
+
+               if (!func) {
+                       DRM_DEBUG("no function\n");
+                       retcode = -EINVAL;
+               } else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN))
+                           || (ioctl->auth_needed && !priv->authenticated)) {
+                       retcode = -EACCES;
+               } else {
+                       retcode = (func)(inode, filp, cmd, arg);
+               }
+       }
+       
+       atomic_dec(&dev->ioctl_count);
+       return retcode;
+}
+
+int r128_lock(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;
+        DECLARE_WAITQUEUE(entry, current);
+        int               ret   = 0;
+        drm_lock_t        lock;
+#if DRM_DMA_HISTOGRAM
+        cycles_t          start;
+
+        dev->lck_start = start = get_cycles();
+#endif
+
+        copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+
+        if (lock.context == DRM_KERNEL_CONTEXT) {
+                DRM_ERROR("Process %d using kernel context %d\n",
+                          current->pid, lock.context);
+                return -EINVAL;
+        }
+
+        DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
+                  lock.context, current->pid, dev->lock.hw_lock->lock,
+                  lock.flags);
+
+#if 0
+                               /* dev->queue_count == 0 right now for
+                                   r128.  FIXME? */
+        if (lock.context < 0 || lock.context >= dev->queue_count)
+                return -EINVAL;
+#endif
+        
+        if (!ret) {
+#if 0
+                if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)
+                    != lock.context) {
+                        long j = jiffies - dev->lock.lock_time;
+
+                        if (lock.context == r128_res_ctx.handle &&
+                               j >= 0 && j < DRM_LOCK_SLICE) {
+                                /* Can't take lock if we just had it and
+                                   there is contention. */
+                                DRM_DEBUG("%d (pid %d) delayed j=%d dev=%d jiffies=%d\n",
+                                       lock.context, current->pid, j, 
+                                       dev->lock.lock_time, jiffies);
+                                current->state = TASK_INTERRUPTIBLE;
+                               current->policy |= SCHED_YIELD;
+                                schedule_timeout(DRM_LOCK_SLICE-j);
+                               DRM_DEBUG("jiffies=%d\n", jiffies);
+                        }
+                }
+#endif
+                add_wait_queue(&dev->lock.lock_queue, &entry);
+                for (;;) {
+                        if (!dev->lock.hw_lock) {
+                                /* Device has been unregistered */
+                                ret = -EINTR;
+                                break;
+                        }
+                        if (drm_lock_take(&dev->lock.hw_lock->lock,
+                                          lock.context)) {
+                                dev->lock.pid       = current->pid;
+                                dev->lock.lock_time = jiffies;
+                                atomic_inc(&dev->total_locks);
+                                break;  /* Got lock */
+                        }
+                        
+                                /* Contention */
+                        atomic_inc(&dev->total_sleeps);
+                        current->state = TASK_INTERRUPTIBLE;
+#if 1
+                       current->policy |= SCHED_YIELD;
+#endif
+                        schedule();
+                        if (signal_pending(current)) {
+                                ret = -ERESTARTSYS;
+                                break;
+                        }
+                }
+                current->state = TASK_RUNNING;
+                remove_wait_queue(&dev->lock.lock_queue, &entry);
+        }
+
+#if 0
+       if (!ret && dev->last_context != lock.context &&
+               lock.context != r128_res_ctx.handle &&
+               dev->last_context != r128_res_ctx.handle) {
+               add_wait_queue(&dev->context_wait, &entry);
+               current->state = TASK_INTERRUPTIBLE;
+                /* PRE: dev->last_context != lock.context */
+               r128_context_switch(dev, dev->last_context, lock.context);
+               /* POST: we will wait for the context
+                   switch and will dispatch on a later call
+                   when dev->last_context == lock.context
+                   NOTE WE HOLD THE LOCK THROUGHOUT THIS
+                   TIME! */
+               current->policy |= SCHED_YIELD;
+               schedule();
+               current->state = TASK_RUNNING;
+               remove_wait_queue(&dev->context_wait, &entry);
+               if (signal_pending(current)) {
+                       ret = -EINTR;
+               } else if (dev->last_context != lock.context) {
+                       DRM_ERROR("Context mismatch: %d %d\n",
+                               dev->last_context, lock.context);
+               }
+       }
+#endif
+
+        if (!ret) {
+                if (lock.flags & _DRM_LOCK_READY) {
+                               /* Wait for space in DMA/FIFO */
+               }
+                if (lock.flags & _DRM_LOCK_QUIESCENT) {
+                               /* Make hardware quiescent */
+#if 0
+                        r128_quiescent(dev);
+#endif
+               }
+        }
+
+#if 0
+       DRM_ERROR("pid = %5d, old counter = %5ld\n", 
+               current->pid, current->counter);
+#endif
+       if (lock.context != r128_res_ctx.handle) {
+               current->counter = 5;
+               current->priority = DEF_PRIORITY/4;
+       }
+#if 0
+       while (current->counter > 25)
+               current->counter >>= 1; /* decrease time slice */
+       DRM_ERROR("pid = %5d, new counter = %5ld\n",
+                current->pid, current->counter);
+#endif
+        DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
+
+#if DRM_DMA_HISTOGRAM
+        atomic_inc(&dev->histo.lacq[drm_histogram_slot(get_cycles() - start)]);
+#endif
+        
+        return ret;
+}
+
+
+int r128_unlock(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_lock_t        lock;
+
+       copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+       
+       if (lock.context == DRM_KERNEL_CONTEXT) {
+               DRM_ERROR("Process %d using kernel context %d\n",
+                         current->pid, lock.context);
+               return -EINVAL;
+       }
+
+       DRM_DEBUG("%d frees lock (%d holds)\n",
+                 lock.context,
+                 _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+       atomic_inc(&dev->total_unlocks);
+       if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock))
+               atomic_inc(&dev->total_contends);
+       drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT);
+                               /* FIXME: Try to send data to card here */
+       if (!dev->context_flag) {
+               if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
+                                 DRM_KERNEL_CONTEXT)) {
+                       DRM_ERROR("\n");
+               }
+       }
+
+#if 0
+       current->policy |= SCHED_YIELD;
+       current->state = TASK_INTERRUPTIBLE;
+       schedule_timeout(1000);
+#endif
+
+       if (lock.context != r128_res_ctx.handle) {
+               current->counter = 5;
+               current->priority = DEF_PRIORITY;
+       }
+#if 0
+       current->state = TASK_INTERRUPTIBLE;
+       schedule_timeout(10);
+#endif
+       
+       return 0;
+}
diff --git a/linux/r128_drv.h b/linux/r128_drv.h
new file mode 100644 (file)
index 0000000..3b888c4
--- /dev/null
@@ -0,0 +1,226 @@
+/* r128_drv.h -- Private header for r128 driver -*- linux-c -*-
+ * Created: Mon Dec 13 09:51:11 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * 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@precisioninsight.com>
+ *          Kevin E. Martin <kevin@precisioninsight.com>
+ *
+ * $XFree86$
+ * 
+ */
+
+#ifndef _R128_DRV_H_
+#define _R128_DRV_H_
+
+typedef struct drm_r128_private {
+       int               is_pci;
+
+       int               cce_mode;
+       int               cce_fifo_size;
+       int               cce_is_bm_mode;
+       int               cce_secure;
+
+       drm_r128_sarea_t *sarea_priv;
+
+       __volatile__ u32 *ring_read_ptr;
+
+       u32              *ring_start;
+       u32              *ring_end;
+       int               ring_size;
+       int               ring_sizel2qw;
+       int               ring_entries;
+
+       int               submit_age;
+
+       int               usec_timeout;
+
+       drm_map_t        *sarea;
+       drm_map_t        *fb;
+       drm_map_t        *agp_ring;
+       drm_map_t        *agp_read_ptr;
+       drm_map_t        *agp_vertbufs;
+       drm_map_t        *agp_indbufs;
+       drm_map_t        *agp_textures;
+       drm_map_t        *mmio;
+} drm_r128_private_t;
+
+typedef struct drm_r128_buf_priv {
+       u32               age;
+} drm_r128_buf_priv_t;
+
+                               /* r128_drv.c */
+extern int  r128_init(void);
+extern void r128_cleanup(void);
+extern int  r128_version(struct inode *inode, struct file *filp,
+                         unsigned int cmd, unsigned long arg);
+extern int  r128_open(struct inode *inode, struct file *filp);
+extern int  r128_release(struct inode *inode, struct file *filp);
+extern int  r128_ioctl(struct inode *inode, struct file *filp,
+                       unsigned int cmd, unsigned long arg);
+extern int  r128_lock(struct inode *inode, struct file *filp,
+                      unsigned int cmd, unsigned long arg);
+extern int  r128_unlock(struct inode *inode, struct file *filp,
+                        unsigned int cmd, unsigned long arg);
+
+                               /* r128_dma.c */
+extern int r128_init_cce(struct inode *inode, struct file *filp,
+                        unsigned int cmd, unsigned long arg);
+extern int r128_eng_reset(struct inode *inode, struct file *filp,
+                         unsigned int cmd, unsigned long arg);
+extern int r128_eng_flush(struct inode *inode, struct file *filp,
+                         unsigned int cmd, unsigned long arg);
+extern int r128_submit_pkt(struct inode *inode, struct file *filp,
+                          unsigned int cmd, unsigned long arg);
+extern int r128_cce_idle(struct inode *inode, struct file *filp,
+                        unsigned int cmd, unsigned long arg);
+extern int r128_vertex_buf(struct inode *inode, struct file *filp,
+                          unsigned int cmd, unsigned long arg);
+
+                               /* r128_bufs.c */
+extern int r128_addbufs(struct inode *inode, struct file *filp,
+                       unsigned int cmd, unsigned long arg);
+extern int r128_mapbufs(struct inode *inode, struct file *filp,
+                       unsigned int cmd, unsigned long arg);
+
+                               /* r128_context.c */
+extern int  r128_resctx(struct inode *inode, struct file *filp,
+                       unsigned int cmd, unsigned long arg);
+extern int  r128_addctx(struct inode *inode, struct file *filp,
+                       unsigned int cmd, unsigned long arg);
+extern int  r128_modctx(struct inode *inode, struct file *filp,
+                       unsigned int cmd, unsigned long arg);
+extern int  r128_getctx(struct inode *inode, struct file *filp,
+                       unsigned int cmd, unsigned long arg);
+extern int  r128_switchctx(struct inode *inode, struct file *filp,
+                          unsigned int cmd, unsigned long arg);
+extern int  r128_newctx(struct inode *inode, struct file *filp,
+                       unsigned int cmd, unsigned long arg);
+extern int  r128_rmctx(struct inode *inode, struct file *filp,
+                      unsigned int cmd, unsigned long arg);
+
+extern int  r128_context_switch(drm_device_t *dev, int old, int new);
+extern int  r128_context_switch_complete(drm_device_t *dev, int new);
+
+
+/* Register definitions, register access macros and drmAddMap constants
+ * for Rage 128 kernel driver.
+ */
+
+#define R128_PC_NGUI_CTLSTAT   0x0184
+#       define R128_PC_FLUSH_ALL       0x00ff
+#       define R128_PC_BUSY            (1 << 31)
+
+#define R128_CLOCK_CNTL_INDEX  0x0008
+#define R128_CLOCK_CNTL_DATA   0x000c
+#       define R128_PLL_WR_EN          (1 << 7)
+
+#define R128_MCLK_CNTL         0x000f
+#       define R128_FORCE_GCP          (1 << 16)
+#       define R128_FORCE_PIPE3D_CPP   (1 << 17)
+
+#define R128_GEN_RESET_CNTL    0x00f0
+#       define R128_SOFT_RESET_GUI     (1 <<  0)
+
+#define R128_PM4_BUFFER_CNTL   0x0704
+#       define R128_PM4_NONPM4                 (0  << 28)
+#       define R128_PM4_192PIO                 (1  << 28)
+#       define R128_PM4_192BM                  (2  << 28)
+#       define R128_PM4_128PIO_64INDBM         (3  << 28)
+#       define R128_PM4_128BM_64INDBM          (4  << 28)
+#       define R128_PM4_64PIO_128INDBM         (5  << 28)
+#       define R128_PM4_64BM_128INDBM          (6  << 28)
+#       define R128_PM4_64PIO_64VCBM_64INDBM   (7  << 28)
+#       define R128_PM4_64BM_64VCBM_64INDBM    (8  << 28)
+#       define R128_PM4_64PIO_64VCPIO_64INDPIO (15 << 28)
+
+
+#define R128_PM4_BUFFER_DL_RPTR        0x0710
+#define R128_PM4_BUFFER_DL_WPTR        0x0714
+#       define R128_PM4_BUFFER_DL_DONE         (1 << 31)
+
+#define R128_PM4_VC_FPU_SETUP  0x071c
+
+#define R128_PM4_STAT          0x07b8
+#       define R128_PM4_FIFOCNT_MASK           0x0fff
+#       define R128_PM4_BUSY                   (1 << 16)
+#       define R128_PM4_GUI_ACTIVE             (1 << 31)
+
+#define R128_PM4_BUFFER_ADDR   0x07f0
+#define R128_PM4_MICRO_CNTL    0x07fc
+#       define R128_PM4_MICRO_FREERUN          (1 << 30)
+
+#define R128_PM4_FIFO_DATA_EVEN        0x1000
+#define R128_PM4_FIFO_DATA_ODD 0x1004
+
+#define R128_GUI_SCRATCH_REG0  0x15e0
+#define R128_GUI_SCRATCH_REG1  0x15e4
+#define R128_GUI_SCRATCH_REG2  0x15e8
+#define R128_GUI_SCRATCH_REG3  0x15ec
+#define R128_GUI_SCRATCH_REG4  0x15f0
+#define R128_GUI_SCRATCH_REG5  0x15f4
+
+#define R128_GUI_STAT          0x1740
+#       define R128_GUI_FIFOCNT_MASK           0x0fff
+#       define R128_GUI_ACTIVE                 (1 << 31)
+
+
+/* CCE command packets */
+#define R128_CCE_PACKET0       0x00000000
+#define R128_CCE_PACKET1       0x40000000
+#define R128_CCE_PACKET2       0x80000000
+#       define R128_CCE_PACKET_MASK            0xC0000000
+#       define R128_CCE_PACKET_COUNT_MASK      0x3fff0000
+#       define R128_CCE_PACKET0_REG_MASK       0x000007ff
+#       define R128_CCE_PACKET1_REG0_MASK      0x000007ff
+#       define R128_CCE_PACKET1_REG1_MASK      0x003ff800
+
+
+#define R128_MAX_USEC_TIMEOUT  100000  /* 100 ms */
+
+
+#define R128_BASE(reg)         ((u32)(dev_priv->mmio->handle))
+#define R128_ADDR(reg)         (R128_BASE(reg) + reg)
+
+#define R128_DEREF(reg)                *(__volatile__ int *)R128_ADDR(reg)
+#define R128_READ(reg)         R128_DEREF(reg)
+#define R128_WRITE(reg,val)    do { R128_DEREF(reg) = val; } while (0)
+
+#define R128_DEREF8(reg)       *(__volatile__ char *)R128_ADDR(reg)
+#define R128_READ8(reg)                R128_DEREF8(reg)
+#define R128_WRITE8(reg,val)   do { R128_DEREF8(reg) = val; } while (0)
+
+#define R128_WRITE_PLL(addr,val)                                              \
+do {                                                                          \
+       R128_WRITE8(R128_CLOCK_CNTL_INDEX, ((addr) & 0x1f) | R128_PLL_WR_EN); \
+       R128_WRITE(R128_CLOCK_CNTL_DATA, (val));                              \
+} while (0)
+
+extern int R128_READ_PLL(drm_device_t *dev, int addr);
+
+#define R128CCE0(p,r,n)   ((p) | ((n) << 16) | ((r) >> 2))
+#define R128CCE1(p,r1,r2) ((p) | (((r2) >> 2) << 11) | ((r1) >> 2))
+#define R128CCE2(p)       ((p))
+#define R128CCE3(p,n)     ((p) | ((n) << 16))
+
+#endif
index 389f2fa..9c2cea5 100644 (file)
@@ -1,8 +1,7 @@
 /* vm.c -- Memory mapping for DRM -*- linux-c -*-
  * Created: Mon Jan  4 08:58:31 1999 by faith@precisioninsight.com
- * Revised: Mon Feb 14 00:16:45 2000 by kevin@precisioninsight.com
  *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -246,6 +245,18 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
                                /* Check for valid size. */
        if (map->size != vma->vm_end - vma->vm_start) return -EINVAL;
        
+       if (!capable(CAP_SYS_ADMIN) && (map->flags & _DRM_READ_ONLY)) {
+               vma->vm_flags &= VM_MAYWRITE;
+#if defined(__i386__)
+               pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW;
+#else
+                               /* Ye gads this is ugly.  With more thought
+                                   we could move this up higher and use
+                                   `protection_map' instead.  */
+               vma->vm_page_prot = __pgprot(pte_val(pte_wrprotect(
+                       __pte(pgprot_val(vma->vm_page_prot)))));
+#endif
+       }
 
        switch (map->type) {
        case _DRM_FRAME_BUFFER:
@@ -265,6 +276,10 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
                                     vma->vm_end - vma->vm_start,
                                     vma->vm_page_prot))
                                return -EAGAIN;
+               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));
                vma->vm_ops = &drm_vm_ops;
                break;
        case _DRM_SHM:
@@ -277,19 +292,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
                return -EINVAL; /* This should never happen. */
        }
        vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */
-       if (map->flags & _DRM_READ_ONLY) {
-#if defined(__i386__)
-               pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW;
-#else
-                               /* Ye gads this is ugly.  With more thought
-                                   we could move this up higher and use
-                                   `protection_map' instead.  */
-               vma->vm_page_prot = __pgprot(pte_val(pte_wrprotect(
-                       __pte(pgprot_val(vma->vm_page_prot)))));
-#endif
-       }
 
-       
 #if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */
                                /* In Linux 2.2.3 and above, this is
                                   handled in do_mmap() in mm/mmap.c. */
index ae4c65c..25e4cce 100644 (file)
@@ -1,8 +1,7 @@
 /* drm.h -- Header for Direct Rendering Manager -*- linux-c -*-
  * Created: Mon Jan  4 10:05:05 1999 by faith@precisioninsight.com
- * Revised: Mon Feb 14 00:15:23 2000 by kevin@precisioninsight.com
  *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
  * All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -71,9 +70,10 @@ typedef struct drm_clip_rect {
            unsigned short y2;
 } drm_clip_rect_t;
 
-/* Seperate include files for the i810/mga specific structures */
+/* Seperate include files for the i810/mga/r128 specific structures */
 #include "mga_drm.h"
 #include "i810_drm.h"
+#include "r128_drm.h"
 
 typedef struct drm_version {
        int    version_major;     /* Major version                          */
@@ -349,4 +349,12 @@ typedef struct drm_agp_info {
 #define DRM_IOCTL_I810_FLUSH   DRM_IO ( 0x43)
 #define DRM_IOCTL_I810_GETAGE  DRM_IO ( 0x44)
 
+/* Rage 128 specific ioctls */
+#define DRM_IOCTL_R128_INIT    DRM_IOW( 0x40, drm_r128_init_t)
+#define DRM_IOCTL_R128_RESET   DRM_IO(  0x41)
+#define DRM_IOCTL_R128_FLUSH   DRM_IO(  0x42)
+#define DRM_IOCTL_R128_CCEIDL  DRM_IO(  0x43)
+#define DRM_IOCTL_R128_PACKET  DRM_IOW( 0x44, drm_r128_packet_t)
+#define DRM_IOCTL_R128_VERTEX  DRM_IOW( 0x45, drm_r128_vertex_t)
+
 #endif
index ae4c65c..25e4cce 100644 (file)
@@ -1,8 +1,7 @@
 /* drm.h -- Header for Direct Rendering Manager -*- linux-c -*-
  * Created: Mon Jan  4 10:05:05 1999 by faith@precisioninsight.com
- * Revised: Mon Feb 14 00:15:23 2000 by kevin@precisioninsight.com
  *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
  * All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -71,9 +70,10 @@ typedef struct drm_clip_rect {
            unsigned short y2;
 } drm_clip_rect_t;
 
-/* Seperate include files for the i810/mga specific structures */
+/* Seperate include files for the i810/mga/r128 specific structures */
 #include "mga_drm.h"
 #include "i810_drm.h"
+#include "r128_drm.h"
 
 typedef struct drm_version {
        int    version_major;     /* Major version                          */
@@ -349,4 +349,12 @@ typedef struct drm_agp_info {
 #define DRM_IOCTL_I810_FLUSH   DRM_IO ( 0x43)
 #define DRM_IOCTL_I810_GETAGE  DRM_IO ( 0x44)
 
+/* Rage 128 specific ioctls */
+#define DRM_IOCTL_R128_INIT    DRM_IOW( 0x40, drm_r128_init_t)
+#define DRM_IOCTL_R128_RESET   DRM_IO(  0x41)
+#define DRM_IOCTL_R128_FLUSH   DRM_IO(  0x42)
+#define DRM_IOCTL_R128_CCEIDL  DRM_IO(  0x43)
+#define DRM_IOCTL_R128_PACKET  DRM_IOW( 0x44, drm_r128_packet_t)
+#define DRM_IOCTL_R128_VERTEX  DRM_IOW( 0x45, drm_r128_vertex_t)
+
 #endif