Linux内核4.14版本——drm框架分析(10)——DRM_IOCTL_MODE_CREATE_DUMB(drm_mode_create_dumb_ioctl)

目录

1. 简介

2. drm_gem_cma_dumb_create

3. drm_gem_cma_create_with_handle

3.1 drm_gem_cma_create

3.2 drm_gem_handle_create-->drm_gem_handle_create_tail

4. 调用流程图


目录

1. 简介

2. drm_gem_cma_dumb_create

3. drm_gem_cma_create_with_handle

3.1 drm_gem_cma_create

3.2 drm_gem_handle_create-->drm_gem_handle_create_tail

4. 调用流程图

1. 简介

创建显示buf需要三个参数

  • width //图像宽度
  • height //图像高度
  • bpp //每个像素占用bit数

        将以上参数放入数据结构struct drm_mode_create_dumb create中,并作为参数调用drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create)后内核返回对应的handle赋值给handle,patch给用户使用;至于为什么会返回handle,后面介绍kernel部分的时候再说。

在kernel中会调用drm_mode_create_dumb_ioctl。

int drm_mode_create_dumb_ioctl(struct drm_device *dev,
			       void *data, struct drm_file *file_priv)
{
	struct drm_mode_create_dumb *args = data;
	u32 cpp, stride, size;

	if (!dev->driver->dumb_create)
		return -ENOSYS;
	if (!args->width || !args->height || !args->bpp)
		return -EINVAL;

	/* overflow checks for 32bit size calculations */
	if (args->bpp > U32_MAX - 8)
		return -EINVAL;
	cpp = DIV_ROUND_UP(args->bpp, 8);
	if (cpp > U32_MAX / args->width)
		return -EINVAL;
	stride = cpp * args->width;
	if (args->height > U32_MAX / stride)
		return -EINVAL;

	/* test for wrap-around */
	size = args->height * stride;
	if (PAGE_ALIGN(size) == 0)
		return -EINVAL;

	/*
	 * handle, pitch and size are output parameters. Zero them out to
	 * prevent drivers from accidentally using uninitialized data. Since
	 * not all existing userspace is clearing these fields properly we
	 * cannot reject IOCTL with garbage in them.
	 */
	args->handle = 0;
	args->pitch = 0;
	args->size = 0;

	return dev->driver->dumb_create(file_priv, dev, args);
}

2. drm_gem_cma_dumb_create

        此函数会调用drm_driver中注册的dev->driver->dumb_create(file_priv, dev, args),也就是drm_gem_cma_dumb_create函数,注意变量args,其成员变量handle、pitch、size为输出的参数,用于返回给用户。

int drm_gem_cma_dumb_create(struct drm_file *file_priv,
			    struct drm_device *drm,
			    struct drm_mode_create_dumb *args)
{
	struct drm_gem_cma_object *cma_obj;

	args->pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
	args->size = args->pitch * args->height;

	cma_obj = drm_gem_cma_create_with_handle(file_priv, drm, args->size,
						 &args->handle);
	return PTR_ERR_OR_ZERO(cma_obj);
}

       drm_gem_cma_dumb_create函数,主要两个目的:

      (1)计算pitch和size,返回给用户。

      (2)调用drm_gem_cma_create_with_handle创建struct drm_gem_cma_object结构体,该结构体中包含分配内存的物理地址和虚拟地址,还有一个重要的结构体struct drm_gem_object。

/**
 * struct drm_gem_cma_object - GEM object backed by CMA memory allocations
 * @base: base GEM object
 * @paddr: physical address of the backing memory
 * @sgt: scatter/gather table for imported PRIME buffers
 * @vaddr: kernel virtual address of the backing memory
 */
struct drm_gem_cma_object {
	struct drm_gem_object base;
	dma_addr_t paddr;
	struct sg_table *sgt;

	/* For objects with DMA memory allocated by GEM CMA */
	void *vaddr;
};

3. drm_gem_cma_create_with_handle

       下面我们看下drm_gem_cma_create_with_handle函数是如何创建struct drm_gem_cma_object结构体的。

static struct drm_gem_cma_object *
drm_gem_cma_create_with_handle(struct drm_file *file_priv,
			       struct drm_device *drm, size_t size,
			       uint32_t *handle)
{
	struct drm_gem_cma_object *cma_obj;
	struct drm_gem_object *gem_obj;
	int ret;

	cma_obj = drm_gem_cma_create(drm, size);
	if (IS_ERR(cma_obj))
		return cma_obj;

	gem_obj = &cma_obj->base;

	/*
	 * allocate a id of idr table where the obj is registered
	 * and handle has the id what user can see.
	 */
	ret = drm_gem_handle_create(file_priv, gem_obj, handle);
	/* drop reference from allocate - handle holds it now. */
	drm_gem_object_put_unlocked(gem_obj);
	if (ret)
		return ERR_PTR(ret);

	return cma_obj;
}

        该函数调用了drm_gem_cma_create和drm_gem_handle_create,我们下面分别分析一下。

3.1 drm_gem_cma_create

struct drm_gem_cma_object *drm_gem_cma_create(struct drm_device *drm,
					      size_t size)
{
	struct drm_gem_cma_object *cma_obj;
	int ret;

	size = round_up(size, PAGE_SIZE);

	cma_obj = __drm_gem_cma_create(drm, size);
	if (IS_ERR(cma_obj))
		return cma_obj;

	cma_obj->vaddr = dma_alloc_wc(drm->dev, size, &cma_obj->paddr,
				      GFP_KERNEL | __GFP_NOWARN);
	if (!cma_obj->vaddr) {
		dev_err(drm->dev, "failed to allocate buffer with size %zu\n",
			size);
		ret = -ENOMEM;
		goto error;
	}

	return cma_obj;

error:
	drm_gem_object_put_unlocked(&cma_obj->base);
	return ERR_PTR(ret);
}

         (1)创建一个struct drm_gem_cma_object结构体对象,并初始化其中的struct drm_gem_object。

         (2)使用dma_alloc_wc分配内存并将物理地址存入paddr,虚拟地址存入vaddr

3.2 drm_gem_handle_create-->drm_gem_handle_create_tail

int
drm_gem_handle_create_tail(struct drm_file *file_priv,
			   struct drm_gem_object *obj,
			   u32 *handlep)
{
	struct drm_device *dev = obj->dev;
	u32 handle;
	int ret;

	......
	ret = idr_alloc(&file_priv->object_idr, obj, 1, 0, GFP_NOWAIT);    // (1)

	handle = ret;                                                      // (2)
	.....
	*handlep = handle;                                                 // (3)
	return 0;
	.....
}

         drm_gem_handle_create主要使用idr_alloc将drm_gem_object对象添加到file_priv->object_idr,并返回handle。

         idr_alloc:是为了使用一个id与一个obj绑定。这样就可以通过id找到对应obj。这里将handle与分配的gem_object进行绑定,后面通过handle可以找到gem_object进而找到cma_object获取到物理地址或者虚拟地址。

         到这里就完成了显示内存的获取。

4. 调用流程图

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值