Esempio n. 1
0
long drm_ioctl_kernel(struct file *file, drm_ioctl_t *func, void *kdata,
		      u32 flags)
{
	struct drm_file *file_priv = file->private_data;
	struct drm_device *dev = file_priv->minor->dev;
	int retcode;

	if (drm_dev_is_unplugged(dev))
		return -ENODEV;

	retcode = drm_ioctl_permit(flags, file_priv);
	if (unlikely(retcode))
		return retcode;

	/* Enforce sane locking for modern driver ioctls. */
	if (!drm_core_check_feature(dev, DRIVER_LEGACY) ||
	    (flags & DRM_UNLOCKED))
		retcode = func(dev, kdata, file_priv);
	else {
		mutex_lock(&drm_global_mutex);
		retcode = func(dev, kdata, file_priv);
		mutex_unlock(&drm_global_mutex);
	}
	return retcode;
}
Esempio n. 2
0
static long vmw_generic_ioctl(struct file *filp, unsigned int cmd,
			      unsigned long arg,
			      long (*ioctl_func)(struct file *, unsigned int,
						 unsigned long))
{
	struct drm_file *file_priv = filp->private_data;
	struct drm_device *dev = file_priv->minor->dev;
	unsigned int nr = DRM_IOCTL_NR(cmd);
	struct vmw_master *vmaster;
	unsigned int flags;
	long ret;

	/*
	 * Do extra checking on driver private ioctls.
	 */

	if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END)
	    && (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) {
		const struct drm_ioctl_desc *ioctl =
			&vmw_ioctls[nr - DRM_COMMAND_BASE];

		if (nr == DRM_COMMAND_BASE + DRM_VMW_EXECBUF) {
			ret = (long) drm_ioctl_permit(ioctl->flags, file_priv);
			if (unlikely(ret != 0))
				return ret;

			if (unlikely((cmd & (IOC_IN | IOC_OUT)) != IOC_IN))
				goto out_io_encoding;

			return (long) vmw_execbuf_ioctl(dev, arg, file_priv,
							_IOC_SIZE(cmd));
		}

		if (unlikely(ioctl->cmd != cmd))
			goto out_io_encoding;

		flags = ioctl->flags;
	} else if (!drm_ioctl_flags(nr, &flags))
		return -EINVAL;

	vmaster = vmw_master_check(dev, file_priv, flags);
	if (IS_ERR(vmaster)) {
		ret = PTR_ERR(vmaster);

		if (ret != -ERESTARTSYS)
			DRM_INFO("IOCTL ERROR Command %d, Error %ld.\n",
				 nr, ret);
		return ret;
	}

	ret = ioctl_func(filp, cmd, arg);
	if (vmaster)
		ttm_read_unlock(&vmaster->lock);

	return ret;

out_io_encoding:
	DRM_ERROR("Invalid command format, ioctl %d\n",
		  nr - DRM_COMMAND_BASE);

	return -EINVAL;
}
Esempio n. 3
0
/**
 * Called whenever a process performs an ioctl on /dev/drm.
 *
 * \param inode device inode.
 * \param file_priv DRM file private.
 * \param cmd command.
 * \param arg user argument.
 * \return zero on success or negative number on failure.
 *
 * Looks up the ioctl function in the ::ioctls table, checking for root
 * previleges if so required, and dispatches to the respective function.
 */
long drm_ioctl(struct file *filp,
	      unsigned int cmd, unsigned long arg)
{
	struct drm_file *file_priv = filp->private_data;
	struct drm_device *dev;
	const struct drm_ioctl_desc *ioctl = NULL;
	drm_ioctl_t *func;
	unsigned int nr = DRM_IOCTL_NR(cmd);
	int retcode = -EINVAL;
	char stack_kdata[128];
	char *kdata = NULL;
	unsigned int usize, asize;

	dev = file_priv->minor->dev;

	if (drm_device_is_unplugged(dev))
		return -ENODEV;

	if ((nr >= DRM_CORE_IOCTL_COUNT) &&
	    ((nr < DRM_COMMAND_BASE) || (nr >= DRM_COMMAND_END)))
		goto err_i1;
	if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) &&
	    (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) {
		u32 drv_size;
		ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE];
		drv_size = _IOC_SIZE(ioctl->cmd_drv);
		usize = asize = _IOC_SIZE(cmd);
		if (drv_size > asize)
			asize = drv_size;
		cmd = ioctl->cmd_drv;
	}
	else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE)) {
		u32 drv_size;

		ioctl = &drm_ioctls[nr];

		drv_size = _IOC_SIZE(ioctl->cmd);
		usize = asize = _IOC_SIZE(cmd);
		if (drv_size > asize)
			asize = drv_size;

		cmd = ioctl->cmd;
	} else
		goto err_i1;

	DRM_DEBUG("pid=%d, dev=0x%lx, auth=%d, %s\n",
		  task_pid_nr(current),
		  (long)old_encode_dev(file_priv->minor->kdev->devt),
		  file_priv->authenticated, ioctl->name);

	/* Do not trust userspace, use our own definition */
	func = ioctl->func;

	if (unlikely(!func)) {
		DRM_DEBUG("no function\n");
		retcode = -EINVAL;
		goto err_i1;
	}

	retcode = drm_ioctl_permit(ioctl->flags, file_priv);
	if (unlikely(retcode))
		goto err_i1;

	if (cmd & (IOC_IN | IOC_OUT)) {
		if (asize <= sizeof(stack_kdata)) {
			kdata = stack_kdata;
		} else {
			kdata = kmalloc(asize, GFP_KERNEL);
			if (!kdata) {
				retcode = -ENOMEM;
				goto err_i1;
			}
		}
		if (asize > usize)
			memset(kdata + usize, 0, asize - usize);
	}

	if (cmd & IOC_IN) {
		if (copy_from_user(kdata, (void __user *)arg,
				   usize) != 0) {
			retcode = -EFAULT;
			goto err_i1;
		}
	} else if (cmd & IOC_OUT) {
		memset(kdata, 0, usize);
	}

	if (ioctl->flags & DRM_UNLOCKED)
		retcode = func(dev, kdata, file_priv);
	else {
		mutex_lock(&drm_global_mutex);
		retcode = func(dev, kdata, file_priv);
		mutex_unlock(&drm_global_mutex);
	}

	if (cmd & IOC_OUT) {
		if (copy_to_user((void __user *)arg, kdata,
				 usize) != 0)
			retcode = -EFAULT;
	}

      err_i1:
	if (!ioctl)
		DRM_DEBUG("invalid ioctl: pid=%d, dev=0x%lx, auth=%d, cmd=0x%02x, nr=0x%02x\n",
			  task_pid_nr(current),
			  (long)old_encode_dev(file_priv->minor->kdev->devt),
			  file_priv->authenticated, cmd, nr);

	if (kdata != stack_kdata)
		kfree(kdata);
	if (retcode)
		DRM_DEBUG("ret = %d\n", retcode);
	return retcode;
}
Esempio n. 4
0
static int init_drm(void) {
	int err;
	int i;

	struct drm_file *file_priv;

	struct drm_mode_card_res res = {0};

	PTR_TYPE res_fb_buf[10] = {0};
	PTR_TYPE res_crtc_buf[10] = {0};
	PTR_TYPE res_conn_buf[10] = {0};
	PTR_TYPE res_enc_buf[10] = {0};
	
	struct drm_mode_modeinfo conn_mode_buf[20];
	PTR_TYPE conn_prop_buf[20];
	PTR_TYPE conn_propval_buf[20];
	PTR_TYPE conn_enc_buf[20];

	struct drm_mode_get_connector conn;

	struct drm_mode_create_dumb create_dumb;
	struct drm_mode_map_dumb map_dumb;
	struct drm_mode_fb_cmd cmd_dumb;

	struct drm_mode_get_encoder enc;
	struct drm_mode_crtc crtc;


	// make kernel and user memory in common space
	old_fs = get_fs();
	set_fs(KERNEL_DS);

	// open device file
	filp = filp_open(DRM_DEV_PATH, O_RDWR | O_CLOEXEC, 0);
	if (IS_ERR(filp)) {
		err = PTR_ERR(filp);
		printk(KERN_ERR "drmtest: unable to open file: %s (%d)", DRM_DEV_PATH, err);
		return err;
	}
 
 	// set master
  	err = drm_ioctl(filp, DRM_IOCTL_SET_MASTER, 0);
	if(err) {
		printk(KERN_ERR "drmtest: error in drm_ioctl, DRM_IOCTL_SET_MASTER (%d)", err);
		goto master_release;
	}

	// check if master permission is set
	file_priv = filp->private_data;
	err = drm_ioctl_permit(DRM_MASTER, file_priv);
	if(err) {
		printk(KERN_ERR "drmtest: cannot set MASTER permissions (%d)", err);
		goto master_release;
	}

	// get resources count
	err = drm_ioctl(filp, DRM_IOCTL_MODE_GETRESOURCES, (long unsigned int)&res);
	if(err) {
		printk(KERN_ERR "drmtest: error in drm_ioctl, DRM_IOCTL_MODE_GETRESOURCES (%d)", err);
		goto master_release;
	}

	// set pointers
	res.fb_id_ptr=(PTR_TYPE)res_fb_buf;
	res.crtc_id_ptr=(PTR_TYPE)res_crtc_buf;
	res.connector_id_ptr=(PTR_TYPE)res_conn_buf;
	res.encoder_id_ptr=(PTR_TYPE)res_enc_buf;

	// get resources data
	err = drm_ioctl(filp, DRM_IOCTL_MODE_GETRESOURCES, (long unsigned int)&res);
	if(err) {
		printk(KERN_ERR "drmtest: error in drm_ioctl, DRM_IOCTL_MODE_GETRESOURCES (%d)", err);
		goto master_release;
	}

	// print resources info
	printk("fb: %d, crtc: %d, conn: %d, enc: %d\n",res.count_fbs,res.count_crtcs,res.count_connectors,res.count_encoders);

	//Loop though all available connectors
	for (i=0; i<res.count_connectors; i++)
	{
		// clear
		memset(conn_mode_buf, 0, sizeof(struct drm_mode_modeinfo)*20);
		memset(conn_prop_buf, 0, sizeof(PTR_TYPE)*20);
		memset(conn_propval_buf, 0, sizeof(PTR_TYPE)*20);
		memset(conn_enc_buf, 0, sizeof(PTR_TYPE)*20);
		memset(&conn, 0, sizeof(struct drm_mode_get_connector));

		conn.connector_id = res_conn_buf[i];

		//get connector resource counts
		err = drm_ioctl(filp, DRM_IOCTL_MODE_GETCONNECTOR, (long unsigned int)&conn);	
		if(err) {
			printk(KERN_ERR "drmtest: error in drm_ioctl, DRM_IOCTL_MODE_GETCONNECTOR (%d)", err);
			goto master_release;
		}

		// set pointers
		conn.modes_ptr=(PTR_TYPE)conn_mode_buf;
		conn.props_ptr=(PTR_TYPE)conn_prop_buf;
		conn.prop_values_ptr=(PTR_TYPE)conn_propval_buf;
		conn.encoders_ptr=(PTR_TYPE)conn_enc_buf;

		// get connector resources
		err = drm_ioctl(filp, DRM_IOCTL_MODE_GETCONNECTOR, (long unsigned int)&conn);
		if(err) {
			printk(KERN_ERR "drmtest: error in drm_ioctl, DRM_IOCTL_MODE_GETCONNECTOR (%d)", err);
			goto master_release;
		}

		// check if the connector is connected
		if (conn.count_encoders<1 || conn.count_modes<1 || !conn.encoder_id || !conn.connection) {
			printk("Not connected\n");
			continue;
		}


		// *****************************
		//      create dumb buffer
		// *****************************

		memset(&create_dumb, 0, sizeof(struct drm_mode_create_dumb));
		memset(&map_dumb, 0, sizeof(struct drm_mode_map_dumb));
		memset(&cmd_dumb, 0, sizeof(struct drm_mode_fb_cmd));

		// set screen params
		create_dumb.width = conn_mode_buf[0].hdisplay;
		create_dumb.height = conn_mode_buf[0].vdisplay;
		create_dumb.bpp = 32;
		create_dumb.flags = 0;
		create_dumb.pitch = 0;
		create_dumb.size = 0;
		create_dumb.handle = 0;

		// create dumb buffer
		err = drm_ioctl(filp, DRM_IOCTL_MODE_CREATE_DUMB, (long unsigned int)&create_dumb);
		if(err) {
			printk(KERN_ERR "drmtest: error in drm_ioctl, DRM_IOCTL_MODE_CREATE_DUMB (%d)", err);
			goto master_release;
		}

		cmd_dumb.width=create_dumb.width;
		cmd_dumb.height=create_dumb.height;
		cmd_dumb.bpp=create_dumb.bpp;
		cmd_dumb.pitch=create_dumb.pitch;
		cmd_dumb.depth=24;
		cmd_dumb.handle=create_dumb.handle;

		// add framebuffer
		err = drm_ioctl(filp, DRM_IOCTL_MODE_ADDFB, (long unsigned int)&cmd_dumb);
		if(err) {
			printk(KERN_ERR "drmtest: error in drm_ioctl, DRM_IOCTL_MODE_ADDFB (%d)", err);
			goto master_release;
		}

		// prepare dumb buffer to mmap
		map_dumb.handle=create_dumb.handle;
		err = drm_ioctl(filp, DRM_IOCTL_MODE_MAP_DUMB, (long unsigned int)&map_dumb);
		if(err) {
			printk(KERN_ERR "drmtest: error in drm_ioctl, DRM_IOCTL_MODE_MAP_DUMB (%d)", err);
			goto master_release;
		}

		
		// map buffer to memory
		fb_base[i] = (void *)vm_mmap(filp, 0, create_dumb.size, PROT_READ | PROT_WRITE, MAP_SHARED, map_dumb.offset);

		fb_w[i]=create_dumb.width;
		fb_h[i]=create_dumb.height;


		// *************************
		// kernel mode setting
		// *************************


		printk("%d : mode: %d, prop: %d, enc: %d\n",conn.connection,conn.count_modes,conn.count_props,conn.count_encoders);
		printk("modes: %dx%d FB: %d\n", conn_mode_buf[0].hdisplay, conn_mode_buf[0].vdisplay, (int)fb_base[i]);


		// init encoder
		memset(&enc, 0, sizeof(struct drm_mode_get_encoder));

		enc.encoder_id=conn.encoder_id;

		// get encoder
		err = drm_ioctl(filp, DRM_IOCTL_MODE_GETENCODER, (long unsigned int)&enc);	
		if(err) {
			printk(KERN_ERR "drmtest: error in drm_ioctl, DRM_IOCTL_MODE_GETENCODER (%d)", err);
			goto master_release;
		}

		// init crtc
		memset(&crtc, 0, sizeof(struct drm_mode_crtc));

		crtc.crtc_id=enc.crtc_id;

		err = drm_ioctl(filp, DRM_IOCTL_MODE_GETCRTC, (long unsigned int)&crtc);
		if(err) {
			printk(KERN_ERR "drmtest: error in drm_ioctl, DRM_IOCTL_MODE_GETCRTC (%d)", err);
			goto master_release;
		}

		crtc.fb_id=cmd_dumb.fb_id;
		crtc.set_connectors_ptr=(PTR_TYPE)&res_conn_buf[i];
		crtc.count_connectors=1;
		crtc.mode=conn_mode_buf[0];
		crtc.mode_valid=1;

		err = drm_ioctl(filp, DRM_IOCTL_MODE_SETCRTC, (long unsigned int)&crtc);
		if(err) {
			printk(KERN_ERR "drmtest: error in drm_ioctl, DRM_IOCTL_MODE_SETCRTC (%d)", err);
			goto master_release;
		}
	}

	connectors_count = res.count_connectors;


	return 0;

master_release:
	exit_drm();	
	return err;
}
Esempio n. 5
0
/**
 * drm_ioctl - ioctl callback implementation for DRM drivers
 * @filp: file this ioctl is called on
 * @cmd: ioctl cmd number
 * @arg: user argument
 *
 * Looks up the ioctl function in the ::ioctls table, checking for root
 * previleges if so required, and dispatches to the respective function.
 *
 * Returns:
 * Zero on success, negative error code on failure.
 */
long drm_ioctl(struct file *filp,
	      unsigned int cmd, unsigned long arg)
{
	struct drm_file *file_priv = filp->private_data;
	struct drm_device *dev;
	const struct drm_ioctl_desc *ioctl = NULL;
	drm_ioctl_t *func;
	unsigned int nr = DRM_IOCTL_NR(cmd);
	int retcode = -EINVAL;
	char stack_kdata[128];
	char *kdata = NULL;
	unsigned int in_size, out_size, drv_size, ksize;
	bool is_driver_ioctl;

	dev = file_priv->minor->dev;

	if (drm_device_is_unplugged(dev))
		return -ENODEV;

	is_driver_ioctl = nr >= DRM_COMMAND_BASE && nr < DRM_COMMAND_END;

	if (is_driver_ioctl) {
		/* driver ioctl */
		if (nr - DRM_COMMAND_BASE >= dev->driver->num_ioctls)
			goto err_i1;
		ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE];
	} else {
		/* core ioctl */
		if (nr >= DRM_CORE_IOCTL_COUNT)
			goto err_i1;
		ioctl = &drm_ioctls[nr];
	}

	drv_size = _IOC_SIZE(ioctl->cmd);
	out_size = in_size = _IOC_SIZE(cmd);
	if ((cmd & ioctl->cmd & IOC_IN) == 0)
		in_size = 0;
	if ((cmd & ioctl->cmd & IOC_OUT) == 0)
		out_size = 0;
	ksize = max(max(in_size, out_size), drv_size);

	DRM_DEBUG("pid=%d, dev=0x%lx, auth=%d, %s\n",
		  task_pid_nr(current),
		  (long)old_encode_dev(file_priv->minor->kdev->devt),
		  file_priv->authenticated, ioctl->name);

	/* Do not trust userspace, use our own definition */
	func = ioctl->func;

	if (unlikely(!func)) {
		DRM_DEBUG("no function\n");
		retcode = -EINVAL;
		goto err_i1;
	}

	retcode = drm_ioctl_permit(ioctl->flags, file_priv);
	if (unlikely(retcode))
		goto err_i1;

	if (ksize <= sizeof(stack_kdata)) {
		kdata = stack_kdata;
	} else {
		kdata = kmalloc(ksize, GFP_KERNEL);
		if (!kdata) {
			retcode = -ENOMEM;
			goto err_i1;
		}
	}

	if (copy_from_user(kdata, (void __user *)arg, in_size) != 0) {
		retcode = -EFAULT;
		goto err_i1;
	}

	if (ksize > in_size)
		memset(kdata + in_size, 0, ksize - in_size);

	/* Enforce sane locking for modern driver ioctls. Core ioctls are
	 * too messy still. */
	if ((!drm_core_check_feature(dev, DRIVER_LEGACY) && is_driver_ioctl) ||
	    (ioctl->flags & DRM_UNLOCKED))
		retcode = func(dev, kdata, file_priv);
	else {
		mutex_lock(&drm_global_mutex);
		retcode = func(dev, kdata, file_priv);
		mutex_unlock(&drm_global_mutex);
	}

	if (copy_to_user((void __user *)arg, kdata, out_size) != 0)
		retcode = -EFAULT;

      err_i1:
	if (!ioctl)
		DRM_DEBUG("invalid ioctl: pid=%d, dev=0x%lx, auth=%d, cmd=0x%02x, nr=0x%02x\n",
			  task_pid_nr(current),
			  (long)old_encode_dev(file_priv->minor->kdev->devt),
			  file_priv->authenticated, cmd, nr);

	if (kdata != stack_kdata)
		kfree(kdata);
	if (retcode)
		DRM_DEBUG("ret = %d\n", retcode);
	return retcode;
}