drm_vm.c revision 145132
190075Sobrien/*-
290075Sobrien * Copyright 2003 Eric Anholt
390075Sobrien * All Rights Reserved.
490075Sobrien *
590075Sobrien * Permission is hereby granted, free of charge, to any person obtaining a
690075Sobrien * copy of this software and associated documentation files (the "Software"),
790075Sobrien * to deal in the Software without restriction, including without limitation
890075Sobrien * the rights to use, copy, modify, merge, publish, distribute, sublicense,
990075Sobrien * and/or sell copies of the Software, and to permit persons to whom the
1090075Sobrien * Software is furnished to do so, subject to the following conditions:
1190075Sobrien *
1290075Sobrien * The above copyright notice and this permission notice (including the next
1390075Sobrien * paragraph) shall be included in all copies or substantial portions of the
1490075Sobrien * Software.
1590075Sobrien *
1690075Sobrien * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1790075Sobrien * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1890075Sobrien * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1990075Sobrien * ERIC ANHOLT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
2090075Sobrien * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2190075Sobrien * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2290075Sobrien *
2390075Sobrien * $FreeBSD: head/sys/dev/drm/drm_vm.c 145132 2005-04-16 03:44:47Z anholt $
2490075Sobrien */
2590075Sobrien
2690075Sobrien#include "dev/drm/drmP.h"
2790075Sobrien#include "dev/drm/drm.h"
2890075Sobrien
2990075Sobrien#if defined(__FreeBSD__) && __FreeBSD_version >= 500102
3090075Sobrienint drm_mmap(struct cdev *kdev, vm_offset_t offset, vm_paddr_t *paddr,
3190075Sobrien    int prot)
3290075Sobrien#elif defined(__FreeBSD__)
3390075Sobrienint drm_mmap(dev_t kdev, vm_offset_t offset, int prot)
3490075Sobrien#elif defined(__NetBSD__) || defined(__OpenBSD__)
3590075Sobrienpaddr_t drm_mmap(dev_t kdev, off_t offset, int prot)
3690075Sobrien#endif
3790075Sobrien{
3890075Sobrien	DRM_DEVICE;
3990075Sobrien	drm_local_map_t *map;
4090075Sobrien	drm_file_t *priv;
4190075Sobrien	drm_map_type_t type;
4290075Sobrien
4390075Sobrien	DRM_LOCK();
4490075Sobrien	priv = drm_find_file_by_proc(dev, DRM_CURPROC);
4590075Sobrien	DRM_UNLOCK();
4690075Sobrien	if (priv == NULL) {
4790075Sobrien		DRM_ERROR("can't find authenticator\n");
4890075Sobrien		return EINVAL;
4990075Sobrien	}
5090075Sobrien
5190075Sobrien	if (!priv->authenticated)
5290075Sobrien		return DRM_ERR(EACCES);
5390075Sobrien
5490075Sobrien	DRM_SPINLOCK(&dev->dma_lock);
5590075Sobrien	if (dev->dma && offset >= 0 && offset < ptoa(dev->dma->page_count)) {
5690075Sobrien		drm_device_dma_t *dma = dev->dma;
5790075Sobrien
5890075Sobrien		if (dma->pagelist != NULL) {
5990075Sobrien			unsigned long page = offset >> PAGE_SHIFT;
6090075Sobrien			unsigned long phys = dma->pagelist[page];
6190075Sobrien
6290075Sobrien#if defined(__FreeBSD__) && __FreeBSD_version >= 500102
6390075Sobrien			*paddr = phys;
6490075Sobrien			DRM_SPINUNLOCK(&dev->dma_lock);
6590075Sobrien			return 0;
6690075Sobrien#else
6790075Sobrien			return atop(phys);
6890075Sobrien#endif
6990075Sobrien		} else {
7090075Sobrien			DRM_SPINUNLOCK(&dev->dma_lock);
7190075Sobrien			return -1;
7290075Sobrien		}
7390075Sobrien	}
7490075Sobrien	DRM_SPINUNLOCK(&dev->dma_lock);
7590075Sobrien
7690075Sobrien				/* A sequential search of a linked list is
7790075Sobrien				   fine here because: 1) there will only be
7890075Sobrien				   about 5-10 entries in the list and, 2) a
7990075Sobrien				   DRI client only has to do this mapping
8090075Sobrien				   once, so it doesn't have to be optimized
8190075Sobrien				   for performance, even if the list was a
8290075Sobrien				   bit longer. */
8390075Sobrien	DRM_LOCK();
8490075Sobrien	TAILQ_FOREACH(map, &dev->maplist, link) {
8590075Sobrien		if (offset >= map->offset && offset < map->offset + map->size)
8690075Sobrien			break;
8790075Sobrien	}
8890075Sobrien
8990075Sobrien	if (map == NULL) {
9090075Sobrien		DRM_UNLOCK();
9190075Sobrien		DRM_DEBUG("can't find map\n");
9290075Sobrien		return -1;
9390075Sobrien	}
9490075Sobrien	if (((map->flags&_DRM_RESTRICTED) && DRM_SUSER(DRM_CURPROC))) {
9590075Sobrien		DRM_UNLOCK();
9690075Sobrien		DRM_DEBUG("restricted map\n");
9790075Sobrien		return -1;
9890075Sobrien	}
9990075Sobrien	type = map->type;
10090075Sobrien	DRM_UNLOCK();
10190075Sobrien
10290075Sobrien	switch (type) {
10390075Sobrien	case _DRM_FRAME_BUFFER:
10490075Sobrien	case _DRM_REGISTERS:
10590075Sobrien	case _DRM_AGP:
10690075Sobrien#if defined(__FreeBSD__) && __FreeBSD_version >= 500102
10790075Sobrien		*paddr = offset;
10890075Sobrien		return 0;
10990075Sobrien#else
11090075Sobrien		return atop(offset);
11190075Sobrien#endif
11290075Sobrien	case _DRM_SCATTER_GATHER:
11390075Sobrien	case _DRM_SHM:
11490075Sobrien#if defined(__FreeBSD__) && __FreeBSD_version >= 500102
11590075Sobrien		*paddr = vtophys(offset);
11690075Sobrien		return 0;
11790075Sobrien#else
11890075Sobrien		return atop(vtophys(offset));
11990075Sobrien#endif
12090075Sobrien	default:
12190075Sobrien		return -1;	/* This should never happen. */
12290075Sobrien	}
12390075Sobrien	DRM_DEBUG("bailing out\n");
12490075Sobrien
12590075Sobrien	return -1;
12690075Sobrien}
12790075Sobrien
12890075Sobrien