DrmOpenWithType

发布时间:2023年12月25日

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 = 16
    for (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;
                    }
                    else
                        drmFreeBusid(id);
                }
                else
                    drmFreeVersion(version);
            }
            close(fd);
        }
    }

#ifdef __linux__
    // 后向兼容性的东西,打开/proc/dri/i/name 。。。
#endif

    return -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,...,143
    const 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/renderD128
    const 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,返回一个 fd
    fd = 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;
}
文章来源:https://blog.csdn.net/qq_38350702/article/details/131899557
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。