summaryrefslogtreecommitdiff
path: root/linux-core
diff options
context:
space:
mode:
Diffstat (limited to 'linux-core')
-rw-r--r--linux-core/Makefile.kernel4
-rw-r--r--linux-core/drmP.h485
-rw-r--r--linux-core/drm_agpsupport.c335
-rw-r--r--linux-core/drm_auth.c162
-rw-r--r--linux-core/drm_bufs.c757
-rw-r--r--linux-core/drm_context.c270
-rw-r--r--linux-core/drm_dma.c576
-rw-r--r--linux-core/drm_drawable.c51
-rw-r--r--linux-core/drm_drv.c927
-rw-r--r--linux-core/drm_fops.c252
-rw-r--r--linux-core/drm_init.c112
-rw-r--r--linux-core/drm_ioctl.c192
-rw-r--r--linux-core/drm_lock.c251
-rw-r--r--linux-core/drm_memory.h460
-rw-r--r--linux-core/drm_proc.c623
-rw-r--r--linux-core/drm_stub.c142
-rw-r--r--linux-core/drm_vm.c370
-rw-r--r--linux-core/i810_dma.c396
-rw-r--r--linux-core/i810_drv.c692
-rw-r--r--linux-core/i810_drv.h60
-rw-r--r--linux-core/mga_drv.c708
-rw-r--r--linux-core/r128_drv.c755
-rw-r--r--linux-core/radeon_drv.c759
-rw-r--r--linux-core/tdfx_drv.c691
24 files changed, 6263 insertions, 3767 deletions
diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel
index 9fe0038f..a39b3cc5 100644
--- a/linux-core/Makefile.kernel
+++ b/linux-core/Makefile.kernel
@@ -62,7 +62,7 @@ obj-$(CONFIG_DRM_MGA) += mga.o
obj-$(CONFIG_DRM_I810) += i810.o
-# When linking into the kernel, link the library just once.
+# When linking into the kernel, link the library just once.
# If making modules, we include the library into each module
lib-objs-mod := $(patsubst %.o,%-mod.o,$(lib-objs))
@@ -75,7 +75,7 @@ endif
include $(TOPDIR)/Rules.make
-$(patsubst %.o,%.c,$(lib-objs-mod)):
+$(patsubst %.o,%.c,$(lib-objs-mod)):
@ln -sf $(subst -mod,,$@) $@
drmlib-mod.a: $(lib-objs-mod)
diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index 9a8fe61f..58d98f50 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -19,14 +19,14 @@
* 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*
* Authors:
* Rickard E. (Rik) Faith <faith@valinux.com>
- *
+ * Gareth Hughes <gareth@valinux.com>
*/
#ifndef _DRM_P_H_
@@ -75,6 +75,32 @@
#endif
#include "drm.h"
+/* DRM template customization defaults
+ */
+#ifndef __HAVE_AGP
+#define __HAVE_AGP 0
+#endif
+#ifndef __HAVE_MTRR
+#define __HAVE_MTRR 0
+#endif
+#ifndef __HAVE_DMA
+#define __HAVE_DMA 0
+#endif
+#ifndef __HAVE_DMA_WAITLIST
+#define __HAVE_DMA_WAITLIST 0
+#endif
+#ifndef __HAVE_DMA_FREELIST
+#define __HAVE_DMA_FREELIST 0
+#endif
+
+#define __REALLY_HAVE_AGP (__HAVE_AGP && (defined(CONFIG_AGP) || \
+ defined(CONFIG_AGP_MODULE)))
+#define __REALLY_HAVE_MTRR (__HAVE_MTRR && defined(CONFIG_MTRR))
+
+
+/* Begin the DRM...
+ */
+
#define DRM_DEBUG_CODE 2 /* Include debugging code (if > 1, then
also include looping detection. */
#define DRM_DMA_HISTOGRAM 1 /* Make histogram of DMA latency. */
@@ -109,6 +135,7 @@
#define DRM_MEM_TOTALAGP 16
#define DRM_MEM_BOUNDAGP 17
#define DRM_MEM_CTXBITMAP 18
+#define DRM_MEM_STUB 19
#define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8)
@@ -259,16 +286,16 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
printk(KERN_ERR "[" DRM_NAME ":" __FUNCTION__ "] *ERROR* " fmt , ##arg)
#define DRM_MEM_ERROR(area, fmt, arg...) \
printk(KERN_ERR "[" DRM_NAME ":" __FUNCTION__ ":%s] *ERROR* " fmt , \
- drm_mem_stats[area].name , ##arg)
+ DRM(mem_stats)[area].name , ##arg)
#define DRM_INFO(fmt, arg...) printk(KERN_INFO "[" DRM_NAME "] " fmt , ##arg)
#if DRM_DEBUG_CODE
-#define DRM_DEBUG(fmt, arg...) \
- do { \
- if (drm_flags&DRM_FLAG_DEBUG) \
- printk(KERN_DEBUG \
- "[" DRM_NAME ":" __FUNCTION__ "] " fmt , \
- ##arg); \
+#define DRM_DEBUG(fmt, arg...) \
+ do { \
+ if ( DRM(flags) & DRM_FLAG_DEBUG ) \
+ printk(KERN_DEBUG \
+ "[" DRM_NAME ":" __FUNCTION__ "] " fmt , \
+ ##arg); \
} while (0)
#else
#define DRM_DEBUG(fmt, arg...) do { } while (0)
@@ -276,22 +303,22 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
#define DRM_PROC_LIMIT (PAGE_SIZE-80)
-#define DRM_PROC_PRINT(fmt, arg...) \
- len += sprintf(&buf[len], fmt , ##arg); \
- if (len > DRM_PROC_LIMIT) return len;
+#define DRM_PROC_PRINT(fmt, arg...) \
+ len += sprintf(&buf[len], fmt , ##arg); \
+ if (len > DRM_PROC_LIMIT) { *eof = 1; return len - offset; }
-#define DRM_PROC_PRINT_RET(ret, fmt, arg...) \
- len += sprintf(&buf[len], fmt , ##arg); \
- if (len > DRM_PROC_LIMIT) { ret; return len; }
+#define DRM_PROC_PRINT_RET(ret, fmt, arg...) \
+ len += sprintf(&buf[len], fmt , ##arg); \
+ if (len > DRM_PROC_LIMIT) { ret; *eof = 1; return len - offset; }
/* Mapping helper macros */
#define DRM_IOREMAP(map) \
- (map)->handle = drm_ioremap( (map)->offset, (map)->size )
+ (map)->handle = DRM(ioremap)( (map)->offset, (map)->size )
#define DRM_IOREMAPFREE(map) \
do { \
if ( (map)->handle && (map)->size ) \
- drm_ioremapfree( (map)->handle, (map)->size ); \
+ DRM(ioremapfree)( (map)->handle, (map)->size ); \
} while (0)
#define DRM_FIND_MAP(map, o) \
@@ -314,8 +341,8 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
#define DRM_BUFCOUNT(x) ((x)->count - DRM_LEFTCOUNT(x))
#define DRM_WAITCOUNT(dev,idx) DRM_BUFCOUNT(&dev->queuelist[idx]->waitlist)
-typedef int drm_ioctl_t(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+typedef int drm_ioctl_t( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg );
typedef struct drm_ioctl_desc {
drm_ioctl_t *func;
@@ -463,9 +490,11 @@ typedef struct drm_queue {
wait_queue_head_t read_queue; /* Processes waiting on block_read */
atomic_t block_write; /* Queue blocked for writes */
wait_queue_head_t write_queue; /* Processes waiting on block_write */
+#if 1
atomic_t total_queued; /* Total queued statistic */
atomic_t total_flushed;/* Total flushes statistic */
atomic_t total_locks; /* Total locks statistics */
+#endif
drm_ctx_flags_t flags; /* Context preserving and 2D-only */
drm_waitlist_t waitlist; /* Pending buffers */
wait_queue_head_t flush_queue; /* Processes waiting until flush */
@@ -479,6 +508,7 @@ typedef struct drm_lock_data {
} drm_lock_data_t;
typedef struct drm_device_dma {
+#if 0
/* Performance Counters */
atomic_t total_prio; /* Total DRM_DMA_PRIORITY */
atomic_t total_bytes; /* Total bytes DMA'd */
@@ -492,6 +522,7 @@ typedef struct drm_device_dma {
atomic_t total_tried; /* Tried next_buffer */
atomic_t total_hit; /* Sent next_buffer */
atomic_t total_lost; /* Lost interrupt */
+#endif
drm_buf_entry_t bufs[DRM_MAX_ORDER+1];
int buf_count;
@@ -501,7 +532,7 @@ typedef struct drm_device_dma {
unsigned long *pagelist;
unsigned long byte_count;
enum {
- _DRM_DMA_USE_AGP = 0x01
+ _DRM_DMA_USE_AGP = 0x01
} flags;
/* DMA support */
@@ -511,7 +542,7 @@ typedef struct drm_device_dma {
wait_queue_head_t waiting; /* Processes waiting on free bufs */
} drm_device_dma_t;
-#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+#if __REALLY_HAVE_AGP
typedef struct drm_agp_mem {
unsigned long handle;
agp_memory *memory;
@@ -559,17 +590,10 @@ typedef struct drm_device {
int buf_use; /* Buffers in use -- cannot alloc */
atomic_t buf_alloc; /* Buffer allocation in progress */
- /* Performance Counters */
- atomic_t total_open;
- atomic_t total_close;
- atomic_t total_ioctl;
- atomic_t total_irq; /* Total interruptions */
- atomic_t total_ctx; /* Total context switches */
-
- atomic_t total_locks;
- atomic_t total_unlocks;
- atomic_t total_contends;
- atomic_t total_sleeps;
+ /* Performance counters */
+ unsigned long counters;
+ drm_stat_type_t types[15];
+ atomic_t counts[15];
/* Authentication */
drm_file_t *file_first;
@@ -617,7 +641,7 @@ typedef struct drm_device {
wait_queue_head_t buf_readers; /* Processes waiting to read */
wait_queue_head_t buf_writers; /* Processes waiting to ctx switch */
-#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+#if __REALLY_HAVE_AGP
drm_agp_head_t *agp;
#endif
unsigned long *ctx_bitmap;
@@ -630,227 +654,262 @@ typedef struct drm_device {
/* Internal function definitions */
/* Misc. support (init.c) */
-extern int drm_flags;
-extern void drm_parse_options(char *s);
-extern int drm_cpu_valid(void);
+extern int DRM(flags);
+extern void DRM(parse_options)( char *s );
+extern int DRM(cpu_valid)( void );
+ /* Driver support (drm_drv.h) */
+extern int DRM(version)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int DRM(open)(struct inode *inode, struct file *filp);
+extern int DRM(release)(struct inode *inode, struct file *filp);
+extern int DRM(ioctl)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int DRM(lock)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int DRM(unlock)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
/* Device support (fops.c) */
-extern int drm_open_helper(struct inode *inode, struct file *filp,
- drm_device_t *dev);
-extern int drm_flush(struct file *filp);
-extern int drm_release(struct inode *inode, struct file *filp);
-extern int drm_fasync(int fd, struct file *filp, int on);
-extern ssize_t drm_read(struct file *filp, char *buf, size_t count,
- loff_t *off);
-extern int drm_write_string(drm_device_t *dev, const char *s);
-extern unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait);
+extern int DRM(open_helper)(struct inode *inode, struct file *filp,
+ drm_device_t *dev);
+extern int DRM(flush)(struct file *filp);
+extern int DRM(release_fuck)(struct inode *inode, struct file *filp);
+extern int DRM(fasync)(int fd, struct file *filp, int on);
+extern ssize_t DRM(read)(struct file *filp, char *buf, size_t count,
+ loff_t *off);
+extern int DRM(write_string)(drm_device_t *dev, const char *s);
+extern unsigned int DRM(poll)(struct file *filp,
+ struct poll_table_struct *wait);
/* Mapping support (vm.c) */
#if LINUX_VERSION_CODE < 0x020317
-extern unsigned long drm_vm_nopage(struct vm_area_struct *vma,
+extern unsigned long DRM(vm_nopage)(struct vm_area_struct *vma,
+ unsigned long address,
+ int write_access);
+extern unsigned long DRM(vm_shm_nopage)(struct vm_area_struct *vma,
+ unsigned long address,
+ int write_access);
+extern unsigned long DRM(vm_shm_nopage_lock)(struct vm_area_struct *vma,
+ unsigned long address,
+ int write_access);
+extern unsigned long DRM(vm_dma_nopage)(struct vm_area_struct *vma,
+ unsigned long address,
+ int write_access);
+#else
+ /* Return type changed in 2.3.23 */
+extern struct page *DRM(vm_nopage)(struct vm_area_struct *vma,
unsigned long address,
int write_access);
-extern unsigned long drm_vm_shm_nopage(struct vm_area_struct *vma,
+extern struct page *DRM(vm_shm_nopage)(struct vm_area_struct *vma,
unsigned long address,
int write_access);
-extern unsigned long drm_vm_shm_nopage_lock(struct vm_area_struct *vma,
+extern struct page *DRM(vm_shm_nopage_lock)(struct vm_area_struct *vma,
unsigned long address,
int write_access);
-extern unsigned long drm_vm_dma_nopage(struct vm_area_struct *vma,
+extern struct page *DRM(vm_dma_nopage)(struct vm_area_struct *vma,
unsigned long address,
int write_access);
-#else
- /* Return type changed in 2.3.23 */
-extern struct page *drm_vm_nopage(struct vm_area_struct *vma,
- unsigned long address,
- int write_access);
-extern struct page *drm_vm_shm_nopage(struct vm_area_struct *vma,
- unsigned long address,
- int write_access);
-extern struct page *drm_vm_shm_nopage_lock(struct vm_area_struct *vma,
- unsigned long address,
- int write_access);
-extern struct page *drm_vm_dma_nopage(struct vm_area_struct *vma,
- unsigned long address,
- int write_access);
-#endif
-extern void drm_vm_open(struct vm_area_struct *vma);
-extern void drm_vm_close(struct vm_area_struct *vma);
-extern int drm_mmap_dma(struct file *filp,
- struct vm_area_struct *vma);
-extern int drm_mmap(struct file *filp, struct vm_area_struct *vma);
+#endif
+extern void DRM(vm_open)(struct vm_area_struct *vma);
+extern void DRM(vm_close)(struct vm_area_struct *vma);
+extern int DRM(mmap_dma)(struct file *filp,
+ struct vm_area_struct *vma);
+extern int DRM(mmap)(struct file *filp, struct vm_area_struct *vma);
/* Proc support (proc.c) */
-extern int drm_proc_init(drm_device_t *dev);
-extern int drm_proc_cleanup(void);
+extern struct proc_dir_entry *drm_proc_init(drm_device_t *dev,
+ int minor,
+ struct proc_dir_entry *root,
+ struct proc_dir_entry **dev_root);
+extern int drm_proc_cleanup(int minor,
+ struct proc_dir_entry *root,
+ struct proc_dir_entry *dev_root);
/* Memory management support (memory.c) */
-extern void drm_mem_init(void);
-extern int drm_mem_info(char *buf, char **start, off_t offset,
- int len, int *eof, void *data);
-extern void *drm_alloc(size_t size, int area);
-extern void *drm_realloc(void *oldpt, size_t oldsize, size_t size,
- int area);
-extern char *drm_strdup(const char *s, int area);
-extern void drm_strfree(const char *s, int area);
-extern void drm_free(void *pt, size_t size, int area);
-extern unsigned long drm_alloc_pages(int order, int area);
-extern void drm_free_pages(unsigned long address, int order,
- int area);
-extern void *drm_ioremap(unsigned long offset, unsigned long size);
-extern void drm_ioremapfree(void *pt, unsigned long size);
-
-#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
-extern agp_memory *drm_alloc_agp(int pages, u32 type);
-extern int drm_free_agp(agp_memory *handle, int pages);
-extern int drm_bind_agp(agp_memory *handle, unsigned int start);
-extern int drm_unbind_agp(agp_memory *handle);
+extern void DRM(mem_init)(void);
+extern int DRM(mem_info)(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data);
+extern void *DRM(alloc)(size_t size, int area);
+extern void *DRM(realloc)(void *oldpt, size_t oldsize, size_t size,
+ int area);
+extern char *DRM(strdup)(const char *s, int area);
+extern void DRM(strfree)(const char *s, int area);
+extern void DRM(free)(void *pt, size_t size, int area);
+extern unsigned long DRM(alloc_pages)(int order, int area);
+extern void DRM(free_pages)(unsigned long address, int order,
+ int area);
+extern void *DRM(ioremap)(unsigned long offset, unsigned long size);
+extern void DRM(ioremapfree)(void *pt, unsigned long size);
+
+#if __REALLY_HAVE_AGP
+extern agp_memory *DRM(alloc_agp)(int pages, u32 type);
+extern int DRM(free_agp)(agp_memory *handle, int pages);
+extern int DRM(bind_agp)(agp_memory *handle, unsigned int start);
+extern int DRM(unbind_agp)(agp_memory *handle);
#endif
-
- /* Buffer management support (bufs.c) */
-extern int drm_order(unsigned long size);
-extern int drm_addmap(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_addbufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_infobufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_markbufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_freebufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_mapbufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-
-
- /* Buffer list management support (lists.c) */
-extern int drm_waitlist_create(drm_waitlist_t *bl, int count);
-extern int drm_waitlist_destroy(drm_waitlist_t *bl);
-extern int drm_waitlist_put(drm_waitlist_t *bl, drm_buf_t *buf);
-extern drm_buf_t *drm_waitlist_get(drm_waitlist_t *bl);
-
-extern int drm_freelist_create(drm_freelist_t *bl, int count);
-extern int drm_freelist_destroy(drm_freelist_t *bl);
-extern int drm_freelist_put(drm_device_t *dev, drm_freelist_t *bl,
- drm_buf_t *buf);
-extern drm_buf_t *drm_freelist_get(drm_freelist_t *bl, int block);
-
- /* DMA support (gen_dma.c) */
-extern void drm_dma_setup(drm_device_t *dev);
-extern void drm_dma_takedown(drm_device_t *dev);
-extern void drm_free_buffer(drm_device_t *dev, drm_buf_t *buf);
-extern void drm_reclaim_buffers(drm_device_t *dev, pid_t pid);
-extern int drm_context_switch(drm_device_t *dev, int old, int new);
-extern int drm_context_switch_complete(drm_device_t *dev, int new);
-extern void drm_clear_next_buffer(drm_device_t *dev);
-extern int drm_select_queue(drm_device_t *dev,
- void (*wrapper)(unsigned long));
-extern int drm_dma_enqueue(drm_device_t *dev, drm_dma_t *dma);
-extern int drm_dma_get_buffers(drm_device_t *dev, drm_dma_t *dma);
-#if DRM_DMA_HISTOGRAM
-extern int drm_histogram_slot(unsigned long count);
-extern void drm_histogram_compute(drm_device_t *dev, drm_buf_t *buf);
-#endif
-
-
/* Misc. IOCTL support (ioctl.c) */
-extern int drm_irq_busid(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_getunique(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_setunique(struct inode *inode, struct file *filp,
+extern int DRM(irq_busid)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int DRM(getunique)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int DRM(setunique)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int DRM(getmap)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int DRM(getclient)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int DRM(getstats)(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-
/* Context IOCTL support (context.c) */
-extern int drm_resctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_addctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_modctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_getctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_switchctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_newctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_rmctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-
+extern int DRM(resctx)( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg );
+extern int DRM(addctx)( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg );
+extern int DRM(modctx)( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg );
+extern int DRM(getctx)( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg );
+extern int DRM(switchctx)( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg );
+extern int DRM(newctx)( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg );
+extern int DRM(rmctx)( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg );
+
+extern int DRM(context_switch)(drm_device_t *dev, int old, int new);
+extern int DRM(context_switch_complete)(drm_device_t *dev, int new);
/* Drawable IOCTL support (drawable.c) */
-extern int drm_adddraw(struct inode *inode, struct file *filp,
+extern int DRM(adddraw)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int DRM(rmdraw)(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-extern int drm_rmdraw(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
/* Authentication IOCTL support (auth.c) */
-extern int drm_add_magic(drm_device_t *dev, drm_file_t *priv,
- drm_magic_t magic);
-extern int drm_remove_magic(drm_device_t *dev, drm_magic_t magic);
-extern int drm_getmagic(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_authmagic(struct inode *inode, struct file *filp,
+extern int DRM(add_magic)(drm_device_t *dev, drm_file_t *priv,
+ drm_magic_t magic);
+extern int DRM(remove_magic)(drm_device_t *dev, drm_magic_t magic);
+extern int DRM(getmagic)(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
+extern int DRM(authmagic)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
/* Locking IOCTL support (lock.c) */
-extern int drm_block(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_unblock(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_lock_take(__volatile__ unsigned int *lock,
- unsigned int context);
-extern int drm_lock_transfer(drm_device_t *dev,
- __volatile__ unsigned int *lock,
- unsigned int context);
-extern int drm_lock_free(drm_device_t *dev,
- __volatile__ unsigned int *lock,
- unsigned int context);
-extern int drm_finish(struct inode *inode, struct file *filp,
+extern int DRM(block)(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-extern int drm_flush_unblock(drm_device_t *dev, int context,
- drm_lock_flags_t flags);
-extern int drm_flush_block_and_flush(drm_device_t *dev, int context,
- drm_lock_flags_t flags);
-extern int drm_notifier(void *priv);
+extern int DRM(unblock)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int DRM(lock_take)(__volatile__ unsigned int *lock,
+ unsigned int context);
+extern int DRM(lock_transfer)(drm_device_t *dev,
+ __volatile__ unsigned int *lock,
+ unsigned int context);
+extern int DRM(lock_free)(drm_device_t *dev,
+ __volatile__ unsigned int *lock,
+ unsigned int context);
+extern int DRM(finish)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int DRM(flush_unblock)(drm_device_t *dev, int context,
+ drm_lock_flags_t flags);
+extern int DRM(flush_block_and_flush)(drm_device_t *dev, int context,
+ drm_lock_flags_t flags);
+extern int DRM(notifier)(void *priv);
/* Context Bitmap support (ctxbitmap.c) */
-extern int drm_ctxbitmap_init(drm_device_t *dev);
-extern void drm_ctxbitmap_cleanup(drm_device_t *dev);
-extern int drm_ctxbitmap_next(drm_device_t *dev);
-extern void drm_ctxbitmap_free(drm_device_t *dev, int ctx_handle);
+extern int DRM(ctxbitmap_init)( drm_device_t *dev );
+extern void DRM(ctxbitmap_cleanup)( drm_device_t *dev );
-#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+
+
+
+ /* Buffer management support (bufs.c) */
+extern int DRM(order)( unsigned long size );
+extern int DRM(addmap)( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg );
+extern int DRM(addbufs)( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg );
+extern int DRM(infobufs)( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg );
+extern int DRM(markbufs)( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg );
+extern int DRM(freebufs)( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg );
+extern int DRM(mapbufs)( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg );
+
+
+#if __HAVE_DMA
+ /* DMA support (dma.c) */
+extern int DRM(dma_setup)(drm_device_t *dev);
+extern void DRM(dma_takedown)(drm_device_t *dev);
+extern void DRM(free_buffer)(drm_device_t *dev, drm_buf_t *buf);
+extern void DRM(reclaim_buffers)(drm_device_t *dev, pid_t pid);
+extern void DRM(clear_next_buffer)(drm_device_t *dev);
+extern int DRM(select_queue)(drm_device_t *dev,
+ void (*wrapper)(unsigned long));
+extern int DRM(dma_enqueue)(drm_device_t *dev, drm_dma_t *dma);
+#if 0
+extern int DRM(dma_get_buffers)(drm_device_t *dev, drm_dma_t *dma);
+#endif
+#if DRM_DMA_HISTOGRAM
+extern int DRM(histogram_slot)(unsigned long count);
+extern void DRM(histogram_compute)(drm_device_t *dev, drm_buf_t *buf);
+#endif
+#endif
+
+ /* Buffer list management support (lists.c) */
+#if __HAVE_DMA_WAITLIST
+extern int DRM(waitlist_create)(drm_waitlist_t *bl, int count);
+extern int DRM(waitlist_destroy)(drm_waitlist_t *bl);
+extern int DRM(waitlist_put)(drm_waitlist_t *bl, drm_buf_t *buf);
+extern drm_buf_t *DRM(waitlist_get)(drm_waitlist_t *bl);
+#endif
+#if __HAVE_DMA_FREELIST
+extern int DRM(freelist_create)(drm_freelist_t *bl, int count);
+extern int DRM(freelist_destroy)(drm_freelist_t *bl);
+extern int DRM(freelist_put)(drm_device_t *dev, drm_freelist_t *bl,
+ drm_buf_t *buf);
+extern drm_buf_t *DRM(freelist_get)(drm_freelist_t *bl, int block);
+#endif
+
+#if __REALLY_HAVE_AGP
/* AGP/GART support (agpsupport.c) */
-extern drm_agp_head_t *drm_agp_init(void);
-extern void drm_agp_uninit(void);
-extern int drm_agp_acquire(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern void _drm_agp_release(void);
-extern int drm_agp_release(struct inode *inode, struct file *filp,
+extern drm_agp_head_t *DRM(agp_init)(void);
+extern void DRM(agp_uninit)(void);
+extern int DRM(agp_acquire)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern void DRM(agp_do_release)(void);
+extern int DRM(agp_release)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int DRM(agp_enable)(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-extern int drm_agp_enable(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_agp_info(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_agp_alloc(struct inode *inode, struct file *filp,
+extern int DRM(agp_info)(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-extern int drm_agp_free(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_agp_unbind(struct inode *inode, struct file *filp,
+extern int DRM(agp_alloc)(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-extern int drm_agp_bind(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern agp_memory *drm_agp_allocate_memory(size_t pages, u32 type);
-extern int drm_agp_free_memory(agp_memory *handle);
-extern int drm_agp_bind_memory(agp_memory *handle, off_t start);
-extern int drm_agp_unbind_memory(agp_memory *handle);
+extern int DRM(agp_free)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int DRM(agp_unbind)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int DRM(agp_bind)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern agp_memory *DRM(agp_allocate_memory)(size_t pages, u32 type);
+extern int DRM(agp_free_memory)(agp_memory *handle);
+extern int DRM(agp_bind_memory)(agp_memory *handle, off_t start);
+extern int DRM(agp_unbind_memory)(agp_memory *handle);
+
+ /* Stub support (drm_stub.h) */
+int DRM(stub_register)(const char *name,
+ struct file_operations *fops,
+ drm_device_t *dev);
+int DRM(stub_unregister)(int minor);
+
#endif
#endif
#endif
diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c
new file mode 100644
index 00000000..b070a59e
--- /dev/null
+++ b/linux-core/drm_agpsupport.c
@@ -0,0 +1,335 @@
+/* drm_agpsupport.h -- DRM support for AGP/GART backend -*- linux-c -*-
+ * Created: Mon Dec 13 09:56:45 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author:
+ * Rickard E. (Rik) Faith <faith@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include <linux/module.h>
+
+#if __REALLY_HAVE_AGP
+
+#if LINUX_VERSION_CODE < 0x020400
+#include "agpsupport-pre24.h"
+#else
+#define DRM_AGP_GET (drm_agp_t *)inter_module_get("drm_agp")
+#define DRM_AGP_PUT inter_module_put("drm_agp")
+#endif
+
+static const drm_agp_t *drm_agp = NULL;
+
+int DRM(agp_info)(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;
+ agp_kern_info *kern;
+ drm_agp_info_t info;
+
+ if (!dev->agp->acquired || !drm_agp->copy_info) return -EINVAL;
+
+ kern = &dev->agp->agp_info;
+ info.agp_version_major = kern->version.major;
+ info.agp_version_minor = kern->version.minor;
+ info.mode = kern->mode;
+ info.aperture_base = kern->aper_base;
+ info.aperture_size = kern->aper_size * 1024 * 1024;
+ info.memory_allowed = kern->max_memory << PAGE_SHIFT;
+ info.memory_used = kern->current_memory << PAGE_SHIFT;
+ info.id_vendor = kern->device->vendor;
+ info.id_device = kern->device->device;
+
+ if (copy_to_user((drm_agp_info_t *)arg, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+}
+
+int DRM(agp_acquire)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ int retcode;
+
+ if (dev->agp->acquired || !drm_agp->acquire) return -EINVAL;
+ if ((retcode = drm_agp->acquire())) return retcode;
+ dev->agp->acquired = 1;
+ return 0;
+}
+
+int DRM(agp_release)(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 (!dev->agp->acquired || !drm_agp->release) return -EINVAL;
+ drm_agp->release();
+ dev->agp->acquired = 0;
+ return 0;
+
+}
+
+void DRM(agp_do_release)(void)
+{
+ if (drm_agp->release) drm_agp->release();
+}
+
+int DRM(agp_enable)(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_agp_mode_t mode;
+
+ if (!dev->agp->acquired || !drm_agp->enable) return -EINVAL;
+
+ if (copy_from_user(&mode, (drm_agp_mode_t *)arg, sizeof(mode)))
+ return -EFAULT;
+
+ dev->agp->mode = mode.mode;
+ drm_agp->enable(mode.mode);
+ dev->agp->base = dev->agp->agp_info.aper_base;
+ dev->agp->enabled = 1;
+ return 0;
+}
+
+int DRM(agp_alloc)(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_agp_buffer_t request;
+ drm_agp_mem_t *entry;
+ agp_memory *memory;
+ unsigned long pages;
+ u32 type;
+
+ if (!dev->agp->acquired) return -EINVAL;
+ if (copy_from_user(&request, (drm_agp_buffer_t *)arg, sizeof(request)))
+ return -EFAULT;
+ if (!(entry = DRM(alloc)(sizeof(*entry), DRM_MEM_AGPLISTS)))
+ return -ENOMEM;
+
+ memset(entry, 0, sizeof(*entry));
+
+ pages = (request.size + PAGE_SIZE - 1) / PAGE_SIZE;
+ type = (u32) request.type;
+
+ if (!(memory = DRM(alloc_agp)(pages, type))) {
+ DRM(free)(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
+ return -ENOMEM;
+ }
+
+ entry->handle = (unsigned long)memory->memory;
+ entry->memory = memory;
+ entry->bound = 0;
+ entry->pages = pages;
+ entry->prev = NULL;
+ entry->next = dev->agp->memory;
+ if (dev->agp->memory) dev->agp->memory->prev = entry;
+ dev->agp->memory = entry;
+
+ request.handle = entry->handle;
+ request.physical = memory->physical;
+
+ if (copy_to_user((drm_agp_buffer_t *)arg, &request, sizeof(request))) {
+ dev->agp->memory = entry->next;
+ dev->agp->memory->prev = NULL;
+ DRM(free_agp)(memory, pages);
+ DRM(free)(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
+ return -EFAULT;
+ }
+ return 0;
+}
+
+static drm_agp_mem_t *DRM(agp_lookup_entry)(drm_device_t *dev,
+ unsigned long handle)
+{
+ drm_agp_mem_t *entry;
+
+ for (entry = dev->agp->memory; entry; entry = entry->next) {
+ if (entry->handle == handle) return entry;
+ }
+ return NULL;
+}
+
+int DRM(agp_unbind)(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_agp_binding_t request;
+ drm_agp_mem_t *entry;
+
+ if (!dev->agp->acquired) return -EINVAL;
+ if (copy_from_user(&request, (drm_agp_binding_t *)arg, sizeof(request)))
+ return -EFAULT;
+ if (!(entry = DRM(agp_lookup_entry)(dev, request.handle)))
+ return -EINVAL;
+ if (!entry->bound) return -EINVAL;
+ return DRM(unbind_agp)(entry->memory);
+}
+
+int DRM(agp_bind)(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_agp_binding_t request;
+ drm_agp_mem_t *entry;
+ int retcode;
+ int page;
+
+ if (!dev->agp->acquired || !drm_agp->bind_memory) return -EINVAL;
+ if (copy_from_user(&request, (drm_agp_binding_t *)arg, sizeof(request)))
+ return -EFAULT;
+ if (!(entry = DRM(agp_lookup_entry)(dev, request.handle)))
+ return -EINVAL;
+ if (entry->bound) return -EINVAL;
+ 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;
+}
+
+int DRM(agp_free)(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_agp_buffer_t request;
+ drm_agp_mem_t *entry;
+
+ if (!dev->agp->acquired) return -EINVAL;
+ if (copy_from_user(&request, (drm_agp_buffer_t *)arg, sizeof(request)))
+ return -EFAULT;
+ if (!(entry = DRM(agp_lookup_entry)(dev, request.handle)))
+ return -EINVAL;
+ if (entry->bound) DRM(unbind_agp)(entry->memory);
+
+ if (entry->prev) entry->prev->next = entry->next;
+ else dev->agp->memory = entry->next;
+ if (entry->next) entry->next->prev = entry->prev;
+ DRM(free_agp)(entry->memory, entry->pages);
+ DRM(free)(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
+ return 0;
+}
+
+drm_agp_head_t *DRM(agp_init)(void)
+{
+ drm_agp_head_t *head = NULL;
+
+ drm_agp = DRM_AGP_GET;
+ if (drm_agp) {
+ if (!(head = DRM(alloc)(sizeof(*head), DRM_MEM_AGPLISTS)))
+ return NULL;
+ memset((void *)head, 0, sizeof(*head));
+ drm_agp->copy_info(&head->agp_info);
+ if (head->agp_info.chipset == NOT_SUPPORTED) {
+ DRM(free)(head, sizeof(*head), DRM_MEM_AGPLISTS);
+ return NULL;
+ }
+ head->memory = NULL;
+ switch (head->agp_info.chipset) {
+ case INTEL_GENERIC: head->chipset = "Intel"; break;
+ case INTEL_LX: head->chipset = "Intel 440LX"; break;
+ case INTEL_BX: head->chipset = "Intel 440BX"; break;
+ case INTEL_GX: head->chipset = "Intel 440GX"; break;
+ case INTEL_I810: head->chipset = "Intel i810"; break;
+
+#if LINUX_VERSION_CODE >= 0x020400
+ case INTEL_I840: head->chipset = "Intel i840"; break;
+#endif
+
+ case VIA_GENERIC: head->chipset = "VIA"; break;
+ case VIA_VP3: head->chipset = "VIA VP3"; break;
+ case VIA_MVP3: head->chipset = "VIA MVP3"; break;
+
+#if LINUX_VERSION_CODE >= 0x020400
+ case VIA_MVP4: head->chipset = "VIA MVP4"; break;
+ case VIA_APOLLO_KX133: head->chipset = "VIA Apollo KX133";
+ break;
+ case VIA_APOLLO_KT133: head->chipset = "VIA Apollo KT133";
+ break;
+#endif
+
+ case VIA_APOLLO_PRO: head->chipset = "VIA Apollo Pro";
+ break;
+ case SIS_GENERIC: head->chipset = "SiS"; break;
+ case AMD_GENERIC: head->chipset = "AMD"; break;
+ case AMD_IRONGATE: head->chipset = "AMD Irongate"; break;
+ case ALI_GENERIC: head->chipset = "ALi"; break;
+ case ALI_M1541: head->chipset = "ALi M1541"; break;
+ default: head->chipset = "Unknown"; break;
+ }
+ DRM_INFO("AGP %d.%d on %s @ 0x%08lx %ZuMB\n",
+ head->agp_info.version.major,
+ head->agp_info.version.minor,
+ head->chipset,
+ head->agp_info.aper_base,
+ head->agp_info.aper_size);
+ }
+ return head;
+}
+
+void DRM(agp_uninit)(void)
+{
+ DRM_AGP_PUT;
+ drm_agp = NULL;
+}
+
+agp_memory *DRM(agp_allocate_memory)(size_t pages, u32 type)
+{
+ if (!drm_agp->allocate_memory) return NULL;
+ return drm_agp->allocate_memory(pages, type);
+}
+
+int DRM(agp_free_memory)(agp_memory *handle)
+{
+ if (!handle || !drm_agp->free_memory) return 0;
+ drm_agp->free_memory(handle);
+ return 1;
+}
+
+int DRM(agp_bind_memory)(agp_memory *handle, off_t start)
+{
+ if (!handle || !drm_agp->bind_memory) return -EINVAL;
+ return drm_agp->bind_memory(handle, start);
+}
+
+int DRM(agp_unbind_memory)(agp_memory *handle)
+{
+ if (!handle || !drm_agp->unbind_memory) return -EINVAL;
+ return drm_agp->unbind_memory(handle);
+}
+
+#endif /* __REALLY_HAVE_AGP */
diff --git a/linux-core/drm_auth.c b/linux-core/drm_auth.c
new file mode 100644
index 00000000..2636e617
--- /dev/null
+++ b/linux-core/drm_auth.c
@@ -0,0 +1,162 @@
+/* drm_auth.h -- IOCTLs for authentication -*- linux-c -*-
+ * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rickard E. (Rik) Faith <faith@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+static int DRM(hash_magic)(drm_magic_t magic)
+{
+ return magic & (DRM_HASH_SIZE-1);
+}
+
+static drm_file_t *DRM(find_file)(drm_device_t *dev, drm_magic_t magic)
+{
+ drm_file_t *retval = NULL;
+ drm_magic_entry_t *pt;
+ int hash = DRM(hash_magic)(magic);
+
+ down(&dev->struct_sem);
+ for (pt = dev->magiclist[hash].head; pt; pt = pt->next) {
+ if (pt->magic == magic) {
+ retval = pt->priv;
+ break;
+ }
+ }
+ up(&dev->struct_sem);
+ return retval;
+}
+
+int DRM(add_magic)(drm_device_t *dev, drm_file_t *priv, drm_magic_t magic)
+{
+ int hash;
+ drm_magic_entry_t *entry;
+
+ DRM_DEBUG("%d\n", magic);
+
+ hash = DRM(hash_magic)(magic);
+ entry = DRM(alloc)(sizeof(*entry), DRM_MEM_MAGIC);
+ if (!entry) return -ENOMEM;
+ entry->magic = magic;
+ entry->priv = priv;
+ entry->next = NULL;
+
+ down(&dev->struct_sem);
+ if (dev->magiclist[hash].tail) {
+ dev->magiclist[hash].tail->next = entry;
+ dev->magiclist[hash].tail = entry;
+ } else {
+ dev->magiclist[hash].head = entry;
+ dev->magiclist[hash].tail = entry;
+ }
+ up(&dev->struct_sem);
+
+ return 0;
+}
+
+int DRM(remove_magic)(drm_device_t *dev, drm_magic_t magic)
+{
+ drm_magic_entry_t *prev = NULL;
+ drm_magic_entry_t *pt;
+ int hash;
+
+ DRM_DEBUG("%d\n", magic);
+ hash = DRM(hash_magic)(magic);
+
+ down(&dev->struct_sem);
+ for (pt = dev->magiclist[hash].head; pt; prev = pt, pt = pt->next) {
+ if (pt->magic == magic) {
+ if (dev->magiclist[hash].head == pt) {
+ dev->magiclist[hash].head = pt->next;
+ }
+ if (dev->magiclist[hash].tail == pt) {
+ dev->magiclist[hash].tail = prev;
+ }
+ if (prev) {
+ prev->next = pt->next;
+ }
+ up(&dev->struct_sem);
+ return 0;
+ }
+ }
+ up(&dev->struct_sem);
+
+ DRM(free)(pt, sizeof(*pt), DRM_MEM_MAGIC);
+
+ return -EINVAL;
+}
+
+int DRM(getmagic)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ static drm_magic_t sequence = 0;
+ static spinlock_t lock = SPIN_LOCK_UNLOCKED;
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_auth_t auth;
+
+ /* Find unique magic */
+ if (priv->magic) {
+ auth.magic = priv->magic;
+ } else {
+ do {
+ spin_lock(&lock);
+ if (!sequence) ++sequence; /* reserve 0 */
+ auth.magic = sequence++;
+ spin_unlock(&lock);
+ } while (DRM(find_file)(dev, auth.magic));
+ priv->magic = auth.magic;
+ DRM(add_magic)(dev, priv, auth.magic);
+ }
+
+ DRM_DEBUG("%u\n", auth.magic);
+ if (copy_to_user((drm_auth_t *)arg, &auth, sizeof(auth)))
+ return -EFAULT;
+ return 0;
+}
+
+int DRM(authmagic)(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_auth_t auth;
+ drm_file_t *file;
+
+ if (copy_from_user(&auth, (drm_auth_t *)arg, sizeof(auth)))
+ return -EFAULT;
+ DRM_DEBUG("%u\n", auth.magic);
+ if ((file = DRM(find_file)(dev, auth.magic))) {
+ file->authenticated = 1;
+ DRM(remove_magic)(dev, auth.magic);
+ return 0;
+ }
+ return -EINVAL;
+}
diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c
new file mode 100644
index 00000000..f2613a98
--- /dev/null
+++ b/linux-core/drm_bufs.c
@@ -0,0 +1,757 @@
+/* drm_bufs.h -- Generic buffer template -*- linux-c -*-
+ * Created: Thu Nov 23 03:10:50 2000 by gareth@valinux.com
+ *
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rickard E. (Rik) Faith <faith@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+#ifndef __HAVE_PCI_DMA
+#define __HAVE_PCI_DMA 0
+#endif
+
+#ifndef DRIVER_BUF_PRIV_T
+#define DRIVER_BUF_PRIV_T u32
+#endif
+#ifndef DRIVER_AGP_BUFFERS_MAP
+#if __HAVE_AGP && __HAVE_DMA
+#error "You must define DRIVER_AGP_BUFFERS_MAP()"
+#else
+#define DRIVER_AGP_BUFFERS_MAP( dev ) NULL
+#endif
+#endif
+
+/*
+ * Compute order. Can be made faster.
+ */
+int DRM(order)( unsigned long size )
+{
+ int order;
+ unsigned long tmp;
+
+ for ( order = 0, tmp = size ; tmp >>= 1 ; ++order );
+
+ if ( size & ~(1 << order) )
+ ++order;
+
+ return order;
+}
+
+int DRM(addmap)( 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_map_t *map;
+
+ if ( !(filp->f_mode & 3) ) return -EACCES; /* Require read/write */
+
+ map = DRM(alloc)( sizeof(*map), DRM_MEM_MAPS );
+ if ( !map )
+ return -ENOMEM;
+
+ if ( copy_from_user( map, (drm_map_t *)arg, sizeof(*map) ) ) {
+ DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
+ return -EFAULT;
+ }
+
+ DRM_DEBUG( "offset = 0x%08lx, size = 0x%08lx, type = %d\n",
+ map->offset, map->size, map->type );
+ if ( (map->offset & (~PAGE_MASK)) || (map->size & (~PAGE_MASK)) ) {
+ DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
+ return -EINVAL;
+ }
+ map->mtrr = -1;
+ map->handle = 0;
+
+ switch ( map->type ) {
+ case _DRM_REGISTERS:
+ case _DRM_FRAME_BUFFER:
+#ifndef __sparc__
+ if ( map->offset + map->size < map->offset ||
+ map->offset < virt_to_phys(high_memory) ) {
+ DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
+ return -EINVAL;
+ }
+#endif
+#ifdef CONFIG_MTRR
+ if ( map->type == _DRM_FRAME_BUFFER ||
+ (map->flags & _DRM_WRITE_COMBINING) ) {
+ map->mtrr = mtrr_add( map->offset, map->size,
+ MTRR_TYPE_WRCOMB, 1 );
+ }
+#endif
+ map->handle = DRM(ioremap)( map->offset, map->size );
+ break;
+
+ case _DRM_SHM:
+ map->handle = (void *)DRM(alloc_pages)( DRM(order)( map->size )
+ - PAGE_SHIFT,
+ DRM_MEM_SAREA );
+ DRM_DEBUG( "%ld %d %p\n",
+ map->size, DRM(order)( map->size ), map->handle );
+ if ( !map->handle ) {
+ DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
+ return -ENOMEM;
+ }
+ map->offset = (unsigned long)map->handle;
+ if ( map->flags & _DRM_CONTAINS_LOCK ) {
+ dev->lock.hw_lock = map->handle; /* Pointer to lock */
+ }
+ break;
+#if __REALLY_HAVE_AGP
+ case _DRM_AGP:
+ map->offset = map->offset + dev->agp->base;
+ break;
+#endif
+ default:
+ DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
+ return -EINVAL;
+ }
+
+ down( &dev->struct_sem );
+ if ( dev->maplist ) {
+ ++dev->map_count;
+ dev->maplist = DRM(realloc)( dev->maplist,
+ (dev->map_count-1)
+ * sizeof(*dev->maplist),
+ dev->map_count
+ * sizeof(*dev->maplist),
+ DRM_MEM_MAPS );
+ } else {
+ dev->map_count = 1;
+ dev->maplist = DRM(alloc)( dev->map_count*sizeof(*dev->maplist),
+ DRM_MEM_MAPS );
+ }
+ dev->maplist[dev->map_count-1] = map;
+ up( &dev->struct_sem );
+
+ if ( copy_to_user( (drm_map_t *)arg, map, sizeof(*map) ) )
+ return -EFAULT;
+ if ( map->type != _DRM_SHM ) {
+ if ( copy_to_user( &((drm_map_t *)arg)->handle,
+ &map->offset,
+ sizeof(map->offset) ) )
+ return -EFAULT;
+ }
+ return 0;
+}
+
+#if __HAVE_DMA
+
+#if __REALLY_HAVE_AGP
+int DRM(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;
+
+ if ( copy_from_user( &request, (drm_buf_desc_t *)arg,
+ sizeof(request) ) )
+ return -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;
+
+ while ( entry->buf_count < count ) {
+ buf = &entry->buflist[entry->buf_count];
+ buf->idx = dma->buf_count + entry->buf_count;
+ buf->total = alignment;
+ buf->order = order;
+ buf->used = 0;
+
+ buf->offset = (dma->byte_count + offset); /* ******** */
+ buf->bus_address = agp_offset + offset;
+ buf->address = (void *)(agp_offset + offset);
+ buf->next = NULL;
+ buf->waiting = 0;
+ buf->pending = 0;
+ init_waitqueue_head( &buf->dma_wait );
+ buf->pid = 0;
+
+ buf->dev_priv_size = sizeof(DRIVER_BUF_PRIV_T);
+ buf->dev_private = DRM(alloc)( sizeof(DRIVER_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
+ DRM_DEBUG( "buffer %d @ %p\n",
+ entry->buf_count, buf->address );
+
+ offset += alignment;
+ entry->buf_count++;
+ byte_count += PAGE_SIZE << page_order;
+ }
+
+ DRM_DEBUG( "byte_count: %d\n", byte_count );
+
+ 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 = 0 ; i < entry->buf_count ; i++ ) {
+ dma->buflist[i + dma->buf_count] = &entry->buflist[i];
+ }
+
+ dma->buf_count += entry->buf_count;
+ dma->byte_count += byte_count;
+
+ DRM_DEBUG( "dma->buf_count : %d\n", dma->buf_count );
+ DRM_DEBUG( "entry->buf_count : %d\n", entry->buf_count );
+
+/* GH: Please leave this disabled for now. I need to fix this properly...
+ */
+#if 0
+ /* FIXME: work this mess out...
+ */
+ 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] );
+ }
+#endif
+
+ up( &dev->struct_sem );
+
+ request.count = entry->buf_count;
+ request.size = size;
+
+ if ( copy_to_user( (drm_buf_desc_t *)arg, &request, sizeof(request) ) )
+ return -EFAULT;
+
+ dma->flags = _DRM_DMA_USE_AGP;
+
+ atomic_dec( &dev->buf_alloc );
+ return 0;
+}
+#endif /* __REALLY_HAVE_AGP */
+
+#if __HAVE_PCI_DMA
+int DRM(addbufs_pci)( 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;
+ int count;
+ int order;
+ int size;
+ int total;
+ int page_order;
+ drm_buf_entry_t *entry;
+ unsigned long page;
+ drm_buf_t *buf;
+ int alignment;
+ unsigned long offset;
+ int i;
+ int byte_count;
+ int page_count;
+
+ if ( !dma ) return -EINVAL;
+
+ if ( copy_from_user( &request, (drm_buf_desc_t *)arg,
+ sizeof(request) ) )
+ return -EFAULT;
+
+ count = request.count;
+ order = DRM(order)( request.size );
+ size = 1 << order;
+
+ DRM_DEBUG( "count=%d, size=%d (%d), order=%d, queue_count=%d\n",
+ request.count, request.size, size,
+ order, dev->queue_count );
+
+ if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) return -EINVAL;
+ if ( dev->queue_count ) return -EBUSY; /* Not while in use */
+
+ alignment = (request.flags & _DRM_PAGE_ALIGN)
+ ? PAGE_ALIGN(size) : size;
+ page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
+ total = PAGE_SIZE << page_order;
+
+ 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->seglist = DRM(alloc)( count * sizeof(*entry->seglist),
+ DRM_MEM_SEGS );
+ if ( !entry->seglist ) {
+ DRM(free)( entry->buflist,
+ count * sizeof(*entry->buflist),
+ DRM_MEM_BUFS );
+ up( &dev->struct_sem );
+ atomic_dec( &dev->buf_alloc );
+ return -ENOMEM;
+ }
+ memset( entry->seglist, 0, count * sizeof(*entry->seglist) );
+
+ dma->pagelist = DRM(realloc)( dma->pagelist,
+ dma->page_count * sizeof(*dma->pagelist),
+ (dma->page_count + (count << page_order))
+ * sizeof(*dma->pagelist),
+ DRM_MEM_PAGES );
+ DRM_DEBUG( "pagelist: %d entries\n",
+ dma->page_count + (count << page_order) );
+
+ entry->buf_size = size;
+ entry->page_order = page_order;
+ byte_count = 0;
+ page_count = 0;
+
+ while ( entry->buf_count < count ) {
+ page = DRM(alloc_pages)( page_order, DRM_MEM_DMA );
+ if ( !page ) break;
+ entry->seglist[entry->seg_count++] = page;
+ for ( i = 0 ; i < (1 << page_order) ; i++ ) {
+ DRM_DEBUG( "page %d @ 0x%08lx\n",
+ dma->page_count + page_count,
+ page + PAGE_SIZE * i );
+ dma->pagelist[dma->page_count + page_count++]
+ = page + PAGE_SIZE * i;
+ }
+ for ( offset = 0 ;
+ offset + size <= total && 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 + byte_count + offset);
+ buf->address = (void *)(page + offset);
+ buf->next = NULL;
+ buf->waiting = 0;
+ buf->pending = 0;
+ init_waitqueue_head( &buf->dma_wait );
+ buf->pid = 0;
+#if DRM_DMA_HISTOGRAM
+ buf->time_queued = 0;
+ buf->time_dispatched = 0;
+ buf->time_completed = 0;
+ buf->time_freed = 0;
+#endif
+ DRM_DEBUG( "buffer %d @ %p\n",
+ entry->buf_count, buf->address );
+ }
+ byte_count += PAGE_SIZE << page_order;
+ }
+
+ 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 = 0 ; i < entry->buf_count ; i++ ) {
+ dma->buflist[i + dma->buf_count] = &entry->buflist[i];
+ }
+
+ dma->buf_count += entry->buf_count;
+ dma->seg_count += entry->seg_count;
+ dma->page_count += entry->seg_count << page_order;
+ dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order);
+
+/* GH: Please leave this disabled for now. I need to fix this properly...
+ */
+#if 0
+ /* FIXME: work this mess out...
+ */
+ 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] );
+ }
+#endif
+
+ up( &dev->struct_sem );
+
+ request.count = entry->buf_count;
+ request.size = size;
+
+ if ( copy_to_user( (drm_buf_desc_t *)arg, &request, sizeof(request) ) )
+ return -EFAULT;
+
+ atomic_dec( &dev->buf_alloc );
+ return 0;
+}
+#endif /* __HAVE_PCI_DMA */
+
+int DRM(addbufs)( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg )
+{
+ drm_buf_desc_t request;
+
+ if ( copy_from_user( &request, (drm_buf_desc_t *)arg,
+ sizeof(request) ) )
+ return -EFAULT;
+
+#if __REALLY_HAVE_AGP
+ if ( request.flags & _DRM_AGP_BUFFER )
+ return DRM(addbufs_agp)( inode, filp, cmd, arg );
+ else
+#endif
+#if __HAVE_PCI_DMA
+ return DRM(addbufs_pci)( inode, filp, cmd, arg );
+#else
+ return -EINVAL;
+#endif
+}
+
+int DRM(infobufs)( 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_info_t request;
+ int i;
+ int count;
+
+ if ( !dma ) return -EINVAL;
+
+ 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 );
+
+ if ( copy_from_user( &request,
+ (drm_buf_info_t *)arg,
+ sizeof(request) ) )
+ return -EFAULT;
+
+ for ( i = 0, count = 0 ; i < DRM_MAX_ORDER + 1 ; i++ ) {
+ if ( dma->bufs[i].buf_count ) ++count;
+ }
+
+ DRM_DEBUG( "count = %d\n", count );
+
+ if ( request.count >= count ) {
+ for ( i = 0, count = 0 ; i < DRM_MAX_ORDER + 1 ; i++ ) {
+ if ( dma->bufs[i].buf_count ) {
+ drm_buf_desc_t *to = &request.list[count];
+ drm_buf_entry_t *from = &dma->bufs[i];
+ drm_freelist_t *list = &dma->bufs[i].freelist;
+ if ( copy_to_user( &to->count,
+ &from->buf_count,
+ sizeof(from->buf_count) ) ||
+ copy_to_user( &to->size,
+ &from->buf_size,
+ sizeof(from->buf_size) ) ||
+ copy_to_user( &to->low_mark,
+ &list->low_mark,
+ sizeof(list->low_mark) ) ||
+ copy_to_user( &to->high_mark,
+ &list->high_mark,
+ sizeof(list->high_mark) ) )
+ return -EFAULT;
+
+ DRM_DEBUG( "%d %d %d %d %d\n",
+ i,
+ dma->bufs[i].buf_count,
+ dma->bufs[i].buf_size,
+ dma->bufs[i].freelist.low_mark,
+ dma->bufs[i].freelist.high_mark );
+ ++count;
+ }
+ }
+ }
+ request.count = count;
+
+ if ( copy_to_user( (drm_buf_info_t *)arg,
+ &request,
+ sizeof(request) ) )
+ return -EFAULT;
+
+ return 0;
+}
+
+int DRM(markbufs)( 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;
+ int order;
+ drm_buf_entry_t *entry;
+
+ if ( !dma ) return -EINVAL;
+
+ if ( copy_from_user( &request,
+ (drm_buf_desc_t *)arg,
+ sizeof(request) ) )
+ return -EFAULT;
+
+ DRM_DEBUG( "%d, %d, %d\n",
+ request.size, request.low_mark, request.high_mark );
+ order = DRM(order)( request.size );
+ if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) return -EINVAL;
+ entry = &dma->bufs[order];
+
+ if ( request.low_mark < 0 || request.low_mark > entry->buf_count )
+ return -EINVAL;
+ if ( request.high_mark < 0 || request.high_mark > entry->buf_count )
+ return -EINVAL;
+
+ entry->freelist.low_mark = request.low_mark;
+ entry->freelist.high_mark = request.high_mark;
+
+ return 0;
+}
+
+int DRM(freebufs)( 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_free_t request;
+ int i;
+ int idx;
+ drm_buf_t *buf;
+
+ if ( !dma ) return -EINVAL;
+
+ if ( copy_from_user( &request,
+ (drm_buf_free_t *)arg,
+ sizeof(request) ) )
+ return -EFAULT;
+
+ DRM_DEBUG( "%d\n", request.count );
+ for ( i = 0 ; i < request.count ; i++ ) {
+ if ( copy_from_user( &idx,
+ &request.list[i],
+ sizeof(idx) ) )
+ return -EFAULT;
+ 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 freeing buffer owned by %d\n",
+ current->pid, buf->pid );
+ return -EINVAL;
+ }
+ DRM(free_buffer)( dev, buf );
+ }
+
+ return 0;
+}
+
+int DRM(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_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 ) return -EINVAL;
+
+ 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 );
+
+ if ( copy_from_user( &request, (drm_buf_map_t *)arg,
+ sizeof(request) ) )
+ return -EFAULT;
+
+ if ( request.count >= dma->buf_count ) {
+ if ( __HAVE_AGP && (dma->flags & _DRM_DMA_USE_AGP) ) {
+ drm_map_t *map = DRIVER_AGP_BUFFERS_MAP( dev );
+
+ 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 );
+
+ if ( copy_to_user( (drm_buf_map_t *)arg, &request, sizeof(request) ) )
+ return -EFAULT;
+
+ return retcode;
+}
+
+#endif /* __HAVE_DMA */
diff --git a/linux-core/drm_context.c b/linux-core/drm_context.c
new file mode 100644
index 00000000..6bbcfca8
--- /dev/null
+++ b/linux-core/drm_context.c
@@ -0,0 +1,270 @@
+/* drm_context.h -- IOCTLs for generic contexts -*- linux-c -*-
+ * Created: Fri Nov 24 18:31:37 2000 by gareth@valinux.com
+ *
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rickard E. (Rik) Faith <faith@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ */
+
+/* ================================================================
+ * Context bitmap support
+ */
+
+void DRM(ctxbitmap_free)( drm_device_t *dev, int ctx_handle )
+{
+ if ( ctx_handle < 0 ) goto failed;
+
+ if ( ctx_handle < DRM_MAX_CTXBITMAP ) {
+ clear_bit( ctx_handle, dev->ctx_bitmap );
+ return;
+ }
+failed:
+ DRM_ERROR( "Attempt to free invalid context handle: %d\n",
+ ctx_handle );
+ return;
+}
+
+int DRM(ctxbitmap_next)( drm_device_t *dev )
+{
+ int bit;
+
+ bit = find_first_zero_bit( dev->ctx_bitmap, DRM_MAX_CTXBITMAP );
+ if ( bit < DRM_MAX_CTXBITMAP ) {
+ set_bit( bit, dev->ctx_bitmap );
+ DRM_DEBUG( "drm_ctxbitmap_next bit : %d\n", bit );
+ return bit;
+ }
+ return -1;
+}
+
+int DRM(ctxbitmap_init)( drm_device_t *dev )
+{
+ int i;
+ int temp;
+
+ dev->ctx_bitmap = (unsigned long *) DRM(alloc)( PAGE_SIZE,
+ DRM_MEM_CTXBITMAP );
+ if ( dev->ctx_bitmap == NULL ) {
+ return -ENOMEM;
+ }
+ memset( (void *)dev->ctx_bitmap, 0, PAGE_SIZE );
+ for ( i = 0 ; i < DRM_RESERVED_CONTEXTS ; i++ ) {
+ temp = DRM(ctxbitmap_next)( dev );
+ DRM_DEBUG( "drm_ctxbitmap_init : %d\n", temp );
+ }
+
+ return 0;
+}
+
+void DRM(ctxbitmap_cleanup)( drm_device_t *dev )
+{
+ DRM(free)( (void *)dev->ctx_bitmap, PAGE_SIZE, DRM_MEM_CTXBITMAP );
+}
+
+
+/* ================================================================
+ * The actual DRM context handling routines
+ */
+
+int DRM(context_switch)( drm_device_t *dev, int old, int new )
+{
+ char buf[64];
+
+ 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 ) {
+ DRM(context_switch_complete)( dev, new );
+ } else {
+ sprintf( buf, "C %d %d\n", old, new );
+ DRM(write_string)( dev, buf );
+ }
+
+ return 0;
+}
+
+int DRM(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 DRM(resctx)( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg )
+{
+ drm_ctx_res_t res;
+ drm_ctx_t ctx;
+ int i;
+
+ if ( copy_from_user( &res, (drm_ctx_res_t *)arg, sizeof(res) ) )
+ return -EFAULT;
+
+ if ( res.count >= DRM_RESERVED_CONTEXTS ) {
+ memset( &ctx, 0, sizeof(ctx) );
+ for ( i = 0 ; i < DRM_RESERVED_CONTEXTS ; i++ ) {
+ ctx.handle = i;
+ if ( copy_to_user( &res.contexts[i],
+ &i, sizeof(i) ) )
+ return -EFAULT;
+ }
+ }
+ res.count = DRM_RESERVED_CONTEXTS;
+
+ if ( copy_to_user( (drm_ctx_res_t *)arg, &res, sizeof(res) ) )
+ return -EFAULT;
+ return 0;
+}
+
+int DRM(addctx)( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg )
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_ctx_t ctx;
+
+ if ( copy_from_user( &ctx, (drm_ctx_t *)arg, sizeof(ctx) ) )
+ return -EFAULT;
+
+ ctx.handle = DRM(ctxbitmap_next)( dev );
+ if ( ctx.handle == DRM_KERNEL_CONTEXT ) {
+ /* Skip kernel's context and get a new one. */
+ ctx.handle = DRM(ctxbitmap_next)( 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;
+ }
+
+ if ( copy_to_user( (drm_ctx_t *)arg, &ctx, sizeof(ctx) ) )
+ return -EFAULT;
+ return 0;
+}
+
+int DRM(modctx)( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg )
+{
+ /* This does nothing */
+ return 0;
+}
+
+int DRM(getctx)( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg )
+{
+ drm_ctx_t ctx;
+
+ if ( copy_from_user( &ctx, (drm_ctx_t*)arg, sizeof(ctx) ) )
+ return -EFAULT;
+
+ /* This is 0, because we don't handle any context flags */
+ ctx.flags = 0;
+
+ if ( copy_to_user( (drm_ctx_t*)arg, &ctx, sizeof(ctx) ) )
+ return -EFAULT;
+ return 0;
+}
+
+int DRM(switchctx)( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg )
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_ctx_t ctx;
+
+ if ( copy_from_user( &ctx, (drm_ctx_t *)arg, sizeof(ctx) ) )
+ return -EFAULT;
+
+ DRM_DEBUG( "%d\n", ctx.handle );
+ return DRM(context_switch)( dev, dev->last_context, ctx.handle );
+}
+
+int DRM(newctx)( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg )
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_ctx_t ctx;
+
+ if ( copy_from_user( &ctx, (drm_ctx_t *)arg, sizeof(ctx) ) )
+ return -EFAULT;
+
+ DRM_DEBUG( "%d\n", ctx.handle );
+ DRM(context_switch_complete)( dev, ctx.handle );
+
+ return 0;
+}
+
+int DRM(rmctx)( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg )
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_ctx_t ctx;
+
+ if ( copy_from_user( &ctx, (drm_ctx_t *)arg, sizeof(ctx) ) )
+ return -EFAULT;
+
+ DRM_DEBUG( "%d\n", ctx.handle );
+ if ( ctx.handle == DRM_KERNEL_CONTEXT + 1 ) {
+ priv->remove_auth_on_close = 1;
+ }
+ if ( ctx.handle != DRM_KERNEL_CONTEXT ) {
+ DRM(ctxbitmap_free)( dev, ctx.handle );
+ }
+
+ return 0;
+}
diff --git a/linux-core/drm_dma.c b/linux-core/drm_dma.c
new file mode 100644
index 00000000..35eb896e
--- /dev/null
+++ b/linux-core/drm_dma.c
@@ -0,0 +1,576 @@
+/* drm_dma.c -- DMA IOCTL and function support -*- linux-c -*-
+ * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com
+ *
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rickard E. (Rik) Faith <faith@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+#include <linux/interrupt.h> /* For task queue support */
+
+#ifndef __HAVE_DMA_WAITQUEUE
+#define __HAVE_DMA_WAITQUEUE 0
+#endif
+#ifndef __HAVE_DMA_RECLAIM
+#define __HAVE_DMA_RECLAIM 0
+#endif
+
+#if __HAVE_DMA
+
+int DRM(dma_setup)( drm_device_t *dev )
+{
+ int i;
+
+ dev->dma = DRM(alloc)( sizeof(*dev->dma), DRM_MEM_DRIVER );
+ if ( !dev->dma )
+ return -ENOMEM;
+
+ memset( dev->dma, 0, sizeof(*dev->dma) );
+
+ for ( i = 0 ; i <= DRM_MAX_ORDER ; i++ )
+ memset(&dev->dma->bufs[i], 0, sizeof(dev->dma->bufs[0]));
+
+ return 0;
+}
+
+void DRM(dma_takedown)(drm_device_t *dev)
+{
+ drm_device_dma_t *dma = dev->dma;
+ int i, j;
+
+ if (!dma) return;
+
+ /* Clear dma buffers */
+ for (i = 0; i <= DRM_MAX_ORDER; i++) {
+ if (dma->bufs[i].seg_count) {
+ DRM_DEBUG("order %d: buf_count = %d,"
+ " seg_count = %d\n",
+ i,
+ dma->bufs[i].buf_count,
+ dma->bufs[i].seg_count);
+ for (j = 0; j < dma->bufs[i].seg_count; j++) {
+ DRM(free_pages)(dma->bufs[i].seglist[j],
+ dma->bufs[i].page_order,
+ DRM_MEM_DMA);
+ }
+ DRM(free)(dma->bufs[i].seglist,
+ dma->bufs[i].seg_count
+ * sizeof(*dma->bufs[0].seglist),
+ DRM_MEM_SEGS);
+ }
+ if(dma->bufs[i].buf_count) {
+ for(j = 0; j < dma->bufs[i].buf_count; j++) {
+ if(dma->bufs[i].buflist[j].dev_private) {
+ DRM(free)(dma->bufs[i].buflist[j].dev_private,
+ dma->bufs[i].buflist[j].dev_priv_size,
+ DRM_MEM_BUFS);
+ }
+ }
+ DRM(free)(dma->bufs[i].buflist,
+ dma->bufs[i].buf_count *
+ sizeof(*dma->bufs[0].buflist),
+ DRM_MEM_BUFS);
+#if __HAVE_DMA_FREELIST
+ DRM(freelist_destroy)(&dma->bufs[i].freelist);
+#endif
+ }
+ }
+
+ if (dma->buflist) {
+ DRM(free)(dma->buflist,
+ dma->buf_count * sizeof(*dma->buflist),
+ DRM_MEM_BUFS);
+ }
+
+ if (dma->pagelist) {
+ DRM(free)(dma->pagelist,
+ dma->page_count * sizeof(*dma->pagelist),
+ DRM_MEM_PAGES);
+ }
+ DRM(free)(dev->dma, sizeof(*dev->dma), DRM_MEM_DRIVER);
+ dev->dma = NULL;
+}
+
+
+#if DRM_DMA_HISTOGRAM
+/* This is slow, but is useful for debugging. */
+int DRM(histogram_slot)(unsigned long count)
+{
+ int value = DRM_DMA_HISTOGRAM_INITIAL;
+ int slot;
+
+ for (slot = 0;
+ slot < DRM_DMA_HISTOGRAM_SLOTS;
+ ++slot, value = DRM_DMA_HISTOGRAM_NEXT(value)) {
+ if (count < value) return slot;
+ }
+ return DRM_DMA_HISTOGRAM_SLOTS - 1;
+}
+
+void DRM(histogram_compute)(drm_device_t *dev, drm_buf_t *buf)
+{
+ cycles_t queued_to_dispatched;
+ cycles_t dispatched_to_completed;
+ cycles_t completed_to_freed;
+ int q2d, d2c, c2f, q2c, q2f;
+
+ if (buf->time_queued) {
+ queued_to_dispatched = (buf->time_dispatched
+ - buf->time_queued);
+ dispatched_to_completed = (buf->time_completed
+ - buf->time_dispatched);
+ completed_to_freed = (buf->time_freed
+ - buf->time_completed);
+
+ q2d = DRM(histogram_slot)(queued_to_dispatched);
+ d2c = DRM(histogram_slot)(dispatched_to_completed);
+ c2f = DRM(histogram_slot)(completed_to_freed);
+
+ q2c = DRM(histogram_slot)(queued_to_dispatched
+ + dispatched_to_completed);
+ q2f = DRM(histogram_slot)(queued_to_dispatched
+ + dispatched_to_completed
+ + completed_to_freed);
+
+ atomic_inc(&dev->histo.total);
+ atomic_inc(&dev->histo.queued_to_dispatched[q2d]);
+ atomic_inc(&dev->histo.dispatched_to_completed[d2c]);
+ atomic_inc(&dev->histo.completed_to_freed[c2f]);
+
+ atomic_inc(&dev->histo.queued_to_completed[q2c]);
+ atomic_inc(&dev->histo.queued_to_freed[q2f]);
+
+ }
+ buf->time_queued = 0;
+ buf->time_dispatched = 0;
+ buf->time_completed = 0;
+ buf->time_freed = 0;
+}
+#endif
+
+void DRM(free_buffer)(drm_device_t *dev, drm_buf_t *buf)
+{
+ if (!buf) return;
+
+ buf->waiting = 0;
+ buf->pending = 0;
+ buf->pid = 0;
+ buf->used = 0;
+#if DRM_DMA_HISTOGRAM
+ buf->time_completed = get_cycles();
+#endif
+
+ if ( __HAVE_DMA_WAITQUEUE && waitqueue_active(&buf->dma_wait)) {
+ wake_up_interruptible(&buf->dma_wait);
+ }
+#if __HAVE_DMA_FREELIST
+ else {
+ drm_device_dma_t *dma = dev->dma;
+ /* If processes are waiting, the last one
+ to wake will put the buffer on the free
+ list. If no processes are waiting, we
+ put the buffer on the freelist here. */
+ DRM(freelist_put)(dev, &dma->bufs[buf->order].freelist, buf);
+ }
+#endif
+}
+
+#if !__HAVE_DMA_RECLAIM
+void DRM(reclaim_buffers)(drm_device_t *dev, pid_t pid)
+{
+ drm_device_dma_t *dma = dev->dma;
+ int i;
+
+ if (!dma) return;
+ for (i = 0; i < dma->buf_count; i++) {
+ if (dma->buflist[i]->pid == pid) {
+ switch (dma->buflist[i]->list) {
+ case DRM_LIST_NONE:
+ DRM(free_buffer)(dev, dma->buflist[i]);
+ break;
+ case DRM_LIST_WAIT:
+ dma->buflist[i]->list = DRM_LIST_RECLAIM;
+ break;
+ default:
+ /* Buffer already on hardware. */
+ break;
+ }
+ }
+ }
+}
+#endif
+
+
+/* GH: This is a big hack for now...
+ */
+#if __HAVE_OLD_DMA
+
+int drm_context_switch(drm_device_t *dev, int old, int new)
+{
+ char buf[64];
+ drm_queue_t *q;
+
+#if 0
+ atomic_inc(&dev->total_ctx);
+#endif
+
+ 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->queue_count) {
+ clear_bit(0, &dev->context_flag);
+ return -EINVAL;
+ }
+
+ if (new == dev->last_context) {
+ clear_bit(0, &dev->context_flag);
+ return 0;
+ }
+
+ q = dev->queuelist[new];
+ atomic_inc(&q->use_count);
+ if (atomic_read(&q->use_count) == 1) {
+ atomic_dec(&q->use_count);
+ clear_bit(0, &dev->context_flag);
+ return -EINVAL;
+ }
+
+ if (DRM(flags) & DRM_FLAG_NOCTX) {
+ drm_context_switch_complete(dev, new);
+ } else {
+ sprintf(buf, "C %d %d\n", old, new);
+ DRM(write_string)(dev, buf);
+ }
+
+ atomic_dec(&q->use_count);
+
+ return 0;
+}
+
+int drm_context_switch_complete(drm_device_t *dev, int new)
+{
+ drm_device_dma_t *dma = dev->dma;
+
+ dev->last_context = new; /* PRE/POST: This is the _only_ writer. */
+ dev->last_switch = jiffies;
+
+ if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+ DRM_ERROR("Lock isn't held after context switch\n");
+ }
+
+ if (!dma || !(dma->next_buffer && dma->next_buffer->while_locked)) {
+ if (DRM(lock_free)(dev, &dev->lock.hw_lock->lock,
+ DRM_KERNEL_CONTEXT)) {
+ DRM_ERROR("Cannot free lock\n");
+ }
+ }
+
+#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_interruptible(&dev->context_wait);
+
+ return 0;
+}
+
+void DRM(clear_next_buffer)(drm_device_t *dev)
+{
+ drm_device_dma_t *dma = dev->dma;
+
+ dma->next_buffer = NULL;
+ if (dma->next_queue && !DRM_BUFCOUNT(&dma->next_queue->waitlist)) {
+ wake_up_interruptible(&dma->next_queue->flush_queue);
+ }
+ dma->next_queue = NULL;
+}
+
+int DRM(select_queue)(drm_device_t *dev, void (*wrapper)(unsigned long))
+{
+ int i;
+ int candidate = -1;
+ int j = jiffies;
+
+ if (!dev) {
+ DRM_ERROR("No device\n");
+ return -1;
+ }
+ if (!dev->queuelist || !dev->queuelist[DRM_KERNEL_CONTEXT]) {
+ /* This only happens between the time the
+ interrupt is initialized and the time
+ the queues are initialized. */
+ return -1;
+ }
+
+ /* Doing "while locked" DMA? */
+ if (DRM_WAITCOUNT(dev, DRM_KERNEL_CONTEXT)) {
+ return DRM_KERNEL_CONTEXT;
+ }
+
+ /* If there are buffers on the last_context
+ queue, and we have not been executing
+ this context very long, continue to
+ execute this context. */
+ if (dev->last_switch <= j
+ && dev->last_switch + DRM_TIME_SLICE > j
+ && DRM_WAITCOUNT(dev, dev->last_context)) {
+ return dev->last_context;
+ }
+
+ /* Otherwise, find a candidate */
+ for (i = dev->last_checked + 1; i < dev->queue_count; i++) {
+ if (DRM_WAITCOUNT(dev, i)) {
+ candidate = dev->last_checked = i;
+ break;
+ }
+ }
+
+ if (candidate < 0) {
+ for (i = 0; i < dev->queue_count; i++) {
+ if (DRM_WAITCOUNT(dev, i)) {
+ candidate = dev->last_checked = i;
+ break;
+ }
+ }
+ }
+
+ if (wrapper
+ && candidate >= 0
+ && candidate != dev->last_context
+ && dev->last_switch <= j
+ && dev->last_switch + DRM_TIME_SLICE > j) {
+ if (dev->timer.expires != dev->last_switch + DRM_TIME_SLICE) {
+ del_timer(&dev->timer);
+ dev->timer.function = wrapper;
+ dev->timer.data = (unsigned long)dev;
+ dev->timer.expires = dev->last_switch+DRM_TIME_SLICE;
+ add_timer(&dev->timer);
+ }
+ return -1;
+ }
+
+ return candidate;
+}
+
+
+int DRM(dma_enqueue)(drm_device_t *dev, drm_dma_t *d)
+{
+ int i;
+ drm_queue_t *q;
+ drm_buf_t *buf;
+ int idx;
+ int while_locked = 0;
+ drm_device_dma_t *dma = dev->dma;
+ DECLARE_WAITQUEUE(entry, current);
+
+ DRM_DEBUG("%d\n", d->send_count);
+
+ if (d->flags & _DRM_DMA_WHILE_LOCKED) {
+ int context = dev->lock.hw_lock->lock;
+
+ if (!_DRM_LOCK_IS_HELD(context)) {
+ DRM_ERROR("No lock held during \"while locked\""
+ " request\n");
+ return -EINVAL;
+ }
+ if (d->context != _DRM_LOCKING_CONTEXT(context)
+ && _DRM_LOCKING_CONTEXT(context) != DRM_KERNEL_CONTEXT) {
+ DRM_ERROR("Lock held by %d while %d makes"
+ " \"while locked\" request\n",
+ _DRM_LOCKING_CONTEXT(context),
+ d->context);
+ return -EINVAL;
+ }
+ q = dev->queuelist[DRM_KERNEL_CONTEXT];
+ while_locked = 1;
+ } else {
+ q = dev->queuelist[d->context];
+ }
+
+
+ atomic_inc(&q->use_count);
+ if (atomic_read(&q->block_write)) {
+ add_wait_queue(&q->write_queue, &entry);
+ atomic_inc(&q->block_count);
+ for (;;) {
+ current->state = TASK_INTERRUPTIBLE;
+ if (!atomic_read(&q->block_write)) break;
+ schedule();
+ if (signal_pending(current)) {
+ atomic_dec(&q->use_count);
+ remove_wait_queue(&q->write_queue, &entry);
+ return -EINTR;
+ }
+ }
+ atomic_dec(&q->block_count);
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&q->write_queue, &entry);
+ }
+
+ for (i = 0; i < d->send_count; i++) {
+ idx = d->send_indices[i];
+ if (idx < 0 || idx >= dma->buf_count) {
+ atomic_dec(&q->use_count);
+ DRM_ERROR("Index %d (of %d max)\n",
+ d->send_indices[i], dma->buf_count - 1);
+ return -EINVAL;
+ }
+ buf = dma->buflist[ idx ];
+ if (buf->pid != current->pid) {
+ atomic_dec(&q->use_count);
+ DRM_ERROR("Process %d using buffer owned by %d\n",
+ current->pid, buf->pid);
+ return -EINVAL;
+ }
+ if (buf->list != DRM_LIST_NONE) {
+ atomic_dec(&q->use_count);
+ DRM_ERROR("Process %d using buffer %d on list %d\n",
+ current->pid, buf->idx, buf->list);
+ }
+ buf->used = d->send_sizes[i];
+ buf->while_locked = while_locked;
+ buf->context = d->context;
+ if (!buf->used) {
+ DRM_ERROR("Queueing 0 length buffer\n");
+ }
+ if (buf->pending) {
+ atomic_dec(&q->use_count);
+ DRM_ERROR("Queueing pending buffer:"
+ " buffer %d, offset %d\n",
+ d->send_indices[i], i);
+ return -EINVAL;
+ }
+ if (buf->waiting) {
+ atomic_dec(&q->use_count);
+ DRM_ERROR("Queueing waiting buffer:"
+ " buffer %d, offset %d\n",
+ d->send_indices[i], i);
+ return -EINVAL;
+ }
+ buf->waiting = 1;
+ if (atomic_read(&q->use_count) == 1
+ || atomic_read(&q->finalization)) {
+ DRM(free_buffer)(dev, buf);
+ } else {
+ DRM(waitlist_put)(&q->waitlist, buf);
+ atomic_inc(&q->total_queued);
+ }
+ }
+ atomic_dec(&q->use_count);
+
+ return 0;
+}
+
+static int DRM(dma_get_buffers_of_order)(drm_device_t *dev, drm_dma_t *d,
+ int order)
+{
+ int i;
+ drm_buf_t *buf;
+ drm_device_dma_t *dma = dev->dma;
+
+ for (i = d->granted_count; i < d->request_count; i++) {
+ buf = DRM(freelist_get)(&dma->bufs[order].freelist,
+ d->flags & _DRM_DMA_WAIT);
+ if (!buf) break;
+ if (buf->pending || buf->waiting) {
+ DRM_ERROR("Free buffer %d in use by %d (w%d, p%d)\n",
+ buf->idx,
+ buf->pid,
+ buf->waiting,
+ buf->pending);
+ }
+ buf->pid = current->pid;
+ if (copy_to_user(&d->request_indices[i],
+ &buf->idx,
+ sizeof(buf->idx)))
+ return -EFAULT;
+
+ if (copy_to_user(&d->request_sizes[i],
+ &buf->total,
+ sizeof(buf->total)))
+ return -EFAULT;
+
+ ++d->granted_count;
+ }
+ return 0;
+}
+
+
+int DRM(dma_get_buffers)(drm_device_t *dev, drm_dma_t *dma)
+{
+ int order;
+ int retcode = 0;
+ int tmp_order;
+
+ order = DRM(order)(dma->request_size);
+
+ dma->granted_count = 0;
+ retcode = DRM(dma_get_buffers_of_order)(dev, dma, order);
+
+ if (dma->granted_count < dma->request_count
+ && (dma->flags & _DRM_DMA_SMALLER_OK)) {
+ for (tmp_order = order - 1;
+ !retcode
+ && dma->granted_count < dma->request_count
+ && tmp_order >= DRM_MIN_ORDER;
+ --tmp_order) {
+
+ retcode = DRM(dma_get_buffers_of_order)(dev, dma,
+ tmp_order);
+ }
+ }
+
+ if (dma->granted_count < dma->request_count
+ && (dma->flags & _DRM_DMA_LARGER_OK)) {
+ for (tmp_order = order + 1;
+ !retcode
+ && dma->granted_count < dma->request_count
+ && tmp_order <= DRM_MAX_ORDER;
+ ++tmp_order) {
+
+ retcode = DRM(dma_get_buffers_of_order)(dev, dma,
+ tmp_order);
+ }
+ }
+ return 0;
+}
+
+#endif
+
+#endif
diff --git a/linux-core/drm_drawable.c b/linux-core/drm_drawable.c
new file mode 100644
index 00000000..13e46b9f
--- /dev/null
+++ b/linux-core/drm_drawable.c
@@ -0,0 +1,51 @@
+/* drm_drawable.h -- IOCTLs for drawables -*- linux-c -*-
+ * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rickard E. (Rik) Faith <faith@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+int DRM(adddraw)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ drm_draw_t draw;
+
+ draw.handle = 0; /* NOOP */
+ DRM_DEBUG("%d\n", draw.handle);
+ if (copy_to_user((drm_draw_t *)arg, &draw, sizeof(draw)))
+ return -EFAULT;
+ return 0;
+}
+
+int DRM(rmdraw)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ return 0; /* NOOP */
+}
diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c
new file mode 100644
index 00000000..b24d213e
--- /dev/null
+++ b/linux-core/drm_drv.c
@@ -0,0 +1,927 @@
+/* drm_drv.h -- Generic driver template -*- linux-c -*-
+ * Created: Thu Nov 23 03:10:50 2000 by gareth@valinux.com
+ *
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rickard E. (Rik) Faith <faith@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ */
+
+/*
+ * To use this template, you must at least define the following (samples
+ * given for the MGA driver):
+ *
+ * #define DRIVER_AUTHOR "VA Linux Systems, Inc."
+ *
+ * #define DRIVER_NAME "mga"
+ * #define DRIVER_DESC "Matrox G200/G400"
+ * #define DRIVER_DATE "20001127"
+ *
+ * #define DRIVER_MAJOR 2
+ * #define DRIVER_MINOR 0
+ * #define DRIVER_PATCHLEVEL 2
+ *
+ * #define DRIVER_IOCTL_COUNT DRM_ARRAY_SIZE( mga_ioctls )
+ *
+ * #define DRM(x) mga_##x
+ */
+
+#ifndef __MUST_HAVE_AGP
+#define __MUST_HAVE_AGP 0
+#endif
+#ifndef __HAVE_CTX_BITMAP
+#define __HAVE_CTX_BITMAP 0
+#endif
+#ifndef __HAVE_DMA_IRQ
+#define __HAVE_DMA_IRQ 0
+#endif
+#ifndef __HAVE_DMA_QUEUE
+#define __HAVE_DMA_QUEUE 0
+#endif
+#ifndef __HAVE_MULTIPLE_DMA_QUEUES
+#define __HAVE_MULTIPLE_DMA_QUEUES 0
+#endif
+#ifndef __HAVE_DMA_SCHEDULE
+#define __HAVE_DMA_SCHEDULE 0
+#endif
+#ifndef __HAVE_DMA_FLUSH
+#define __HAVE_DMA_FLUSH 0
+#endif
+#ifndef __HAVE_DMA_READY
+#define __HAVE_DMA_READY 0
+#endif
+#ifndef __HAVE_DMA_QUIESCENT
+#define __HAVE_DMA_QUIESCENT 0
+#endif
+#ifndef __HAVE_RELEASE
+#define __HAVE_RELEASE 0
+#endif
+#ifndef __HAVE_COUNTERS
+#define __HAVE_COUNTERS 0
+#endif
+
+#ifndef DRIVER_PREINIT
+#define DRIVER_PREINIT()
+#endif
+#ifndef DRIVER_POSTINIT
+#define DRIVER_POSTINIT()
+#endif
+#ifndef DRIVER_PRERELEASE
+#define DRIVER_PRERELEASE()
+#endif
+#ifndef DRIVER_PRETAKEDOWN
+#define DRIVER_PRETAKEDOWN()
+#endif
+#ifndef DRIVER_IOCTLS
+#define DRIVER_IOCTLS
+#endif
+
+
+static drm_device_t DRM(device);
+static int DRM(minor);
+
+static struct file_operations DRM(fops) = {
+#if LINUX_VERSION_CODE >= 0x020400
+ /* This started being used during 2.4.0-test */
+ owner: THIS_MODULE,
+#endif
+ open: DRM(open),
+ flush: DRM(flush),
+ release: DRM(release),
+ ioctl: DRM(ioctl),
+ mmap: DRM(mmap),
+ read: DRM(read),
+ fasync: DRM(fasync),
+ poll: DRM(poll),
+};
+
+
+static drm_ioctl_desc_t DRM(ioctls)[] = {
+ [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { DRM(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_GET_MAP)] = { DRM(getmap), 0, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT)] = { DRM(getclient), 0, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_GET_STATS)] = { DRM(getstats), 0, 0 },
+
+ [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_CTX)] = { DRM(addctx), 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { DRM(rmctx), 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { DRM(modctx), 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { DRM(getctx), 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { DRM(switchctx), 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { DRM(newctx), 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { DRM(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)] = { DRM(lock), 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { DRM(unlock), 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { DRM(finish), 1, 0 },
+
+#if __HAVE_DMA
+ [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = { DRM(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)] = { DRM(mapbufs), 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { DRM(freebufs), 1, 0 },
+
+ /* The DRM_IOCTL_DMA ioctl should be defined by the driver.
+ */
+#if __HAVE_DMA_IRQ
+ [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { DRM(control), 1, 1 },
+#endif
+#endif
+
+#if __REALLY_HAVE_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
+
+ DRIVER_IOCTLS
+};
+
+#define DRIVER_IOCTL_COUNT DRM_ARRAY_SIZE( DRM(ioctls) )
+
+#ifdef MODULE
+static char *drm_opts = NULL;
+#endif
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_PARM( drm_opts, "s" );
+
+#ifndef MODULE
+/* DRM(options) 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.
+ */
+
+static int __init DRM(options)( char *str )
+{
+ DRM(parse_options)( str );
+ return 1;
+}
+
+__setup( DRIVER_NAME "=", DRM(options) );
+#endif
+
+static int DRM(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 );
+
+#if __HAVE_DMA
+ i = DRM(dma_setup)( dev );
+ if ( i < 0 )
+ return i;
+#endif
+
+ dev->counters = 6 + __HAVE_COUNTERS;
+ dev->types[0] = _DRM_STAT_LOCK;
+ dev->types[1] = _DRM_STAT_OPENS;
+ dev->types[2] = _DRM_STAT_CLOSES;
+ dev->types[3] = _DRM_STAT_IOCTLS;
+ dev->types[4] = _DRM_STAT_LOCKS;
+ dev->types[5] = _DRM_STAT_UNLOCKS;
+#ifdef __HAVE_COUNTER6
+ dev->types[6] = __HAVE_COUNTER6;
+#endif
+#ifdef __HAVE_COUNTER7
+ dev->types[7] = __HAVE_COUNTER7;
+#endif
+#ifdef __HAVE_COUNTER8
+ dev->types[8] = __HAVE_COUNTER8;
+#endif
+#ifdef __HAVE_COUNTER9
+ dev->types[9] = __HAVE_COUNTER9;
+#endif
+#ifdef __HAVE_COUNTER10
+ dev->types[10] = __HAVE_COUNTER10;
+#endif
+#ifdef __HAVE_COUNTER11
+ dev->types[11] = __HAVE_COUNTER11;
+#endif
+#ifdef __HAVE_COUNTER12
+ dev->types[12] = __HAVE_COUNTER12;
+#endif
+#ifdef __HAVE_COUNTER13
+ dev->types[13] = __HAVE_COUNTER13;
+#endif
+#ifdef __HAVE_COUNTER14
+ dev->types[14] = __HAVE_COUNTER14;
+#endif
+#ifdef __HAVE_COUNTER15
+ dev->types[14] = __HAVE_COUNTER14;
+#endif
+
+ for ( i = 0 ; i < DRM_ARRAY_SIZE(dev->counts) ; i++ )
+ atomic_set( &dev->counts[i], 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 );
+
+ 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 DRM(takedown)( drm_device_t *dev )
+{
+ drm_magic_entry_t *pt, *next;
+ drm_map_t *map;
+ drm_vma_entry_t *vma, *vma_next;
+ int i;
+
+ DRM_DEBUG( "\n" );
+
+ DRIVER_PRETAKEDOWN();
+#if __HAVE_DMA_IRQ
+ if ( dev->irq ) DRM(irq_uninstall)( dev );
+#endif
+
+ 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;
+ }
+
+#if __REALLY_HAVE_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 drv_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_do_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:
+#if __REALLY_HAVE_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;
+ }
+
+#if __HAVE_DMA_QUEUE || __HAVE_MULTIPLE_DMA_QUEUES
+ if ( dev->queuelist ) {
+ for ( i = 0 ; i < dev->queue_count ; i++ ) {
+ DRM(waitlist_destroy)( &dev->queuelist[i]->waitlist );
+ if ( dev->queuelist[i] ) {
+ DRM(free)( dev->queuelist[i],
+ sizeof(*dev->queuelist[0]),
+ DRM_MEM_QUEUES );
+ dev->queuelist[i] = NULL;
+ }
+ }
+ DRM(free)( dev->queuelist,
+ dev->queue_slots * sizeof(*dev->queuelist),
+ DRM_MEM_QUEUES );
+ dev->queuelist = NULL;
+ }
+ dev->queue_count = 0;
+#endif
+
+#if __HAVE_DMA
+ DRM(dma_takedown)( dev );
+#endif
+ 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;
+}
+
+/* drm_init is called via init_module at module load time, or via
+ * linux/init/main.c (this is not currently supported).
+ */
+static int __init drm_init( void )
+{
+ drm_device_t *dev = &DRM(device);
+#if __HAVE_CTX_BITMAP
+ int retcode;
+#endif
+ 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)( drm_opts );
+#endif
+ DRIVER_PREINIT();
+
+ DRM(mem_init)();
+
+ if ((DRM(minor) = DRM(stub_register)(DRIVER_NAME, &DRM(fops),dev)) < 0)
+ return -EPERM;
+ dev->device = MKDEV(DRM_MAJOR, DRM(minor) );
+ dev->name = DRIVER_NAME;
+
+#if __REALLY_HAVE_AGP
+ dev->agp = DRM(agp_init)();
+#if __MUST_HAVE_AGP
+ if ( dev->agp == NULL ) {
+ DRM_ERROR( "Cannot initialize the agpgart module.\n" );
+ DRM(stub_unregister)(DRM(minor));
+ DRM(takedown)( dev );
+ return -ENOMEM;
+ }
+#endif
+#if __REALLY_HAVE_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 __HAVE_CTX_BITMAP
+ retcode = DRM(ctxbitmap_init)( dev );
+ if( retcode ) {
+ DRM_ERROR( "Cannot allocate memory for context bitmap.\n" );
+ DRM(stub_unregister)(DRM(minor));
+ DRM(takedown)( dev );
+ return retcode;
+ }
+#endif
+
+ DRIVER_POSTINIT();
+
+ DRM_INFO( "Initialized %s %d.%d.%d %s on minor %d\n",
+ DRIVER_NAME,
+ DRIVER_MAJOR,
+ DRIVER_MINOR,
+ DRIVER_PATCHLEVEL,
+ DRIVER_DATE,
+ DRM(minor) );
+
+ return 0;
+}
+
+/* drm_cleanup is called via cleanup_module at module unload time.
+ */
+static void __exit drm_cleanup( void )
+{
+ drm_device_t *dev = &DRM(device);
+
+ DRM_DEBUG( "\n" );
+
+ if ( DRM(stub_unregister)(DRM(minor)) ) {
+ DRM_ERROR( "Cannot unload module\n" );
+ } else {
+ DRM_INFO( "Module unloaded\n" );
+ }
+#if __HAVE_CTX_BITMAP
+ DRM(ctxbitmap_cleanup)( dev );
+#endif
+
+#if __REALLY_HAVE_AGP && __REALLY_HAVE_MTRR
+ if ( dev->agp && dev->agp->agp_mtrr ) {
+ int retval;
+ retval = mtrr_del( dev->agp->agp_mtrr,
+ dev->agp->agp_info.aper_base,
+ dev->agp->agp_info.aper_size*1024*1024 );
+ DRM_DEBUG( "mtrr_del=%d\n", retval );
+ }
+#endif
+
+ DRM(takedown)( dev );
+
+#if __REALLY_HAVE_AGP
+ if ( dev->agp ) {
+ DRM(agp_uninit)();
+ DRM(free)( dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS );
+ dev->agp = NULL;
+ }
+#endif
+}
+
+module_init( drm_init );
+module_exit( drm_cleanup );
+
+
+int DRM(version)( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg )
+{
+ drm_version_t version;
+ int len;
+
+ if ( copy_from_user( &version,
+ (drm_version_t *)arg,
+ sizeof(version) ) )
+ return -EFAULT;
+
+#define DRM_COPY( name, value ) \
+ len = strlen( value ); \
+ if ( len > name##_len ) len = name##_len; \
+ name##_len = strlen( value ); \
+ if ( len && name ) { \
+ if ( copy_to_user( name, value, len ) ) \
+ return -EFAULT; \
+ }
+
+ version.version_major = DRIVER_MAJOR;
+ version.version_minor = DRIVER_MINOR;
+ version.version_patchlevel = DRIVER_PATCHLEVEL;
+
+ DRM_COPY( version.name, DRIVER_NAME );
+ DRM_COPY( version.date, DRIVER_DATE );
+ DRM_COPY( version.desc, DRIVER_DESC );
+
+ if ( copy_to_user( (drm_version_t *)arg,
+ &version,
+ sizeof(version) ) )
+ return -EFAULT;
+ return 0;
+}
+
+int DRM(open)( struct inode *inode, struct file *filp )
+{
+ drm_device_t *dev = &DRM(device);
+ int retcode = 0;
+
+ DRM_DEBUG( "open_count = %d\n", dev->open_count );
+
+ retcode = DRM(open_helper)( inode, filp, dev );
+ if ( !retcode ) {
+#if LINUX_VERSION_CODE < 0x020333
+ MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
+ atomic_inc( &dev->counts[_DRM_STAT_OPENS] );
+ spin_lock( &dev->count_lock );
+ if ( !dev->open_count++ ) {
+ spin_unlock( &dev->count_lock );
+ return DRM(setup)( dev );
+ }
+ spin_unlock( &dev->count_lock );
+ }
+
+ return retcode;
+}
+
+int DRM(release)( struct inode *inode, struct file *filp )
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev;
+ int retcode = 0;
+
+ lock_kernel();
+ dev = priv->dev;
+
+ DRM_DEBUG( "open_count = %d\n", dev->open_count );
+
+ DRIVER_PRERELEASE();
+
+ /* ========================================================
+ * Begin inline drm_release
+ */
+
+ DRM_DEBUG( "pid = %d, device = 0x%x, open_count = %d\n",
+ current->pid, dev->device, dev->open_count );
+
+ if ( dev->lock.hw_lock &&
+ _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) &&
+ dev->lock.pid == current->pid ) {
+ DRM_ERROR( "Process %d dead, freeing lock for context %d\n",
+ current->pid,
+ _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) );
+#if __HAVE_RELEASE
+ DRIVER_RELEASE();
+#endif
+ DRM(lock_free)( dev, &dev->lock.hw_lock->lock,
+ _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) );
+
+ /* FIXME: may require heavy-handed reset of
+ hardware at this point, possibly
+ processed via a callback to the X
+ server. */
+ }
+#if __HAVE_RELEASE
+ else if ( dev->lock.hw_lock ) {
+ /* The lock is required to reclaim buffers */
+ DECLARE_WAITQUEUE( entry, current );
+ add_wait_queue( &dev->lock.lock_queue, &entry );
+ for (;;) {
+ current->state = TASK_INTERRUPTIBLE;
+ if ( !dev->lock.hw_lock ) {
+ /* Device has been unregistered */
+ retcode = -EINTR;
+ break;
+ }
+ if ( DRM(lock_take)( &dev->lock.hw_lock->lock,
+ DRM_KERNEL_CONTEXT ) ) {
+ dev->lock.pid = priv->pid;
+ dev->lock.lock_time = jiffies;
+ atomic_inc( &dev->counts[_DRM_STAT_LOCKS] );
+ break; /* Got lock */
+ }
+ /* Contention */
+#if 0
+ atomic_inc( &dev->total_sleeps );
+#endif
+ schedule();
+ if ( signal_pending( current ) ) {
+ retcode = -ERESTARTSYS;
+ break;
+ }
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue( &dev->lock.lock_queue, &entry );
+ if( !retcode ) {
+ DRIVER_RELEASE();
+ DRM(lock_free)( dev, &dev->lock.hw_lock->lock,
+ DRM_KERNEL_CONTEXT );
+ }
+ }
+#else
+ DRM(reclaim_buffers)( dev, priv->pid );
+#endif
+
+ DRM(fasync)( -1, filp, 0 );
+
+ down( &dev->struct_sem );
+ if ( priv->remove_auth_on_close == 1 ) {
+ drm_file_t *temp = dev->file_first;
+ while ( temp ) {
+ temp->authenticated = 0;
+ temp = temp->next;
+ }
+ }
+ if ( priv->prev ) {
+ priv->prev->next = priv->next;
+ } else {
+ dev->file_first = priv->next;
+ }
+ if ( priv->next ) {
+ priv->next->prev = priv->prev;
+ } else {
+ dev->file_last = priv->prev;
+ }
+ up( &dev->struct_sem );
+
+ DRM(free)( priv, sizeof(*priv), DRM_MEM_FILES );
+
+ /* ========================================================
+ * End inline drm_release
+ */
+
+#if LINUX_VERSION_CODE < 0x020333
+ MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
+ atomic_inc( &dev->counts[_DRM_STAT_CLOSES] );
+ 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 );
+ unlock_kernel();
+ return -EBUSY;
+ }
+ spin_unlock( &dev->count_lock );
+ unlock_kernel();
+ return DRM(takedown)( dev );
+ }
+ spin_unlock( &dev->count_lock );
+
+ unlock_kernel();
+ return retcode;
+}
+
+/* DRM(ioctl) is called whenever a process performs an ioctl on /dev/drm.
+ */
+int DRM(ioctl)( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg )
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_ioctl_desc_t *ioctl;
+ drm_ioctl_t *func;
+ int nr = DRM_IOCTL_NR(cmd);
+ int retcode = 0;
+
+ atomic_inc( &dev->ioctl_count );
+ atomic_inc( &dev->counts[_DRM_STAT_IOCTLS] );
+ ++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 >= DRIVER_IOCTL_COUNT ) {
+ retcode = -EINVAL;
+ } else {
+ ioctl = &DRM(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 DRM(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 );
+ drm_lock_t lock;
+ int ret = 0;
+#if __HAVE_MULTIPLE_DMA_QUEUES
+ drm_queue_t *q;
+#endif
+#if DRM_DMA_HISTOGRAM
+ cycles_t start;
+
+ dev->lck_start = start = get_cycles();
+#endif
+
+ if ( copy_from_user( &lock, (drm_lock_t *)arg, sizeof(lock) ) )
+ return -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 __HAVE_DMA_QUEUE
+ if ( lock.context < 0 )
+ return -EINVAL;
+#elif __HAVE_MULTIPLE_DMA_QUEUES
+ if ( lock.context < 0 || lock.context >= dev->queue_count )
+ return -EINVAL;
+ q = dev->queuelist[lock.context];
+#endif
+
+#if __HAVE_DMA_FLUSH
+ ret = DRM(flush_block_and_flush)( dev, lock.context, lock.flags );
+#endif
+ if ( !ret ) {
+ add_wait_queue( &dev->lock.lock_queue, &entry );
+ for (;;) {
+ current->state = TASK_INTERRUPTIBLE;
+ 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->counts[_DRM_STAT_LOCKS] );
+ break; /* Got lock */
+ }
+
+ /* Contention */
+ schedule();
+ if ( signal_pending( current ) ) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue( &dev->lock.lock_queue, &entry );
+ }
+
+#if __HAVE_DMA_FLUSH
+ DRM(flush_unblock)( dev, lock.context, lock.flags ); /* cleanup phase */
+#endif
+
+ if ( !ret ) {
+ sigemptyset( &dev->sigmask );
+ sigaddset( &dev->sigmask, SIGSTOP );
+ sigaddset( &dev->sigmask, SIGTSTP );
+ sigaddset( &dev->sigmask, SIGTTIN );
+ sigaddset( &dev->sigmask, SIGTTOU );
+ dev->sigdata.context = lock.context;
+ dev->sigdata.lock = dev->lock.hw_lock;
+ block_all_signals( DRM(notifier),
+ &dev->sigdata, &dev->sigmask );
+
+#if __HAVE_DMA_READY
+ if ( lock.flags & _DRM_LOCK_READY ) {
+ DRIVER_DMA_READY();
+ }
+#endif
+#if __HAVE_DMA_QUIESCENT
+ if ( lock.flags & _DRM_LOCK_QUIESCENT ) {
+ DRIVER_DMA_QUIESCENT();
+ }
+#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 DRM(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;
+
+ if ( copy_from_user( &lock, (drm_lock_t *)arg, sizeof(lock) ) )
+ return -EFAULT;
+
+ if ( lock.context == DRM_KERNEL_CONTEXT ) {
+ DRM_ERROR( "Process %d using kernel context %d\n",
+ current->pid, lock.context );
+ return -EINVAL;
+ }
+
+ atomic_inc( &dev->counts[_DRM_STAT_UNLOCKS] );
+
+ DRM(lock_transfer)( dev, &dev->lock.hw_lock->lock,
+ DRM_KERNEL_CONTEXT );
+#if __HAVE_DMA_SCHEDULE
+ DRM(dma_schedule)( dev, 1 );
+#endif
+
+ /* FIXME: Do we ever really need to check this???
+ */
+ if ( 1 /* !dev->context_flag */ ) {
+ if ( DRM(lock_free)( dev, &dev->lock.hw_lock->lock,
+ DRM_KERNEL_CONTEXT ) ) {
+ DRM_ERROR( "\n" );
+ }
+ }
+
+ unblock_all_signals();
+ return 0;
+}
diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c
new file mode 100644
index 00000000..d646f318
--- /dev/null
+++ b/linux-core/drm_fops.c
@@ -0,0 +1,252 @@
+/* drm_fops.h -- File operations for DRM -*- linux-c -*-
+ * Created: Mon Jan 4 08:58:31 1999 by faith@valinux.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rickard E. (Rik) Faith <faith@valinux.com>
+ * Daryll Strauss <daryll@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include <linux/poll.h>
+
+/* drm_open is called whenever a process opens /dev/drm. */
+
+int DRM(open_helper)(struct inode *inode, struct file *filp, drm_device_t *dev)
+{
+ kdev_t minor = MINOR(inode->i_rdev);
+ drm_file_t *priv;
+
+ if (filp->f_flags & O_EXCL) return -EBUSY; /* No exclusive opens */
+ if (!DRM(cpu_valid)()) return -EINVAL;
+
+ DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor);
+
+ priv = DRM(alloc)(sizeof(*priv), DRM_MEM_FILES);
+ memset(priv, 0, sizeof(*priv));
+ filp->private_data = priv;
+ priv->uid = current->euid;
+ priv->pid = current->pid;
+ priv->minor = minor;
+ priv->dev = dev;
+ priv->ioctl_count = 0;
+ priv->authenticated = capable(CAP_SYS_ADMIN);
+
+ down(&dev->struct_sem);
+ if (!dev->file_last) {
+ priv->next = NULL;
+ priv->prev = NULL;
+ dev->file_first = priv;
+ dev->file_last = priv;
+ } else {
+ priv->next = NULL;
+ priv->prev = dev->file_last;
+ dev->file_last->next = priv;
+ dev->file_last = priv;
+ }
+ up(&dev->struct_sem);
+
+ return 0;
+}
+
+int DRM(flush)(struct file *filp)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+
+ DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n",
+ current->pid, dev->device, dev->open_count);
+ return 0;
+}
+
+#if 0
+/* drm_release is called whenever a process closes /dev/drm*. Linux calls
+ this only if any mappings have been closed. */
+
+int drm_release(struct inode *inode, struct file *filp)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+
+ DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n",
+ current->pid, dev->device, dev->open_count);
+
+ if (dev->lock.hw_lock
+ && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
+ && dev->lock.pid == current->pid) {
+ DRM_ERROR("Process %d dead, freeing lock for context %d\n",
+ current->pid,
+ _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+ drm_lock_free(dev,
+ &dev->lock.hw_lock->lock,
+ _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+
+ /* FIXME: may require heavy-handed reset of
+ hardware at this point, possibly
+ processed via a callback to the X
+ server. */
+ }
+ drm_reclaim_buffers(dev, priv->pid);
+
+ drm_fasync(-1, filp, 0);
+
+ down(&dev->struct_sem);
+ if (priv->prev) priv->prev->next = priv->next;
+ else dev->file_first = priv->next;
+ if (priv->next) priv->next->prev = priv->prev;
+ else dev->file_last = priv->prev;
+ up(&dev->struct_sem);
+
+ drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
+
+ return 0;
+}
+#endif
+
+int DRM(fasync)(int fd, struct file *filp, int on)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ int retcode;
+
+ DRM_DEBUG("fd = %d, device = 0x%x\n", fd, dev->device);
+ retcode = fasync_helper(fd, filp, on, &dev->buf_async);
+ if (retcode < 0) return retcode;
+ return 0;
+}
+
+
+/* The drm_read and drm_write_string code (especially that which manages
+ the circular buffer), is based on Alessandro Rubini's LINUX DEVICE
+ DRIVERS (Cambridge: O'Reilly, 1998), pages 111-113. */
+
+ssize_t DRM(read)(struct file *filp, char *buf, size_t count, loff_t *off)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ int left;
+ int avail;
+ int send;
+ int cur;
+
+ DRM_DEBUG("%p, %p\n", dev->buf_rp, dev->buf_wp);
+
+ while (dev->buf_rp == dev->buf_wp) {
+ DRM_DEBUG(" sleeping\n");
+ if (filp->f_flags & O_NONBLOCK) {
+ return -EAGAIN;
+ }
+ interruptible_sleep_on(&dev->buf_readers);
+ if (signal_pending(current)) {
+ DRM_DEBUG(" interrupted\n");
+ return -ERESTARTSYS;
+ }
+ DRM_DEBUG(" awake\n");
+ }
+
+ left = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ;
+ avail = DRM_BSZ - left;
+ send = DRM_MIN(avail, count);
+
+ while (send) {
+ if (dev->buf_wp > dev->buf_rp) {
+ cur = DRM_MIN(send, dev->buf_wp - dev->buf_rp);
+ } else {
+ cur = DRM_MIN(send, dev->buf_end - dev->buf_rp);
+ }
+ if (copy_to_user(buf, dev->buf_rp, cur))
+ return -EFAULT;
+ dev->buf_rp += cur;
+ if (dev->buf_rp == dev->buf_end) dev->buf_rp = dev->buf;
+ send -= cur;
+ }
+
+ wake_up_interruptible(&dev->buf_writers);
+ return DRM_MIN(avail, count);;
+}
+
+int DRM(write_string)(drm_device_t *dev, const char *s)
+{
+ int left = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ;
+ int send = strlen(s);
+ int count;
+
+ DRM_DEBUG("%d left, %d to send (%p, %p)\n",
+ left, send, dev->buf_rp, dev->buf_wp);
+
+ if (left == 1 || dev->buf_wp != dev->buf_rp) {
+ DRM_ERROR("Buffer not empty (%d left, wp = %p, rp = %p)\n",
+ left,
+ dev->buf_wp,
+ dev->buf_rp);
+ }
+
+ while (send) {
+ if (dev->buf_wp >= dev->buf_rp) {
+ count = DRM_MIN(send, dev->buf_end - dev->buf_wp);
+ if (count == left) --count; /* Leave a hole */
+ } else {
+ count = DRM_MIN(send, dev->buf_rp - dev->buf_wp - 1);
+ }
+ strncpy(dev->buf_wp, s, count);
+ dev->buf_wp += count;
+ if (dev->buf_wp == dev->buf_end) dev->buf_wp = dev->buf;
+ send -= count;
+ }
+
+#if LINUX_VERSION_CODE < 0x020315 && !defined(KILLFASYNCHASTHREEPARAMETERS)
+ /* The extra parameter to kill_fasync was added in 2.3.21, and is
+ _not_ present in _stock_ 2.2.14 and 2.2.15. However, some
+ distributions patch 2.2.x kernels to add this parameter. The
+ Makefile.linux attempts to detect this addition and defines
+ KILLFASYNCHASTHREEPARAMETERS if three parameters are found. */
+ if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO);
+#else
+
+ /* Parameter added in 2.3.21. */
+#if LINUX_VERSION_CODE < 0x020400
+ if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO, POLL_IN);
+#else
+ /* Type of first parameter changed in
+ Linux 2.4.0-test2... */
+ if (dev->buf_async) kill_fasync(&dev->buf_async, SIGIO, POLL_IN);
+#endif
+#endif
+ DRM_DEBUG("waking\n");
+ wake_up_interruptible(&dev->buf_readers);
+ return 0;
+}
+
+unsigned int DRM(poll)(struct file *filp, struct poll_table_struct *wait)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+
+ poll_wait(filp, &dev->buf_readers, wait);
+ if (dev->buf_wp != dev->buf_rp) return POLLIN | POLLRDNORM;
+ return 0;
+}
diff --git a/linux-core/drm_init.c b/linux-core/drm_init.c
new file mode 100644
index 00000000..9ae98414
--- /dev/null
+++ b/linux-core/drm_init.c
@@ -0,0 +1,112 @@
+/* drm_init.h -- Setup/Cleanup for DRM -*- linux-c -*-
+ * Created: Mon Jan 4 08:58:31 1999 by faith@valinux.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rickard E. (Rik) Faith <faith@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+int DRM(flags) = 0;
+
+/* drm_parse_option parses a single option. See description for
+ * drm_parse_options for details.
+ */
+static void DRM(parse_option)(char *s)
+{
+ char *c, *r;
+
+ DRM_DEBUG("\"%s\"\n", s);
+ if (!s || !*s) return;
+ for (c = s; *c && *c != ':'; c++); /* find : or \0 */
+ if (*c) r = c + 1; else r = NULL; /* remember remainder */
+ *c = '\0'; /* terminate */
+ if (!strcmp(s, "noctx")) {
+ DRM(flags) |= DRM_FLAG_NOCTX;
+ DRM_INFO("Server-mediated context switching OFF\n");
+ return;
+ }
+ if (!strcmp(s, "debug")) {
+ DRM(flags) |= DRM_FLAG_DEBUG;
+ DRM_INFO("Debug messages ON\n");
+ return;
+ }
+ DRM_ERROR("\"%s\" is not a valid option\n", s);
+ return;
+}
+
+/* drm_parse_options parse the insmod "drm=" options, or the command-line
+ * options passed to the kernel via LILO. The grammar of the format is as
+ * follows:
+ *
+ * drm ::= 'drm=' option_list
+ * option_list ::= option [ ';' option_list ]
+ * option ::= 'device:' major
+ * | 'debug'
+ * | 'noctx'
+ * major ::= INTEGER
+ *
+ * Note that 's' contains option_list without the 'drm=' part.
+ *
+ * device=major,minor specifies the device number used for /dev/drm
+ * if major == 0 then the misc device is used
+ * if major == 0 and minor == 0 then dynamic misc allocation is used
+ * debug=on specifies that debugging messages will be printk'd
+ * debug=trace specifies that each function call will be logged via printk
+ * debug=off turns off all debugging options
+ *
+ */
+
+void DRM(parse_options)(char *s)
+{
+ char *h, *t, *n;
+
+ DRM_DEBUG("\"%s\"\n", s ?: "");
+ if (!s || !*s) return;
+
+ for (h = t = n = s; h && *h; h = n) {
+ for (; *t && *t != ';'; t++); /* find ; or \0 */
+ if (*t) n = t + 1; else n = NULL; /* remember next */
+ *t = '\0'; /* terminate */
+ DRM(parse_option)(h); /* parse */
+ }
+}
+
+/* drm_cpu_valid returns non-zero if the DRI will run on this CPU, and 0
+ * otherwise.
+ */
+int DRM(cpu_valid)(void)
+{
+#if defined(__i386__)
+ if (boot_cpu_data.x86 == 3) return 0; /* No cmpxchg on a 386 */
+#endif
+#if defined(__sparc__) && !defined(__sparc_v9__)
+ return 0; /* No cmpxchg before v9 sparc. */
+#endif
+ return 1;
+}
diff --git a/linux-core/drm_ioctl.c b/linux-core/drm_ioctl.c
new file mode 100644
index 00000000..ce6ac2e6
--- /dev/null
+++ b/linux-core/drm_ioctl.c
@@ -0,0 +1,192 @@
+/* drm_ioctl.h -- IOCTL processing for DRM -*- linux-c -*-
+ * Created: Fri Jan 8 09:01:26 1999 by faith@valinux.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rickard E. (Rik) Faith <faith@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+int DRM(irq_busid)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ drm_irq_busid_t p;
+ struct pci_dev *dev;
+
+ if (copy_from_user(&p, (drm_irq_busid_t *)arg, sizeof(p)))
+ return -EFAULT;
+ dev = pci_find_slot(p.busnum, PCI_DEVFN(p.devnum, p.funcnum));
+ if (dev) p.irq = dev->irq;
+ else p.irq = 0;
+ DRM_DEBUG("%d:%d:%d => IRQ %d\n",
+ p.busnum, p.devnum, p.funcnum, p.irq);
+ if (copy_to_user((drm_irq_busid_t *)arg, &p, sizeof(p)))
+ return -EFAULT;
+ return 0;
+}
+
+int DRM(getunique)(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_unique_t u;
+
+ if (copy_from_user(&u, (drm_unique_t *)arg, sizeof(u)))
+ return -EFAULT;
+ if (u.unique_len >= dev->unique_len) {
+ if (copy_to_user(u.unique, dev->unique, dev->unique_len))
+ return -EFAULT;
+ }
+ u.unique_len = dev->unique_len;
+ if (copy_to_user((drm_unique_t *)arg, &u, sizeof(u)))
+ return -EFAULT;
+ return 0;
+}
+
+int DRM(setunique)(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_unique_t u;
+
+ if (dev->unique_len || dev->unique)
+ return -EBUSY;
+
+ if (copy_from_user(&u, (drm_unique_t *)arg, sizeof(u)))
+ return -EFAULT;
+
+ if (!u.unique_len)
+ return -EINVAL;
+
+ dev->unique_len = u.unique_len;
+ dev->unique = DRM(alloc)(u.unique_len + 1, DRM_MEM_DRIVER);
+ if (copy_from_user(dev->unique, u.unique, dev->unique_len))
+ return -EFAULT;
+ dev->unique[dev->unique_len] = '\0';
+
+ dev->devname = DRM(alloc)(strlen(dev->name) + strlen(dev->unique) + 2,
+ DRM_MEM_DRIVER);
+ sprintf(dev->devname, "%s@%s", dev->name, dev->unique);
+
+ return 0;
+}
+
+
+int DRM(getmap)( 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_map_t map;
+ int idx;
+
+ if (copy_from_user(&map, (drm_map_t *)arg, sizeof(map)))
+ return -EFAULT;
+ idx = map.offset;
+ down(&dev->struct_sem);
+ if (idx < 0 || idx >= dev->map_count) {
+ up(&dev->struct_sem);
+ return -EINVAL;
+ }
+ map.offset = dev->maplist[idx]->offset;
+ map.size = dev->maplist[idx]->size;
+ map.type = dev->maplist[idx]->type;
+ map.flags = dev->maplist[idx]->flags;
+ map.handle = dev->maplist[idx]->handle;
+ map.mtrr = dev->maplist[idx]->mtrr;
+ up(&dev->struct_sem);
+
+ if (copy_to_user((drm_map_t *)arg, &map, sizeof(map))) return -EFAULT;
+ return 0;
+}
+
+int DRM(getclient)( 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_client_t client;
+ drm_file_t *pt;
+ int idx;
+ int i;
+
+ if (copy_from_user(&client, (drm_client_t *)arg, sizeof(client)))
+ return -EFAULT;
+ idx = client.idx;
+ down(&dev->struct_sem);
+ for (i = 0, pt = dev->file_first; i < idx && pt; i++, pt = pt->next)
+ ;
+
+ if (!pt) {
+ up(&dev->struct_sem);
+ return -EINVAL;
+ }
+ client.auth = pt->authenticated;
+ client.pid = pt->pid;
+ client.uid = pt->uid;
+ client.magic = pt->magic;
+ client.iocs = pt->ioctl_count;
+ up(&dev->struct_sem);
+
+ if (copy_to_user((drm_client_t *)arg, &client, sizeof(client)))
+ return -EFAULT;
+ return 0;
+}
+
+int DRM(getstats)( 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_stats_t stats;
+ int i;
+
+ memset(&stats, 0, sizeof(stats));
+
+ down(&dev->struct_sem);
+
+ for (i = 0; i < dev->counters; i++) {
+ if (dev->types[i] == _DRM_STAT_LOCK)
+ stats.data[i].value
+ = (dev->lock.hw_lock
+ ? dev->lock.hw_lock->lock : 0);
+ else
+ stats.data[i].value = atomic_read(&dev->counts[i]);
+ stats.data[i].type = dev->types[i];
+ }
+
+ stats.count = dev->counters;
+
+ up(&dev->struct_sem);
+
+ if (copy_to_user((drm_stats_t *)arg, &stats, sizeof(stats)))
+ return -EFAULT;
+ return 0;
+}
diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c
new file mode 100644
index 00000000..c10cfe2c
--- /dev/null
+++ b/linux-core/drm_lock.c
@@ -0,0 +1,251 @@
+/* lock.c -- IOCTLs for locking -*- linux-c -*-
+ * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rickard E. (Rik) Faith <faith@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+int DRM(block)(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ DRM_DEBUG("\n");
+ return 0;
+}
+
+int DRM(unblock)(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ DRM_DEBUG("\n");
+ return 0;
+}
+
+int DRM(lock_take)(__volatile__ unsigned int *lock, unsigned int context)
+{
+ unsigned int old, new, prev;
+
+ do {
+ old = *lock;
+ if (old & _DRM_LOCK_HELD) new = old | _DRM_LOCK_CONT;
+ else new = context | _DRM_LOCK_HELD;
+ prev = cmpxchg(lock, old, new);
+ } while (prev != old);
+ if (_DRM_LOCKING_CONTEXT(old) == context) {
+ if (old & _DRM_LOCK_HELD) {
+ if (context != DRM_KERNEL_CONTEXT) {
+ DRM_ERROR("%d holds heavyweight lock\n",
+ context);
+ }
+ return 0;
+ }
+ }
+ if (new == (context | _DRM_LOCK_HELD)) {
+ /* Have lock */
+ return 1;
+ }
+ return 0;
+}
+
+/* This takes a lock forcibly and hands it to context. Should ONLY be used
+ inside *_unlock to give lock to kernel before calling *_dma_schedule. */
+int DRM(lock_transfer)(drm_device_t *dev,
+ __volatile__ unsigned int *lock, unsigned int context)
+{
+ unsigned int old, new, prev;
+
+ dev->lock.pid = 0;
+ do {
+ old = *lock;
+ new = context | _DRM_LOCK_HELD;
+ prev = cmpxchg(lock, old, new);
+ } while (prev != old);
+ return 1;
+}
+
+int DRM(lock_free)(drm_device_t *dev,
+ __volatile__ unsigned int *lock, unsigned int context)
+{
+ unsigned int old, new, prev;
+ pid_t pid = dev->lock.pid;
+
+ dev->lock.pid = 0;
+ do {
+ old = *lock;
+ new = 0;
+ prev = cmpxchg(lock, old, new);
+ } while (prev != old);
+ if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) {
+ DRM_ERROR("%d freed heavyweight lock held by %d (pid %d)\n",
+ context,
+ _DRM_LOCKING_CONTEXT(old),
+ pid);
+ return 1;
+ }
+ wake_up_interruptible(&dev->lock.lock_queue);
+ return 0;
+}
+
+static int DRM(flush_queue)(drm_device_t *dev, int context)
+{
+ DECLARE_WAITQUEUE(entry, current);
+ int ret = 0;
+ drm_queue_t *q = dev->queuelist[context];
+
+ DRM_DEBUG("\n");
+
+ atomic_inc(&q->use_count);
+ if (atomic_read(&q->use_count) > 1) {
+ atomic_inc(&q->block_write);
+ add_wait_queue(&q->flush_queue, &entry);
+ atomic_inc(&q->block_count);
+ for (;;) {
+ current->state = TASK_INTERRUPTIBLE;
+ if (!DRM_BUFCOUNT(&q->waitlist)) break;
+ schedule();
+ if (signal_pending(current)) {
+ ret = -EINTR; /* Can't restart */
+ break;
+ }
+ }
+ atomic_dec(&q->block_count);
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&q->flush_queue, &entry);
+ }
+ atomic_dec(&q->use_count);
+
+ /* NOTE: block_write is still incremented!
+ Use drm_flush_unlock_queue to decrement. */
+ return ret;
+}
+
+static int DRM(flush_unblock_queue)(drm_device_t *dev, int context)
+{
+ drm_queue_t *q = dev->queuelist[context];
+
+ DRM_DEBUG("\n");
+
+ atomic_inc(&q->use_count);
+ if (atomic_read(&q->use_count) > 1) {
+ if (atomic_read(&q->block_write)) {
+ atomic_dec(&q->block_write);
+ wake_up_interruptible(&q->write_queue);
+ }
+ }
+ atomic_dec(&q->use_count);
+ return 0;
+}
+
+int DRM(flush_block_and_flush)(drm_device_t *dev, int context,
+ drm_lock_flags_t flags)
+{
+ int ret = 0;
+ int i;
+
+ DRM_DEBUG("\n");
+
+ if (flags & _DRM_LOCK_FLUSH) {
+ ret = DRM(flush_queue)(dev, DRM_KERNEL_CONTEXT);
+ if (!ret) ret = DRM(flush_queue)(dev, context);
+ }
+ if (flags & _DRM_LOCK_FLUSH_ALL) {
+ for (i = 0; !ret && i < dev->queue_count; i++) {
+ ret = DRM(flush_queue)(dev, i);
+ }
+ }
+ return ret;
+}
+
+int DRM(flush_unblock)(drm_device_t *dev, int context, drm_lock_flags_t flags)
+{
+ int ret = 0;
+ int i;
+
+ DRM_DEBUG("\n");
+
+ if (flags & _DRM_LOCK_FLUSH) {
+ ret = DRM(flush_unblock_queue)(dev, DRM_KERNEL_CONTEXT);
+ if (!ret) ret = DRM(flush_unblock_queue)(dev, context);
+ }
+ if (flags & _DRM_LOCK_FLUSH_ALL) {
+ for (i = 0; !ret && i < dev->queue_count; i++) {
+ ret = DRM(flush_unblock_queue)(dev, i);
+ }
+ }
+
+ return ret;
+}
+
+int DRM(finish)(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ int ret = 0;
+ drm_lock_t lock;
+
+ DRM_DEBUG("\n");
+
+ if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
+ return -EFAULT;
+ ret = DRM(flush_block_and_flush)(dev, lock.context, lock.flags);
+ DRM(flush_unblock)(dev, lock.context, lock.flags);
+ return ret;
+}
+
+/* If we get here, it means that the process has called DRM_IOCTL_LOCK
+ without calling DRM_IOCTL_UNLOCK.
+
+ If the lock is not held, then let the signal proceed as usual.
+
+ If the lock is held, then set the contended flag and keep the signal
+ blocked.
+
+
+ Return 1 if the signal should be delivered normally.
+ Return 0 if the signal should be blocked. */
+
+int DRM(notifier)(void *priv)
+{
+ drm_sigdata_t *s = (drm_sigdata_t *)priv;
+ unsigned int old, new, prev;
+
+
+ /* Allow signal delivery if lock isn't held */
+ if (!_DRM_LOCK_IS_HELD(s->lock->lock)
+ || _DRM_LOCKING_CONTEXT(s->lock->lock) != s->context) return 1;
+
+ /* Otherwise, set flag to force call to
+ drmUnlock */
+ do {
+ old = s->lock->lock;
+ new = old | _DRM_LOCK_CONT;
+ prev = cmpxchg(&s->lock->lock, old, new);
+ } while (prev != old);
+ return 0;
+}
diff --git a/linux-core/drm_memory.h b/linux-core/drm_memory.h
new file mode 100644
index 00000000..caf05394
--- /dev/null
+++ b/linux-core/drm_memory.h
@@ -0,0 +1,460 @@
+/* drm_memory.h -- Memory management wrappers for DRM -*- linux-c -*-
+ * Created: Thu Feb 4 14:00:34 1999 by faith@valinux.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rickard E. (Rik) Faith <faith@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ */
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include "drmP.h"
+#include <linux/wrapper.h>
+
+typedef struct drm_mem_stats {
+ const char *name;
+ int succeed_count;
+ int free_count;
+ int fail_count;
+ unsigned long bytes_allocated;
+ unsigned long bytes_freed;
+} drm_mem_stats_t;
+
+static spinlock_t DRM(mem_lock) = SPIN_LOCK_UNLOCKED;
+static unsigned long DRM(ram_available) = 0; /* In pages */
+static unsigned long DRM(ram_used) = 0;
+static drm_mem_stats_t DRM(mem_stats)[] = {
+ [DRM_MEM_DMA] = { "dmabufs" },
+ [DRM_MEM_SAREA] = { "sareas" },
+ [DRM_MEM_DRIVER] = { "driver" },
+ [DRM_MEM_MAGIC] = { "magic" },
+ [DRM_MEM_IOCTLS] = { "ioctltab" },
+ [DRM_MEM_MAPS] = { "maplist" },
+ [DRM_MEM_VMAS] = { "vmalist" },
+ [DRM_MEM_BUFS] = { "buflist" },
+ [DRM_MEM_SEGS] = { "seglist" },
+ [DRM_MEM_PAGES] = { "pagelist" },
+ [DRM_MEM_FILES] = { "files" },
+ [DRM_MEM_QUEUES] = { "queues" },
+ [DRM_MEM_CMDS] = { "commands" },
+ [DRM_MEM_MAPPINGS] = { "mappings" },
+ [DRM_MEM_BUFLISTS] = { "buflists" },
+ [DRM_MEM_AGPLISTS] = { "agplist" },
+ [DRM_MEM_TOTALAGP] = { "totalagp" },
+ [DRM_MEM_BOUNDAGP] = { "boundagp" },
+ [DRM_MEM_CTXBITMAP] = { "ctxbitmap"},
+ [DRM_MEM_STUB] = { "stub" },
+ { NULL, 0, } /* Last entry must be null */
+};
+
+void DRM(mem_init)(void)
+{
+ drm_mem_stats_t *mem;
+ struct sysinfo si;
+
+ for (mem = DRM(mem_stats); mem->name; ++mem) {
+ mem->succeed_count = 0;
+ mem->free_count = 0;
+ mem->fail_count = 0;
+ mem->bytes_allocated = 0;
+ mem->bytes_freed = 0;
+ }
+
+ si_meminfo(&si);
+#if LINUX_VERSION_CODE < 0x020317
+ /* Changed to page count in 2.3.23 */
+ DRM(ram_available) = si.totalram >> PAGE_SHIFT;
+#else
+ DRM(ram_available) = si.totalram;
+#endif
+ DRM(ram_used) = 0;
+}
+
+/* drm_mem_info is called whenever a process reads /dev/drm/mem. */
+
+static int DRM(_mem_info)(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data)
+{
+ drm_mem_stats_t *pt;
+ int len = 0;
+
+ if (offset > DRM_PROC_LIMIT) {
+ *eof = 1;
+ return 0;
+ }
+
+ *eof = 0;
+ *start = &buf[offset];
+
+ DRM_PROC_PRINT(" total counts "
+ " | outstanding \n");
+ DRM_PROC_PRINT("type alloc freed fail bytes freed"
+ " | allocs bytes\n\n");
+ DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB |\n",
+ "system", 0, 0, 0,
+ DRM(ram_available) << (PAGE_SHIFT - 10));
+ DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB |\n",
+ "locked", 0, 0, 0, DRM(ram_used) >> 10);
+ DRM_PROC_PRINT("\n");
+ for (pt = DRM(mem_stats); pt->name; pt++) {
+ DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu %10lu | %6d %10ld\n",
+ pt->name,
+ pt->succeed_count,
+ pt->free_count,
+ pt->fail_count,
+ pt->bytes_allocated,
+ pt->bytes_freed,
+ pt->succeed_count - pt->free_count,
+ (long)pt->bytes_allocated
+ - (long)pt->bytes_freed);
+ }
+
+ if (len > request + offset) return request;
+ *eof = 1;
+ return len - offset;
+}
+
+int DRM(mem_info)(char *buf, char **start, off_t offset,
+ int len, int *eof, void *data)
+{
+ int ret;
+
+ spin_lock(&DRM(mem_lock));
+ ret = DRM(_mem_info)(buf, start, offset, len, eof, data);
+ spin_unlock(&DRM(mem_lock));
+ return ret;
+}
+
+void *DRM(alloc)(size_t size, int area)
+{
+ void *pt;
+
+ if (!size) {
+ DRM_MEM_ERROR(area, "Allocating 0 bytes\n");
+ return NULL;
+ }
+
+ if (!(pt = kmalloc(size, GFP_KERNEL))) {
+ spin_lock(&DRM(mem_lock));
+ ++DRM(mem_stats)[area].fail_count;
+ spin_unlock(&DRM(mem_lock));
+ return NULL;
+ }
+ spin_lock(&DRM(mem_lock));
+ ++DRM(mem_stats)[area].succeed_count;
+ DRM(mem_stats)[area].bytes_allocated += size;
+ spin_unlock(&DRM(mem_lock));
+ return pt;
+}
+
+void *DRM(realloc)(void *oldpt, size_t oldsize, size_t size, int area)
+{
+ void *pt;
+
+ if (!(pt = DRM(alloc)(size, area))) return NULL;
+ if (oldpt && oldsize) {
+ memcpy(pt, oldpt, oldsize);
+ DRM(free)(oldpt, oldsize, area);
+ }
+ return pt;
+}
+
+char *DRM(strdup)(const char *s, int area)
+{
+ char *pt;
+ int length = s ? strlen(s) : 0;
+
+ if (!(pt = DRM(alloc)(length+1, area))) return NULL;
+ strcpy(pt, s);
+ return pt;
+}
+
+void DRM(strfree)(const char *s, int area)
+{
+ unsigned int size;
+
+ if (!s) return;
+
+ size = 1 + (s ? strlen(s) : 0);
+ DRM(free)((void *)s, size, area);
+}
+
+void DRM(free)(void *pt, size_t size, int area)
+{
+ int alloc_count;
+ int free_count;
+
+ if (!pt) DRM_MEM_ERROR(area, "Attempt to free NULL pointer\n");
+ else kfree(pt);
+ spin_lock(&DRM(mem_lock));
+ DRM(mem_stats)[area].bytes_freed += size;
+ free_count = ++DRM(mem_stats)[area].free_count;
+ alloc_count = DRM(mem_stats)[area].succeed_count;
+ spin_unlock(&DRM(mem_lock));
+ if (free_count > alloc_count) {
+ DRM_MEM_ERROR(area, "Excess frees: %d frees, %d allocs\n",
+ free_count, alloc_count);
+ }
+}
+
+unsigned long DRM(alloc_pages)(int order, int area)
+{
+ unsigned long address;
+ unsigned long bytes = PAGE_SIZE << order;
+ unsigned long addr;
+ unsigned int sz;
+
+ spin_lock(&DRM(mem_lock));
+ if ((DRM(ram_used) >> PAGE_SHIFT)
+ > (DRM_RAM_PERCENT * DRM(ram_available)) / 100) {
+ spin_unlock(&DRM(mem_lock));
+ return 0;
+ }
+ spin_unlock(&DRM(mem_lock));
+
+ address = __get_free_pages(GFP_KERNEL, order);
+ if (!address) {
+ spin_lock(&DRM(mem_lock));
+ ++DRM(mem_stats)[area].fail_count;
+ spin_unlock(&DRM(mem_lock));
+ return 0;
+ }
+ spin_lock(&DRM(mem_lock));
+ ++DRM(mem_stats)[area].succeed_count;
+ DRM(mem_stats)[area].bytes_allocated += bytes;
+ DRM(ram_used) += bytes;
+ spin_unlock(&DRM(mem_lock));
+
+
+ /* Zero outside the lock */
+ memset((void *)address, 0, bytes);
+
+ /* Reserve */
+ for (addr = address, sz = bytes;
+ sz > 0;
+ addr += PAGE_SIZE, sz -= PAGE_SIZE) {
+#if LINUX_VERSION_CODE >= 0x020400
+ /* Argument type changed in 2.4.0-test6/pre8 */
+ mem_map_reserve(virt_to_page(addr));
+#else
+ mem_map_reserve(MAP_NR(addr));
+#endif
+ }
+
+ return address;
+}
+
+void DRM(free_pages)(unsigned long address, int order, int area)
+{
+ unsigned long bytes = PAGE_SIZE << order;
+ int alloc_count;
+ int free_count;
+ unsigned long addr;
+ unsigned int sz;
+
+ if (!address) {
+ DRM_MEM_ERROR(area, "Attempt to free address 0\n");
+ } else {
+ /* Unreserve */
+ for (addr = address, sz = bytes;
+ sz > 0;
+ addr += PAGE_SIZE, sz -= PAGE_SIZE) {
+#if LINUX_VERSION_CODE >= 0x020400
+ /* Argument type changed in 2.4.0-test6/pre8 */
+ mem_map_unreserve(virt_to_page(addr));
+#else
+ mem_map_unreserve(MAP_NR(addr));
+#endif
+ }
+ free_pages(address, order);
+ }
+
+ spin_lock(&DRM(mem_lock));
+ free_count = ++DRM(mem_stats)[area].free_count;
+ alloc_count = DRM(mem_stats)[area].succeed_count;
+ DRM(mem_stats)[area].bytes_freed += bytes;
+ DRM(ram_used) -= bytes;
+ spin_unlock(&DRM(mem_lock));
+ if (free_count > alloc_count) {
+ DRM_MEM_ERROR(area,
+ "Excess frees: %d frees, %d allocs\n",
+ free_count, alloc_count);
+ }
+}
+
+void *DRM(ioremap)(unsigned long offset, unsigned long size)
+{
+ void *pt;
+
+ if (!size) {
+ DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
+ "Mapping 0 bytes at 0x%08lx\n", offset);
+ return NULL;
+ }
+
+ if (!(pt = ioremap(offset, size))) {
+ spin_lock(&DRM(mem_lock));
+ ++DRM(mem_stats)[DRM_MEM_MAPPINGS].fail_count;
+ spin_unlock(&DRM(mem_lock));
+ return NULL;
+ }
+ spin_lock(&DRM(mem_lock));
+ ++DRM(mem_stats)[DRM_MEM_MAPPINGS].succeed_count;
+ DRM(mem_stats)[DRM_MEM_MAPPINGS].bytes_allocated += size;
+ spin_unlock(&DRM(mem_lock));
+ return pt;
+}
+
+void DRM(ioremapfree)(void *pt, unsigned long size)
+{
+ int alloc_count;
+ int free_count;
+
+ if (!pt)
+ DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
+ "Attempt to free NULL pointer\n");
+ else
+ iounmap(pt);
+
+ spin_lock(&DRM(mem_lock));
+ DRM(mem_stats)[DRM_MEM_MAPPINGS].bytes_freed += size;
+ free_count = ++DRM(mem_stats)[DRM_MEM_MAPPINGS].free_count;
+ alloc_count = DRM(mem_stats)[DRM_MEM_MAPPINGS].succeed_count;
+ spin_unlock(&DRM(mem_lock));
+ if (free_count > alloc_count) {
+ DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
+ "Excess frees: %d frees, %d allocs\n",
+ free_count, alloc_count);
+ }
+}
+
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+#if __MUST_HAVE_AGP
+
+agp_memory *DRM(alloc_agp)(int pages, u32 type)
+{
+ agp_memory *handle;
+
+ if (!pages) {
+ DRM_MEM_ERROR(DRM_MEM_TOTALAGP, "Allocating 0 pages\n");
+ return NULL;
+ }
+
+ if ((handle = DRM(agp_allocate_memory)(pages, type))) {
+ spin_lock(&DRM(mem_lock));
+ ++DRM(mem_stats)[DRM_MEM_TOTALAGP].succeed_count;
+ DRM(mem_stats)[DRM_MEM_TOTALAGP].bytes_allocated
+ += pages << PAGE_SHIFT;
+ spin_unlock(&DRM(mem_lock));
+ return handle;
+ }
+ spin_lock(&DRM(mem_lock));
+ ++DRM(mem_stats)[DRM_MEM_TOTALAGP].fail_count;
+ spin_unlock(&DRM(mem_lock));
+ return NULL;
+}
+
+int DRM(free_agp)(agp_memory *handle, int pages)
+{
+ int alloc_count;
+ int free_count;
+ int retval = -EINVAL;
+
+ if (!handle) {
+ DRM_MEM_ERROR(DRM_MEM_TOTALAGP,
+ "Attempt to free NULL AGP handle\n");
+ return retval;;
+ }
+
+ if (DRM(agp_free_memory)(handle)) {
+ spin_lock(&DRM(mem_lock));
+ free_count = ++DRM(mem_stats)[DRM_MEM_TOTALAGP].free_count;
+ alloc_count = DRM(mem_stats)[DRM_MEM_TOTALAGP].succeed_count;
+ DRM(mem_stats)[DRM_MEM_TOTALAGP].bytes_freed
+ += pages << PAGE_SHIFT;
+ spin_unlock(&DRM(mem_lock));
+ if (free_count > alloc_count) {
+ DRM_MEM_ERROR(DRM_MEM_TOTALAGP,
+ "Excess frees: %d frees, %d allocs\n",
+ free_count, alloc_count);
+ }
+ return 0;
+ }
+ return retval;
+}
+
+int DRM(bind_agp)(agp_memory *handle, unsigned int start)
+{
+ int retcode = -EINVAL;
+
+ if (!handle) {
+ DRM_MEM_ERROR(DRM_MEM_BOUNDAGP,
+ "Attempt to bind NULL AGP handle\n");
+ return retcode;
+ }
+
+ if (!(retcode = DRM(agp_bind_memory)(handle, start))) {
+ spin_lock(&DRM(mem_lock));
+ ++DRM(mem_stats)[DRM_MEM_BOUNDAGP].succeed_count;
+ DRM(mem_stats)[DRM_MEM_BOUNDAGP].bytes_allocated
+ += handle->page_count << PAGE_SHIFT;
+ spin_unlock(&DRM(mem_lock));
+ return retcode;
+ }
+ spin_lock(&DRM(mem_lock));
+ ++DRM(mem_stats)[DRM_MEM_BOUNDAGP].fail_count;
+ spin_unlock(&DRM(mem_lock));
+ return retcode;
+}
+
+int DRM(unbind_agp)(agp_memory *handle)
+{
+ int alloc_count;
+ int free_count;
+ int retcode = -EINVAL;
+
+ if (!handle) {
+ DRM_MEM_ERROR(DRM_MEM_BOUNDAGP,
+ "Attempt to unbind NULL AGP handle\n");
+ return retcode;
+ }
+
+ if ((retcode = DRM(agp_unbind_memory)(handle))) return retcode;
+ spin_lock(&DRM(mem_lock));
+ free_count = ++DRM(mem_stats)[DRM_MEM_BOUNDAGP].free_count;
+ alloc_count = DRM(mem_stats)[DRM_MEM_BOUNDAGP].succeed_count;
+ DRM(mem_stats)[DRM_MEM_BOUNDAGP].bytes_freed
+ += handle->page_count << PAGE_SHIFT;
+ spin_unlock(&DRM(mem_lock));
+ if (free_count > alloc_count) {
+ DRM_MEM_ERROR(DRM_MEM_BOUNDAGP,
+ "Excess frees: %d frees, %d allocs\n",
+ free_count, alloc_count);
+ }
+ return retcode;
+}
+#endif
+#endif /* defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) */
diff --git a/linux-core/drm_proc.c b/linux-core/drm_proc.c
new file mode 100644
index 00000000..634673d9
--- /dev/null
+++ b/linux-core/drm_proc.c
@@ -0,0 +1,623 @@
+/* drm_proc.h -- /proc support for DRM -*- linux-c -*-
+ * Created: Mon Jan 11 09:48:47 1999 by faith@valinux.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rickard E. (Rik) Faith <faith@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ *
+ * Acknowledgements:
+ * Matthew J Sottek <matthew.j.sottek@intel.com> sent in a patch to fix
+ * the problem with the proc files not outputting all their information.
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+static int DRM(name_info)(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data);
+static int DRM(vm_info)(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data);
+static int DRM(clients_info)(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data);
+static int DRM(queues_info)(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data);
+static int DRM(bufs_info)(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data);
+#if DRM_DEBUG_CODE
+static int DRM(vma_info)(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data);
+#endif
+#if DRM_DMA_HISTOGRAM
+static int DRM(histo_info)(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data);
+#endif
+
+struct drm_proc_list {
+ const char *name;
+ int (*f)(char *, char **, off_t, int, int *, void *);
+} DRM(proc_list)[] = {
+ { "name", DRM(name_info) },
+ { "mem", DRM(mem_info) },
+ { "vm", DRM(vm_info) },
+ { "clients", DRM(clients_info) },
+ { "queues", DRM(queues_info) },
+ { "bufs", DRM(bufs_info) },
+#if DRM_DEBUG_CODE
+ { "vma", DRM(vma_info) },
+#endif
+#if DRM_DMA_HISTOGRAM
+ { "histo", DRM(histo_info) },
+#endif
+};
+#define DRM_PROC_ENTRIES (sizeof(DRM(proc_list))/sizeof(DRM(proc_list)[0]))
+
+struct proc_dir_entry *DRM(proc_init)(drm_device_t *dev, int minor,
+ struct proc_dir_entry *root,
+ struct proc_dir_entry **dev_root)
+{
+ struct proc_dir_entry *ent;
+ int i, j;
+ char name[64];
+
+ if (!minor) root = create_proc_entry("dri", S_IFDIR, NULL);
+ if (!root) {
+ DRM_ERROR("Cannot create /proc/dri\n");
+ return NULL;
+ }
+
+ sprintf(name, "%d", minor);
+ *dev_root = create_proc_entry(name, S_IFDIR, root);
+ if (!*dev_root) {
+ DRM_ERROR("Cannot create /proc/%s\n", name);
+ return NULL;
+ }
+
+ for (i = 0; i < DRM_PROC_ENTRIES; i++) {
+ ent = create_proc_entry(DRM(proc_list)[i].name,
+ S_IFREG|S_IRUGO, *dev_root);
+ if (!ent) {
+ DRM_ERROR("Cannot create /proc/dri/%s/%s\n",
+ name, DRM(proc_list)[i].name);
+ for (j = 0; j < i; j++)
+ remove_proc_entry(DRM(proc_list)[i].name,
+ *dev_root);
+ remove_proc_entry(name, root);
+ if (!minor) remove_proc_entry("dri", NULL);
+ return NULL;
+ }
+ ent->read_proc = DRM(proc_list)[i].f;
+ ent->data = dev;
+ }
+
+ return root;
+}
+
+
+int DRM(proc_cleanup)(int minor, struct proc_dir_entry *root,
+ struct proc_dir_entry *dev_root)
+{
+ int i;
+ char name[64];
+
+ if (!root || !dev_root) return 0;
+
+ for (i = 0; i < DRM_PROC_ENTRIES; i++)
+ remove_proc_entry(DRM(proc_list)[i].name, dev_root);
+ sprintf(name, "%d", minor);
+ remove_proc_entry(name, root);
+ if (!minor) remove_proc_entry("dri", NULL);
+
+ return 0;
+}
+
+static int DRM(name_info)(char *buf, char **start, off_t offset, int request,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ int len = 0;
+
+ if (offset > DRM_PROC_LIMIT) {
+ *eof = 1;
+ return 0;
+ }
+
+ *start = &buf[offset];
+ *eof = 0;
+
+ if (dev->unique) {
+ DRM_PROC_PRINT("%s 0x%x %s\n",
+ dev->name, dev->device, dev->unique);
+ } else {
+ DRM_PROC_PRINT("%s 0x%x\n", dev->name, dev->device);
+ }
+
+ if (len > request + offset) return request;
+ *eof = 1;
+ return len - offset;
+}
+
+static int DRM(_vm_info)(char *buf, char **start, off_t offset, int request,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ int len = 0;
+ drm_map_t *map;
+ /* Hardcoded from _DRM_FRAME_BUFFER,
+ _DRM_REGISTERS, _DRM_SHM, and
+ _DRM_AGP. */
+ const char *types[] = { "FB", "REG", "SHM", "AGP" };
+ const char *type;
+ int i;
+
+ if (offset > DRM_PROC_LIMIT) {
+ *eof = 1;
+ return 0;
+ }
+
+ *start = &buf[offset];
+ *eof = 0;
+
+ DRM_PROC_PRINT("slot offset size type flags "
+ "address mtrr\n\n");
+ for (i = 0; i < dev->map_count; i++) {
+ map = dev->maplist[i];
+ if (map->type < 0 || map->type > 3) type = "??";
+ else type = types[map->type];
+ DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08lx ",
+ i,
+ map->offset,
+ map->size,
+ type,
+ map->flags,
+ (unsigned long)map->handle);
+ if (map->mtrr < 0) {
+ DRM_PROC_PRINT("none\n");
+ } else {
+ DRM_PROC_PRINT("%4d\n", map->mtrr);
+ }
+ }
+
+ if (len > request + offset) return request;
+ *eof = 1;
+ return len - offset;
+}
+
+static int DRM(vm_info)(char *buf, char **start, off_t offset, int request,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ int ret;
+
+ down(&dev->struct_sem);
+ ret = DRM(_vm_info)(buf, start, offset, request, eof, data);
+ up(&dev->struct_sem);
+ return ret;
+}
+
+
+static int DRM(_queues_info)(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ int len = 0;
+ int i;
+ drm_queue_t *q;
+
+ if (offset > DRM_PROC_LIMIT) {
+ *eof = 1;
+ return 0;
+ }
+
+ *start = &buf[offset];
+ *eof = 0;
+
+ DRM_PROC_PRINT(" ctx/flags use fin"
+ " blk/rw/rwf wait flushed queued"
+ " locks\n\n");
+ for (i = 0; i < dev->queue_count; i++) {
+ q = dev->queuelist[i];
+ atomic_inc(&q->use_count);
+ DRM_PROC_PRINT_RET(atomic_dec(&q->use_count),
+ "%5d/0x%03x %5d %5d"
+ " %5d/%c%c/%c%c%c %5Zd\n",
+ i,
+ q->flags,
+ atomic_read(&q->use_count),
+ atomic_read(&q->finalization),
+ atomic_read(&q->block_count),
+ atomic_read(&q->block_read) ? 'r' : '-',
+ atomic_read(&q->block_write) ? 'w' : '-',
+ waitqueue_active(&q->read_queue) ? 'r':'-',
+ waitqueue_active(&q->write_queue) ? 'w':'-',
+ waitqueue_active(&q->flush_queue) ? 'f':'-',
+ DRM_BUFCOUNT(&q->waitlist));
+ atomic_dec(&q->use_count);
+ }
+
+ if (len > request + offset) return request;
+ *eof = 1;
+ return len - offset;
+}
+
+static int DRM(queues_info)(char *buf, char **start, off_t offset, int request,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ int ret;
+
+ down(&dev->struct_sem);
+ ret = DRM(_queues_info)(buf, start, offset, request, eof, data);
+ up(&dev->struct_sem);
+ return ret;
+}
+
+/* drm_bufs_info is called whenever a process reads
+ /dev/dri/<dev>/bufs. */
+
+static int DRM(_bufs_info)(char *buf, char **start, off_t offset, int request,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ int len = 0;
+ drm_device_dma_t *dma = dev->dma;
+ int i;
+
+ if (!dma || offset > DRM_PROC_LIMIT) {
+ *eof = 1;
+ return 0;
+ }
+
+ *start = &buf[offset];
+ *eof = 0;
+
+ DRM_PROC_PRINT(" o size count free segs pages kB\n\n");
+ for (i = 0; i <= DRM_MAX_ORDER; i++) {
+ if (dma->bufs[i].buf_count)
+ DRM_PROC_PRINT("%2d %8d %5d %5d %5d %5d %5ld\n",
+ i,
+ dma->bufs[i].buf_size,
+ dma->bufs[i].buf_count,
+ atomic_read(&dma->bufs[i]
+ .freelist.count),
+ dma->bufs[i].seg_count,
+ dma->bufs[i].seg_count
+ *(1 << dma->bufs[i].page_order),
+ (dma->bufs[i].seg_count
+ * (1 << dma->bufs[i].page_order))
+ * PAGE_SIZE / 1024);
+ }
+ DRM_PROC_PRINT("\n");
+ for (i = 0; i < dma->buf_count; i++) {
+ if (i && !(i%32)) DRM_PROC_PRINT("\n");
+ DRM_PROC_PRINT(" %d", dma->buflist[i]->list);
+ }
+ DRM_PROC_PRINT("\n");
+
+ if (len > request + offset) return request;
+ *eof = 1;
+ return len - offset;
+}
+
+static int DRM(bufs_info)(char *buf, char **start, off_t offset, int request,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ int ret;
+
+ down(&dev->struct_sem);
+ ret = DRM(_bufs_info)(buf, start, offset, request, eof, data);
+ up(&dev->struct_sem);
+ return ret;
+}
+
+
+static int DRM(_clients_info)(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ int len = 0;
+ drm_file_t *priv;
+
+ if (offset > DRM_PROC_LIMIT) {
+ *eof = 1;
+ return 0;
+ }
+
+ *start = &buf[offset];
+ *eof = 0;
+
+ DRM_PROC_PRINT("a dev pid uid magic ioctls\n\n");
+ for (priv = dev->file_first; priv; priv = priv->next) {
+ DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n",
+ priv->authenticated ? 'y' : 'n',
+ priv->minor,
+ priv->pid,
+ priv->uid,
+ priv->magic,
+ priv->ioctl_count);
+ }
+
+ if (len > request + offset) return request;
+ *eof = 1;
+ return len - offset;
+}
+
+static int DRM(clients_info)(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ int ret;
+
+ down(&dev->struct_sem);
+ ret = DRM(_clients_info)(buf, start, offset, request, eof, data);
+ up(&dev->struct_sem);
+ return ret;
+}
+
+#if DRM_DEBUG_CODE
+
+#define DRM_VMA_VERBOSE 0
+
+static int DRM(_vma_info)(char *buf, char **start, off_t offset, int request,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ int len = 0;
+ drm_vma_entry_t *pt;
+ struct vm_area_struct *vma;
+#if DRM_VMA_VERBOSE
+ unsigned long i;
+ unsigned long address;
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *pte;
+#endif
+#if defined(__i386__)
+ unsigned int pgprot;
+#endif
+
+ if (offset > DRM_PROC_LIMIT) {
+ *eof = 1;
+ return 0;
+ }
+
+ *start = &buf[offset];
+ *eof = 0;
+
+ DRM_PROC_PRINT("vma use count: %d, high_memory = %p, 0x%08lx\n",
+ atomic_read(&dev->vma_count),
+ high_memory, virt_to_phys(high_memory));
+ for (pt = dev->vmalist; pt; pt = pt->next) {
+ if (!(vma = pt->vma)) continue;
+ DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx",
+ pt->pid,
+ vma->vm_start,
+ vma->vm_end,
+ vma->vm_flags & VM_READ ? 'r' : '-',
+ vma->vm_flags & VM_WRITE ? 'w' : '-',
+ vma->vm_flags & VM_EXEC ? 'x' : '-',
+ vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
+ vma->vm_flags & VM_LOCKED ? 'l' : '-',
+ vma->vm_flags & VM_IO ? 'i' : '-',
+ VM_OFFSET(vma));
+
+#if defined(__i386__)
+ pgprot = pgprot_val(vma->vm_page_prot);
+ DRM_PROC_PRINT(" %c%c%c%c%c%c%c%c%c",
+ pgprot & _PAGE_PRESENT ? 'p' : '-',
+ pgprot & _PAGE_RW ? 'w' : 'r',
+ pgprot & _PAGE_USER ? 'u' : 's',
+ pgprot & _PAGE_PWT ? 't' : 'b',
+ pgprot & _PAGE_PCD ? 'u' : 'c',
+ pgprot & _PAGE_ACCESSED ? 'a' : '-',
+ pgprot & _PAGE_DIRTY ? 'd' : '-',
+ pgprot & _PAGE_PSE ? 'm' : 'k',
+ 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);
+ pte = pte_offset(pmd, i);
+ if (pte_present(*pte)) {
+ address = __pa(pte_page(*pte))
+ + (i & (PAGE_SIZE-1));
+ DRM_PROC_PRINT(" 0x%08lx -> 0x%08lx"
+ " %c%c%c%c%c\n",
+ i,
+ address,
+ pte_read(*pte) ? 'r' : '-',
+ pte_write(*pte) ? 'w' : '-',
+ pte_exec(*pte) ? 'x' : '-',
+ pte_dirty(*pte) ? 'd' : '-',
+ pte_young(*pte) ? 'a' : '-' );
+ } else {
+ DRM_PROC_PRINT(" 0x%08lx\n", i);
+ }
+ }
+#endif
+ }
+
+ if (len > request + offset) return request;
+ *eof = 1;
+ return len - offset;
+}
+
+static int DRM(vma_info)(char *buf, char **start, off_t offset, int request,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ int ret;
+
+ down(&dev->struct_sem);
+ ret = DRM(_vma_info)(buf, start, offset, request, eof, data);
+ up(&dev->struct_sem);
+ return ret;
+}
+#endif
+
+
+#if DRM_DMA_HISTOGRAM
+static int DRM(_histo_info)(char *buf, char **start, off_t offset, int request,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ int len = 0;
+ drm_device_dma_t *dma = dev->dma;
+ int i;
+ unsigned long slot_value = DRM_DMA_HISTOGRAM_INITIAL;
+ unsigned long prev_value = 0;
+ drm_buf_t *buffer;
+
+ if (offset > DRM_PROC_LIMIT) {
+ *eof = 1;
+ return 0;
+ }
+
+ *start = &buf[offset];
+ *eof = 0;
+
+ DRM_PROC_PRINT("general statistics:\n");
+ DRM_PROC_PRINT("total %10u\n", atomic_read(&dev->histo.total));
+ DRM_PROC_PRINT("open %10u\n",
+ atomic_read(&dev->counts[_DRM_STAT_OPENS]));
+ DRM_PROC_PRINT("close %10u\n",
+ atomic_read(&dev->counts[_DRM_STAT_CLOSES]));
+ DRM_PROC_PRINT("ioctl %10u\n",
+ atomic_read(&dev->counts[_DRM_STAT_IOCTLS]));
+
+ DRM_PROC_PRINT("\nlock statistics:\n");
+ DRM_PROC_PRINT("locks %10u\n",
+ atomic_read(&dev->counts[_DRM_STAT_LOCKS]));
+ DRM_PROC_PRINT("unlocks %10u\n",
+ atomic_read(&dev->counts[_DRM_STAT_UNLOCKS]));
+
+ if (dma) {
+#if 0
+ DRM_PROC_PRINT("\ndma statistics:\n");
+ DRM_PROC_PRINT("prio %10u\n",
+ atomic_read(&dma->total_prio));
+ DRM_PROC_PRINT("bytes %10u\n",
+ atomic_read(&dma->total_bytes));
+ DRM_PROC_PRINT("dmas %10u\n",
+ atomic_read(&dma->total_dmas));
+ DRM_PROC_PRINT("missed:\n");
+ DRM_PROC_PRINT(" dma %10u\n",
+ atomic_read(&dma->total_missed_dma));
+ DRM_PROC_PRINT(" lock %10u\n",
+ atomic_read(&dma->total_missed_lock));
+ DRM_PROC_PRINT(" free %10u\n",
+ atomic_read(&dma->total_missed_free));
+ DRM_PROC_PRINT(" sched %10u\n",
+ atomic_read(&dma->total_missed_sched));
+ DRM_PROC_PRINT("tried %10u\n",
+ atomic_read(&dma->total_tried));
+ DRM_PROC_PRINT("hit %10u\n",
+ atomic_read(&dma->total_hit));
+ DRM_PROC_PRINT("lost %10u\n",
+ atomic_read(&dma->total_lost));
+#endif
+
+ buffer = dma->next_buffer;
+ if (buffer) {
+ DRM_PROC_PRINT("next_buffer %7d\n", buffer->idx);
+ } else {
+ DRM_PROC_PRINT("next_buffer none\n");
+ }
+ buffer = dma->this_buffer;
+ if (buffer) {
+ DRM_PROC_PRINT("this_buffer %7d\n", buffer->idx);
+ } else {
+ DRM_PROC_PRINT("this_buffer none\n");
+ }
+ }
+
+
+ DRM_PROC_PRINT("\nvalues:\n");
+ if (dev->lock.hw_lock) {
+ DRM_PROC_PRINT("lock 0x%08x\n",
+ dev->lock.hw_lock->lock);
+ } else {
+ DRM_PROC_PRINT("lock none\n");
+ }
+ DRM_PROC_PRINT("context_flag 0x%08lx\n", dev->context_flag);
+ DRM_PROC_PRINT("interrupt_flag 0x%08lx\n", dev->interrupt_flag);
+ DRM_PROC_PRINT("dma_flag 0x%08lx\n", dev->dma_flag);
+
+ DRM_PROC_PRINT("queue_count %10d\n", dev->queue_count);
+ DRM_PROC_PRINT("last_context %10d\n", dev->last_context);
+ DRM_PROC_PRINT("last_switch %10lu\n", dev->last_switch);
+ DRM_PROC_PRINT("last_checked %10d\n", dev->last_checked);
+
+
+ DRM_PROC_PRINT("\n q2d d2c c2f"
+ " q2c q2f dma sch"
+ " ctx lacq lhld\n\n");
+ for (i = 0; i < DRM_DMA_HISTOGRAM_SLOTS; i++) {
+ DRM_PROC_PRINT("%s %10lu %10u %10u %10u %10u %10u"
+ " %10u %10u %10u %10u %10u\n",
+ i == DRM_DMA_HISTOGRAM_SLOTS - 1 ? ">=" : "< ",
+ i == DRM_DMA_HISTOGRAM_SLOTS - 1
+ ? prev_value : slot_value ,
+
+ atomic_read(&dev->histo
+ .queued_to_dispatched[i]),
+ atomic_read(&dev->histo
+ .dispatched_to_completed[i]),
+ atomic_read(&dev->histo
+ .completed_to_freed[i]),
+
+ atomic_read(&dev->histo
+ .queued_to_completed[i]),
+ atomic_read(&dev->histo
+ .queued_to_freed[i]),
+ atomic_read(&dev->histo.dma[i]),
+ atomic_read(&dev->histo.schedule[i]),
+ atomic_read(&dev->histo.ctx[i]),
+ atomic_read(&dev->histo.lacq[i]),
+ atomic_read(&dev->histo.lhld[i]));
+ prev_value = slot_value;
+ slot_value = DRM_DMA_HISTOGRAM_NEXT(slot_value);
+ }
+
+ if (len > request + offset) return request;
+ *eof = 1;
+ return len - offset;
+}
+
+static int DRM(histo_info)(char *buf, char **start, off_t offset, int request,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ int ret;
+
+ down(&dev->struct_sem);
+ ret = DRM(_histo_info)(buf, start, offset, request, eof, data);
+ up(&dev->struct_sem);
+ return ret;
+}
+#endif
diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c
new file mode 100644
index 00000000..ed37af4d
--- /dev/null
+++ b/linux-core/drm_stub.c
@@ -0,0 +1,142 @@
+/* drm_stub.c -- -*- linux-c -*-
+ * Created: Fri Jan 19 10:48:35 2001 by faith@acm.org
+ *
+ * Copyright 2001 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#define DRM_STUB_MAXCARDS 16 /* Enough for one machine */
+
+static struct drm_stub_list {
+ const char *name;
+ struct file_operations *fops;
+ struct proc_dir_entry *dev_root;
+} *DRM(stub_list);
+
+static struct proc_dir_entry *DRM(stub_root);
+
+static struct drm_stub_info {
+ int (*info_register)(const char *name, struct file_operations *fops,
+ drm_device_t *dev);
+ int (*info_unregister)(int minor);
+} DRM(stub_info);
+
+static int DRM(stub_open)(struct inode *inode, struct file *filp)
+{
+ int minor = MINOR(inode->i_rdev);
+ int err = -ENODEV;
+ struct file_operations *old_fops;
+
+ if (!DRM(stub_list) || !DRM(stub_list)[minor].fops) return -ENODEV;
+ old_fops = filp->f_op;
+ filp->f_op = fops_get(DRM(stub_list)[minor].fops);
+ if (filp->f_op->open && (err = filp->f_op->open(inode, filp))) {
+ fops_put(filp->f_op);
+ filp->f_op = fops_get(old_fops);
+ }
+ fops_put(old_fops);
+
+ return err;
+}
+
+static struct file_operations DRM(stub_fops) = {
+#if LINUX_VERSION_CODE >= 0x020400
+ owner: THIS_MODULE,
+#endif
+ open: DRM(stub_open)
+};
+
+static int DRM(stub_getminor)(const char *name, struct file_operations *fops,
+ drm_device_t *dev)
+{
+ int i;
+
+ if (!DRM(stub_list)) {
+ DRM(stub_list) = DRM(alloc)(sizeof(*DRM(stub_list))
+ * DRM_STUB_MAXCARDS, DRM_MEM_STUB);
+ for (i = 0; i < DRM_STUB_MAXCARDS; i++) {
+ DRM(stub_list)[i].name = NULL;
+ DRM(stub_list)[i].fops = NULL;
+ }
+ }
+ for (i = 0; i < DRM_STUB_MAXCARDS; i++) {
+ if (!DRM(stub_list)[i].fops) {
+ DRM(stub_list)[i].name = name;
+ DRM(stub_list)[i].fops = fops;
+ DRM(stub_root) = DRM(proc_init)(dev, i, DRM(stub_root),
+ &DRM(stub_list)[i]
+ .dev_root);
+ return i;
+ }
+ }
+ return -1;
+}
+
+static int DRM(stub_putminor)(int minor)
+{
+ if (minor < 0 || minor >= DRM_STUB_MAXCARDS) return -1;
+ DRM(stub_list)[minor].name = NULL;
+ DRM(stub_list)[minor].fops = NULL;
+ DRM(proc_cleanup)(minor, DRM(stub_root),
+ DRM(stub_list)[minor].dev_root);
+ if (minor) {
+ inter_module_put("drm");
+ } else {
+ inter_module_unregister("drm");
+ DRM(free)(DRM(stub_list),
+ sizeof(*DRM(stub_list)) * DRM_STUB_MAXCARDS,
+ DRM_MEM_STUB);
+ unregister_chrdev(DRM_MAJOR, "drm");
+ }
+ return 0;
+}
+
+int DRM(stub_register)(const char *name, struct file_operations *fops,
+ drm_device_t *dev)
+{
+ if (register_chrdev(DRM_MAJOR, "drm", &DRM(stub_fops))) {
+ /* Already registered */
+ struct drm_stub_info *i;
+ i = (struct drm_stub_info *)inter_module_get("drm");
+ DRM(stub_info).info_register = i->info_register;
+ DRM(stub_info).info_unregister = i->info_unregister;
+ } else {
+ DRM(stub_info).info_register = DRM(stub_getminor);
+ DRM(stub_info).info_unregister = DRM(stub_putminor);
+ inter_module_register("drm", THIS_MODULE, &DRM(stub_info));
+ }
+ if (DRM(stub_info).info_register)
+ return DRM(stub_info).info_register(name, fops, dev);
+ return -1;
+}
+
+int DRM(stub_unregister)(int minor)
+{
+ DRM_DEBUG("%d\n", minor);
+ if (DRM(stub_info).info_unregister)
+ return DRM(stub_info).info_unregister(minor);
+ return -1;
+}
diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c
new file mode 100644
index 00000000..347816ac
--- /dev/null
+++ b/linux-core/drm_vm.c
@@ -0,0 +1,370 @@
+/* drm_vm.h -- Memory mapping for DRM -*- linux-c -*-
+ * Created: Mon Jan 4 08:58:31 1999 by faith@valinux.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rickard E. (Rik) Faith <faith@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+struct vm_operations_struct drm_vm_ops = {
+ nopage: DRM(vm_nopage),
+ open: DRM(vm_open),
+ close: DRM(vm_close),
+};
+
+struct vm_operations_struct drm_vm_shm_ops = {
+ nopage: DRM(vm_shm_nopage),
+ open: DRM(vm_open),
+ close: DRM(vm_close),
+};
+
+struct vm_operations_struct drm_vm_shm_lock_ops = {
+ nopage: DRM(vm_shm_nopage_lock),
+ open: DRM(vm_open),
+ close: DRM(vm_close),
+};
+
+struct vm_operations_struct drm_vm_dma_ops = {
+ nopage: DRM(vm_dma_nopage),
+ open: DRM(vm_open),
+ close: DRM(vm_close),
+};
+
+#if LINUX_VERSION_CODE < 0x020317
+unsigned long DRM(vm_nopage)(struct vm_area_struct *vma,
+ unsigned long address,
+ int write_access)
+#else
+ /* Return type changed in 2.3.23 */
+struct page *DRM(vm_nopage)(struct vm_area_struct *vma,
+ unsigned long address,
+ int write_access)
+#endif
+{
+ return NOPAGE_SIGBUS; /* Disallow mremap */
+}
+
+#if LINUX_VERSION_CODE < 0x020317
+unsigned long DRM(vm_shm_nopage)(struct vm_area_struct *vma,
+ unsigned long address,
+ int write_access)
+#else
+ /* Return type changed in 2.3.23 */
+struct page *DRM(vm_shm_nopage)(struct vm_area_struct *vma,
+ unsigned long address,
+ int write_access)
+#endif
+{
+#if LINUX_VERSION_CODE >= 0x020300
+ drm_map_t *map = (drm_map_t *)vma->vm_private_data;
+#else
+ drm_map_t *map = (drm_map_t *)vma->vm_pte;
+#endif
+ unsigned long physical;
+ unsigned long offset;
+
+ if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */
+ if (!map) return NOPAGE_OOM; /* Nothing allocated */
+
+ offset = address - vma->vm_start;
+ physical = (unsigned long)map->handle + offset;
+ atomic_inc(&virt_to_page(physical)->count); /* Dec. by kernel */
+
+ DRM_DEBUG("0x%08lx => 0x%08lx\n", address, physical);
+#if LINUX_VERSION_CODE < 0x020317
+ return physical;
+#else
+ return virt_to_page(physical);
+#endif
+}
+
+#if LINUX_VERSION_CODE < 0x020317
+unsigned long DRM(vm_shm_nopage_lock)(struct vm_area_struct *vma,
+ unsigned long address,
+ int write_access)
+#else
+ /* Return type changed in 2.3.23 */
+struct page *DRM(vm_shm_nopage_lock)(struct vm_area_struct *vma,
+ unsigned long address,
+ int write_access)
+#endif
+{
+ drm_file_t *priv = vma->vm_file->private_data;
+ drm_device_t *dev = priv->dev;
+ unsigned long physical;
+ unsigned long offset;
+ unsigned long page;
+
+ if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */
+ if (!dev->lock.hw_lock) return NOPAGE_OOM; /* Nothing allocated */
+
+ offset = address - vma->vm_start;
+ page = offset >> PAGE_SHIFT;
+ physical = (unsigned long)dev->lock.hw_lock + offset;
+ atomic_inc(&virt_to_page(physical)->count); /* Dec. by kernel */
+
+ DRM_DEBUG("0x%08lx (page %lu) => 0x%08lx\n", address, page, physical);
+#if LINUX_VERSION_CODE < 0x020317
+ return physical;
+#else
+ return virt_to_page(physical);
+#endif
+}
+
+#if LINUX_VERSION_CODE < 0x020317
+unsigned long DRM(vm_dma_nopage)(struct vm_area_struct *vma,
+ unsigned long address,
+ int write_access)
+#else
+ /* Return type changed in 2.3.23 */
+struct page *DRM(vm_dma_nopage)(struct vm_area_struct *vma,
+ unsigned long address,
+ int write_access)
+#endif
+{
+ drm_file_t *priv = vma->vm_file->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_device_dma_t *dma = dev->dma;
+ unsigned long physical;
+ unsigned long offset;
+ unsigned long page;
+
+ if (!dma) return NOPAGE_SIGBUS; /* Error */
+ if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */
+ if (!dma->pagelist) return NOPAGE_OOM ; /* Nothing allocated */
+
+ offset = address - vma->vm_start; /* vm_[pg]off[set] should be 0 */
+ page = offset >> PAGE_SHIFT;
+ physical = dma->pagelist[page] + (offset & (~PAGE_MASK));
+ atomic_inc(&virt_to_page(physical)->count); /* Dec. by kernel */
+
+ DRM_DEBUG("0x%08lx (page %lu) => 0x%08lx\n", address, page, physical);
+#if LINUX_VERSION_CODE < 0x020317
+ return physical;
+#else
+ return virt_to_page(physical);
+#endif
+}
+
+void DRM(vm_open)(struct vm_area_struct *vma)
+{
+ drm_file_t *priv = vma->vm_file->private_data;
+ drm_device_t *dev = priv->dev;
+#if DRM_DEBUG_CODE
+ drm_vma_entry_t *vma_entry;
+#endif
+
+ DRM_DEBUG("0x%08lx,0x%08lx\n",
+ vma->vm_start, vma->vm_end - vma->vm_start);
+ atomic_inc(&dev->vma_count);
+#if LINUX_VERSION_CODE < 0x020333
+ /* The map can exist after the fd is closed. */
+ MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
+
+
+#if DRM_DEBUG_CODE
+ vma_entry = DRM(alloc)(sizeof(*vma_entry), DRM_MEM_VMAS);
+ if (vma_entry) {
+ down(&dev->struct_sem);
+ vma_entry->vma = vma;
+ vma_entry->next = dev->vmalist;
+ vma_entry->pid = current->pid;
+ dev->vmalist = vma_entry;
+ up(&dev->struct_sem);
+ }
+#endif
+}
+
+void DRM(vm_close)(struct vm_area_struct *vma)
+{
+ drm_file_t *priv = vma->vm_file->private_data;
+ drm_device_t *dev = priv->dev;
+#if DRM_DEBUG_CODE
+ drm_vma_entry_t *pt, *prev;
+#endif
+
+ DRM_DEBUG("0x%08lx,0x%08lx\n",
+ vma->vm_start, vma->vm_end - vma->vm_start);
+#if LINUX_VERSION_CODE < 0x020333
+ MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
+ atomic_dec(&dev->vma_count);
+
+#if DRM_DEBUG_CODE
+ down(&dev->struct_sem);
+ for (pt = dev->vmalist, prev = NULL; pt; prev = pt, pt = pt->next) {
+ if (pt->vma == vma) {
+ if (prev) {
+ prev->next = pt->next;
+ } else {
+ dev->vmalist = pt->next;
+ }
+ DRM(free)(pt, sizeof(*pt), DRM_MEM_VMAS);
+ break;
+ }
+ }
+ up(&dev->struct_sem);
+#endif
+}
+
+int DRM(mmap_dma)(struct file *filp, struct vm_area_struct *vma)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev;
+ drm_device_dma_t *dma;
+ unsigned long length = vma->vm_end - vma->vm_start;
+
+ lock_kernel();
+ dev = priv->dev;
+ dma = dev->dma;
+ DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
+ vma->vm_start, vma->vm_end, VM_OFFSET(vma));
+
+ /* Length must match exact page count */
+ if (!dma || (length >> PAGE_SHIFT) != dma->page_count) {
+ unlock_kernel();
+ return -EINVAL;
+ }
+ unlock_kernel();
+
+ vma->vm_ops = &drm_vm_dma_ops;
+ vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */
+
+#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. */
+ ++filp->f_count;
+#endif
+ vma->vm_file = filp; /* Needed for drm_vm_open() */
+ DRM(vm_open)(vma);
+ return 0;
+}
+
+int DRM(mmap)(struct file *filp, struct vm_area_struct *vma)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_map_t *map = NULL;
+ int i;
+
+ DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
+ vma->vm_start, vma->vm_end, VM_OFFSET(vma));
+
+ if (!VM_OFFSET(vma)) return DRM(mmap_dma)(filp, vma);
+
+ /* A sequential search of a linked list is
+ fine here because: 1) there will only be
+ about 5-10 entries in the list and, 2) a
+ DRI client only has to do this mapping
+ once, so it doesn't have to be optimized
+ for performance, even if the list was a
+ bit longer. */
+ for (i = 0; i < dev->map_count; i++) {
+ map = dev->maplist[i];
+ if (map->offset == VM_OFFSET(vma)) break;
+ }
+
+ if (i >= dev->map_count) return -EINVAL;
+ if (!map || ((map->flags&_DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN)))
+ return -EPERM;
+
+ /* 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:
+ case _DRM_REGISTERS:
+ case _DRM_AGP:
+ if (VM_OFFSET(vma) >= __pa(high_memory)) {
+#if defined(__i386__)
+ if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) {
+ pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
+ pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT;
+ }
+#elif defined(__ia64__)
+ if (map->type != _DRM_AGP)
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+#endif
+ vma->vm_flags |= VM_IO; /* not in core dump */
+ }
+ if (remap_page_range(vma->vm_start,
+ VM_OFFSET(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:
+ if (map->flags & _DRM_CONTAINS_LOCK)
+ vma->vm_ops = &drm_vm_shm_lock_ops;
+ else {
+ vma->vm_ops = &drm_vm_shm_ops;
+#if LINUX_VERSION_CODE >= 0x020300
+ vma->vm_private_data = (void *)map;
+#else
+ vma->vm_pte = (unsigned long)map;
+#endif
+ }
+
+ /* Don't let this area swap. Change when
+ DRM_KERNEL advisory is supported. */
+ vma->vm_flags |= VM_LOCKED;
+ break;
+ default:
+ return -EINVAL; /* This should never happen. */
+ }
+ vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */
+
+#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. */
+ ++filp->f_count;
+#endif
+ vma->vm_file = filp; /* Needed for drm_vm_open() */
+ DRM(vm_open)(vma);
+ return 0;
+}
diff --git a/linux-core/i810_dma.c b/linux-core/i810_dma.c
index aa824a79..8585fef1 100644
--- a/linux-core/i810_dma.c
+++ b/linux-core/i810_dma.c
@@ -11,11 +11,11 @@
* 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
@@ -31,6 +31,7 @@
*/
#define __NO_VERSION__
+#include "i810.h"
#include "drmP.h"
#include "i810_drv.h"
#include <linux/interrupt.h> /* For task queue support */
@@ -107,14 +108,14 @@ static drm_buf_t *i810_freelist_get(drm_device_t *dev)
drm_device_dma_t *dma = dev->dma;
int i;
int used;
-
+
/* Linear search might not be the best solution */
for (i = 0; i < dma->buf_count; i++) {
drm_buf_t *buf = dma->buflist[ i ];
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
/* In use is already a pointer */
- used = cmpxchg(buf_priv->in_use, I810_BUF_FREE,
+ used = cmpxchg(buf_priv->in_use, I810_BUF_FREE,
I810_BUF_CLIENT);
if(used == I810_BUF_FREE) {
return buf;
@@ -131,26 +132,26 @@ static int i810_freelist_put(drm_device_t *dev, drm_buf_t *buf)
{
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
int used;
-
+
/* In use is already a pointer */
used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, I810_BUF_FREE);
if(used != I810_BUF_CLIENT) {
DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx);
return -EINVAL;
}
-
+
return 0;
}
static struct file_operations i810_buffer_fops = {
- open: i810_open,
- flush: drm_flush,
- release: i810_release,
- ioctl: i810_ioctl,
+ open: DRM(open),
+ flush: DRM(flush),
+ release: DRM(release),
+ ioctl: DRM(ioctl),
mmap: i810_mmap_buffers,
- read: drm_read,
- fasync: drm_fasync,
- poll: drm_poll,
+ read: DRM(read),
+ fasync: DRM(fasync),
+ poll: DRM(poll),
};
int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
@@ -166,10 +167,10 @@ int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
dev_priv = dev->dev_private;
buf = dev_priv->mmap_buffer;
buf_priv = buf->dev_private;
-
+
vma->vm_flags |= (VM_IO | VM_DONTCOPY);
vma->vm_file = filp;
-
+
buf_priv->currently_mapped = I810_BUF_MAPPED;
unlock_kernel();
@@ -196,9 +197,9 @@ static int i810_map_buffer(drm_buf_t *buf, struct file *filp)
old_fops = filp->f_op;
filp->f_op = &i810_buffer_fops;
dev_priv->mmap_buffer = buf;
- buf_priv->virtual = (void *)do_mmap(filp, 0, buf->total,
+ buf_priv->virtual = (void *)do_mmap(filp, 0, buf->total,
PROT_READ|PROT_WRITE,
- MAP_SHARED,
+ MAP_SHARED,
buf->bus_address);
dev_priv->mmap_buffer = NULL;
filp->f_op = old_fops;
@@ -222,15 +223,15 @@ static int i810_unmap_buffer(drm_buf_t *buf)
int retcode = 0;
if(VM_DONTCOPY != 0) {
- if(buf_priv->currently_mapped != I810_BUF_MAPPED)
+ if(buf_priv->currently_mapped != I810_BUF_MAPPED)
return -EINVAL;
down(&current->mm->mmap_sem);
#if LINUX_VERSION_CODE < 0x020399
- retcode = do_munmap((unsigned long)buf_priv->virtual,
+ retcode = do_munmap((unsigned long)buf_priv->virtual,
(size_t) buf->total);
#else
- retcode = do_munmap(current->mm,
- (unsigned long)buf_priv->virtual,
+ retcode = do_munmap(current->mm,
+ (unsigned long)buf_priv->virtual,
(size_t) buf->total);
#endif
up(&current->mm->mmap_sem);
@@ -241,7 +242,7 @@ static int i810_unmap_buffer(drm_buf_t *buf)
return retcode;
}
-static int i810_dma_get_buffer(drm_device_t *dev, drm_i810_dma_t *d,
+static int i810_dma_get_buffer(drm_device_t *dev, drm_i810_dma_t *d,
struct file *filp)
{
drm_file_t *priv = filp->private_data;
@@ -255,7 +256,7 @@ static int i810_dma_get_buffer(drm_device_t *dev, drm_i810_dma_t *d,
DRM_DEBUG("retcode=%d\n", retcode);
return retcode;
}
-
+
retcode = i810_map_buffer(buf, filp);
if(retcode) {
i810_freelist_put(dev, buf);
@@ -263,7 +264,7 @@ static int i810_dma_get_buffer(drm_device_t *dev, drm_i810_dma_t *d,
return retcode;
}
buf->pid = priv->pid;
- buf_priv = buf->dev_private;
+ buf_priv = buf->dev_private;
d->granted = 1;
d->request_idx = buf->idx;
d->request_size = buf->total;
@@ -275,22 +276,22 @@ static int i810_dma_get_buffer(drm_device_t *dev, drm_i810_dma_t *d,
static unsigned long i810_alloc_page(drm_device_t *dev)
{
unsigned long address;
-
+
address = __get_free_page(GFP_KERNEL);
- if(address == 0UL)
+ if(address == 0UL)
return 0;
-
+
atomic_inc(&virt_to_page(address)->count);
set_bit(PG_locked, &virt_to_page(address)->flags);
-
+
return address;
}
static void i810_free_page(drm_device_t *dev, unsigned long page)
{
- if(page == 0UL)
+ if(page == 0UL)
return;
-
+
atomic_dec(&virt_to_page(page)->count);
clear_bit(PG_locked, &virt_to_page(page)->flags);
wake_up(&virt_to_page(page)->wait);
@@ -304,26 +305,26 @@ static int i810_dma_cleanup(drm_device_t *dev)
if(dev->dev_private) {
int i;
- drm_i810_private_t *dev_priv =
+ drm_i810_private_t *dev_priv =
(drm_i810_private_t *) dev->dev_private;
-
+
if(dev_priv->ring.virtual_start) {
- drm_ioremapfree((void *) dev_priv->ring.virtual_start,
- dev_priv->ring.Size);
+ DRM(ioremapfree)((void *) dev_priv->ring.virtual_start,
+ dev_priv->ring.Size);
}
if(dev_priv->hw_status_page != 0UL) {
i810_free_page(dev, dev_priv->hw_status_page);
/* Need to rewrite hardware status page */
I810_WRITE(0x02080, 0x1ffff000);
}
- drm_free(dev->dev_private, sizeof(drm_i810_private_t),
+ DRM(free)(dev->dev_private, sizeof(drm_i810_private_t),
DRM_MEM_DRIVER);
dev->dev_private = NULL;
for (i = 0; i < dma->buf_count; i++) {
drm_buf_t *buf = dma->buflist[ i ];
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
- drm_ioremapfree(buf_priv->kernel_virtual, buf->total);
+ DRM(ioremapfree)(buf_priv->kernel_virtual, buf->total);
}
}
return 0;
@@ -340,14 +341,14 @@ static int i810_wait_ring(drm_device_t *dev, int n)
end = jiffies + (HZ*3);
while (ring->space < n) {
int i;
-
+
ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
ring->space = ring->head - (ring->tail+8);
if (ring->space < 0) ring->space += ring->Size;
-
+
if (ring->head != last_head)
end = jiffies + (HZ*3);
-
+
iters++;
if((signed)(end - jiffies) <= 0) {
DRM_ERROR("space: %d wanted %d\n", ring->space, n);
@@ -358,7 +359,7 @@ static int i810_wait_ring(drm_device_t *dev, int n)
for (i = 0 ; i < 2000 ; i++) ;
}
-out_wait_ring:
+out_wait_ring:
return iters;
}
@@ -366,7 +367,7 @@ static void i810_kernel_lost_context(drm_device_t *dev)
{
drm_i810_private_t *dev_priv = dev->dev_private;
drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
-
+
ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
ring->tail = I810_READ(LP_RING + RING_TAIL);
ring->space = ring->head - (ring->tail+8);
@@ -380,7 +381,7 @@ static int i810_freelist_init(drm_device_t *dev)
int my_idx = 24;
u32 *hw_status = (u32 *)(dev_priv->hw_status_page + my_idx);
int i;
-
+
if(dma->buf_count > 1019) {
/* Not enough space in the status page for the freelist */
return -EINVAL;
@@ -389,20 +390,20 @@ static int i810_freelist_init(drm_device_t *dev)
for (i = 0; i < dma->buf_count; i++) {
drm_buf_t *buf = dma->buflist[ i ];
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
-
+
buf_priv->in_use = hw_status++;
buf_priv->my_use_idx = my_idx;
my_idx += 4;
*buf_priv->in_use = I810_BUF_FREE;
- buf_priv->kernel_virtual = drm_ioremap(buf->bus_address,
- buf->total);
+ buf_priv->kernel_virtual = DRM(ioremap)(buf->bus_address,
+ buf->total);
}
return 0;
}
-static int i810_dma_initialize(drm_device_t *dev,
+static int i810_dma_initialize(drm_device_t *dev,
drm_i810_private_t *dev_priv,
drm_i810_init_t *init)
{
@@ -417,27 +418,27 @@ static int i810_dma_initialize(drm_device_t *dev,
DRM_ERROR("ring_map or buffer_map are invalid\n");
return -EINVAL;
}
-
+
dev_priv->ring_map_idx = init->ring_map_idx;
dev_priv->buffer_map_idx = init->buffer_map_idx;
sarea_map = dev->maplist[0];
- dev_priv->sarea_priv = (drm_i810_sarea_t *)
- ((u8 *)sarea_map->handle +
+ dev_priv->sarea_priv = (drm_i810_sarea_t *)
+ ((u8 *)sarea_map->handle +
init->sarea_priv_offset);
atomic_set(&dev_priv->flush_done, 0);
init_waitqueue_head(&dev_priv->flush_queue);
-
+
dev_priv->ring.Start = init->ring_start;
dev_priv->ring.End = init->ring_end;
dev_priv->ring.Size = init->ring_size;
- dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base +
- init->ring_start,
- init->ring_size);
+ dev_priv->ring.virtual_start = DRM(ioremap)(dev->agp->base +
+ init->ring_start,
+ init->ring_size);
dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
-
+
if (dev_priv->ring.virtual_start == NULL) {
i810_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for"
@@ -454,8 +455,8 @@ static int i810_dma_initialize(drm_device_t *dev,
dev_priv->front_di1 = init->front_offset | init->pitch_bits;
dev_priv->back_di1 = init->back_offset | init->pitch_bits;
dev_priv->zi1 = init->depth_offset | init->pitch_bits;
-
-
+
+
/* Program Hardware Status Page */
dev_priv->hw_status_page = i810_alloc_page(dev);
memset((void *) dev_priv->hw_status_page, 0, PAGE_SIZE);
@@ -465,10 +466,10 @@ static int i810_dma_initialize(drm_device_t *dev,
return -ENOMEM;
}
DRM_DEBUG("hw status page @ %lx\n", dev_priv->hw_status_page);
-
+
I810_WRITE(0x02080, virt_to_bus((void *)dev_priv->hw_status_page));
DRM_DEBUG("Enabled hardware status page\n");
-
+
/* Now we need to init our freelist */
if(i810_freelist_init(dev) != 0) {
i810_dma_cleanup(dev);
@@ -487,13 +488,13 @@ int i810_dma_init(struct inode *inode, struct file *filp,
drm_i810_private_t *dev_priv;
drm_i810_init_t init;
int retcode = 0;
-
+
if (copy_from_user(&init, (drm_i810_init_t *)arg, sizeof(init)))
return -EFAULT;
-
+
switch(init.func) {
case I810_INIT_DMA:
- dev_priv = drm_alloc(sizeof(drm_i810_private_t),
+ dev_priv = DRM(alloc)(sizeof(drm_i810_private_t),
DRM_MEM_DRIVER);
if(dev_priv == NULL) return -ENOMEM;
retcode = i810_dma_initialize(dev, dev_priv, &init);
@@ -505,7 +506,7 @@ int i810_dma_init(struct inode *inode, struct file *filp,
retcode = -EINVAL;
break;
}
-
+
return retcode;
}
@@ -517,9 +518,9 @@ int i810_dma_init(struct inode *inode, struct file *filp,
* Use 'volatile' & local var tmp to force the emitted values to be
* identical to the verified ones.
*/
-static void i810EmitContextVerified( drm_device_t *dev,
- volatile unsigned int *code )
-{
+static void i810EmitContextVerified( drm_device_t *dev,
+ volatile unsigned int *code )
+{
drm_i810_private_t *dev_priv = dev->dev_private;
int i, j = 0;
unsigned int tmp;
@@ -537,22 +538,22 @@ static void i810EmitContextVerified( drm_device_t *dev,
tmp = code[i];
if ((tmp & (7<<29)) == (3<<29) &&
- (tmp & (0x1f<<24)) < (0x1d<<24))
+ (tmp & (0x1f<<24)) < (0x1d<<24))
{
- OUT_RING( tmp );
+ OUT_RING( tmp );
j++;
- }
+ }
}
- if (j & 1)
- OUT_RING( 0 );
+ if (j & 1)
+ OUT_RING( 0 );
ADVANCE_LP_RING();
}
-static void i810EmitTexVerified( drm_device_t *dev,
- volatile unsigned int *code )
-{
+static void i810EmitTexVerified( drm_device_t *dev,
+ volatile unsigned int *code )
+{
drm_i810_private_t *dev_priv = dev->dev_private;
int i, j = 0;
unsigned int tmp;
@@ -569,15 +570,15 @@ static void i810EmitTexVerified( drm_device_t *dev,
tmp = code[i];
if ((tmp & (7<<29)) == (3<<29) &&
- (tmp & (0x1f<<24)) < (0x1d<<24))
+ (tmp & (0x1f<<24)) < (0x1d<<24))
{
- OUT_RING( tmp );
+ OUT_RING( tmp );
j++;
}
- }
-
- if (j & 1)
- OUT_RING( 0 );
+ }
+
+ if (j & 1)
+ OUT_RING( 0 );
ADVANCE_LP_RING();
}
@@ -585,9 +586,9 @@ static void i810EmitTexVerified( drm_device_t *dev,
/* Need to do some additional checking when setting the dest buffer.
*/
-static void i810EmitDestVerified( drm_device_t *dev,
- volatile unsigned int *code )
-{
+static void i810EmitDestVerified( drm_device_t *dev,
+ volatile unsigned int *code )
+{
drm_i810_private_t *dev_priv = dev->dev_private;
unsigned int tmp;
RING_LOCALS;
@@ -651,9 +652,9 @@ static void i810EmitState( drm_device_t *dev )
-/* need to verify
+/* need to verify
*/
-static void i810_dma_dispatch_clear( drm_device_t *dev, int flags,
+static void i810_dma_dispatch_clear( drm_device_t *dev, int flags,
unsigned int clear_color,
unsigned int clear_zval )
{
@@ -684,10 +685,10 @@ static void i810_dma_dispatch_clear( drm_device_t *dev, int flags,
pbox->y2 > dev_priv->h)
continue;
- if ( flags & I810_FRONT ) {
+ if ( flags & I810_FRONT ) {
DRM_DEBUG("clear front\n");
- BEGIN_LP_RING( 6 );
- OUT_RING( BR00_BITBLT_CLIENT |
+ BEGIN_LP_RING( 6 );
+ OUT_RING( BR00_BITBLT_CLIENT |
BR00_OP_COLOR_BLT | 0x3 );
OUT_RING( BR13_SOLID_PATTERN | (0xF0 << 16) | pitch );
OUT_RING( (height << 16) | width );
@@ -699,8 +700,8 @@ static void i810_dma_dispatch_clear( drm_device_t *dev, int flags,
if ( flags & I810_BACK ) {
DRM_DEBUG("clear back\n");
- BEGIN_LP_RING( 6 );
- OUT_RING( BR00_BITBLT_CLIENT |
+ BEGIN_LP_RING( 6 );
+ OUT_RING( BR00_BITBLT_CLIENT |
BR00_OP_COLOR_BLT | 0x3 );
OUT_RING( BR13_SOLID_PATTERN | (0xF0 << 16) | pitch );
OUT_RING( (height << 16) | width );
@@ -712,8 +713,8 @@ static void i810_dma_dispatch_clear( drm_device_t *dev, int flags,
if ( flags & I810_DEPTH ) {
DRM_DEBUG("clear depth\n");
- BEGIN_LP_RING( 6 );
- OUT_RING( BR00_BITBLT_CLIENT |
+ BEGIN_LP_RING( 6 );
+ OUT_RING( BR00_BITBLT_CLIENT |
BR00_OP_COLOR_BLT | 0x3 );
OUT_RING( BR13_SOLID_PATTERN | (0xF0 << 16) | pitch );
OUT_RING( (height << 16) | width );
@@ -744,7 +745,7 @@ static void i810_dma_dispatch_swap( drm_device_t *dev )
if (nbox > I810_NR_SAREA_CLIPRECTS)
nbox = I810_NR_SAREA_CLIPRECTS;
- for (i = 0 ; i < nbox; i++, pbox++)
+ for (i = 0 ; i < nbox; i++, pbox++)
{
unsigned int w = pbox->x2 - pbox->x1;
unsigned int h = pbox->y2 - pbox->y1;
@@ -756,7 +757,7 @@ static void i810_dma_dispatch_swap( drm_device_t *dev )
pbox->x2 > dev_priv->w ||
pbox->y2 > dev_priv->h)
continue;
-
+
DRM_DEBUG("dispatch swap %d,%d-%d,%d!\n",
pbox[i].x1, pbox[i].y1,
pbox[i].x2, pbox[i].y2);
@@ -766,14 +767,14 @@ static void i810_dma_dispatch_swap( drm_device_t *dev )
OUT_RING( pitch | (0xCC << 16));
OUT_RING( (h << 16) | (w * cpp));
OUT_RING( dst );
- OUT_RING( pitch );
+ OUT_RING( pitch );
OUT_RING( start );
ADVANCE_LP_RING();
}
}
-static void i810_dma_dispatch_vertex(drm_device_t *dev,
+static void i810_dma_dispatch_vertex(drm_device_t *dev,
drm_buf_t *buf,
int discard,
int used)
@@ -784,30 +785,30 @@ static void i810_dma_dispatch_vertex(drm_device_t *dev,
drm_clip_rect_t *box = sarea_priv->boxes;
int nbox = sarea_priv->nbox;
unsigned long address = (unsigned long)buf->bus_address;
- unsigned long start = address - dev->agp->base;
+ unsigned long start = address - dev->agp->base;
int i = 0, u;
RING_LOCALS;
i810_kernel_lost_context(dev);
- if (nbox > I810_NR_SAREA_CLIPRECTS)
+ if (nbox > I810_NR_SAREA_CLIPRECTS)
nbox = I810_NR_SAREA_CLIPRECTS;
if (discard) {
- u = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT,
+ u = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT,
I810_BUF_HARDWARE);
if(u != I810_BUF_CLIENT) {
DRM_DEBUG("xxxx 2\n");
}
}
- if (used > 4*1024)
+ if (used > 4*1024)
used = 0;
if (sarea_priv->dirty)
i810EmitState( dev );
- DRM_DEBUG("dispatch vertex addr 0x%lx, used 0x%x nbox %d\n",
+ DRM_DEBUG("dispatch vertex addr 0x%lx, used 0x%x nbox %d\n",
address, used, nbox);
dev_priv->counter++;
@@ -821,7 +822,7 @@ static void i810_dma_dispatch_vertex(drm_device_t *dev,
*(u32 *)buf_priv->virtual = (GFX_OP_PRIMITIVE |
sarea_priv->vertex_prim |
((used/4)-2));
-
+
if (used & 4) {
*(u32 *)((u32)buf_priv->virtual + used) = 0;
used += 4;
@@ -829,26 +830,26 @@ static void i810_dma_dispatch_vertex(drm_device_t *dev,
i810_unmap_buffer(buf);
}
-
+
if (used) {
do {
if (i < nbox) {
BEGIN_LP_RING(4);
- OUT_RING( GFX_OP_SCISSOR | SC_UPDATE_SCISSOR |
+ OUT_RING( GFX_OP_SCISSOR | SC_UPDATE_SCISSOR |
SC_ENABLE );
OUT_RING( GFX_OP_SCISSOR_INFO );
OUT_RING( box[i].x1 | (box[i].y1<<16) );
OUT_RING( (box[i].x2-1) | ((box[i].y2-1)<<16) );
ADVANCE_LP_RING();
}
-
+
BEGIN_LP_RING(4);
OUT_RING( CMD_OP_BATCH_BUFFER );
OUT_RING( start | BB1_PROTECTED );
OUT_RING( start + used - 4 );
OUT_RING( 0 );
ADVANCE_LP_RING();
-
+
} while (++i < nbox);
}
@@ -876,15 +877,15 @@ static void i810_dma_service(int irq, void *device, struct pt_regs *regs)
{
drm_device_t *dev = (drm_device_t *)device;
u16 temp;
-
- atomic_inc(&dev->total_irq);
+
+ atomic_inc(&dev->counts[_DRM_STAT_IRQ]);
temp = I810_READ16(I810REG_INT_IDENTITY_R);
temp = temp & ~(0x6000);
- if(temp != 0) I810_WRITE16(I810REG_INT_IDENTITY_R,
+ if(temp != 0) I810_WRITE16(I810REG_INT_IDENTITY_R,
temp); /* Clear all interrupts */
else
return;
-
+
queue_task(&dev->tq, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
@@ -902,9 +903,9 @@ int i810_irq_install(drm_device_t *dev, int irq)
{
int retcode;
u16 temp;
-
+
if (!irq) return -EINVAL;
-
+
down(&dev->struct_sem);
if (dev->irq) {
up(&dev->struct_sem);
@@ -912,14 +913,14 @@ int i810_irq_install(drm_device_t *dev, int irq)
}
dev->irq = irq;
up(&dev->struct_sem);
-
+
DRM_DEBUG( "Interrupt Install : %d\n", irq);
DRM_DEBUG("%d\n", irq);
dev->context_flag = 0;
dev->interrupt_flag = 0;
dev->dma_flag = 0;
-
+
dev->dma->next_buffer = NULL;
dev->dma->next_queue = NULL;
dev->dma->this_buffer = NULL;
@@ -933,7 +934,7 @@ int i810_irq_install(drm_device_t *dev, int irq)
temp = I810_READ16(I810REG_HWSTAM);
temp = temp & 0x6000;
I810_WRITE16(I810REG_HWSTAM, temp);
-
+
temp = I810_READ16(I810REG_INT_MASK_R);
temp = temp & 0x6000;
I810_WRITE16(I810REG_INT_MASK_R, temp); /* Unmask interrupts */
@@ -955,7 +956,7 @@ int i810_irq_install(drm_device_t *dev, int irq)
temp = I810_READ16(I810REG_INT_ENABLE_R);
temp = temp & 0x6000;
temp = temp | 0x0003;
- I810_WRITE16(I810REG_INT_ENABLE_R,
+ I810_WRITE16(I810REG_INT_ENABLE_R,
temp); /* Enable bp & user interrupts */
return 0;
}
@@ -972,20 +973,20 @@ int i810_irq_uninstall(drm_device_t *dev)
irq = dev->irq;
dev->irq = 0;
up(&dev->struct_sem);
-
+
if (!irq) return -EINVAL;
- DRM_DEBUG( "Interrupt UnInstall: %d\n", irq);
+ DRM_DEBUG( "Interrupt UnInstall: %d\n", irq);
DRM_DEBUG("%d\n", irq);
-
+
temp = I810_READ16(I810REG_INT_IDENTITY_R);
temp = temp & ~(0x6000);
- if(temp != 0) I810_WRITE16(I810REG_INT_IDENTITY_R,
+ if(temp != 0) I810_WRITE16(I810REG_INT_IDENTITY_R,
temp); /* Clear all interrupts */
-
+
temp = I810_READ16(I810REG_INT_ENABLE_R);
temp = temp & 0x6000;
- I810_WRITE16(I810REG_INT_ENABLE_R,
+ I810_WRITE16(I810REG_INT_ENABLE_R,
temp); /* Disable all interrupts */
free_irq(irq, dev);
@@ -1000,12 +1001,12 @@ int i810_control(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_control_t ctl;
int retcode;
-
+
DRM_DEBUG( "i810_control\n");
if (copy_from_user(&ctl, (drm_control_t *)arg, sizeof(ctl)))
return -EFAULT;
-
+
switch (ctl.func) {
case DRM_INST_HANDLER:
if ((retcode = i810_irq_install(dev, ctl.irq)))
@@ -1057,11 +1058,11 @@ static inline void i810_dma_quiescent_emit(drm_device_t *dev)
/* wake_up_interruptible(&dev_priv->flush_queue); */
}
-static void i810_dma_quiescent(drm_device_t *dev)
+void i810_dma_quiescent(drm_device_t *dev)
{
DECLARE_WAITQUEUE(entry, current);
drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
- unsigned long end;
+ unsigned long end;
if(dev_priv == NULL) {
return;
@@ -1069,7 +1070,7 @@ static void i810_dma_quiescent(drm_device_t *dev)
atomic_set(&dev_priv->flush_done, 0);
add_wait_queue(&dev_priv->flush_queue, &entry);
end = jiffies + (HZ*3);
-
+
for (;;) {
current->state = TASK_INTERRUPTIBLE;
i810_dma_quiescent_emit(dev);
@@ -1077,16 +1078,16 @@ static void i810_dma_quiescent(drm_device_t *dev)
if((signed)(end - jiffies) <= 0) {
DRM_ERROR("lockup\n");
break;
- }
+ }
schedule_timeout(HZ*3);
if (signal_pending(current)) {
break;
}
}
-
+
current->state = TASK_RUNNING;
remove_wait_queue(&dev_priv->flush_queue, &entry);
-
+
return;
}
@@ -1096,7 +1097,7 @@ static int i810_flush_queue(drm_device_t *dev)
drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
drm_device_dma_t *dma = dev->dma;
unsigned long end;
- int i, ret = 0;
+ int i, ret = 0;
if(dev_priv == NULL) {
return 0;
@@ -1111,14 +1112,14 @@ static int i810_flush_queue(drm_device_t *dev)
if((signed)(end - jiffies) <= 0) {
DRM_ERROR("lockup\n");
break;
- }
+ }
schedule_timeout(HZ*3);
if (signal_pending(current)) {
ret = -EINTR; /* Can't restart */
break;
}
}
-
+
current->state = TASK_RUNNING;
remove_wait_queue(&dev_priv->flush_queue, &entry);
@@ -1126,8 +1127,8 @@ static int i810_flush_queue(drm_device_t *dev)
for (i = 0; i < dma->buf_count; i++) {
drm_buf_t *buf = dma->buflist[ i ];
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
-
- int used = cmpxchg(buf_priv->in_use, I810_BUF_HARDWARE,
+
+ int used = cmpxchg(buf_priv->in_use, I810_BUF_HARDWARE,
I810_BUF_FREE);
if (used == I810_BUF_HARDWARE)
@@ -1154,9 +1155,9 @@ void i810_reclaim_buffers(drm_device_t *dev, pid_t pid)
for (i = 0; i < dma->buf_count; i++) {
drm_buf_t *buf = dma->buflist[ i ];
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
-
+
if (buf->pid == pid && buf_priv) {
- int used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT,
+ int used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT,
I810_BUF_FREE);
if (used == I810_BUF_CLIENT)
@@ -1167,91 +1168,12 @@ void i810_reclaim_buffers(drm_device_t *dev, pid_t pid)
}
}
-int i810_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 (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
- return -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 (lock.context < 0) {
- return -EINVAL;
- }
- /* Only one queue:
- */
-
- if (!ret) {
- add_wait_queue(&dev->lock.lock_queue, &entry);
- for (;;) {
- current->state = TASK_INTERRUPTIBLE;
- 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);
- DRM_DEBUG("Calling lock schedule\n");
- schedule();
- if (signal_pending(current)) {
- ret = -ERESTARTSYS;
- break;
- }
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&dev->lock.lock_queue, &entry);
- }
-
- if (!ret) {
- sigemptyset(&dev->sigmask);
- sigaddset(&dev->sigmask, SIGSTOP);
- sigaddset(&dev->sigmask, SIGTSTP);
- sigaddset(&dev->sigmask, SIGTTIN);
- sigaddset(&dev->sigmask, SIGTTOU);
- dev->sigdata.context = lock.context;
- dev->sigdata.lock = dev->lock.hw_lock;
- block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask);
-
- if (lock.flags & _DRM_LOCK_QUIESCENT) {
- DRM_DEBUG("_DRM_LOCK_QUIESCENT\n");
- DRM_DEBUG("fred\n");
- i810_dma_quiescent(dev);
- }
- }
- DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
- return ret;
-}
-
-int i810_flush_ioctl(struct inode *inode, struct file *filp,
+int i810_flush_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->dev;
-
+
DRM_DEBUG("i810_flush_ioctl\n");
if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
DRM_ERROR("i810_flush_ioctl called without lock held\n");
@@ -1271,8 +1193,8 @@ int i810_dma_vertex(struct inode *inode, struct file *filp,
drm_device_dma_t *dma = dev->dma;
drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
u32 *hw_status = (u32 *)dev_priv->hw_status_page;
- drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
- dev_priv->sarea_priv;
+ drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
+ dev_priv->sarea_priv;
drm_i810_vertex_t vertex;
if (copy_from_user(&vertex, (drm_i810_vertex_t *)arg, sizeof(vertex)))
@@ -1286,15 +1208,15 @@ int i810_dma_vertex(struct inode *inode, struct file *filp,
DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n",
vertex.idx, vertex.used, vertex.discard);
- i810_dma_dispatch_vertex( dev,
- dma->buflist[ vertex.idx ],
+ i810_dma_dispatch_vertex( dev,
+ dma->buflist[ vertex.idx ],
vertex.discard, vertex.used );
- atomic_add(vertex.used, &dma->total_bytes);
- atomic_inc(&dma->total_dmas);
+ atomic_add(vertex.used, &dev->counts[_DRM_STAT_SECONDARY]);
+ atomic_inc(&dev->counts[_DRM_STAT_DMA]);
sarea_priv->last_enqueue = dev_priv->counter-1;
sarea_priv->last_dispatch = (int) hw_status[5];
-
+
return 0;
}
@@ -1309,14 +1231,14 @@ int i810_clear_bufs(struct inode *inode, struct file *filp,
if (copy_from_user(&clear, (drm_i810_clear_t *)arg, sizeof(clear)))
return -EFAULT;
-
+
if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
DRM_ERROR("i810_clear_bufs called without lock held\n");
return -EINVAL;
}
- i810_dma_dispatch_clear( dev, clear.flags,
- clear.clear_color,
+ i810_dma_dispatch_clear( dev, clear.flags,
+ clear.clear_color,
clear.clear_depth );
return 0;
}
@@ -1326,7 +1248,7 @@ int i810_swap_bufs(struct inode *inode, struct file *filp,
{
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->dev;
-
+
DRM_DEBUG("i810_swap_bufs\n");
if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
@@ -1345,8 +1267,8 @@ int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
u32 *hw_status = (u32 *)dev_priv->hw_status_page;
- drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
- dev_priv->sarea_priv;
+ drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
+ dev_priv->sarea_priv;
sarea_priv->last_dispatch = (int) hw_status[5];
return 0;
@@ -1361,18 +1283,18 @@ int i810_getbuf(struct inode *inode, struct file *filp, unsigned int cmd,
drm_i810_dma_t d;
drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
u32 *hw_status = (u32 *)dev_priv->hw_status_page;
- drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
- dev_priv->sarea_priv;
+ drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
+ dev_priv->sarea_priv;
DRM_DEBUG("getbuf\n");
if (copy_from_user(&d, (drm_i810_dma_t *)arg, sizeof(d)))
return -EFAULT;
-
+
if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
DRM_ERROR("i810_dma called without lock held\n");
return -EINVAL;
}
-
+
d.granted = 0;
retcode = i810_dma_get_buffer(dev, &d, filp);
@@ -1395,8 +1317,8 @@ int i810_copybuf(struct inode *inode, struct file *filp, unsigned int cmd,
drm_i810_copy_t d;
drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
u32 *hw_status = (u32 *)dev_priv->hw_status_page;
- drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
- dev_priv->sarea_priv;
+ drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
+ dev_priv->sarea_priv;
drm_buf_t *buf;
drm_i810_buf_priv_t *buf_priv;
drm_device_dma_t *dma = dev->dma;
@@ -1405,7 +1327,7 @@ int i810_copybuf(struct inode *inode, struct file *filp, unsigned int cmd,
DRM_ERROR("i810_dma called without lock held\n");
return -EINVAL;
}
-
+
if (copy_from_user(&d, (drm_i810_copy_t *)arg, sizeof(d)))
return -EFAULT;
diff --git a/linux-core/i810_drv.c b/linux-core/i810_drv.c
index 7152eac3..5b4d1c34 100644
--- a/linux-core/i810_drv.c
+++ b/linux-core/i810_drv.c
@@ -19,630 +19,84 @@
* 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
- * Jeff Hartmann <jhartmann@valinux.com>
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*
+ * Authors:
+ * Rickard E. (Rik) Faith <faith@valinux.com>
+ * Jeff Hartmann <jhartmann@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
*/
#include <linux/config.h>
+#include "i810.h"
#include "drmP.h"
#include "i810_drv.h"
-#define I810_NAME "i810"
-#define I810_DESC "Intel I810"
-#define I810_DATE "20000928"
-#define I810_MAJOR 1
-#define I810_MINOR 1
-#define I810_PATCHLEVEL 0
-
-static drm_device_t i810_device;
-drm_ctx_t i810_res_ctx;
-
-static struct file_operations i810_fops = {
-#if LINUX_VERSION_CODE >= 0x020400
- /* This started being used during 2.4.0-test */
- owner: THIS_MODULE,
-#endif
- open: i810_open,
- flush: drm_flush,
- release: i810_release,
- ioctl: i810_ioctl,
- mmap: drm_mmap,
- read: drm_read,
- fasync: drm_fasync,
- poll: drm_poll,
-};
-
-static struct miscdevice i810_misc = {
- minor: MISC_DYNAMIC_MINOR,
- name: I810_NAME,
- fops: &i810_fops,
-};
-
-static drm_ioctl_desc_t i810_ioctls[] = {
- [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { i810_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_CONTROL)] = { i810_control, 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)] = { i810_addbufs, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = { i810_markbufs, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { i810_infobufs, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { i810_freebufs, 1, 0 },
-
- [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { i810_addctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { i810_rmctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { i810_modctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { i810_getctx, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { i810_switchctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { i810_newctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { i810_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)] = { i810_lock, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { i810_unlock, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { drm_finish, 1, 0 },
-
- [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 },
-
- [DRM_IOCTL_NR(DRM_IOCTL_I810_INIT)] = { i810_dma_init, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_I810_VERTEX)] = { i810_dma_vertex, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_I810_CLEAR)] = { i810_clear_bufs, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_I810_FLUSH)] = { i810_flush_ioctl,1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_I810_GETAGE)] = { i810_getage, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_I810_GETBUF)] = { i810_getbuf, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_I810_SWAP)] = { i810_swap_bufs, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_I810_COPY)] = { i810_copybuf, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_I810_DOCOPY)] = { i810_docopy, 1, 0 },
-};
-
-#define I810_IOCTL_COUNT DRM_ARRAY_SIZE(i810_ioctls)
-
-#ifdef MODULE
-static char *i810 = NULL;
-#endif
-
-MODULE_AUTHOR("VA Linux Systems, Inc.");
-MODULE_DESCRIPTION("Intel I810");
-MODULE_PARM(i810, "s");
-
-#ifndef MODULE
-/* i810_options 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.
- */
-
-static int __init i810_options(char *str)
-{
- drm_parse_options(str);
- return 1;
-}
-
-__setup("i810=", i810_options);
-#endif
-
-static int i810_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);
-#if DRM_DMA_HISTO
- memset(&dev->histo, 0, sizeof(dev->histo));
-#endif
- 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);
-
- 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 i810_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");
-
- if (dev->irq) i810_irq_uninstall(dev);
-
- 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;
- }
- /* 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();
-
- dev->agp->acquired = 0;
- dev->agp->enabled = 0;
- }
- /* 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:
- 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;
- }
-
- if (dev->queuelist) {
- for (i = 0; i < dev->queue_count; i++) {
- drm_waitlist_destroy(&dev->queuelist[i]->waitlist);
- if (dev->queuelist[i]) {
- drm_free(dev->queuelist[i],
- sizeof(*dev->queuelist[0]),
- DRM_MEM_QUEUES);
- dev->queuelist[i] = NULL;
- }
- }
- drm_free(dev->queuelist,
- dev->queue_slots * sizeof(*dev->queuelist),
- DRM_MEM_QUEUES);
- dev->queuelist = NULL;
- }
-
- 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;
-}
-
-/* i810_init is called via init_module at module load time, or via
- * linux/init/main.c (this is not currently supported). */
-
-static int __init i810_init(void)
-{
- int retcode;
- drm_device_t *dev = &i810_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(i810);
-#endif
- DRM_DEBUG("doing misc_register\n");
- if ((retcode = misc_register(&i810_misc))) {
- DRM_ERROR("Cannot register \"%s\"\n", I810_NAME);
- return retcode;
- }
- dev->device = MKDEV(MISC_MAJOR, i810_misc.minor);
- dev->name = I810_NAME;
-
- DRM_DEBUG("doing mem init\n");
- drm_mem_init();
- DRM_DEBUG("doing proc init\n");
- drm_proc_init(dev);
- DRM_DEBUG("doing agp init\n");
- dev->agp = drm_agp_init();
- if(dev->agp == NULL) {
- DRM_INFO("The i810 drm module requires the agpgart module"
- " to function correctly\nPlease load the agpgart"
- " module before you load the i810 module\n");
- drm_proc_cleanup();
- misc_deregister(&i810_misc);
- i810_takedown(dev);
- return -ENOMEM;
- }
- DRM_DEBUG("doing ctxbitmap init\n");
- if((retcode = drm_ctxbitmap_init(dev))) {
- DRM_ERROR("Cannot allocate memory for context bitmap.\n");
- drm_proc_cleanup();
- misc_deregister(&i810_misc);
- i810_takedown(dev);
- return retcode;
- }
-
- DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
- I810_NAME,
- I810_MAJOR,
- I810_MINOR,
- I810_PATCHLEVEL,
- I810_DATE,
- i810_misc.minor);
-
- return 0;
-}
-
-/* i810_cleanup is called via cleanup_module at module unload time. */
-
-static void __exit i810_cleanup(void)
-{
- drm_device_t *dev = &i810_device;
-
- DRM_DEBUG("\n");
-
- drm_proc_cleanup();
- if (misc_deregister(&i810_misc)) {
- DRM_ERROR("Cannot unload module\n");
- } else {
- DRM_INFO("Module unloaded\n");
- }
- drm_ctxbitmap_cleanup(dev);
- i810_takedown(dev);
- if (dev->agp) {
- drm_agp_uninit();
- drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS);
- dev->agp = NULL;
- }
-}
-
-module_init(i810_init);
-module_exit(i810_cleanup);
-
-
-int i810_version(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
-{
- drm_version_t version;
- int len;
-
- if (copy_from_user(&version,
- (drm_version_t *)arg,
- sizeof(version)))
- return -EFAULT;
-
-#define DRM_COPY(name,value) \
- len = strlen(value); \
- if (len > name##_len) len = name##_len; \
- name##_len = strlen(value); \
- if (len && name) { \
- if (copy_to_user(name, value, len)) \
- return -EFAULT; \
- }
-
- version.version_major = I810_MAJOR;
- version.version_minor = I810_MINOR;
- version.version_patchlevel = I810_PATCHLEVEL;
-
- DRM_COPY(version.name, I810_NAME);
- DRM_COPY(version.date, I810_DATE);
- DRM_COPY(version.desc, I810_DESC);
-
- if (copy_to_user((drm_version_t *)arg,
- &version,
- sizeof(version)))
- return -EFAULT;
- return 0;
-}
-
-int i810_open(struct inode *inode, struct file *filp)
-{
- drm_device_t *dev = &i810_device;
- int retcode = 0;
-
- DRM_DEBUG("open_count = %d\n", dev->open_count);
- if (!(retcode = drm_open_helper(inode, filp, dev))) {
-#if LINUX_VERSION_CODE < 0x020333
- MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */
-#endif
- atomic_inc(&dev->total_open);
- spin_lock(&dev->count_lock);
- if (!dev->open_count++) {
- spin_unlock(&dev->count_lock);
- return i810_setup(dev);
- }
- spin_unlock(&dev->count_lock);
- }
- return retcode;
-}
-
-int i810_release(struct inode *inode, struct file *filp)
-{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev;
- int retcode = 0;
-
- lock_kernel();
- dev = priv->dev;
- DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n",
- current->pid, dev->device, dev->open_count);
-
- if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
- && dev->lock.pid == current->pid) {
- i810_reclaim_buffers(dev, priv->pid);
- DRM_ERROR("Process %d dead, freeing lock for context %d\n",
- current->pid,
- _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
- drm_lock_free(dev,
- &dev->lock.hw_lock->lock,
- _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
-
- /* FIXME: may require heavy-handed reset of
- hardware at this point, possibly
- processed via a callback to the X
- server. */
- } else if (dev->lock.hw_lock) {
- /* The lock is required to reclaim buffers */
- DECLARE_WAITQUEUE(entry, current);
- add_wait_queue(&dev->lock.lock_queue, &entry);
- for (;;) {
- current->state = TASK_INTERRUPTIBLE;
- if (!dev->lock.hw_lock) {
- /* Device has been unregistered */
- retcode = -EINTR;
- break;
- }
- if (drm_lock_take(&dev->lock.hw_lock->lock,
- DRM_KERNEL_CONTEXT)) {
- dev->lock.pid = priv->pid;
- dev->lock.lock_time = jiffies;
- atomic_inc(&dev->total_locks);
- break; /* Got lock */
- }
- /* Contention */
- atomic_inc(&dev->total_sleeps);
- schedule();
- if (signal_pending(current)) {
- retcode = -ERESTARTSYS;
- break;
- }
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&dev->lock.lock_queue, &entry);
- if(!retcode) {
- i810_reclaim_buffers(dev, priv->pid);
- drm_lock_free(dev, &dev->lock.hw_lock->lock,
- DRM_KERNEL_CONTEXT);
- }
- }
- drm_fasync(-1, filp, 0);
-
- down(&dev->struct_sem);
- if (priv->prev) priv->prev->next = priv->next;
- else dev->file_first = priv->next;
- if (priv->next) priv->next->prev = priv->prev;
- else dev->file_last = priv->prev;
- up(&dev->struct_sem);
-
- drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
-#if LINUX_VERSION_CODE < 0x020333
- MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
-#endif
- 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);
- unlock_kernel();
- return -EBUSY;
- }
- spin_unlock(&dev->count_lock);
- unlock_kernel();
- return i810_takedown(dev);
- }
- spin_unlock(&dev->count_lock);
- unlock_kernel();
- return retcode;
-}
-
-/* drm_ioctl is called whenever a process performs an ioctl on /dev/drm. */
-
-int i810_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 >= I810_IOCTL_COUNT) {
- retcode = -EINVAL;
- } else {
- ioctl = &i810_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 i810_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;
-
- if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
- return -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);
- if (!dev->context_flag) {
- if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
- DRM_KERNEL_CONTEXT)) {
- DRM_ERROR("\n");
- }
- }
-#if DRM_DMA_HISTOGRAM
- atomic_inc(&dev->histo.lhld[drm_histogram_slot(get_cycles()
- - dev->lck_start)]);
-#endif
-
- unblock_all_signals();
- return 0;
-}
+#define DRIVER_AUTHOR "VA Linux Systems Inc."
+
+#define DRIVER_NAME "i810"
+#define DRIVER_DESC "Intel i810"
+#define DRIVER_DATE "20010215"
+
+#define DRIVER_MAJOR 1
+#define DRIVER_MINOR 1
+#define DRIVER_PATCHLEVEL 0
+
+#define DRIVER_IOCTLS \
+ [DRM_IOCTL_NR(DRM_IOCTL_I810_INIT)] = { i810_dma_init, 1, 1 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_I810_VERTEX)] = { i810_dma_vertex, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_I810_CLEAR)] = { i810_clear_bufs, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_I810_FLUSH)] = { i810_flush_ioctl, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_I810_GETAGE)] = { i810_getage, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_I810_GETBUF)] = { i810_getbuf, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_I810_SWAP)] = { i810_swap_bufs, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_I810_COPY)] = { i810_copybuf, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_I810_DOCOPY)] = { i810_docopy, 1, 0 },
+
+#define __HAVE_COUNTERS 4
+#define __HAVE_COUNTER6 _DRM_STAT_IRQ
+#define __HAVE_COUNTER7 _DRM_STAT_PRIMARY
+#define __HAVE_COUNTER8 _DRM_STAT_SECONDARY
+#define __HAVE_COUNTER9 _DRM_STAT_DMA
+
+#define __HAVE_DMA_QUIESCENT 1
+#define DRIVER_DMA_QUIESCENT() do { \
+ i810_dma_quiescent( dev ); \
+} while (0)
+
+#define __HAVE_RELEASE 1
+#define DRIVER_RELEASE() do { \
+ i810_reclaim_buffers( dev, priv->pid ); \
+} while (0)
+
+#include "drm_drv.h"
+
+
+#define DRIVER_BUF_PRIV_T drm_i810_buf_priv_t
+
+#define DRIVER_AGP_BUFFERS_MAP( dev ) \
+({ \
+ drm_i810_private_t *dev_priv = (dev)->dev_private; \
+ drm_map_t *map = (dev)->maplist[dev_priv->buffer_map_idx]; \
+ map; \
+})
+
+#include "drm_bufs.h"
+
+
+#include "drm_agpsupport.h"
+#include "drm_auth.h"
+#include "drm_context.h"
+#include "drm_dma.h"
+#include "drm_drawable.h"
+#include "drm_fops.h"
+#include "drm_init.h"
+#include "drm_ioctl.h"
+#include "drm_lock.h"
+#include "drm_memory.h"
+#include "drm_proc.h"
+#include "drm_vm.h"
+#include "drm_stub.h"
diff --git a/linux-core/i810_drv.h b/linux-core/i810_drv.h
index 1c957401..e7824093 100644
--- a/linux-core/i810_drv.h
+++ b/linux-core/i810_drv.h
@@ -11,11 +11,11 @@
* 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
@@ -67,25 +67,15 @@ typedef struct drm_i810_private {
wait_queue_head_t flush_queue; /* Processes waiting until flush */
drm_buf_t *mmap_buffer;
-
+
u32 front_di1, back_di1, zi1;
-
+
int back_offset;
int depth_offset;
int w, h;
int pitch;
} drm_i810_private_t;
- /* i810_drv.c */
-extern int i810_version(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int i810_open(struct inode *inode, struct file *filp);
-extern int i810_release(struct inode *inode, struct file *filp);
-extern int i810_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int i810_unlock(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-
/* i810_dma.c */
extern int i810_dma_schedule(drm_device_t *dev, int locked);
extern int i810_getbuf(struct inode *inode, struct file *filp,
@@ -101,44 +91,15 @@ extern int i810_dma_init(struct inode *inode, struct file *filp,
extern int i810_flush_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern void i810_reclaim_buffers(drm_device_t *dev, pid_t pid);
-extern int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg);
-extern int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma);
-extern int i810_copybuf(struct inode *inode, struct file *filp,
+extern int i810_getage(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-extern int i810_docopy(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-
- /* i810_bufs.c */
-extern int i810_addbufs(struct inode *inode, struct file *filp,
+extern int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma);
+extern int i810_copybuf(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-extern int i810_infobufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int i810_markbufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int i810_freebufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int i810_addmap(struct inode *inode, struct file *filp,
+extern int i810_docopy(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
- /* i810_context.c */
-extern int i810_resctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int i810_addctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int i810_modctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int i810_getctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int i810_switchctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int i810_newctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int i810_rmctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-
-extern int i810_context_switch(drm_device_t *dev, int old, int new);
-extern int i810_context_switch_complete(drm_device_t *dev, int new);
+extern void i810_dma_quiescent(drm_device_t *dev);
#define I810_VERBOSE 0
@@ -184,7 +145,7 @@ int i810_clear_bufs(struct inode *inode, struct file *filp,
#define RING_START 0x08
#define START_ADDR 0x00FFFFF8
#define RING_LEN 0x0C
-#define RING_NR_PAGES 0x000FF000
+#define RING_NR_PAGES 0x000FF000
#define RING_REPORT_MASK 0x00000006
#define RING_REPORT_64K 0x00000002
#define RING_REPORT_128K 0x00000004
@@ -222,4 +183,3 @@ int i810_clear_bufs(struct inode *inode, struct file *filp,
#endif
-
diff --git a/linux-core/mga_drv.c b/linux-core/mga_drv.c
index d1c39e99..b498a3e1 100644
--- a/linux-core/mga_drv.c
+++ b/linux-core/mga_drv.c
@@ -1,4 +1,4 @@
-/* mga_drv.c -- Matrox g200/g400 driver -*- linux-c -*-
+/* mga_drv.c -- Matrox G200/G400 driver -*- linux-c -*-
* Created: Mon Dec 13 01:56:22 1999 by jhartmann@precisioninsight.com
*
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
@@ -19,648 +19,80 @@
* 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
- * Jeff Hartmann <jhartmann@valinux.com>
- *
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*
+ * Authors:
+ * Rickard E. (Rik) Faith <faith@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
*/
#include <linux/config.h>
+#include "mga.h"
#include "drmP.h"
#include "mga_drv.h"
-#define MGA_NAME "mga"
-#define MGA_DESC "Matrox G200/G400"
-#define MGA_DATE "20000928"
-#define MGA_MAJOR 2
-#define MGA_MINOR 1
-#define MGA_PATCHLEVEL 1
-
-static drm_device_t mga_device;
-drm_ctx_t mga_res_ctx;
-
-static struct file_operations mga_fops = {
-#if LINUX_VERSION_CODE >= 0x020400
- /* This started being used during 2.4.0-test */
- owner: THIS_MODULE,
-#endif
- open: mga_open,
- flush: drm_flush,
- release: mga_release,
- ioctl: mga_ioctl,
- mmap: drm_mmap,
- read: drm_read,
- fasync: drm_fasync,
- poll: drm_poll,
-};
-
-static struct miscdevice mga_misc = {
- minor: MISC_DYNAMIC_MINOR,
- name: MGA_NAME,
- fops: &mga_fops,
-};
-
-static drm_ioctl_desc_t mga_ioctls[] = {
- [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { mga_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_CONTROL)] = { mga_control, 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)] = { mga_addbufs, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = { mga_markbufs, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { mga_infobufs, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { mga_mapbufs, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { mga_freebufs, 1, 0 },
-
- [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { mga_addctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { mga_rmctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { mga_modctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { mga_getctx, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { mga_switchctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { mga_newctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { mga_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_DMA)] = { mga_dma, 1, 0 },
-
- [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { mga_lock, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { mga_unlock, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { drm_finish, 1, 0 },
-
- [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 },
- [DRM_IOCTL_NR(DRM_IOCTL_MGA_INIT)] = { mga_dma_init, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_MGA_SWAP)] = { mga_swap_bufs, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_MGA_CLEAR)] = { mga_clear_bufs, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_MGA_ILOAD)] = { mga_iload, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_MGA_VERTEX)] = { mga_vertex, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_MGA_FLUSH)] = { mga_flush_ioctl, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_MGA_INDICES)] = { mga_indices, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_MGA_BLIT)] = { mga_blit, 1, 0 },
-};
-
-#define MGA_IOCTL_COUNT DRM_ARRAY_SIZE(mga_ioctls)
-
-#ifdef MODULE
-static char *mga = NULL;
-#endif
-
-MODULE_AUTHOR("VA Linux Systems, Inc.");
-MODULE_DESCRIPTION("Matrox G200/G400");
-MODULE_PARM(mga, "s");
-
-#ifndef MODULE
-/* mga_options 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.
- */
-
-static int __init mga_options(char *str)
-{
- drm_parse_options(str);
- return 1;
-}
-
-__setup("mga=", mga_options);
-#endif
-
-static int mga_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);
-
- 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 mga_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");
-
- if (dev->dev_private) mga_dma_cleanup(dev);
- if (dev->irq) mga_irq_uninstall(dev);
-
- 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;
- }
- /* 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 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();
-
- dev->agp->acquired = 0;
- dev->agp->enabled = 0;
- }
- /* 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:
- 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;
- }
-
- if (dev->queuelist) {
- for (i = 0; i < dev->queue_count; i++) {
- drm_waitlist_destroy(&dev->queuelist[i]->waitlist);
- if (dev->queuelist[i]) {
- drm_free(dev->queuelist[i],
- sizeof(*dev->queuelist[0]),
- DRM_MEM_QUEUES);
- dev->queuelist[i] = NULL;
- }
- }
- drm_free(dev->queuelist,
- dev->queue_slots * sizeof(*dev->queuelist),
- DRM_MEM_QUEUES);
- dev->queuelist = NULL;
- }
-
- 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;
-}
-
-/* mga_init is called via init_module at module load time, or via
- * linux/init/main.c (this is not currently supported). */
-
-static int __init mga_init(void)
-{
- int retcode;
- drm_device_t *dev = &mga_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(mga);
-#endif
- if ((retcode = misc_register(&mga_misc))) {
- DRM_ERROR("Cannot register \"%s\"\n", MGA_NAME);
- return retcode;
- }
- dev->device = MKDEV(MISC_MAJOR, mga_misc.minor);
- dev->name = MGA_NAME;
-
- drm_mem_init();
- drm_proc_init(dev);
- dev->agp = drm_agp_init();
- if(dev->agp == NULL) {
- DRM_INFO("The mga drm module requires the agpgart module"
- " to function correctly\nPlease load the agpgart"
- " module before you load the mga module\n");
- drm_proc_cleanup();
- misc_deregister(&mga_misc);
- mga_takedown(dev);
- return -ENOMEM;
- }
-#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
- if((retcode = drm_ctxbitmap_init(dev))) {
- DRM_ERROR("Cannot allocate memory for context bitmap.\n");
- drm_proc_cleanup();
- misc_deregister(&mga_misc);
- mga_takedown(dev);
- return retcode;
- }
-
- DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
- MGA_NAME,
- MGA_MAJOR,
- MGA_MINOR,
- MGA_PATCHLEVEL,
- MGA_DATE,
- mga_misc.minor);
-
- return 0;
-}
-
-/* mga_cleanup is called via cleanup_module at module unload time. */
-
-static void __exit mga_cleanup(void)
-{
- drm_device_t *dev = &mga_device;
-
- DRM_DEBUG("\n");
-
- drm_proc_cleanup();
- if (misc_deregister(&mga_misc)) {
- DRM_ERROR("Cannot unload module\n");
- } else {
- DRM_INFO("Module unloaded\n");
- }
- drm_ctxbitmap_cleanup(dev);
-#ifdef CONFIG_MTRR
- if(dev->agp && dev->agp->agp_mtrr) {
- int retval;
- retval = mtrr_del(dev->agp->agp_mtrr,
- dev->agp->agp_info.aper_base,
- dev->agp->agp_info.aper_size * 1024*1024);
- DRM_DEBUG("mtrr_del = %d\n", retval);
- }
-#endif
-
- mga_takedown(dev);
- if (dev->agp) {
- drm_agp_uninit();
- drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS);
- dev->agp = NULL;
- }
-}
-
-module_init(mga_init);
-module_exit(mga_cleanup);
-
-
-int mga_version(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
-{
- drm_version_t version;
- int len;
-
- if (copy_from_user(&version,
- (drm_version_t *)arg,
- sizeof(version)))
- return -EFAULT;
-
-#define DRM_COPY(name,value) \
- len = strlen(value); \
- if (len > name##_len) len = name##_len; \
- name##_len = strlen(value); \
- if (len && name) { \
- if (copy_to_user(name, value, len)) \
- return -EFAULT; \
- }
-
- version.version_major = MGA_MAJOR;
- version.version_minor = MGA_MINOR;
- version.version_patchlevel = MGA_PATCHLEVEL;
-
- DRM_COPY(version.name, MGA_NAME);
- DRM_COPY(version.date, MGA_DATE);
- DRM_COPY(version.desc, MGA_DESC);
-
- if (copy_to_user((drm_version_t *)arg,
- &version,
- sizeof(version)))
- return -EFAULT;
- return 0;
-}
-
-int mga_open(struct inode *inode, struct file *filp)
-{
- drm_device_t *dev = &mga_device;
- int retcode = 0;
-
- DRM_DEBUG("open_count = %d\n", dev->open_count);
- if (!(retcode = drm_open_helper(inode, filp, dev))) {
-#if LINUX_VERSION_CODE < 0x020333
- MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */
-#endif
- atomic_inc(&dev->total_open);
- spin_lock(&dev->count_lock);
- if (!dev->open_count++) {
- spin_unlock(&dev->count_lock);
- return mga_setup(dev);
- }
- spin_unlock(&dev->count_lock);
- }
- return retcode;
-}
-
-int mga_release(struct inode *inode, struct file *filp)
-{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev;
- int retcode = 0;
-
- lock_kernel();
- dev = priv->dev;
- DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n",
- current->pid, dev->device, dev->open_count);
-
- if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
- && dev->lock.pid == current->pid) {
- mga_reclaim_buffers(dev, priv->pid);
- DRM_INFO("Process %d dead (ctx %d, d_s = 0x%02lx)\n",
- current->pid,
- _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock),
- dev->dev_private ?
- ((drm_mga_private_t *)dev->dev_private)
- ->dispatch_status
- : 0);
-
- if (dev->dev_private)
- ((drm_mga_private_t *)dev->dev_private)
- ->dispatch_status &= MGA_IN_DISPATCH;
-
- drm_lock_free(dev,
- &dev->lock.hw_lock->lock,
- _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
- } else if (dev->lock.hw_lock) {
- /* The lock is required to reclaim buffers */
- DECLARE_WAITQUEUE(entry, current);
- add_wait_queue(&dev->lock.lock_queue, &entry);
- for (;;) {
- current->state = TASK_INTERRUPTIBLE;
- if (!dev->lock.hw_lock) {
- /* Device has been unregistered */
- retcode = -EINTR;
- break;
- }
- if (drm_lock_take(&dev->lock.hw_lock->lock,
- DRM_KERNEL_CONTEXT)) {
- dev->lock.pid = priv->pid;
- dev->lock.lock_time = jiffies;
- atomic_inc(&dev->total_locks);
- break; /* Got lock */
- }
- /* Contention */
- atomic_inc(&dev->total_sleeps);
- schedule();
- if (signal_pending(current)) {
- retcode = -ERESTARTSYS;
- break;
- }
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&dev->lock.lock_queue, &entry);
- if(!retcode) {
- mga_reclaim_buffers(dev, priv->pid);
- if (dev->dev_private)
- ((drm_mga_private_t *)dev->dev_private)
- ->dispatch_status &= MGA_IN_DISPATCH;
- drm_lock_free(dev, &dev->lock.hw_lock->lock,
- DRM_KERNEL_CONTEXT);
- }
- }
- drm_fasync(-1, filp, 0);
-
- down(&dev->struct_sem);
- if (priv->remove_auth_on_close == 1) {
- drm_file_t *temp = dev->file_first;
- while(temp) {
- temp->authenticated = 0;
- temp = temp->next;
- }
- }
- if (priv->prev) priv->prev->next = priv->next;
- else dev->file_first = priv->next;
- if (priv->next) priv->next->prev = priv->prev;
- else dev->file_last = priv->prev;
- up(&dev->struct_sem);
-
- drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
-#if LINUX_VERSION_CODE < 0x020333
- MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
-#endif
- 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);
- unlock_kernel();
- return -EBUSY;
- }
- spin_unlock(&dev->count_lock);
- unlock_kernel();
- return mga_takedown(dev);
- }
- spin_unlock(&dev->count_lock);
- unlock_kernel();
- return retcode;
-}
-
-
-/* drm_ioctl is called whenever a process performs an ioctl on /dev/drm. */
-
-int mga_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;
-
- if (nr >= MGA_IOCTL_COUNT) {
- retcode = -EINVAL;
- } else {
- ioctl = &mga_ioctls[nr];
- func = ioctl->func;
-
- if (!func) {
- DRM_DEBUG("no function: pid = %d, cmd = 0x%02x,"
- " nr = 0x%02x, dev 0x%x, auth = %d\n",
- current->pid, cmd, nr, dev->device,
- priv->authenticated);
- 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 mga_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;
-
- if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
- return -EFAULT;
-
- if (lock.context == DRM_KERNEL_CONTEXT) {
- DRM_ERROR("Process %d using kernel context %d\n",
- current->pid, lock.context);
- return -EINVAL;
- }
-
- 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);
- mga_dma_schedule(dev, 1);
-
- if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
- DRM_KERNEL_CONTEXT)) DRM_ERROR("\n");
-
- unblock_all_signals();
- return 0;
-}
+#define DRIVER_AUTHOR "Gareth Hughes, VA Linux Systems Inc."
+
+#define DRIVER_NAME "mga"
+#define DRIVER_DESC "Matrox G200/G400"
+#define DRIVER_DATE "20010212"
+
+#define DRIVER_MAJOR 3
+#define DRIVER_MINOR 0
+#define DRIVER_PATCHLEVEL 0
+
+#define DRIVER_IOCTLS \
+ [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { mga_dma_buffers, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_MGA_INIT)] = { mga_dma_init, 1, 1 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_MGA_FLUSH)] = { mga_dma_flush, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_MGA_RESET)] = { mga_dma_reset, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_MGA_SWAP)] = { mga_dma_swap, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_MGA_CLEAR)] = { mga_dma_clear, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_MGA_VERTEX)] = { mga_dma_vertex, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_MGA_INDICES)] = { mga_dma_indices, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_MGA_ILOAD)] = { mga_dma_iload, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_MGA_BLIT)] = { mga_dma_blit, 1, 0 },
+
+#define __HAVE_COUNTERS 3
+#define __HAVE_COUNTER6 _DRM_STAT_IRQ
+#define __HAVE_COUNTER7 _DRM_STAT_PRIMARY
+#define __HAVE_COUNTER8 _DRM_STAT_SECONDARY
+
+#define __HAVE_DMA_QUIESCENT 1
+#define DRIVER_DMA_QUIESCENT() \
+do { \
+ drm_mga_private_t *dev_priv = dev->dev_private; \
+ return mga_do_wait_for_idle( dev_priv ); \
+} while (0)
+
+#define DRIVER_PRETAKEDOWN() do { \
+ if ( dev->dev_private ) mga_do_cleanup_dma( dev ); \
+} while (0)
+
+#include "drm_drv.h"
+
+
+#define DRIVER_BUF_PRIV_T drm_mga_buf_priv_t
+
+#define DRIVER_AGP_BUFFERS_MAP( dev ) \
+ ((drm_mga_private_t *)((dev)->dev_private))->buffers
+
+#include "drm_bufs.h"
+
+
+#include "drm_agpsupport.h"
+#include "drm_auth.h"
+#include "drm_context.h"
+#include "drm_dma.h"
+#include "drm_drawable.h"
+#include "drm_fops.h"
+#include "drm_init.h"
+#include "drm_ioctl.h"
+#include "drm_lock.h"
+#include "drm_memory.h"
+#include "drm_proc.h"
+#include "drm_vm.h"
+#include "drm_stub.h"
diff --git a/linux-core/r128_drv.c b/linux-core/r128_drv.c
index cd5c0e88..08de2039 100644
--- a/linux-core/r128_drv.c
+++ b/linux-core/r128_drv.c
@@ -1,7 +1,7 @@
/* 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.
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
* All Rights Reserved.
*
@@ -19,687 +19,98 @@
* 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*
* Authors:
* Rickard E. (Rik) Faith <faith@valinux.com>
- * Kevin E. Martin <martin@valinux.com>
* Gareth Hughes <gareth@valinux.com>
- *
*/
#include <linux/config.h>
+#include "r128.h"
#include "drmP.h"
#include "r128_drv.h"
-#define R128_NAME "r128"
-#define R128_DESC "ATI Rage 128"
-#define R128_DATE "20010130"
-#define R128_MAJOR 2
-#define R128_MINOR 1
-#define R128_PATCHLEVEL 4
-
-static drm_device_t r128_device;
-drm_ctx_t r128_res_ctx;
-
-static struct file_operations r128_fops = {
-#if LINUX_VERSION_CODE >= 0x020400
- /* This started being used during 2.4.0-test */
- owner: THIS_MODULE,
-#endif
- 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_DMA)] = { r128_cce_buffers, 1, 0 },
- [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 },
-
-#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
- [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_cce_init, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_R128_CCE_START)] = { r128_cce_start, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_R128_CCE_STOP)] = { r128_cce_stop, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_R128_CCE_RESET)] = { r128_cce_reset, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_R128_CCE_IDLE)] = { r128_cce_idle, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_R128_RESET)] = { r128_engine_reset, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_R128_FULLSCREEN)]= { r128_fullscreen, 1, 0 },
-
- [DRM_IOCTL_NR(DRM_IOCTL_R128_SWAP)] = { r128_cce_swap, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_R128_CLEAR)] = { r128_cce_clear, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_R128_VERTEX)] = { r128_cce_vertex, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_R128_INDICES)] = { r128_cce_indices, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_R128_BLIT)] = { r128_cce_blit, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_R128_DEPTH)] = { r128_cce_depth, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_R128_STIPPLE)] = { r128_cce_stipple, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_R128_INDIRECT)] = { r128_cce_indirect, 1, 1 },
-};
-#define R128_IOCTL_COUNT DRM_ARRAY_SIZE(r128_ioctls)
-
-#ifdef MODULE
-static char *r128 = NULL;
-#endif
-
-MODULE_AUTHOR("VA Linux Systems, Inc.");
-MODULE_DESCRIPTION("r128");
-MODULE_PARM(r128, "s");
-
-#ifndef MODULE
-/* r128_options 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.
- */
-
-static int __init r128_options(char *str)
-{
- drm_parse_options(str);
- return 1;
-}
-
-__setup("r128=", r128_options);
-#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;
- }
-
-#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
- /* 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();
-
- 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). */
-
-static int __init 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);
-
-#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
- dev->agp = drm_agp_init();
- if (dev->agp == NULL) {
- DRM_ERROR("Cannot initialize agpgart module.\n");
- drm_proc_cleanup();
- misc_deregister(&r128_misc);
- r128_takedown(dev);
- return -ENOMEM;
- }
-
-#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. */
-
-static void __exit 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);
-#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
- if (dev->agp) {
- drm_agp_uninit();
- drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS);
- dev->agp = NULL;
- }
-#endif
-}
-
-module_init(r128_init);
-module_exit(r128_cleanup);
-
-
-int r128_version(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- drm_version_t version;
- int len;
-
- if (copy_from_user(&version,
- (drm_version_t *)arg,
- sizeof(version)))
- return -EFAULT;
-
-#define DRM_COPY(name,value) \
- len = strlen(value); \
- if (len > name##_len) len = name##_len; \
- name##_len = strlen(value); \
- if (len && name) { \
- if (copy_to_user(name, value, len)) \
- return -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);
-
- if (copy_to_user((drm_version_t *)arg,
- &version,
- sizeof(version)))
- return -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))) {
-#if LINUX_VERSION_CODE < 0x020333
- MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */
-#endif
- 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;
- int retcode = 0;
-
- lock_kernel();
- dev = priv->dev;
-
- DRM_DEBUG("open_count = %d\n", dev->open_count);
-
- /* Force the cleanup of page flipping when required */
- if ( dev->dev_private ) {
- drm_r128_private_t *dev_priv = dev->dev_private;
- if ( dev_priv->page_flipping ) {
- r128_do_cleanup_pageflip( dev );
- }
- }
-
- if (!(retcode = drm_release(inode, filp))) {
-#if LINUX_VERSION_CODE < 0x020333
- MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
-#endif
- 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);
- unlock_kernel();
- return -EBUSY;
- }
- spin_unlock(&dev->count_lock);
- unlock_kernel();
- return r128_takedown(dev);
- }
- spin_unlock(&dev->count_lock);
- }
-
- unlock_kernel();
- return retcode;
-}
+#define DRIVER_AUTHOR "Gareth Hughes, VA Linux Systems Inc."
+
+#define DRIVER_NAME "r128"
+#define DRIVER_DESC "ATI Rage 128"
+#define DRIVER_DATE "20010214"
+
+#define DRIVER_MAJOR 2
+#define DRIVER_MINOR 1
+#define DRIVER_PATCHLEVEL 4
+
+#define DRIVER_IOCTLS \
+ [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { r128_cce_buffers, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_R128_INIT)] = { r128_cce_init, 1, 1 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_R128_CCE_START)] = { r128_cce_start, 1, 1 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_R128_CCE_STOP)] = { r128_cce_stop, 1, 1 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_R128_CCE_RESET)] = { r128_cce_reset, 1, 1 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_R128_CCE_IDLE)] = { r128_cce_idle, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_R128_RESET)] = { r128_engine_reset, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_R128_FULLSCREEN)] = { r128_fullscreen, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_R128_SWAP)] = { r128_cce_swap, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_R128_CLEAR)] = { r128_cce_clear, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_R128_VERTEX)] = { r128_cce_vertex, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_R128_INDICES)] = { r128_cce_indices, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_R128_BLIT)] = { r128_cce_blit, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_R128_DEPTH)] = { r128_cce_depth, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_R128_STIPPLE)] = { r128_cce_stipple, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_R128_INDIRECT)] = { r128_cce_indirect, 1, 1 },
-/* 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
-
- if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
- return -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 (lock.context < 0)
- return -EINVAL;
-
- if (!ret) {
- add_wait_queue(&dev->lock.lock_queue, &entry);
- for (;;) {
- current->state = TASK_INTERRUPTIBLE;
- 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);
- schedule();
- if (signal_pending(current)) {
- ret = -ERESTARTSYS;
- break;
- }
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&dev->lock.lock_queue, &entry);
- }
-
- if (!ret) {
- sigemptyset(&dev->sigmask);
- sigaddset(&dev->sigmask, SIGSTOP);
- sigaddset(&dev->sigmask, SIGTSTP);
- sigaddset(&dev->sigmask, SIGTTIN);
- sigaddset(&dev->sigmask, SIGTTOU);
- dev->sigdata.context = lock.context;
- dev->sigdata.lock = dev->lock.hw_lock;
- block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask);
- if (lock.flags & _DRM_LOCK_READY) {
- /* Wait for space in DMA/FIFO */
- }
- if (lock.flags & _DRM_LOCK_QUIESCENT) {
- /* Make hardware quiescent */
- DRM_DEBUG( "not quiescent!\n" );
#if 0
- r128_quiescent(dev);
-#endif
- }
- }
-
-#if LINUX_VERSION_CODE < 0x020400
- if (lock.context != r128_res_ctx.handle) {
- current->counter = 5;
- current->priority = DEF_PRIORITY/4;
- }
-#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;
-
- if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
- return -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 LINUX_VERSION_CODE < 0x020400
- if (lock.context != r128_res_ctx.handle) {
- current->counter = 5;
- current->priority = DEF_PRIORITY;
- }
-#endif
- unblock_all_signals();
- return 0;
-}
+/* GH: Count data sent to card via ring or vertex/indirect buffers.
+ */
+#define __HAVE_COUNTERS 3
+#define __HAVE_COUNTER6 _DRM_STAT_IRQ
+#define __HAVE_COUNTER7 _DRM_STAT_PRIMARY
+#define __HAVE_COUNTER8 _DRM_STAT_SECONDARY
+#endif
+
+#define __HAVE_DMA_QUIESCENT 1
+#define DRIVER_DMA_QUIESCENT() do { \
+ drm_r128_private_t *dev_priv = dev->dev_private; \
+ return r128_do_cce_idle( dev_priv ); \
+} while (0)
+
+#define DRIVER_PRERELEASE() do { \
+ if ( dev->dev_private ) { \
+ drm_r128_private_t *dev_priv = dev->dev_private; \
+ if ( dev_priv->page_flipping ) { \
+ r128_do_cleanup_pageflip( dev ); \
+ } \
+ } \
+} while (0)
+
+#define DRIVER_PRETAKEDOWN() do { \
+ if ( dev->dev_private ) r128_do_cleanup_cce( dev ); \
+} while (0)
+
+#include "drm_drv.h"
+
+
+#define DRIVER_BUF_PRIV_T drm_r128_buf_priv_t
+
+#define DRIVER_AGP_BUFFERS_MAP( dev ) \
+ ((drm_r128_private_t *)((dev)->dev_private))->buffers
+
+#include "drm_bufs.h"
+
+
+#include "drm_agpsupport.h"
+#include "drm_auth.h"
+#include "drm_context.h"
+#include "drm_dma.h"
+#include "drm_drawable.h"
+#include "drm_fops.h"
+#include "drm_init.h"
+#include "drm_ioctl.h"
+#include "drm_lock.h"
+#include "drm_memory.h"
+#include "drm_proc.h"
+#include "drm_vm.h"
+#include "drm_stub.h"
diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c
index 0113ed97..da046106 100644
--- a/linux-core/radeon_drv.c
+++ b/linux-core/radeon_drv.c
@@ -1,7 +1,7 @@
/* radeon_drv.c -- ATI Radeon driver -*- linux-c -*-
+ * Created: Wed Feb 14 17:10:04 2001 by gareth@valinux.com
*
- * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Fremont, California.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -18,685 +18,96 @@
* 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors: Kevin E. Martin <martin@valinux.com>
- * Rickard E. (Rik) Faith <faith@valinux.com>
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*
+ * Authors:
+ * Gareth Hughes <gareth@valinux.com>
*/
#include <linux/config.h>
+#include "radeon.h"
#include "drmP.h"
#include "radeon_drv.h"
-#define RADEON_NAME "radeon"
-#define RADEON_DESC "ATI Radeon"
-#define RADEON_DATE "20010105"
-#define RADEON_MAJOR 1
-#define RADEON_MINOR 0
-#define RADEON_PATCHLEVEL 0
-
-static drm_device_t radeon_device;
-drm_ctx_t radeon_res_ctx;
-
-static struct file_operations radeon_fops = {
-#if LINUX_VERSION_CODE >= 0x020400
- /* This started being used during 2.4.0-test */
- owner: THIS_MODULE,
-#endif
- open: radeon_open,
- flush: drm_flush,
- release: radeon_release,
- ioctl: radeon_ioctl,
- mmap: drm_mmap,
- read: drm_read,
- fasync: drm_fasync,
- poll: drm_poll,
-};
-
-static struct miscdevice radeon_misc = {
- minor: MISC_DYNAMIC_MINOR,
- name: RADEON_NAME,
- fops: &radeon_fops,
-};
-
-static drm_ioctl_desc_t radeon_ioctls[] = {
- [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { radeon_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)] = { radeon_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)] = { radeon_mapbufs, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { drm_freebufs, 1, 0 },
-
- [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { radeon_addctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { radeon_rmctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { radeon_modctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { radeon_getctx, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { radeon_switchctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { radeon_newctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { radeon_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_DMA)] = { radeon_cp_buffers, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { radeon_lock, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { radeon_unlock, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { drm_finish, 1, 0 },
-
-#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
- [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_RADEON_CP_INIT)] = { radeon_cp_init, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_START)] = { radeon_cp_start, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_STOP)] = { radeon_cp_stop, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_RESET)] = { radeon_cp_reset, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_IDLE)] = { radeon_cp_idle, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_RADEON_RESET)] = { radeon_engine_reset, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_RADEON_FULLSCREEN)] = { radeon_fullscreen, 1, 0 },
-
- [DRM_IOCTL_NR(DRM_IOCTL_RADEON_SWAP)] = { radeon_cp_swap, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CLEAR)] = { radeon_cp_clear, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_RADEON_VERTEX)] = { radeon_cp_vertex, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_RADEON_INDICES)] = { radeon_cp_indices, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_RADEON_BLIT)] = { radeon_cp_blit, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_RADEON_STIPPLE)] = { radeon_cp_stipple, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_RADEON_INDIRECT)]= { radeon_cp_indirect,1, 1 },
-};
-#define RADEON_IOCTL_COUNT DRM_ARRAY_SIZE(radeon_ioctls)
-
-#ifdef MODULE
-static char *radeon = NULL;
-#endif
-
-MODULE_AUTHOR("VA Linux Systems, Inc.");
-MODULE_DESCRIPTION("radeon");
-MODULE_PARM(radeon, "s");
-
-#ifndef MODULE
-/* radeon_options 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.
- */
-
-static int __init radeon_options(char *str)
-{
- drm_parse_options(str);
- return 1;
-}
-
-__setup("radeon=", radeon_options);
-#endif
-
-static int radeon_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);
-
- radeon_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. */
+#define DRIVER_AUTHOR "Gareth Hughes, VA Linux Systems Inc."
+
+#define DRIVER_NAME "radeon"
+#define DRIVER_DESC "ATI Radeon"
+#define DRIVER_DATE "20010214"
+
+#define DRIVER_MAJOR 1
+#define DRIVER_MINOR 0
+#define DRIVER_PATCHLEVEL 0
+
+#define DRIVER_IOCTLS \
+ [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { radeon_cp_buffers, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_INIT)] = { radeon_cp_init, 1, 1 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_START)] = { radeon_cp_start, 1, 1 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_STOP)] = { radeon_cp_stop, 1, 1 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_RESET)] = { radeon_cp_reset, 1, 1 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_IDLE)] = { radeon_cp_idle, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_RESET)] = { radeon_engine_reset, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_FULLSCREEN)] = { radeon_fullscreen, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_SWAP)] = { radeon_cp_swap, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CLEAR)] = { radeon_cp_clear, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_VERTEX)] = { radeon_cp_vertex, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_INDICES)] = { radeon_cp_indices, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_BLIT)] = { radeon_cp_blit, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_STIPPLE)] = { radeon_cp_stipple, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_INDIRECT)] = { radeon_cp_indirect, 1, 1 },
- return 0;
-}
-
-
-static int radeon_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;
- }
-
-#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
- /* 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 radeon_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();
-
- 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;
-}
-
-/* radeon_init is called via init_module at module load time, or via
- * linux/init/main.c (this is not currently supported). */
-
-static int __init radeon_init(void)
-{
- int retcode;
- drm_device_t *dev = &radeon_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(radeon);
-#endif
-
- if ((retcode = misc_register(&radeon_misc))) {
- DRM_ERROR("Cannot register \"%s\"\n", RADEON_NAME);
- return retcode;
- }
- dev->device = MKDEV(MISC_MAJOR, radeon_misc.minor);
- dev->name = RADEON_NAME;
-
- drm_mem_init();
- drm_proc_init(dev);
-
-#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
- dev->agp = drm_agp_init();
- if (dev->agp == NULL) {
- DRM_ERROR("Cannot initialize agpgart module.\n");
- drm_proc_cleanup();
- misc_deregister(&radeon_misc);
- radeon_takedown(dev);
- return -ENOMEM;
- }
-
-#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(&radeon_misc);
- radeon_takedown(dev);
- return retcode;
- }
-
- DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
- RADEON_NAME,
- RADEON_MAJOR,
- RADEON_MINOR,
- RADEON_PATCHLEVEL,
- RADEON_DATE,
- radeon_misc.minor);
-
- return 0;
-}
-
-/* radeon_cleanup is called via cleanup_module at module unload time. */
-
-static void __exit radeon_cleanup(void)
-{
- drm_device_t *dev = &radeon_device;
-
- DRM_DEBUG("\n");
-
- drm_proc_cleanup();
- if (misc_deregister(&radeon_misc)) {
- DRM_ERROR("Cannot unload module\n");
- } else {
- DRM_INFO("Module unloaded\n");
- }
- drm_ctxbitmap_cleanup(dev);
- radeon_takedown(dev);
-#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
- if (dev->agp) {
- drm_agp_uninit();
- drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS);
- dev->agp = NULL;
- }
-#endif
-}
-
-module_init(radeon_init);
-module_exit(radeon_cleanup);
-
-
-int radeon_version(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
-{
- drm_version_t version;
- int len;
-
- if (copy_from_user(&version,
- (drm_version_t *)arg,
- sizeof(version)))
- return -EFAULT;
-
-#define DRM_COPY(name,value) \
- len = strlen(value); \
- if (len > name##_len) len = name##_len; \
- name##_len = strlen(value); \
- if (len && name) { \
- if (copy_to_user(name, value, len)) \
- return -EFAULT; \
- }
-
- version.version_major = RADEON_MAJOR;
- version.version_minor = RADEON_MINOR;
- version.version_patchlevel = RADEON_PATCHLEVEL;
-
- DRM_COPY(version.name, RADEON_NAME);
- DRM_COPY(version.date, RADEON_DATE);
- DRM_COPY(version.desc, RADEON_DESC);
-
- if (copy_to_user((drm_version_t *)arg,
- &version,
- sizeof(version)))
- return -EFAULT;
- return 0;
-}
-
-int radeon_open(struct inode *inode, struct file *filp)
-{
- drm_device_t *dev = &radeon_device;
- int retcode = 0;
-
- DRM_DEBUG("open_count = %d\n", dev->open_count);
- if (!(retcode = drm_open_helper(inode, filp, dev))) {
-#if LINUX_VERSION_CODE < 0x020333
- MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */
-#endif
- atomic_inc(&dev->total_open);
- spin_lock(&dev->count_lock);
- if (!dev->open_count++) {
- spin_unlock(&dev->count_lock);
- return radeon_setup(dev);
- }
- spin_unlock(&dev->count_lock);
- }
-
- return retcode;
-}
-
-int radeon_release(struct inode *inode, struct file *filp)
-{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev;
- int retcode = 0;
-
- lock_kernel();
- dev = priv->dev;
-
- DRM_DEBUG("open_count = %d\n", dev->open_count);
-
- /* Force the cleanup of page flipping when required */
- if ( dev->dev_private ) {
- drm_radeon_private_t *dev_priv = dev->dev_private;
- if ( dev_priv->page_flipping ) {
- radeon_do_cleanup_pageflip( dev );
- }
- }
-
- if (!(retcode = drm_release(inode, filp))) {
-#if LINUX_VERSION_CODE < 0x020333
- MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
-#endif
- 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);
- unlock_kernel();
- return -EBUSY;
- }
- spin_unlock(&dev->count_lock);
- unlock_kernel();
- return radeon_takedown(dev);
- }
- spin_unlock(&dev->count_lock);
- }
-
- unlock_kernel();
- return retcode;
-}
-
-/* radeon_ioctl is called whenever a process performs an ioctl on /dev/drm. */
-
-int radeon_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 >= RADEON_IOCTL_COUNT) {
- retcode = -EINVAL;
- } else {
- ioctl = &radeon_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 radeon_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
-
- if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
- return -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 (lock.context < 0 /* || lock.context >= dev->queue_count */)
- return -EINVAL;
-
- if (!ret) {
- add_wait_queue(&dev->lock.lock_queue, &entry);
- for (;;) {
- current->state = TASK_INTERRUPTIBLE;
- 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);
- schedule();
- if (signal_pending(current)) {
- ret = -ERESTARTSYS;
- break;
- }
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&dev->lock.lock_queue, &entry);
- }
-
- if (!ret) {
- sigemptyset(&dev->sigmask);
- sigaddset(&dev->sigmask, SIGSTOP);
- sigaddset(&dev->sigmask, SIGTSTP);
- sigaddset(&dev->sigmask, SIGTTIN);
- sigaddset(&dev->sigmask, SIGTTOU);
- dev->sigdata.context = lock.context;
- dev->sigdata.lock = dev->lock.hw_lock;
- block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask);
- if (lock.flags & _DRM_LOCK_READY) {
- /* Wait for space in DMA/FIFO */
- }
- if (lock.flags & _DRM_LOCK_QUIESCENT) {
- /* Make hardware quiescent */
- DRM_DEBUG("not quiescent!\n");
#if 0
- radeon_quiescent(dev);
-#endif
- }
- }
-
-#if LINUX_VERSION_CODE < 0x020400
- if (lock.context != radeon_res_ctx.handle) {
- current->counter = 5;
- current->priority = DEF_PRIORITY/4;
- }
-#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 radeon_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;
-
- if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
- return -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 LINUX_VERSION_CODE < 0x020400
- if (lock.context != radeon_res_ctx.handle) {
- current->counter = 5;
- current->priority = DEF_PRIORITY;
- }
-#endif
- unblock_all_signals();
- return 0;
-}
+/* GH: Count data sent to card via ring or vertex/indirect buffers.
+ */
+#define __HAVE_COUNTERS 3
+#define __HAVE_COUNTER6 _DRM_STAT_IRQ
+#define __HAVE_COUNTER7 _DRM_STAT_PRIMARY
+#define __HAVE_COUNTER8 _DRM_STAT_SECONDARY
+#endif
+
+#define __HAVE_DMA_QUIESCENT 1
+#define DRIVER_DMA_QUIESCENT() do { \
+ drm_radeon_private_t *dev_priv = dev->dev_private; \
+ return radeon_do_cp_idle( dev_priv ); \
+} while (0)
+
+#define DRIVER_PRERELEASE() do { \
+ if ( dev->dev_private ) { \
+ drm_radeon_private_t *dev_priv = dev->dev_private; \
+ if ( dev_priv->page_flipping ) { \
+ radeon_do_cleanup_pageflip( dev ); \
+ } \
+ } \
+} while (0)
+
+#define DRIVER_PRETAKEDOWN() do { \
+ if ( dev->dev_private ) radeon_do_cleanup_cp( dev ); \
+} while (0)
+
+#include "drm_drv.h"
+
+
+#define DRIVER_BUF_PRIV_T drm_radeon_buf_priv_t
+
+#define DRIVER_AGP_BUFFERS_MAP( dev ) \
+ ((drm_radeon_private_t *)((dev)->dev_private))->buffers
+
+#include "drm_bufs.h"
+
+
+#include "drm_agpsupport.h"
+#include "drm_auth.h"
+#include "drm_context.h"
+#include "drm_dma.h"
+#include "drm_drawable.h"
+#include "drm_fops.h"
+#include "drm_init.h"
+#include "drm_ioctl.h"
+#include "drm_lock.h"
+#include "drm_memory.h"
+#include "drm_proc.h"
+#include "drm_vm.h"
+#include "drm_stub.h"
diff --git a/linux-core/tdfx_drv.c b/linux-core/tdfx_drv.c
index b98a2988..9bb7b84a 100644
--- a/linux-core/tdfx_drv.c
+++ b/linux-core/tdfx_drv.c
@@ -27,670 +27,37 @@
* Authors:
* Rickard E. (Rik) Faith <faith@valinux.com>
* Daryll Strauss <daryll@valinux.com>
- *
+ * Gareth Hughes <gareth@valinux.com>
*/
#include <linux/config.h>
+#include "tdfx.h"
#include "drmP.h"
-#include "tdfx_drv.h"
-
-#define TDFX_NAME "tdfx"
-#define TDFX_DESC "3dfx Banshee/Voodoo3+"
-#define TDFX_DATE "20001030"
-#define TDFX_MAJOR 1
-#define TDFX_MINOR 0
-#define TDFX_PATCHLEVEL 0
-
-static drm_device_t tdfx_device;
-drm_ctx_t tdfx_res_ctx;
-
-static struct file_operations tdfx_fops = {
-#if LINUX_VERSION_CODE >= 0x020400
- /* This started being used during 2.4.0-test */
- owner: THIS_MODULE,
-#endif
- open: tdfx_open,
- flush: drm_flush,
- release: tdfx_release,
- ioctl: tdfx_ioctl,
- mmap: drm_mmap,
- read: drm_read,
- fasync: drm_fasync,
- poll: drm_poll,
-};
-
-static struct miscdevice tdfx_misc = {
- minor: MISC_DYNAMIC_MINOR,
- name: TDFX_NAME,
- fops: &tdfx_fops,
-};
-
-static drm_ioctl_desc_t tdfx_ioctls[] = {
- [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { tdfx_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_CTX)] = { tdfx_addctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { tdfx_rmctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { tdfx_modctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { tdfx_getctx, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { tdfx_switchctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { tdfx_newctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { tdfx_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)] = { tdfx_lock, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { tdfx_unlock, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { drm_finish, 1, 0 },
-#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
- [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, 1},
- [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_unbind, 1, 1},
- [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = {drm_agp_bind, 1, 1},
-#endif
-};
-#define TDFX_IOCTL_COUNT DRM_ARRAY_SIZE(tdfx_ioctls)
-
-#ifdef MODULE
-static char *tdfx = NULL;
-#endif
-
-MODULE_AUTHOR("VA Linux Systems, Inc.");
-MODULE_DESCRIPTION("tdfx");
-MODULE_PARM(tdfx, "s");
-
-#ifndef MODULE
-/* tdfx_options 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.
- */
-
-static int __init tdfx_options(char *str)
-{
- drm_parse_options(str);
- return 1;
-}
-
-__setup("tdfx=", tdfx_options);
-#endif
-
-static int tdfx_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);
-
- 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 = 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);
-
- tdfx_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 tdfx_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;
- }
-#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
- /* Clear AGP information */
- if (dev->agp) {
- drm_agp_mem_t *temp;
- drm_agp_mem_t *temp_next;
-
- temp = dev->agp->memory;
- while(temp != NULL) {
- temp_next = temp->next;
- drm_free_agp(temp->memory, temp->pages);
- drm_free(temp, sizeof(*temp), DRM_MEM_AGPLISTS);
- temp = temp_next;
- }
- if (dev->agp->acquired) _drm_agp_release();
- }
-#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;
- }
-
- 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;
-}
-
-/* tdfx_init is called via init_module at module load time, or via
- * linux/init/main.c (this is not currently supported). */
-
-static int __init tdfx_init(void)
-{
- int retcode;
- drm_device_t *dev = &tdfx_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(tdfx);
-#endif
-
- if ((retcode = misc_register(&tdfx_misc))) {
- DRM_ERROR("Cannot register \"%s\"\n", TDFX_NAME);
- return retcode;
- }
- dev->device = MKDEV(MISC_MAJOR, tdfx_misc.minor);
- dev->name = TDFX_NAME;
-
- drm_mem_init();
- drm_proc_init(dev);
-#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
- dev->agp = drm_agp_init();
-#endif
- if((retcode = drm_ctxbitmap_init(dev))) {
- DRM_ERROR("Cannot allocate memory for context bitmap.\n");
- drm_proc_cleanup();
- misc_deregister(&tdfx_misc);
- tdfx_takedown(dev);
- return retcode;
- }
-
- DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
- TDFX_NAME,
- TDFX_MAJOR,
- TDFX_MINOR,
- TDFX_PATCHLEVEL,
- TDFX_DATE,
- tdfx_misc.minor);
-
- return 0;
-}
-
-/* tdfx_cleanup is called via cleanup_module at module unload time. */
-
-static void __exit tdfx_cleanup(void)
-{
- drm_device_t *dev = &tdfx_device;
-
- DRM_DEBUG("\n");
-
- drm_proc_cleanup();
- if (misc_deregister(&tdfx_misc)) {
- DRM_ERROR("Cannot unload module\n");
- } else {
- DRM_INFO("Module unloaded\n");
- }
- drm_ctxbitmap_cleanup(dev);
- tdfx_takedown(dev);
-#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
- if (dev->agp) {
- drm_agp_uninit();
- drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS);
- dev->agp = NULL;
- }
-#endif
-}
-
-module_init(tdfx_init);
-module_exit(tdfx_cleanup);
-
-
-int tdfx_version(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
-{
- drm_version_t version;
- int len;
-
- if (copy_from_user(&version,
- (drm_version_t *)arg,
- sizeof(version)))
- return -EFAULT;
-
-#define DRM_COPY(name,value) \
- len = strlen(value); \
- if (len > name##_len) len = name##_len; \
- name##_len = strlen(value); \
- if (len && name) { \
- if (copy_to_user(name, value, len)) \
- return -EFAULT; \
- }
-
- version.version_major = TDFX_MAJOR;
- version.version_minor = TDFX_MINOR;
- version.version_patchlevel = TDFX_PATCHLEVEL;
-
- DRM_COPY(version.name, TDFX_NAME);
- DRM_COPY(version.date, TDFX_DATE);
- DRM_COPY(version.desc, TDFX_DESC);
-
- if (copy_to_user((drm_version_t *)arg,
- &version,
- sizeof(version)))
- return -EFAULT;
- return 0;
-}
-
-int tdfx_open(struct inode *inode, struct file *filp)
-{
- drm_device_t *dev = &tdfx_device;
- int retcode = 0;
-
- DRM_DEBUG("open_count = %d\n", dev->open_count);
- if (!(retcode = drm_open_helper(inode, filp, dev))) {
-#if LINUX_VERSION_CODE < 0x020333
- MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */
-#endif
- atomic_inc(&dev->total_open);
- spin_lock(&dev->count_lock);
- if (!dev->open_count++) {
- spin_unlock(&dev->count_lock);
- return tdfx_setup(dev);
- }
- spin_unlock(&dev->count_lock);
- }
- return retcode;
-}
-
-int tdfx_release(struct inode *inode, struct file *filp)
-{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev;
- int retcode = 0;
-
- lock_kernel();
- dev = priv->dev;
-
- DRM_DEBUG("open_count = %d\n", dev->open_count);
- if (!(retcode = drm_release(inode, filp))) {
-#if LINUX_VERSION_CODE < 0x020333
- MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
-#endif
- 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);
- unlock_kernel();
- return -EBUSY;
- }
- spin_unlock(&dev->count_lock);
- unlock_kernel();
- return tdfx_takedown(dev);
- }
- spin_unlock(&dev->count_lock);
- }
-
- unlock_kernel();
- return retcode;
-}
-
-/* tdfx_ioctl is called whenever a process performs an ioctl on /dev/drm. */
-
-int tdfx_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 >= TDFX_IOCTL_COUNT) {
- retcode = -EINVAL;
- } else {
- ioctl = &tdfx_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 tdfx_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
-
- if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
- return -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
- tdfx. 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 == tdfx_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 (;;) {
- current->state = TASK_INTERRUPTIBLE;
- 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);
-#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 != tdfx_res_ctx.handle &&
- dev->last_context != tdfx_res_ctx.handle) {
- add_wait_queue(&dev->context_wait, &entry);
- current->state = TASK_INTERRUPTIBLE;
- /* PRE: dev->last_context != lock.context */
- tdfx_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) {
- sigemptyset(&dev->sigmask);
- sigaddset(&dev->sigmask, SIGSTOP);
- sigaddset(&dev->sigmask, SIGTSTP);
- sigaddset(&dev->sigmask, SIGTTIN);
- sigaddset(&dev->sigmask, SIGTTOU);
- dev->sigdata.context = lock.context;
- dev->sigdata.lock = dev->lock.hw_lock;
- block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask);
-
- if (lock.flags & _DRM_LOCK_READY) {
- /* Wait for space in DMA/FIFO */
- }
- if (lock.flags & _DRM_LOCK_QUIESCENT) {
- /* Make hardware quiescent */
-#if 0
- tdfx_quiescent(dev);
-#endif
- }
- }
-
-#if LINUX_VERSION_CODE < 0x020400
- if (lock.context != tdfx_res_ctx.handle) {
- current->counter = 5;
- current->priority = DEF_PRIORITY/4;
- }
-#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 tdfx_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;
-
- if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
- return -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 LINUX_VERSION_CODE < 0x020400
- if (lock.context != tdfx_res_ctx.handle) {
- current->counter = 5;
- current->priority = DEF_PRIORITY;
- }
-#endif
- unblock_all_signals();
- return 0;
-}
+#define DRIVER_AUTHOR "VA Linux Systems Inc."
+
+#define DRIVER_NAME "tdfx"
+#define DRIVER_DESC "3dfx Banshee/Voodoo3+"
+#define DRIVER_DATE "20010214"
+
+#define DRIVER_MAJOR 1
+#define DRIVER_MINOR 0
+#define DRIVER_PATCHLEVEL 0
+
+#include "drm_drv.h"
+
+
+#include "drm_agpsupport.h"
+#include "drm_auth.h"
+#include "drm_bufs.h"
+#include "drm_context.h"
+#include "drm_dma.h"
+#include "drm_drawable.h"
+#include "drm_fops.h"
+#include "drm_init.h"
+#include "drm_ioctl.h"
+#include "drm_lock.h"
+#include "drm_memory.h"
+#include "drm_proc.h"
+#include "drm_vm.h"
+#include "drm_stub.h"