patch-2.4.4 linux/drivers/char/drm/ffb_drv.c
Next file: linux/drivers/char/ec3104_keyb.c
Previous file: linux/drivers/char/cyclades.c
Back to the patch index
Back to the overall index
- Lines: 183
- Date:
Fri Apr 13 20:15:55 2001
- Orig file:
v2.4.3/linux/drivers/char/drm/ffb_drv.c
- Orig date:
Sun Mar 25 18:14:20 2001
diff -u --recursive --new-file v2.4.3/linux/drivers/char/drm/ffb_drv.c linux/drivers/char/drm/ffb_drv.c
@@ -1,4 +1,4 @@
-/* $Id: ffb_drv.c,v 1.9 2001/03/23 07:58:39 davem Exp $
+/* $Id: ffb_drv.c,v 1.12 2001/04/14 01:12:03 davem Exp $
* ffb_drv.c: Creator/Creator3D direct rendering driver.
*
* Copyright (C) 2000 David S. Miller (davem@redhat.com)
@@ -6,8 +6,10 @@
#include "drmP.h"
+#include <linux/config.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
+#include <asm/shmparam.h>
#include <asm/oplib.h>
#include <asm/upa.h>
@@ -34,6 +36,7 @@
static int ffb_unlock(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
static int ffb_mmap(struct file *filp, struct vm_area_struct *vma);
+static unsigned long ffb_get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
/* From ffb_context.c */
extern int ffb_resctx(struct inode *, struct file *, unsigned int, unsigned long);
@@ -46,15 +49,16 @@
extern int ffb_context_switch(drm_device_t *, int, int);
static struct file_operations ffb_fops = {
- owner: THIS_MODULE,
- open: ffb_open,
- flush: drm_flush,
- release: ffb_release,
- ioctl: ffb_ioctl,
- mmap: ffb_mmap,
- read: drm_read,
- fasync: drm_fasync,
- poll: drm_poll,
+ owner: THIS_MODULE,
+ open: ffb_open,
+ flush: drm_flush,
+ release: ffb_release,
+ ioctl: ffb_ioctl,
+ mmap: ffb_mmap,
+ read: drm_read,
+ fasync: drm_fasync,
+ poll: drm_poll,
+ get_unmapped_area: ffb_get_unmapped_area,
};
/* This is just a template, we make a new copy for each FFB
@@ -770,45 +774,6 @@
return 0;
}
-static void align_fb_mapping(struct vm_area_struct *vma)
-{
- unsigned long j, alignment;
-
- j = vma->vm_end - vma->vm_start;
- for (alignment = (4 * 1024 * 1024); alignment > PAGE_SIZE; alignment >>= 3)
- if (j >= alignment)
- break;
- if (alignment > PAGE_SIZE) {
- j = alignment;
- alignment = j - (vma->vm_start & (j - 1));
- if (alignment != j) {
- struct vm_area_struct *vmm = find_vma(current->mm,vma->vm_start);
-
- if (!vmm || vmm->vm_start >= vma->vm_end + alignment) {
- vma->vm_start += alignment;
- vma->vm_end += alignment;
- }
- }
- }
-}
-
-/* The problem here is, due to virtual cache aliasing,
- * we must make sure the shared memory area lands in the
- * same dcache line for both the kernel and all drm clients.
- */
-static void align_shm_mapping(struct vm_area_struct *vma, unsigned long kvirt)
-{
- kvirt &= PAGE_SIZE;
- if ((vma->vm_start & PAGE_SIZE) != kvirt) {
- struct vm_area_struct *vmm = find_vma(current->mm, vma->vm_start);
-
- if (!vmm || vmm->vm_start >= vma->vm_end + PAGE_SIZE) {
- vma->vm_start += PAGE_SIZE;
- vma->vm_end += PAGE_SIZE;
- }
- }
-}
-
extern struct vm_operations_struct drm_vm_ops;
extern struct vm_operations_struct drm_vm_shm_ops;
extern struct vm_operations_struct drm_vm_shm_lock_ops;
@@ -868,7 +833,6 @@
switch (map->type) {
case _DRM_FRAME_BUFFER:
- align_fb_mapping(vma);
/* FALLTHROUGH */
case _DRM_REGISTERS:
@@ -887,7 +851,6 @@
vma->vm_ops = &drm_vm_ops;
break;
case _DRM_SHM:
- align_shm_mapping(vma, (unsigned long)dev->lock.hw_lock);
if (map->flags & _DRM_CONTAINS_LOCK)
vma->vm_ops = &drm_vm_shm_lock_ops;
else {
@@ -909,6 +872,69 @@
vma->vm_file = filp; /* Needed for drm_vm_open() */
drm_vm_open(vma);
return 0;
+}
+
+static drm_map_t *ffb_find_map(struct file *filp, unsigned long off)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev;
+ drm_map_t *map;
+ int i;
+
+ if (!priv || (dev = priv->dev) == NULL)
+ return NULL;
+
+ for (i = 0; i < dev->map_count; i++) {
+ unsigned long uoff;
+
+ map = dev->maplist[i];
+
+ /* Ok, a little hack to make 32-bit apps work. */
+ uoff = (map->offset & 0xffffffff);
+ if (uoff == off)
+ return map;
+ }
+ return NULL;
+}
+
+static unsigned long ffb_get_unmapped_area(struct file *filp, unsigned long hint, unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+ drm_map_t *map = ffb_find_map(filp, pgoff << PAGE_SHIFT);
+ unsigned long addr = -ENOMEM;
+
+ if (!map)
+ return get_unmapped_area(NULL, hint, len, pgoff, flags);
+
+ if (map->type == _DRM_FRAME_BUFFER ||
+ map->type == _DRM_REGISTERS) {
+#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
+ addr = get_fb_unmapped_area(filp, hint, len, pgoff, flags);
+#else
+ addr = get_unmapped_area(NULL, hint, len, pgoff, flags);
+#endif
+ } else if (map->type == _DRM_SHM && SHMLBA > PAGE_SIZE) {
+ unsigned long slack = SHMLBA - PAGE_SIZE;
+
+ addr = get_unmapped_area(NULL, hint, len + slack, pgoff, flags);
+ if (!(addr & ~PAGE_MASK)) {
+ unsigned long kvirt = (unsigned long) map->handle;
+
+ if ((kvirt & (SHMLBA - 1)) != (addr & (SHMLBA - 1))) {
+ unsigned long koff, aoff;
+
+ koff = kvirt & (SHMLBA - 1);
+ aoff = addr & (SHMLBA - 1);
+ if (koff < aoff)
+ koff += SHMLBA;
+
+ addr += (koff - aoff);
+ }
+ }
+ } else {
+ addr = get_unmapped_area(NULL, hint, len, pgoff, flags);
+ }
+
+ return addr;
}
module_init(ffb_init);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)