static int agp_mmap(struct file *file, struct vm_area_struct *vma)
{
	unsigned int size, current_size;
	unsigned long offset;
	struct agp_client *client;
	struct agp_file_private *priv = file->private_data;
	struct agp_kern_info kerninfo;

	down(&(agp_fe.agp_mutex));

	if (agp_fe.backend_acquired != TRUE)
		goto out_eperm;

	if (!(test_bit(AGP_FF_IS_VALID, &priv->access_flags)))
		goto out_eperm;

	agp_copy_info(&kerninfo);
	size = vma->vm_end - vma->vm_start;
	current_size = kerninfo.aper_size;
	current_size = current_size * 0x100000;
	offset = vma->vm_pgoff << PAGE_SHIFT;
	DBG("%lx:%lx", offset, offset+size);

	if (test_bit(AGP_FF_IS_CLIENT, &priv->access_flags)) {
		if ((size + offset) > current_size)
			goto out_inval;

		client = agp_find_client_by_pid(current->pid);

		if (client == NULL)
			goto out_eperm;

		if (!agp_find_seg_in_client(client, offset, size, vma->vm_page_prot))
			goto out_inval;

		DBG("client vm_ops=%p", kerninfo.vm_ops);
		if (kerninfo.vm_ops) {
			vma->vm_ops = kerninfo.vm_ops;
		} else if (remap_page_range(vma, vma->vm_start, 
					    (kerninfo.aper_base + offset),
					    size, vma->vm_page_prot)) {
			goto out_again;
		}
		up(&(agp_fe.agp_mutex));
		return 0;
	}

	if (test_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags)) {
		if (size != current_size)
			goto out_inval;

		DBG("controller vm_ops=%p", kerninfo.vm_ops);
		if (kerninfo.vm_ops) {
			vma->vm_ops = kerninfo.vm_ops;
		} else if (remap_page_range(vma, vma->vm_start, 
					    kerninfo.aper_base,
					    size, vma->vm_page_prot)) {
			goto out_again;
		}
		up(&(agp_fe.agp_mutex));
		return 0;
	}

out_eperm:
	up(&(agp_fe.agp_mutex));
	return -EPERM;

out_inval:
	up(&(agp_fe.agp_mutex));
	return -EINVAL;

out_again:
	up(&(agp_fe.agp_mutex));
	return -EAGAIN;
}
Ejemplo n.º 2
0
static int agp_mmap(struct file *file, struct vm_area_struct *vma)
{
	int size;
	int current_size;
	unsigned long offset;
	agp_client *client;
	agp_file_private *priv = (agp_file_private *) file->private_data;
	agp_kern_info kerninfo;

	lock_kernel();
	AGP_LOCK();

	if (agp_fe.backend_acquired != TRUE) {
		AGP_UNLOCK();
		unlock_kernel();
		return -EPERM;
	}
	if (!(test_bit(AGP_FF_IS_VALID, &priv->access_flags))) {
		AGP_UNLOCK();
		unlock_kernel();
		return -EPERM;
	}
	agp_copy_info(&kerninfo);
	size = vma->vm_end - vma->vm_start;
	current_size = kerninfo.aper_size;
	current_size = current_size * 0x100000;
	offset = vma->vm_pgoff << PAGE_SHIFT;

	if (test_bit(AGP_FF_IS_CLIENT, &priv->access_flags)) {
		if ((size + offset) > current_size) {
			AGP_UNLOCK();
			unlock_kernel();
			return -EINVAL;
		}
		client = agp_find_client_by_pid(current->pid);

		if (client == NULL) {
			AGP_UNLOCK();
			unlock_kernel();
			return -EPERM;
		}
		if (!agp_find_seg_in_client(client, offset,
					    size, vma->vm_page_prot)) {
			AGP_UNLOCK();
			unlock_kernel();
			return -EINVAL;
		}
		if (remap_page_range(vma->vm_start,
				     (kerninfo.aper_base + offset),
				     size, vma->vm_page_prot)) {
			AGP_UNLOCK();
			unlock_kernel();
			return -EAGAIN;
		}
		AGP_UNLOCK();
		unlock_kernel();
		return 0;
	}
	if (test_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags)) {
		if (size != current_size) {
			AGP_UNLOCK();
			unlock_kernel();
			return -EINVAL;
		}
		if (remap_page_range(vma->vm_start, kerninfo.aper_base,
				     size, vma->vm_page_prot)) {
			AGP_UNLOCK();
			unlock_kernel();
			return -EAGAIN;
		}
		AGP_UNLOCK();
		unlock_kernel();
		return 0;
	}
	AGP_UNLOCK();
	unlock_kernel();
	return -EPERM;
}