/*
|
* drm_device.cpp - DRM Device Implementation
|
*
|
* Copyright (c) 2021 Rockchip Corporation
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
*
|
*/
|
#include "drm_device.h"
|
|
#include <fcntl.h>
|
#include <sys/mman.h>
|
#include <xf86drm.h>
|
|
#include <string>
|
|
#include "xcam_common.h"
|
#include "xcam_log.h"
|
|
extern "C" {
|
/* assume large file support exists */
|
#define drm_mmap(addr, length, prot, flags, fd, offset) \
|
mmap(addr, length, prot, flags, fd, offset)
|
|
static inline int drm_munmap(void* addr, size_t length) {
|
/* Copied from configure code generated by AC_SYS_LARGEFILE */
|
#define LARGE_OFF_T ((((off_t)1 << 31) << 31) - 1 + (((off_t)1 << 31) << 31))
|
static_assert(LARGE_OFF_T % 2147483629 == 721 &&
|
LARGE_OFF_T % 2147483647 == 1);
|
#undef LARGE_OFF_T
|
return munmap(addr, length);
|
}
|
}
|
|
namespace XCam {
|
|
DrmDevice::DrmDevice() : fd_(Open()) {}
|
|
DrmDevice::~DrmDevice() = default;
|
|
int DrmDevice::Open() {
|
std::string devName(DRM_DIR_NAME);
|
uint64_t has_dumb = 0;
|
int fd;
|
|
devName.append("/card");
|
devName.append(std::to_string(0));
|
fd = drmOpen("rockchip", devName.c_str());
|
if (fd < 0) {
|
LOGE("Failed to open DRM module rockchip");
|
return -1;
|
}
|
|
drmVersionPtr version = drmGetVersion(fd);
|
if (version == nullptr) {
|
LOGE("Failed to get DRM version");
|
::close(fd);
|
return -1;
|
}
|
LOGI("Opened DRM device %s: driver %s version V%d.%d.%d", devName.c_str(),
|
version->name, version->version_major, version->version_minor,
|
version->version_patchlevel);
|
drmFreeVersion(version);
|
|
if (drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0 || !has_dumb) {
|
LOGE("DRM device does not support dumb buffer");
|
::close(fd);
|
return -1;
|
}
|
|
return fd;
|
}
|
|
void DrmDevice::Close() {
|
if (fd_.Get() >= 0) {
|
drmClose(fd_.Get());
|
}
|
}
|
|
bool DrmDevice::Available() { return !!drmAvailable(); }
|
|
std::unique_ptr<DrmDumbObject> DrmDevice::CreateDumbObject(
|
unsigned int width, unsigned int height, unsigned int bpp,
|
unsigned int num_planes) {
|
struct drm_mode_create_dumb arg;
|
int ret;
|
// @cody TODO: use make_unique if use C++ > C++14
|
std::unique_ptr<DrmDumbObject> bo =
|
std::unique_ptr<DrmDumbObject>(new DrmDumbObject());
|
|
memset(&arg, 0, sizeof(arg));
|
arg.bpp = bpp;
|
arg.width = width;
|
arg.height = height;
|
|
bo->num_planes = num_planes;
|
for (unsigned int plane = 0; plane < num_planes; plane++) {
|
ret = drmIoctl(fd_.Get(), DRM_IOCTL_MODE_CREATE_DUMB, &arg);
|
if (ret) {
|
LOGE("failed to create dumb buffer: %s", strerror(errno));
|
return nullptr;
|
}
|
|
ret = drmPrimeHandleToFD(fd_.Get(), arg.handle, DRM_CLOEXEC | DRM_RDWR,
|
&bo->fds[plane]);
|
if (ret) {
|
LOGE("failed to create dumb buffer: %s", strerror(errno));
|
return nullptr;
|
}
|
assert(bo->fds[plane] >= 0);
|
|
bo->handles[plane] = arg.handle;
|
bo->sizes[plane] = arg.size;
|
bo->strides[plane] = arg.pitch;
|
}
|
|
return bo;
|
}
|
|
XCamReturn DrmDevice::DestroyDumbObject(
|
const std::unique_ptr<DrmDumbObject>& bo) {
|
struct drm_mode_destroy_dumb arg;
|
int ret;
|
|
assert(fd_.Get() >= 0);
|
|
memset(&arg, 0, sizeof(arg));
|
for (int plane = 0; plane < bo->num_planes; plane++) {
|
if (bo->handles[plane] == 0) {
|
continue;
|
}
|
arg.handle = bo->handles[plane];
|
|
ret = drmIoctl(fd_.Get(), DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
|
if (ret) {
|
LOGE("failed to destroy dumb buffer: %s", strerror(errno));
|
// return XCAM_RETURN_ERROR_FAILED;
|
}
|
}
|
|
return XCAM_RETURN_NO_ERROR;
|
}
|
|
XCamReturn DrmDevice::RequestMapDumbObject(
|
const std::unique_ptr<DrmDumbObject>& bo, unsigned int plane) {
|
struct drm_mode_map_dumb arg;
|
void* map;
|
int ret;
|
|
assert(fd_.Get() >= 0);
|
|
memset(&arg, 0, sizeof(arg));
|
arg.handle = bo->handles[plane];
|
ret = drmIoctl(fd_.Get(), DRM_IOCTL_MODE_MAP_DUMB, &arg);
|
if (ret) {
|
LOGE("drm ioctrl failed map %s", strerror(errno));
|
return XCAM_RETURN_ERROR_FAILED;
|
}
|
|
return XCAM_RETURN_NO_ERROR;
|
}
|
|
} // namespace RkCam
|