static int mport_cdev_mmap()

in devices/rio_mport_cdev.c [2193:2250]


static int mport_cdev_mmap(struct file *filp, struct vm_area_struct *vma)
{
	struct mport_cdev_priv *priv = filp->private_data;
	struct mport_dev *md;
	size_t size = vma->vm_end - vma->vm_start;
	dma_addr_t baddr;
	unsigned long offset;
	int found = 0, ret;
	struct rio_mport_mapping *map;

	rmcd_debug(MMAP, "0x%x bytes at offset 0x%lx",
		   (unsigned int)size, vma->vm_pgoff);

	md = priv->md;
	baddr = ((dma_addr_t)vma->vm_pgoff << PAGE_SHIFT);

	mutex_lock(&md->buf_mutex);
	list_for_each_entry(map, &md->mappings, node) {
		if (baddr >= map->phys_addr &&
		    baddr < (map->phys_addr + map->size)) {
			found = 1;
			break;
		}
	}
	mutex_unlock(&md->buf_mutex);

	if (!found)
		return -ENOMEM;

	offset = baddr - map->phys_addr;

	if (size + offset > map->size)
		return -EINVAL;

	vma->vm_pgoff = offset >> PAGE_SHIFT;
	rmcd_debug(MMAP, "MMAP adjusted offset = 0x%lx", vma->vm_pgoff);

	if (map->dir == MAP_INBOUND || map->dir == MAP_DMA)
		ret = dma_mmap_coherent(md->mport->dev.parent, vma,
				map->virt_addr, map->phys_addr, map->size);
	else if (map->dir == MAP_OUTBOUND) {
		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
		ret = vm_iomap_memory(vma, map->phys_addr, map->size);
	} else {
		rmcd_error("Attempt to mmap unsupported mapping type");
		ret = -EIO;
	}

	if (!ret) {
		vma->vm_private_data = map;
		vma->vm_ops = &vm_ops;
		mport_mm_open(vma);
	} else {
		rmcd_error("MMAP exit with err=%d", ret);
	}

	return ret;
}