libdrm全解析二十二 —— 源码全解析(19)

接前一篇文章:libdrm全解析二十一 —— 源码全解析(18)

本文参考以下博文:

DRM 驱动程序开发(VKMS)

特此致谢!

前一篇文章介绍了DRM的一般流程,并给出了示例代码。从本回开始,正式对于上一篇文章中用到的函数以及涉及到的宏定义进行解析。

60. DRM_IOCTL_MODE_GETRESOURCES

第60个宏是DRM_IOCTL_MODE_GETRESOURCES,相应代码如下:

#define DRM_IOCTL_MODE_GETRESOURCES	DRM_IOWR(0xA0, struct drm_mode_card_res)

结合之前文章中的_IOWR(type,nr,size)的最终定义,得到如下代码:

#define DRM_IOCTL_MODE_GETRESOURCES        ( ((3)  << 30) | (('d') << 8) | ((0xA0)   << 0) | ((sizeof(struct drm_mode_card_res)) << 16) )

struct drm_mode_card_res在同文件(include/drm/drm.h)中定义,代码如下:

struct drm_mode_card_res {
	__u64 fb_id_ptr;
	__u64 crtc_id_ptr;
	__u64 connector_id_ptr;
	__u64 encoder_id_ptr;
	__u32 count_fbs;
	__u32 count_crtcs;
	__u32 count_connectors;
	__u32 count_encoders;
	__u32 min_width;
	__u32 max_width;
	__u32 min_height;
	__u32 max_height;
};

DRM_IOCTL_MODE_GETRESOURCES对应的Userspace API为:drmIsKMS()和drmModeGetResources()。这函数也是在xf86drm.c中,代码分别如下:

drm_public int drmIsKMS(int fd)
{
	struct drm_mode_card_res res = {0};

	if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res) != 0)
		return 0;

	return res.count_crtcs > 0 && res.count_connectors > 0 && res.count_encoders > 0;
}

drmIsKMS函数通过drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)获取到的资源(struct drm_mode_card_res res),根据crtc、connector、encoders的数量进行判断,如果三者都大于0,则返回真(true),代表是KMS;否则返回假(false),代表不是KMS。 

drm_public drmModeResPtr drmModeGetResources(int fd)
{
	struct drm_mode_card_res res, counts;
	drmModeResPtr r = 0;

retry:
	memclear(res);
	if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
		return 0;

	counts = res;

	if (res.count_fbs) {
		res.fb_id_ptr = VOID2U64(drmMalloc(res.count_fbs*sizeof(uint32_t)));
		if (!res.fb_id_ptr)
			goto err_allocs;
	}
	if (res.count_crtcs) {
		res.crtc_id_ptr = VOID2U64(drmMalloc(res.count_crtcs*sizeof(uint32_t)));
		if (!res.crtc_id_ptr)
			goto err_allocs;
	}
	if (res.count_connectors) {
		res.connector_id_ptr = VOID2U64(drmMalloc(res.count_connectors*sizeof(uint32_t)));
		if (!res.connector_id_ptr)
			goto err_allocs;
	}
	if (res.count_encoders) {
		res.encoder_id_ptr = VOID2U64(drmMalloc(res.count_encoders*sizeof(uint32_t)));
		if (!res.encoder_id_ptr)
			goto err_allocs;
	}

	if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
		goto err_allocs;

	/* The number of available connectors and etc may have changed with a
	 * hotplug event in between the ioctls, in which case the field is
	 * silently ignored by the kernel.
	 */
	if (counts.count_fbs < res.count_fbs ||
	    counts.count_crtcs < res.count_crtcs ||
	    counts.count_connectors < res.count_connectors ||
	    counts.count_encoders < res.count_encoders)
	{
		drmFree(U642VOID(res.fb_id_ptr));
		drmFree(U642VOID(res.crtc_id_ptr));
		drmFree(U642VOID(res.connector_id_ptr));
		drmFree(U642VOID(res.encoder_id_ptr));

		goto retry;
	}

	/*
	 * return
	 */
	if (!(r = drmMalloc(sizeof(*r))))
		goto err_allocs;

	r->min_width     = res.min_width;
	r->max_width     = res.max_width;
	r->min_height    = res.min_height;
	r->max_height    = res.max_height;
	r->count_fbs     = res.count_fbs;
	r->count_crtcs   = res.count_crtcs;
	r->count_connectors = res.count_connectors;
	r->count_encoders = res.count_encoders;

	r->fbs        = drmAllocCpy(U642VOID(res.fb_id_ptr), res.count_fbs, sizeof(uint32_t));
	r->crtcs      = drmAllocCpy(U642VOID(res.crtc_id_ptr), res.count_crtcs, sizeof(uint32_t));
	r->connectors = drmAllocCpy(U642VOID(res.connector_id_ptr), res.count_connectors, sizeof(uint32_t));
	r->encoders   = drmAllocCpy(U642VOID(res.encoder_id_ptr), res.count_encoders, sizeof(uint32_t));
	if ((res.count_fbs && !r->fbs) ||
	    (res.count_crtcs && !r->crtcs) ||
	    (res.count_connectors && !r->connectors) ||
	    (res.count_encoders && !r->encoders))
	{
		drmFree(r->fbs);
		drmFree(r->crtcs);
		drmFree(r->connectors);
		drmFree(r->encoders);
		drmFree(r);
		r = 0;
	}

err_allocs:
	drmFree(U642VOID(res.fb_id_ptr));
	drmFree(U642VOID(res.crtc_id_ptr));
	drmFree(U642VOID(res.connector_id_ptr));
	drmFree(U642VOID(res.encoder_id_ptr));

	return r;
}

drmModeGetResources函数值得深入地进行讲解,其在整个流程中是至关重要的。通过前一篇文章中的两个例程以及一般流程可以看到,它是第一步调用的函数,因此,值得大书特书。

对于这个函数的解析,放在下一篇文章中。这里先把一个同样十分重要的基础函数讲解清楚。这个函数就是:drmIoctl。

其实之前已经太多次遇到这个函数了,只是一直没有正式对其进行讲解。drmIoctl函数也在xf86drm.c中,代码如下:

/**
 * Call ioctl, restarting if it is interrupted
 */
drm_public int
drmIoctl(int fd, unsigned long request, void *arg)
{
    int ret;

    do {
        ret = ioctl(fd, request, arg);
    } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
    return ret;
}

通过代码可以看到,实际上就是ioctl系统调用的一层封装。在ioctl系统调用返回错误(由于EINTR和EAGIN而返回-1)的时候,反复进行ioctl系统调用,直到正确或者出现其它错误为止。

以drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)为例,实际上调用的是:

ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)

对于其它的drmIoctl,也是类似的意思。

猜你喜欢

转载自blog.csdn.net/phmatthaus/article/details/132494774