DrmOpenWithType
DrmOpenWithType
xf86drm.h
// type 指定打开设备的的类型,主要有以下三类:#define DRM_NODE_PRIMARY 0
#define DRM_NODE_CONTROL 1
#define DRM_NODE_RENDER 2 drm_public int drmOpenWithType(const char *name, const char *busid, int type)
{if (name != NULL && drm_server_info && drm_server_info->load_module && !drmAvailable()) {// 试图去加载核模块if (!drm_server_info->load_module(name)) {drmMsg("[drm] failed to load kernel module \"%s\"\n", name);return -1;}}// 如果提供了busid,name参数就不用了,使用busid去打开设备节点if (busid) {int fd = drmOpenByBusid(busid, type);if (fd >= 0)return fd;}// 最后使用指定的设备名称去打开if (name)return drmOpenByName(name, type);return -1;
}
drmOpenByName
/*** 第一个参数 name 为驱动的名称, 第二个参数为设备节点的类型.* 函数调用成功则返回一个文件描述符, 调用失败返回一个负的值.** \internal* This function opens the first minor number that matches the driver name and isn't already in use.* If it's in use it then it will already have a bus ID assigned.** 通过调用 drmOpenMinor(), drmGetVersion() and drmGetBusid(). 来实现的*/
static int drmOpenByName(const char *name, int type)
{int i;int fd;drmVersionPtr version;char * id;int base = drmGetMinorBase(type);if (base < 0)return -1;/** Open the first minor number that matches the driver name and isn't* already in use. If it's in use it will have a busid assigned already.*/// DRM_MAX_MINOR = 16for (i = base; i < base + DRM_MAX_MINOR; i++){if ((fd = drmOpenMinor(i, 1, type)) >= 0){// 从内核态获得drm的名字,但是怎么区分 loongson-drm 和 etnaviv 呢 ?// etnaviv 只是一个renderer node,用上边的type来区分。if ((version = drmGetVersion(fd))){if (!strcmp(version->name, name)){drmFreeVersion(version);id = drmGetBusid(fd);drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL");if (!id || !*id) {if (id)drmFreeBusid(id);return fd;}elsedrmFreeBusid(id);}elsedrmFreeVersion(version);}close(fd);}}#ifdef __linux__// 后向兼容性的东西,打开/proc/dri/i/name 。。。
#endifreturn -1;
}
drmOpenMinor
/*** Open the DRM device** \param minor device minor number.* \param 如果 create 置位则调用drmOpenDevice(), 允许创建设备 ?.** 成功返回一个文件描述符,失败则返回一个负的值.** \internal* Calls if \p create is set, otherwise assembles the device* name from \p minor and opens it.*/
static int drmOpenMinor(int minor, int create, int type)
{// 获取设备节点的名称,如果type = DRM_NODE_RENDER, /dev/dri/renderD128,129,...,143const char *dev_name = drmGetDeviceName(type);// 上边函数调用的create为1, 这里就只分析create为1的情况if (create)return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type);// 。。。
}static const char *drmGetDeviceName(int type)
{switch (type) {case DRM_NODE_PRIMARY:return DRM_DEV_NAME;case DRM_NODE_CONTROL:return DRM_CONTROL_DEV_NAME;case DRM_NODE_RENDER:return DRM_RENDER_DEV_NAME;}return NULL;
}
drmGetVersion
/*** Query the driver version information.** \param fd file descriptor.** \return pointer to a drmVersion structure which should be freed with* drmFreeVersion().** \note Similar information is available via /proc/dri.** \internal* It gets the version information via successive DRM_IOCTL_VERSION ioctls,* first with zeros to get the string lengths, and then the actually strings.* It also null-terminates them since they might not be already.*/
drm_public drmVersionPtr drmGetVersion(int fd)
{drmVersionPtr retval;drm_version_t *version = drmMalloc(sizeof(*version));if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {drmFreeKernelVersion(version);return NULL;}if (version->name_len)version->name = drmMalloc(version->name_len + 1);if (version->date_len)version->date = drmMalloc(version->date_len + 1);if (version->desc_len)version->desc = drmMalloc(version->desc_len + 1);if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno));drmFreeKernelVersion(version);return NULL;}/* The results might not be null-terminated strings, so terminate them. */if (version->name_len) version->name[version->name_len] = '\0';if (version->date_len) version->date[version->date_len] = '\0';if (version->desc_len) version->desc[version->desc_len] = '\0';retval = drmMalloc(sizeof(*retval));drmCopyVersion(retval, version);drmFreeKernelVersion(version);return retval;
}
makedev
#include <sys/sysmacros.h>dev_t makedev(unsigned int maj, unsigned int min);unsigned int major(dev_t dev);unsigned int minor(dev_t dev);
设备 ID 由两部分组成 主ID和子ID,主ID用来辨识设备的类别,子ID用来标识这个类别里面设备的一个特定实例
设备 ID 用 dev_t 来表示。 makedev()用给予的主ID和子ID去生成一个设备ID,这个设别ID是可以传入 mknod的。
major() and minor() 函数则执行相反的工作,给予一个设备id,返回主ID和子ID。
#ifndef DRM_MAJOR
#define DRM_MAJOR 226 /* Linux */
#endif
drmOpenDevice
UDEV 在meson 的 config.h中是定义了的, 所以我们只看使用udev的代码,非udev的我给去掉了。
/*** Open the DRM device, creating it if necessary.** \param dev major and minor numbers of the device.* \param minor minor number of the device.** \return a file descriptor on success, or a negative value on error.** \internal* Assembles the device name from \p minor and opens it, creating the device* special file node with the major and minor numbers specified by \p dev and* parent directory if necessary and was called by root.*/
static int drmOpenDevice(dev_t dev, int minor, int type)
{stat_t st;char buf[DRM_NODE_NAME_MAX];int fd;mode_t devmode = DRM_DEV_MODE, serv_mode;gid_t serv_group;// 这块还是要整出 /dev/dri/renderD128const char * dev_name = drmGetDeviceName(type);sprintf(buf, dev_name, DRM_DIR_NAME, minor);drmMsg("drmOpenDevice: node name is %s\n", buf);if (drm_server_info && drm_server_info->get_perms) {drm_server_info->get_perms(&serv_group, &serv_mode);devmode = serv_mode ? serv_mode : DRM_DEV_MODE;devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);}/* if we modprobed then wait for udev */{int udev_count = 0;
wait_for_udev:if (stat(DRM_DIR_NAME, &st)) {usleep(20);udev_count++;if (udev_count == 50)return -1;goto wait_for_udev;}if (stat(buf, &st)) {usleep(20);udev_count++;if (udev_count == 50)return -1;goto wait_for_udev;}}// 核心就是打开 /dev/dri/renderD128,返回一个 fdfd = open(buf, O_RDWR | O_CLOEXEC, 0);drmMsg("drmOpenDevice: open result is %d, (%s)\n", fd, fd < 0 ? strerror(errno) : "OK");if (fd >= 0)return fd;return -errno;
}