summaryrefslogtreecommitdiff
path: root/sys/dev/pci/drm/drm_drv.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/pci/drm/drm_drv.c')
-rw-r--r--sys/dev/pci/drm/drm_drv.c89
1 files changed, 89 insertions, 0 deletions
diff --git a/sys/dev/pci/drm/drm_drv.c b/sys/dev/pci/drm/drm_drv.c
index f85a91fce30..9b9d72bdd9f 100644
--- a/sys/dev/pci/drm/drm_drv.c
+++ b/sys/dev/pci/drm/drm_drv.c
@@ -1,4 +1,5 @@
/*-
+ * Copyright 2003 Eric Anholt
* Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
* All Rights Reserved.
@@ -696,3 +697,91 @@ drm_getsarea(struct drm_device *dev)
DRM_UNLOCK();
return (map);
}
+
+paddr_t
+drmmmap(dev_t kdev, off_t offset, int prot)
+{
+ struct drm_device *dev = drm_get_device_from_kdev(kdev);
+ drm_local_map_t *map;
+ struct drm_file *priv;
+ enum drm_map_type type;
+
+ DRM_LOCK();
+ priv = drm_find_file_by_minor(dev, minor(kdev));
+ DRM_UNLOCK();
+ if (priv == NULL) {
+ DRM_ERROR("can't find authenticator\n");
+ return (-1);
+ }
+
+ if (!priv->authenticated)
+ return (-1);
+
+ if (dev->dma && offset >= 0 && offset < ptoa(dev->dma->page_count)) {
+ drm_device_dma_t *dma = dev->dma;
+
+ DRM_SPINLOCK(&dev->dma_lock);
+
+ if (dma->pagelist != NULL) {
+ paddr_t phys = dma->pagelist[offset >> PAGE_SHIFT];
+
+ DRM_SPINUNLOCK(&dev->dma_lock);
+ return (atop(phys));
+ } else {
+ DRM_SPINUNLOCK(&dev->dma_lock);
+ return (-1);
+ }
+ }
+
+ /*
+ * 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.
+ */
+ DRM_LOCK();
+ TAILQ_FOREACH(map, &dev->maplist, link) {
+ if (offset >= map->ext &&
+ offset < map->ext + map->size) {
+ offset -= map->ext;
+ break;
+ }
+ }
+
+ if (map == NULL) {
+ DRM_UNLOCK();
+ DRM_DEBUG("can't find map\n");
+ return (-1);
+ }
+ if (((map->flags & _DRM_RESTRICTED) && priv->master == 0)) {
+ DRM_UNLOCK();
+ DRM_DEBUG("restricted map\n");
+ return (-1);
+ }
+ type = map->type;
+ DRM_UNLOCK();
+
+ switch (type) {
+ case _DRM_FRAME_BUFFER:
+ case _DRM_REGISTERS:
+ case _DRM_AGP:
+ return (atop(offset + map->offset));
+ break;
+ /* XXX unify all the bus_dmamem_mmap bits */
+ case _DRM_SCATTER_GATHER:
+ return (bus_dmamem_mmap(dev->dmat, dev->sg->mem->sg_segs,
+ dev->sg->mem->sg_nsegs, map->offset - dev->sg->handle +
+ offset, prot, BUS_DMA_NOWAIT));
+ case _DRM_SHM:
+ case _DRM_CONSISTENT:
+ return (bus_dmamem_mmap(dev->dmat, &map->dmah->seg, 1,
+ offset, prot, BUS_DMA_NOWAIT));
+ default:
+ DRM_ERROR("bad map type %d\n", type);
+ return (-1); /* This should never happen. */
+ }
+ /* NOTREACHED */
+}