/* * 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 #include #include #include #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 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 bo = std::unique_ptr(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& 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& 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