Linux内核4.14版本——drm框架分析(7)——用户态和内核态间的交互

         驱动会注册一个支持KMS的DRM设备时,会在/dev/drm/下创建一个card%d文件,用户态可以通过打开该文件,并对文件描述符做相应的操作实现相应的功能。该文件描述符对应的文件操作回调函数(filesystem_operations)位于drm_driver中,并由驱动程序填充。典型如下:

static const struct file_operations rockchip_drm_driver_fops = {
	.owner = THIS_MODULE,
	.open = drm_open,
	.mmap = rockchip_gem_mmap,
	.poll = drm_poll,
	.read = drm_read,
	.unlocked_ioctl = drm_ioctl,
	.compat_ioctl = drm_compat_ioctl,
	.release = drm_release,
};
 
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_dev_is_unplugged(dev))
		return -ENODEV;
 
	is_driver_ioctl = nr >= DRM_COMMAND_BASE && nr < DRM_COMMAND_END;
 
	if (is_driver_ioctl) {
		/* driver ioctl */
		unsigned int index = nr - DRM_COMMAND_BASE;
 
		if (index >= dev->driver->num_ioctls)
			goto err_i1;
		index = array_index_nospec(index, dev->driver->num_ioctls);
		ioctl = &dev->driver->ioctls[index];
	} else {
		/* core ioctl */
		if (nr >= DRM_CORE_IOCTL_COUNT)
			goto err_i1;
		nr = array_index_nospec(nr, DRM_CORE_IOCTL_COUNT);
		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;
	}
 
	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);
 
	retcode = drm_ioctl_kernel(filp, func, kdata, ioctl->flags);
	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("pid=%d, ret = %d\n", task_pid_nr(current), retcode);
	return retcode;
}

        drm上层是如何调用的呢,我们使用以下命令跟踪。

strace -o 1.txt ./modetest -M mali-dp -P 27@34:1280x720@RG16 

其结果摘抄了一部分使用如下。

ioctl(3, DRM_IOCTL_VERSION, 0x4213f0)   = 0
ioctl(3, DRM_IOCTL_VERSION, 0x4213f0)   = 0
ioctl(3, DRM_IOCTL_GET_UNIQUE, 0x7fd60bb870) = 0
ioctl(3, DRM_IOCTL_GET_UNIQUE, 0x7fd60bb870) = 0
ioctl(3, DRM_IOCTL_SET_CLIENT_CAP, 0x7fd60bbb40) = 0
ioctl(3, DRM_IOCTL_MODE_GETRESOURCES, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_MODE_GETRESOURCES, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_MODE_GETCRTC, 0x7fd60bbae8) = 0
ioctl(3, DRM_IOCTL_MODE_GETENCODER, 0x7fd60bbb38) = 0
ioctl(3, DRM_IOCTL_MODE_GETCONNECTOR, 0x7fd60bbb00) = 0
ioctl(3, DRM_IOCTL_MODE_GETCONNECTOR, 0x7fd60bbb00) = 0
ioctl(3, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, 0x7fd60bbb30) = 0
ioctl(3, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, 0x7fd60bbb30) = 0
ioctl(3, DRM_IOCTL_MODE_GETPROPERTY, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_MODE_GETPROPERTY, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_MODE_GETPROPERTY, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_MODE_GETPROPERTY, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_MODE_GETPROPERTY, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_MODE_GETPROPERTY, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, 0x7fd60bbb30) = 0
ioctl(3, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, 0x7fd60bbb30) = 0
ioctl(3, DRM_IOCTL_MODE_GETPROPERTY, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_MODE_GETPROPERTY, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_MODE_GETPROPERTY, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_MODE_GETPROPERTY, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_MODE_GETPROPERTY, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_MODE_GETPROPERTY, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_MODE_GETPLANERESOURCES, 0x7fd60bbb40) = 0
ioctl(3, DRM_IOCTL_MODE_GETPLANERESOURCES, 0x7fd60bbb40) = 0
ioctl(3, DRM_IOCTL_MODE_GETPLANE, 0x7fd60bbb30) = 0
ioctl(3, DRM_IOCTL_MODE_GETPLANE, 0x7fd60bbb30) = 0
ioctl(3, DRM_IOCTL_MODE_GETPLANE, 0x7fd60bbb30) = 0
ioctl(3, DRM_IOCTL_MODE_GETPLANE, 0x7fd60bbb30) = 0
ioctl(3, DRM_IOCTL_MODE_GETPLANE, 0x7fd60bbb30) = 0
ioctl(3, DRM_IOCTL_MODE_GETPLANE, 0x7fd60bbb30) = 0
ioctl(3, DRM_IOCTL_MODE_GETPLANE, 0x7fd60bbb30) = 0
ioctl(3, DRM_IOCTL_MODE_GETPLANE, 0x7fd60bbb30) = 0
ioctl(3, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, 0x7fd60bbb30) = 0
ioctl(3, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, 0x7fd60bbb30) = 0
ioctl(3, DRM_IOCTL_MODE_GETPROPERTY, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_MODE_GETPROPERTY, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_MODE_GETPROPERTY, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_MODE_GETPROPERTY, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, 0x7fd60bbb30) = 0
ioctl(3, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, 0x7fd60bbb30) = 0
ioctl(3, DRM_IOCTL_MODE_GETPROPERTY, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_MODE_GETPROPERTY, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_MODE_GETPROPERTY, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_MODE_GETPROPERTY, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, 0x7fd60bbb30) = 0
ioctl(3, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, 0x7fd60bbb30) = 0
ioctl(3, DRM_IOCTL_MODE_GETPROPERTY, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_MODE_GETPROPERTY, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_MODE_GETPROPERTY, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_MODE_GETPROPERTY, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, 0x7fd60bbb30) = 0
ioctl(3, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, 0x7fd60bbb30) = 0
ioctl(3, DRM_IOCTL_MODE_GETPROPERTY, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_MODE_GETPROPERTY, 0x7fd60bbb10) = 0
ioctl(3, DRM_IOCTL_GET_CAP, 0x7fd60bbb40) = 0
ioctl(3, DRM_IOCTL_MODE_CREATE_DUMB, 0x7fd60bb980) = 0
ioctl(3, DRM_IOCTL_MODE_MAP_DUMB, 0x7fd60bb980) = 0
mmap(NULL, 8294400, PROT_READ|PROT_WRITE, MAP_SHARED, 3, 0x100e10000) = 0x7f9d4c0000
munmap(0x7f9d4c0000, 8294400)           = 0
ioctl(3, DRM_IOCTL_MODE_ADDFB2, 0x7fd60bb918) = 0
fstat(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(0x5, 0x1), ...}) = 0
ioctl(1, TCGETS, {B115200 opost isig icanon echo ...}) = 0
write(1, "setting mode 1920x1080-75.00Hz o"..., 57) = 57
ioctl(3, DRM_IOCTL_MODE_SETCRTC, 0x7fd60bb9d8) = 0
ioctl(3, DRM_IOCTL_MODE_DIRTYFB, 0x7fd60bba28) = -1 ENOSYS (Function not implemented)
ioctl(3, DRM_IOCTL_MODE_OBJ_SETPROPERTY, 0x7fd60bab88) = 0
ioctl(3, DRM_IOCTL_MODE_OBJ_SETPROPERTY, 0x7fd60bab88) = 0
fstat(0, {st_mode=S_IFCHR|0600, st_rdev=makedev(0x5, 0x1), ...}) = 0
ioctl(0, TCGETS, {B115200 opost isig icanon echo ...}) = 0
read(0, "\n", 4096)                     = 1
ioctl(3, DRM_IOCTL_MODE_RMFB, 0x7fd60bbb4c) = 0
ioctl(3, DRM_IOCTL_MODE_DESTROY_DUMB, 0x7fd60bbb48) = 0
fstat(3, {st_mode=S_IFCHR|0660, st_rdev=makedev(0xe2, 0), ...}) = 0
fstat(3, {st_mode=S_IFCHR|0660, st_rdev=makedev(0xe2, 0), ...}) = 0
close(3)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++

我们从上面简单分析,基本上按以下的ioctl调用顺序,进行调用的。

DRM_IOCTL_MODE_GETRESOURCES     // 获得资源

DRM_IOCTL_MODE_GETCRTC                  // 获得crtc

DRM_IOCTL_MODE_GETENCODER          // 获得encoder

DRM_IOCTL_MODE_GETCONNECTOR                   // 获得connector

DRM_IOCTL_MODE_OBJ_GETPROPERTIES          // 获得参数变量

DRM_IOCTL_MODE_GETPROPERTY                       // 获得参数变量

DRM_IOCTL_MODE_GETPLANERESOURCES        // 获得plane资源

DRM_IOCTL_MODE_GETPLANE                               // 获得plane

DRM_IOCTL_MODE_CREATE_DUMB                       // 获得gem

DRM_IOCTL_MODE_MAP_DUMB                              // map

mmap(NULL, 8294400, PROT_READ|PROT_WRITE, MAP_SHARED, 3, 0x100e10000) = 0x7f9d4c0000

DRM_IOCTL_MODE_ADDFB2                                   //填充fb

DRM_IOCTL_MODE_SETCRTC                                // 设置crtc

DRM_IOCTL_MODE_DIRTYFB

DRM_IOCTL_MODE_RMFB

后面我们会挑选一部分进行分析。

你可能感兴趣的:(Linux,drm框架分析,drm)