• Android12之DRM基本接口实现(二)


    简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!

    优质专栏:Audio工程师进阶系列原创干货持续更新中……】🚀

    人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

    更多原创,欢迎关注:Android系统攻城狮

    欢迎关注Android系统攻城狮

    1.前言

    本篇目的:探究DRM基本接口的实现,底层实现到底是如何与DRM驱动通信的?

    2.DRM基本接口实现解析

    <1>.DRM之drmModeGetResources获取CRTC和Connector的id号

    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;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94

    核心要点1

    1.调用drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)获取CRTC和Connector的id号。

    2.drm_mode_card_res数据结构

    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;
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    <2>.DRM之drmModeGetConnector连接Connector显示器

    static drmModeConnectorPtr
    _drmModeGetConnector(int fd, uint32_t connector_id, int probe)
    {
    	struct drm_mode_get_connector conn, counts;
    	drmModeConnectorPtr r = NULL;
    	struct drm_mode_modeinfo stack_mode;
    
    	memclear(conn);
    	conn.connector_id = connector_id;
    	if (!probe) {
    		conn.count_modes = 1;
    		conn.modes_ptr = VOID2U64(&stack_mode);
    	}
    
    	if (drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))
    		return 0;
    
    retry:
    	counts = conn;
    
    	if (conn.count_props) {
    		conn.props_ptr = VOID2U64(drmMalloc(conn.count_props*sizeof(uint32_t)));
    		if (!conn.props_ptr)
    			goto err_allocs;
    		conn.prop_values_ptr = VOID2U64(drmMalloc(conn.count_props*sizeof(uint64_t)));
    		if (!conn.prop_values_ptr)
    			goto err_allocs;
    	}
    
    	if (conn.count_modes) {
    		conn.modes_ptr = VOID2U64(drmMalloc(conn.count_modes*sizeof(struct drm_mode_modeinfo)));
    		if (!conn.modes_ptr)
    			goto err_allocs;
    	} else {
    		conn.count_modes = 1;
    		conn.modes_ptr = VOID2U64(&stack_mode);
    	}
    
    	if (conn.count_encoders) {
    		conn.encoders_ptr = VOID2U64(drmMalloc(conn.count_encoders*sizeof(uint32_t)));
    		if (!conn.encoders_ptr)
    			goto err_allocs;
    	}
    
    	if (drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))
    		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_props < conn.count_props ||
    	    counts.count_modes < conn.count_modes ||
    	    counts.count_encoders < conn.count_encoders) {
    		drmFree(U642VOID(conn.props_ptr));
    		drmFree(U642VOID(conn.prop_values_ptr));
    		if (U642VOID(conn.modes_ptr) != &stack_mode)
    			drmFree(U642VOID(conn.modes_ptr));
    		drmFree(U642VOID(conn.encoders_ptr));
    
    		goto retry;
    	}
    
    	if(!(r = drmMalloc(sizeof(*r)))) {
    		goto err_allocs;
    	}
    
    	r->connector_id = conn.connector_id;
    	r->encoder_id = conn.encoder_id;
    	r->connection   = conn.connection;
    	r->mmWidth      = conn.mm_width;
    	r->mmHeight     = conn.mm_height;
    	/* convert subpixel from kernel to userspace */
    	r->subpixel     = conn.subpixel + 1;
    	r->count_modes  = conn.count_modes;
    	r->count_props  = conn.count_props;
    	r->props        = drmAllocCpy(U642VOID(conn.props_ptr), conn.count_props, sizeof(uint32_t));
    	r->prop_values  = drmAllocCpy(U642VOID(conn.prop_values_ptr), conn.count_props, sizeof(uint64_t));
    	r->modes        = drmAllocCpy(U642VOID(conn.modes_ptr), conn.count_modes, sizeof(struct drm_mode_modeinfo));
    	r->count_encoders = conn.count_encoders;
    	r->encoders     = drmAllocCpy(U642VOID(conn.encoders_ptr), conn.count_encoders, sizeof(uint32_t));
    	r->connector_type  = conn.connector_type;
    	r->connector_type_id = conn.connector_type_id;
    
    	if ((r->count_props && !r->props) ||
    	    (r->count_props && !r->prop_values) ||
    	    (r->count_modes && !r->modes) ||
    	    (r->count_encoders && !r->encoders)) {
    		drmFree(r->props);
    		drmFree(r->prop_values);
    		drmFree(r->modes);
    		drmFree(r->encoders);
    		drmFree(r);
    		r = 0;
    	}
    
    err_allocs:
    	drmFree(U642VOID(conn.prop_values_ptr));
    	drmFree(U642VOID(conn.props_ptr));
    	if (U642VOID(conn.modes_ptr) != &stack_mode)
    		drmFree(U642VOID(conn.modes_ptr));
    	drmFree(U642VOID(conn.encoders_ptr));
    
    	return r;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106

    核心要点2

    1.drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn):连接CONNECTOR到显示器

    2.drm_mode_get_connector数据结构

    struct drm_mode_get_connector {
      __u64 encoders_ptr;
      __u64 modes_ptr;
      __u64 props_ptr;
      __u64 prop_values_ptr;
      __u32 count_modes;
      __u32 count_props;
      __u32 count_encoders;
      __u32 encoder_id;
      __u32 connector_id;
      __u32 connector_type;
      __u32 connector_type_id;
      __u32 connection;
      __u32 mm_width;
      __u32 mm_height;
      __u32 subpixel;
      __u32 pad;
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    <3>.DRM之modeset_create_fb添加framebuffer设备

    static int modeset_create_fb(int fd, struct buffer_object *bo) {
      struct drm_mode_create_dumb create = {};
      struct drm_mode_map_dumb map = {};
    
      create.width = bo->width;
      create.height = bo->height;
      create.bpp = 32;
      drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create);
      printf("create dumb w %d h %d\n", bo->width, bo->height);
      getchar();
    
      bo->pitch = create.pitch;
      bo->size = create.size;
      bo->handle = create.handle;
      drmModeAddFB(fd, bo->width, bo->height, 24, 32, bo->pitch, bo->handle,
                   &bo->fb_id);
      printf("drmModeAddFB\n");
      getchar();
    
      map.handle = create.handle;
      drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map);
      printf("map dumb\n");
      getchar();
      bo->vaddr = static_cast<unsigned char *>(mmap64(
          0, create.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, map.offset));
      memset(bo->vaddr, 0xff, bo->size);
      return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    核心要点3

    1.drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create): 增加申请DUMB共享内存
    2.drmModeAddFB(fd, bo->width, bo->height, 24, 32, bo->pitch, bo->handle,&bo->fb_id);
    DRM_IOCTL(fd, DRM_IOCTL_MODE_ADDFB, &f);:添加一个FrameBuffer
    3.bo->vaddr = static_cast(mmap64( 0, create.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, map.offset));:映射DRM图形buffer的共享内存到bo->vaddr地址。
    memset(bo->vaddr, 0xff, bo->size);:设置白色。
    4.drm_mode_create_dumb和drm_mode_map_dumb数据结构

    struct drm_mode_create_dumb {
      __u32 height;
      __u32 width;
      __u32 bpp;
      __u32 flags;
      __u32 handle;
      __u32 pitch;
      __u64 size;
    };
    
    struct drm_mode_map_dumb {
      __u32 handle;
      __u32 pad;
      __u64 offset;
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    <4>.DRM之drmModeSetCrtcCRTC开始扫描framebuffer数据显示

    drm_public int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId,
    		   uint32_t x, uint32_t y, uint32_t *connectors, int count,
    		   drmModeModeInfoPtr mode)
    {
    	struct drm_mode_crtc crtc;
    
    	memclear(crtc);
    	crtc.x             = x;
    	crtc.y             = y;
    	crtc.crtc_id       = crtcId;
    	crtc.fb_id         = bufferId;
    	crtc.set_connectors_ptr = VOID2U64(connectors);
    	crtc.count_connectors = count;
    	if (mode) {
    	  memcpy(&crtc.mode, mode, sizeof(struct drm_mode_modeinfo));
    	  crtc.mode_valid = 1;
    	}
    
    	return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETCRTC, &crtc);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    核心要点4

    1.DRM_IOCTL(fd, DRM_IOCTL_MODE_SETCRTC, &crtc):CRTC对framebuffer的数据进行扫描

    2.drm_mode_crtc数据结构

    struct drm_mode_crtc {
      __u64 set_connectors_ptr;
      __u32 count_connectors;
      __u32 crtc_id;
      __u32 fb_id;
      __u32 x;
      __u32 y;
      __u32 gamma_size;
      __u32 mode_valid;
      struct drm_mode_modeinfo mode;
    };
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    <5>.DRM之modeset_destroy_fb关闭framebuffer设备

    static void modeset_destroy_fb(int fd, struct buffer_object *bo) {
      struct drm_mode_destroy_dumb destroy = {};
    
      drmModeRmFB(fd, bo->fb_id);
      munmap(bo->vaddr, bo->size);
      destroy.handle = bo->handle;
      drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    核心要点5

    1.drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy);:销毁DUMB共享内存

    2.drm_mode_destroy_dumb数据结构

    struct drm_mode_destroy_dumb {
      __u32 handle;
    };
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    <6>.DRM之drmModeFreeConnector断开Connector连接

    drm_public void drmModeFreeConnector(drmModeConnectorPtr ptr)
    {
    	if (!ptr)
    		return;
    
    	drmFree(ptr->encoders);
    	drmFree(ptr->prop_values);
    	drmFree(ptr->props);
    	drmFree(ptr->modes);
    	drmFree(ptr);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    核心要点6

    1.调用drmFree释放内存,内部调用free()函数。

    2.drmFree函数实现

    drm_public void drmFree(void *pt)
    {
        free(pt);
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    <7>.DRM之drmModeFreeResources释放资源

    drm_public void drmModeFreeResources(drmModeResPtr ptr)
    {
    	if (!ptr)
    		return;
    
    	drmFree(ptr->fbs);
    	drmFree(ptr->crtcs);
    	drmFree(ptr->connectors);
    	drmFree(ptr->encoders);
    	drmFree(ptr);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    核心要点7

    1.调用drmFree释放资源,本质和drmModeFreeConnector一样,也是释放内存资源。

    3.DRM基本接口总结

    • 1.drmModeGetResources函数调用DRM驱动通过ioctl(DRM_IOCTL_MODE_GETRESOURCES):获取CRTC和Connector的id号。
    • 2.drmModeGetConnector函数调用ioctl(DRM_IOCTL_MODE_GETCONNECTOR):连接CONNECTOR到显示器
    • 3.modeset_create_fb函数调用ioctl(DRM_IOCTL_MODE_ADDFB):添加一个FrameBuffer
    • 4.drmModeSetCrtc函数调用ioctl(DRM_IOCTL_MODE_SETCRTC):CRTC对framebuffer的数据进行扫描
    • 5.modeset_destroy_fb函数调用ioctl(DRM_IOCTL_MODE_DESTROY_DUMB):销毁DUMB共享内存
    • 6.drmModeFreeConnector函数调用drmFree释放内存资源
    • 7.drmModeFreeResources函数调用drmFree释放内存资源
  • 相关阅读:
    基于docker实现JMeter分布式压测
    java毕业设计小区广告位招商系统源码+lw文档+mybatis+系统+mysql数据库+调试
    初识Java内存模型JMM
    Coursera耶鲁大学金融课程:Financial Markets 笔记Week 01
    时间复杂度和空间复杂度
    基于Java毕业设计智慧校园学生选宿系统源码+系统+mysql+lw文档+部署软件
    申请腾讯地图用户Key,在Vue项目中使用腾讯地图
    sq练习2
    平面设计师怎么找素材?
    openGauss学习笔记-61 openGauss 数据库管理-常见主备部署方案
  • 原文地址:https://blog.csdn.net/u010164190/article/details/133902475