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