linux DRM driver 使用示例【轉】


轉自:https://www.jianshu.com/p/f41f98a40455

DRM實例教程

DRM是一個顯示驅動框架,也就是把功能封裝成 open/close/ioctl 等標准接口,應用程序調用這些接口來驅動設備,顯示數據。我們這里將從使用的角度來看看,怎么驗證和使用DRM驅動。

DRM設備節點

DRM驅動會在/dev/dri下創建3個設備節點:

card0
controlD64
renderD128

libdrm庫

DRM驅動,對用戶空間,提供了專門的的調用庫libdrm.so,用戶空間通過該庫可以間接的調用和使用驅動。

打開設備

    int fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC); if (fd < 0) { ret = -errno; fprintf(stderr, "cannot open '%s': %m\n", node); return ret; } 

打開設備有專門的接口:drmOpen

檢查DRM的能力

DRM的能力通過drmGetCap接口獲取,用drm_get_cap結構描述:

/** DRM_IOCTL_GET_CAP ioctl argument type */ struct drm_get_cap { __u64 capability; __u64 value; }; int drmGetCap(int fd, uint64_t capability, uint64_t *value) { struct drm_get_cap cap; int ret; memclear(cap); cap.capability = capability; ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap); if (ret) return ret; *value = cap.value; return 0; } 

使用示例:

        uint64_t has_dumb; if (drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0 || !has_dumb) { fprintf(stderr, "drm device '%s' does not support dumb buffers\n", node); close(fd); return -EOPNOTSUPP; } 

檢索Resource

Resource的獲取需要兩次,第一次,獲取數量大小,第二次才真正獲取具體的Resource。具體看這個函數:

drmModeResPtr drmModeGetResources(int fd) 

Resource結構封裝:

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, max_width; __u32 min_height, max_height; }; 
typedef struct _drmModeRes { int count_fbs; uint32_t *fbs; int count_crtcs; uint32_t *crtcs; int count_connectors; uint32_t *connectors; int count_encoders; uint32_t *encoders; uint32_t min_width, max_width; uint32_t min_height, max_height; } drmModeRes, *drmModeResPtr; 

實例

    /* retrieve resources */ int ret = drmModeGetResources(fd); if (!res) { fprintf(stderr, "cannot retrieve DRM resources (%d): %m\n", errno); return -errno; } 

獲取Connector

_drmModeConnector描述結構:

typedef struct _drmModeConnector { uint32_t connector_id; uint32_t encoder_id; /**< Encoder currently connected to */ uint32_t connector_type; uint32_t connector_type_id; drmModeConnection connection; uint32_t mmWidth, mmHeight; /**< HxW in millimeters */ drmModeSubPixel subpixel; int count_modes; drmModeModeInfoPtr modes; int count_props; uint32_t *props; /**< List of property ids */ uint64_t *prop_values; /**< List of property values */ int count_encoders; uint32_t *encoders; /**< List of encoder ids */ } drmModeConnector, *drmModeConnectorPtr; 

示例:

        drmModeConnector *conn = drmModeGetConnector(fd, res->connectors[i]); if (!conn) { fprintf(stderr, "cannot retrieve DRM connector %u:%u (%d): %m\n", i, res->connectors[i], errno); continue; } 

Encoder

Encoder的結構描述:

typedef struct _drmModeEncoder { uint32_t encoder_id; uint32_t encoder_type; uint32_t crtc_id; uint32_t possible_crtcs; uint32_t possible_clones; } drmModeEncoder, *drmModeEncoderPtr; 

示例:

    if (conn->encoder_id) drmModeEncoder *enc = drmModeGetEncoder(fd, conn->encoder_id); } 
drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id) { struct drm_mode_get_encoder enc; drmModeEncoderPtr r = NULL; memclear(enc); enc.encoder_id = encoder_id; if (drmIoctl(fd, DRM_IOCTL_MODE_GETENCODER, &enc)) return 0; if (!(r = drmMalloc(sizeof(*r)))) return 0; r->encoder_id = enc.encoder_id; r->crtc_id = enc.crtc_id; r->encoder_type = enc.encoder_type; r->possible_crtcs = enc.possible_crtcs; r->possible_clones = enc.possible_clones; return r; } 

crtc

CRTC結構描述:

struct crtc { drmModeCrtc *crtc; drmModeObjectProperties *props; drmModePropertyRes **props_info; drmModeModeInfo *mode; }; 
typedef struct _drmModeCrtc { uint32_t crtc_id; uint32_t buffer_id; /**< FB id to connect to 0 = disconnect */ uint32_t x, y; /**< Position on the framebuffer */ uint32_t width, height; int mode_valid; drmModeModeInfo mode; int gamma_size; /**< Number of gamma stops */ } drmModeCrtc, *drmModeCrtcPtr; 

FrameBuffer

創建DUMB Buffer

    ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq); if (ret < 0) { fprintf(stderr, "cannot create dumb buffer (%d): %m\n", errno); return -errno; } 

添加FB

    /* create framebuffer object for the dumb-buffer */ ret = drmModeAddFB(fd, dev->width, dev->height, 24, 32, dev->stride, dev->handle, &dev->fb); if (ret) { fprintf(stderr, "cannot create framebuffer (%d): %m\n", errno); ret = -errno; goto err_destroy; } 

准備map

    /* prepare buffer for memory mapping */ memset(&mreq, 0, sizeof(mreq)); mreq.handle = dev->handle; ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq); if (ret) { fprintf(stderr, "cannot map dumb buffer (%d): %m\n", errno); ret = -errno; goto err_fb; } 

做map操作:

    /* perform actual memory mapping */ dev->map = mmap(0, dev->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, mreq.offset); if (dev->map == MAP_FAILED) { fprintf(stderr, "cannot mmap dumb buffer (%d): %m\n", errno); ret = -errno; goto err_fb; } 

CRTC的准備

drmModeGetCrtc
drmModeSetCrtc

drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId) { struct drm_mode_crtc crtc; drmModeCrtcPtr r; memclear(crtc); crtc.crtc_id = crtcId; if (drmIoctl(fd, DRM_IOCTL_MODE_GETCRTC, &crtc)) return 0; /* * return */ if (!(r = drmMalloc(sizeof(*r)))) return 0; r->crtc_id = crtc.crtc_id; r->x = crtc.x; r->y = crtc.y; r->mode_valid = crtc.mode_valid; if (r->mode_valid) { memcpy(&r->mode, &crtc.mode, sizeof(struct drm_mode_modeinfo)); r->width = crtc.mode.hdisplay; r->height = crtc.mode.vdisplay; } r->buffer_id = crtc.fb_id; r->gamma_size = crtc.gamma_size; return r; } 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); } 

繪制

static void modeset_draw(void) { uint8_t r, g, b; bool r_up, g_up, b_up; unsigned int i, j, k, off; struct modeset_dev *iter; srand(time(NULL)); r = rand() % 0xff; g = rand() % 0xff; b = rand() % 0xff; r_up = g_up = b_up = true; for (i = 0; i < 50; ++i) { r = next_color(&r_up, r, 20); g = next_color(&g_up, g, 10); b = next_color(&b_up, b, 5); for (iter = modeset_list; iter; iter = iter->next) { for (j = 0; j < iter->height; ++j) { for (k = 0; k < iter->width; ++k) { off = iter->stride * j + k * 4; *(uint32_t*)&iter->map[off] = (r << 16) | (g << 8) | b; } } } usleep(100000); } } 

具體的代碼,可以參考how-to實例:
how-to代碼實例



作者:夕月風
鏈接:https://www.jianshu.com/p/f41f98a40455
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM