コード例 #1
0
static int agp_open(struct inode *inode, struct file *file)
{
	int minor = iminor(inode);
	struct agp_file_private *priv;
	struct agp_client *client;
	int rc = -ENXIO;

	down(&(agp_fe.agp_mutex));

	if (minor != AGPGART_MINOR)
		goto err_out;

	priv = kmalloc(sizeof(struct agp_file_private), GFP_KERNEL);
	if (priv == NULL)
		goto err_out_nomem;

	memset(priv, 0, sizeof(struct agp_file_private));
	set_bit(AGP_FF_ALLOW_CLIENT, &priv->access_flags);
	priv->my_pid = current->pid;

	if ((current->uid == 0) || (current->suid == 0)) {
		/* Root priv, can be controller */
		set_bit(AGP_FF_ALLOW_CONTROLLER, &priv->access_flags);
	}
	client = agp_find_client_by_pid(current->pid);

	if (client != NULL) {
		set_bit(AGP_FF_IS_CLIENT, &priv->access_flags);
		set_bit(AGP_FF_IS_VALID, &priv->access_flags);
	}
	file->private_data = (void *) priv;
	agp_insert_file_private(priv);
	DBG("private=%p, client=%p", priv, client);
	up(&(agp_fe.agp_mutex));
	return 0;

err_out_nomem:
	rc = -ENOMEM;
err_out:
	up(&(agp_fe.agp_mutex));
	return rc;
}
コード例 #2
0
ファイル: compat_ioctl.c プロジェクト: 3sOx/asuswrt-merlin
static int compat_agpioc_reserve_wrap(struct agp_file_private *priv, void __user *arg)
{
	struct agp_region32 ureserve;
	struct agp_region kreserve;
	struct agp_client *client;
	struct agp_file_private *client_priv;

	DBG("");
	if (copy_from_user(&ureserve, arg, sizeof(ureserve)))
		return -EFAULT;

	if ((unsigned) ureserve.seg_count >= ~0U/sizeof(struct agp_segment32))
		return -EFAULT;

	kreserve.pid = ureserve.pid;
	kreserve.seg_count = ureserve.seg_count;

	client = agp_find_client_by_pid(kreserve.pid);

	if (kreserve.seg_count == 0) {
		/* remove a client */
		client_priv = agp_find_private(kreserve.pid);

		if (client_priv != NULL) {
			set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags);
			set_bit(AGP_FF_IS_VALID, &client_priv->access_flags);
		}
		if (client == NULL) {
			/* client is already removed */
			return 0;
		}
		return agp_remove_client(kreserve.pid);
	} else {
		struct agp_segment32 *usegment;
		struct agp_segment *ksegment;
		int seg;

		if (ureserve.seg_count >= 16384)
			return -EINVAL;

		usegment = kmalloc(sizeof(*usegment) * ureserve.seg_count, GFP_KERNEL);
		if (!usegment)
			return -ENOMEM;

		ksegment = kmalloc(sizeof(*ksegment) * kreserve.seg_count, GFP_KERNEL);
		if (!ksegment) {
			kfree(usegment);
			return -ENOMEM;
		}

		if (copy_from_user(usegment, (void __user *) ureserve.seg_list,
				   sizeof(*usegment) * ureserve.seg_count)) {
			kfree(usegment);
			kfree(ksegment);
			return -EFAULT;
		}

		for (seg = 0; seg < ureserve.seg_count; seg++) {
			ksegment[seg].pg_start = usegment[seg].pg_start;
			ksegment[seg].pg_count = usegment[seg].pg_count;
			ksegment[seg].prot = usegment[seg].prot;
		}

		kfree(usegment);
		kreserve.seg_list = ksegment;

		if (client == NULL) {
			/* Create the client and add the segment */
			client = agp_create_client(kreserve.pid);

			if (client == NULL) {
				kfree(ksegment);
				return -ENOMEM;
			}
			client_priv = agp_find_private(kreserve.pid);

			if (client_priv != NULL) {
				set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags);
				set_bit(AGP_FF_IS_VALID, &client_priv->access_flags);
			}
		}
		return agp_create_segment(client, &kreserve);
	}
	/* Will never really happen */
	return -EINVAL;
}
コード例 #3
0
static int agpioc_reserve_wrap(struct agp_file_private *priv, void __user *arg)
{
	struct agp_region reserve;
	struct agp_client *client;
	struct agp_file_private *client_priv;

	DBG("");
	if (copy_from_user(&reserve, arg, sizeof(struct agp_region)))
		return -EFAULT;

	if ((unsigned) reserve.seg_count >= ~0U/sizeof(struct agp_segment))
		return -EFAULT;

	client = agp_find_client_by_pid(reserve.pid);

	if (reserve.seg_count == 0) {
		/* remove a client */
		client_priv = agp_find_private(reserve.pid);

		if (client_priv != NULL) {
			set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags);
			set_bit(AGP_FF_IS_VALID, &client_priv->access_flags);
		}
		if (client == NULL) {
			/* client is already removed */
			return 0;
		}
		return agp_remove_client(reserve.pid);
	} else {
		struct agp_segment *segment;

		if (reserve.seg_count >= 16384)
			return -EINVAL;

		segment = kmalloc((sizeof(struct agp_segment) * reserve.seg_count),
				  GFP_KERNEL);

		if (segment == NULL)
			return -ENOMEM;

		if (copy_from_user(segment, (void __user *) reserve.seg_list,
				   sizeof(struct agp_segment) * reserve.seg_count)) {
			kfree(segment);
			return -EFAULT;
		}
		reserve.seg_list = segment;

		if (client == NULL) {
			/* Create the client and add the segment */
			client = agp_create_client(reserve.pid);

			if (client == NULL) {
				kfree(segment);
				return -ENOMEM;
			}
			client_priv = agp_find_private(reserve.pid);

			if (client_priv != NULL) {
				set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags);
				set_bit(AGP_FF_IS_VALID, &client_priv->access_flags);
			}
		}
		return agp_create_segment(client, &reserve);
	}
	/* Will never really happen */
	return -EINVAL;
}
コード例 #4
0
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;
}
コード例 #5
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;
}