目录
3. drm_gem_cma_create_with_handle
3.2 drm_gem_handle_create-->drm_gem_handle_create_tail
目录
3. drm_gem_cma_create_with_handle
3.2 drm_gem_handle_create-->drm_gem_handle_create_tail
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获取到物理地址或者虚拟地址。
到这里就完成了显示内存的获取。