xref: /OK3568_Linux_fs/external/camera_engine_rkaiq/rkaiq/xcore/drm_device.cpp (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * drm_device.cpp - DRM Device Implementation
3  *
4  *  Copyright (c) 2021 Rockchip Corporation
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19 #include "drm_device.h"
20 
21 #include <fcntl.h>
22 #include <sys/mman.h>
23 #include <xf86drm.h>
24 
25 #include <string>
26 
27 #include "xcam_common.h"
28 #include "xcam_log.h"
29 
30 extern "C" {
31 /* assume large file support exists */
32 #define drm_mmap(addr, length, prot, flags, fd, offset) \
33     mmap(addr, length, prot, flags, fd, offset)
34 
drm_munmap(void * addr,size_t length)35 static inline int drm_munmap(void* addr, size_t length) {
36     /* Copied from configure code generated by AC_SYS_LARGEFILE */
37 #define LARGE_OFF_T ((((off64_t)1 << 31) << 31) - 1 + (((off64_t)1 << 31) << 31))
38     static_assert(LARGE_OFF_T % 2147483629 == 721 &&
39                   LARGE_OFF_T % 2147483647 == 1, "LARGE_OFF_T is wrong");
40 #undef LARGE_OFF_T
41     return munmap(addr, length);
42 }
43 }
44 
45 namespace XCam {
46 
DrmDevice()47 DrmDevice::DrmDevice() : fd_(Open()) {}
48 
49 DrmDevice::~DrmDevice() = default;
50 
Open()51 int DrmDevice::Open() {
52     std::string devName(DRM_DIR_NAME);
53     uint64_t has_dumb = 0;
54     int fd;
55 
56     devName.append("/card");
57     devName.append(std::to_string(0));
58     fd = drmOpen("rockchip", devName.c_str());
59     if (fd < 0) {
60         LOGE("Failed to open DRM module rockchip");
61         return -1;
62     }
63 
64     drmVersionPtr version = drmGetVersion(fd);
65     if (version == nullptr) {
66         LOGE("Failed to get DRM version");
67         ::close(fd);
68         return -1;
69     }
70     LOGI("Opened DRM device %s: driver %s version V%d.%d.%d", devName.c_str(),
71          version->name, version->version_major, version->version_minor,
72          version->version_patchlevel);
73     drmFreeVersion(version);
74 
75     if (drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0 || !has_dumb) {
76         LOGE("DRM device does not support dumb buffer");
77         ::close(fd);
78         return -1;
79     }
80 
81     return fd;
82 }
83 
Close()84 void DrmDevice::Close() {
85     if (fd_.Get() >= 0) {
86         drmClose(fd_.Get());
87     }
88 }
89 
Available()90 bool DrmDevice::Available() { return !!drmAvailable(); }
91 
CreateDumbObject(unsigned int width,unsigned int height,unsigned int bpp,unsigned int num_planes)92 std::unique_ptr<DrmDumbObject> DrmDevice::CreateDumbObject(
93     unsigned int width, unsigned int height, unsigned int bpp,
94     unsigned int num_planes) {
95     struct drm_mode_create_dumb arg;
96     int ret;
97     // @cody TODO: use make_unique if use C++ > C++14
98     std::unique_ptr<DrmDumbObject> bo =
99         std::unique_ptr<DrmDumbObject>(new DrmDumbObject());
100 
101     memset(&arg, 0, sizeof(arg));
102     arg.bpp    = bpp;
103     arg.width  = width;
104     arg.height = height;
105 
106     bo->num_planes = num_planes;
107     for (unsigned int plane = 0; plane < num_planes; plane++) {
108         ret = drmIoctl(fd_.Get(), DRM_IOCTL_MODE_CREATE_DUMB, &arg);
109         if (ret) {
110             LOGE("failed to create dumb buffer: %s", strerror(errno));
111             return nullptr;
112         }
113 
114         ret = drmPrimeHandleToFD(fd_.Get(), arg.handle, DRM_CLOEXEC | DRM_RDWR,
115                                  &bo->fds[plane]);
116         if (ret) {
117             LOGE("failed to create dumb buffer: %s", strerror(errno));
118             return nullptr;
119         }
120         assert(bo->fds[plane] >= 0);
121 
122         bo->handles[plane] = arg.handle;
123         bo->sizes[plane]   = arg.size;
124         bo->strides[plane] = arg.pitch;
125     }
126 
127     return bo;
128 }
129 
DestroyDumbObject(const std::unique_ptr<DrmDumbObject> & bo)130 XCamReturn DrmDevice::DestroyDumbObject(
131     const std::unique_ptr<DrmDumbObject>& bo) {
132     struct drm_mode_destroy_dumb arg;
133     int ret;
134 
135     assert(fd_.Get() >= 0);
136 
137     memset(&arg, 0, sizeof(arg));
138     for (int plane = 0; plane < bo->num_planes; plane++) {
139         if (bo->handles[plane] == 0) {
140             continue;
141         }
142         arg.handle = bo->handles[plane];
143 
144         ret = drmIoctl(fd_.Get(), DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
145         if (ret) {
146             LOGE("failed to destroy dumb buffer: %s", strerror(errno));
147             // return XCAM_RETURN_ERROR_FAILED;
148         }
149     }
150 
151     return XCAM_RETURN_NO_ERROR;
152 }
153 
RequestMapDumbObject(const std::unique_ptr<DrmDumbObject> & bo,unsigned int plane)154 XCamReturn DrmDevice::RequestMapDumbObject(
155     const std::unique_ptr<DrmDumbObject>& bo, unsigned int plane) {
156     struct drm_mode_map_dumb arg;
157     void* map;
158     int ret;
159 
160     assert(fd_.Get() >= 0);
161 
162     memset(&arg, 0, sizeof(arg));
163     arg.handle = bo->handles[plane];
164     ret        = drmIoctl(fd_.Get(), DRM_IOCTL_MODE_MAP_DUMB, &arg);
165     if (ret) {
166         LOGE("drm ioctrl failed map %s", strerror(errno));
167         return XCAM_RETURN_ERROR_FAILED;
168     }
169 
170     return XCAM_RETURN_NO_ERROR;
171 }
172 
173 }  // namespace RkCam
174