1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2020 Collabora, Ltd. 3bf215546Sopenharmony_ci * Author: Antonio Caggiano <antonio.caggiano@collabora.com> 4bf215546Sopenharmony_ci * Author: Rohan Garg <rohan.garg@collabora.com> 5bf215546Sopenharmony_ci * Author: Robert Beckett <bob.beckett@collabora.com> 6bf215546Sopenharmony_ci * 7bf215546Sopenharmony_ci * SPDX-License-Identifier: MIT 8bf215546Sopenharmony_ci */ 9bf215546Sopenharmony_ci 10bf215546Sopenharmony_ci#include "pps_device.h" 11bf215546Sopenharmony_ci 12bf215546Sopenharmony_ci#include <cassert> 13bf215546Sopenharmony_ci#include <fcntl.h> 14bf215546Sopenharmony_ci#include <memory> 15bf215546Sopenharmony_ci#include <unistd.h> 16bf215546Sopenharmony_ci#include <xf86drm.h> 17bf215546Sopenharmony_ci 18bf215546Sopenharmony_cinamespace pps 19bf215546Sopenharmony_ci{ 20bf215546Sopenharmony_ci#define MAX_DRM_DEVICES 64 21bf215546Sopenharmony_ci 22bf215546Sopenharmony_ciuint32_t DrmDevice::device_count() 23bf215546Sopenharmony_ci{ 24bf215546Sopenharmony_ci drmDevicePtr devices[MAX_DRM_DEVICES] = {}; 25bf215546Sopenharmony_ci int num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES); 26bf215546Sopenharmony_ci drmFreeDevices(devices, num_devices); 27bf215546Sopenharmony_ci return static_cast<uint32_t>(num_devices); 28bf215546Sopenharmony_ci} 29bf215546Sopenharmony_ci 30bf215546Sopenharmony_ci/// @return The name of a DRM device, empty string in case of error 31bf215546Sopenharmony_cistd::string query_drm_name(const int fd) 32bf215546Sopenharmony_ci{ 33bf215546Sopenharmony_ci assert(fd && "Failed to query DrmDevice: invalid fd"); 34bf215546Sopenharmony_ci 35bf215546Sopenharmony_ci std::string name = ""; 36bf215546Sopenharmony_ci 37bf215546Sopenharmony_ci if (drmVersionPtr version = drmGetVersion(fd)) { 38bf215546Sopenharmony_ci name = std::string(version->name, version->name_len); 39bf215546Sopenharmony_ci drmFreeVersion(version); 40bf215546Sopenharmony_ci } 41bf215546Sopenharmony_ci 42bf215546Sopenharmony_ci return name; 43bf215546Sopenharmony_ci} 44bf215546Sopenharmony_ci 45bf215546Sopenharmony_ci/// @return A DRM device, nullopt in case of error 46bf215546Sopenharmony_cistd::optional<DrmDevice> create_drm_device(int fd, int32_t gpu_num) 47bf215546Sopenharmony_ci{ 48bf215546Sopenharmony_ci if (fd < 0 || gpu_num < 0) { 49bf215546Sopenharmony_ci return std::nullopt; 50bf215546Sopenharmony_ci } 51bf215546Sopenharmony_ci 52bf215546Sopenharmony_ci // Try getting the name 53bf215546Sopenharmony_ci std::string name = query_drm_name(fd); 54bf215546Sopenharmony_ci if (name.empty()) { 55bf215546Sopenharmony_ci return std::nullopt; 56bf215546Sopenharmony_ci } 57bf215546Sopenharmony_ci 58bf215546Sopenharmony_ci auto ret = DrmDevice(); 59bf215546Sopenharmony_ci ret.fd = fd; 60bf215546Sopenharmony_ci ret.gpu_num = gpu_num; 61bf215546Sopenharmony_ci ret.name = name; 62bf215546Sopenharmony_ci return ret; 63bf215546Sopenharmony_ci} 64bf215546Sopenharmony_ci 65bf215546Sopenharmony_cistd::vector<DrmDevice> DrmDevice::create_all() 66bf215546Sopenharmony_ci{ 67bf215546Sopenharmony_ci std::vector<DrmDevice> ret = {}; 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_ci drmDevicePtr devices[MAX_DRM_DEVICES] = {}; 70bf215546Sopenharmony_ci int num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES); 71bf215546Sopenharmony_ci if (num_devices <= 0) { 72bf215546Sopenharmony_ci return ret; 73bf215546Sopenharmony_ci } 74bf215546Sopenharmony_ci 75bf215546Sopenharmony_ci for (int32_t gpu_num = 0; gpu_num < num_devices; gpu_num++) { 76bf215546Sopenharmony_ci drmDevicePtr device = devices[gpu_num]; 77bf215546Sopenharmony_ci if ((device->available_nodes & (1 << DRM_NODE_RENDER))) { 78bf215546Sopenharmony_ci int fd = open(device->nodes[DRM_NODE_RENDER], O_RDWR); 79bf215546Sopenharmony_ci 80bf215546Sopenharmony_ci // If it can create a device, push it into the vector 81bf215546Sopenharmony_ci if (auto drm_device = create_drm_device(fd, gpu_num)) { 82bf215546Sopenharmony_ci ret.emplace_back(std::move(drm_device.value())); 83bf215546Sopenharmony_ci } 84bf215546Sopenharmony_ci } 85bf215546Sopenharmony_ci } 86bf215546Sopenharmony_ci 87bf215546Sopenharmony_ci drmFreeDevices(devices, num_devices); 88bf215546Sopenharmony_ci return ret; 89bf215546Sopenharmony_ci} 90bf215546Sopenharmony_ci 91bf215546Sopenharmony_cistd::optional<DrmDevice> DrmDevice::create(int32_t gpu_num) 92bf215546Sopenharmony_ci{ 93bf215546Sopenharmony_ci std::optional<DrmDevice> ret = std::nullopt; 94bf215546Sopenharmony_ci 95bf215546Sopenharmony_ci if (gpu_num < 0) { 96bf215546Sopenharmony_ci return ret; 97bf215546Sopenharmony_ci } 98bf215546Sopenharmony_ci 99bf215546Sopenharmony_ci drmDevicePtr devices[MAX_DRM_DEVICES] = {}; 100bf215546Sopenharmony_ci int num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES); 101bf215546Sopenharmony_ci 102bf215546Sopenharmony_ci if (num_devices > 0 && gpu_num < num_devices) { 103bf215546Sopenharmony_ci drmDevicePtr device = devices[gpu_num]; 104bf215546Sopenharmony_ci int fd = open(device->nodes[DRM_NODE_RENDER], O_RDWR); 105bf215546Sopenharmony_ci ret = create_drm_device(fd, gpu_num); 106bf215546Sopenharmony_ci } 107bf215546Sopenharmony_ci 108bf215546Sopenharmony_ci drmFreeDevices(devices, num_devices); 109bf215546Sopenharmony_ci return ret; 110bf215546Sopenharmony_ci} 111bf215546Sopenharmony_ci 112bf215546Sopenharmony_ciDrmDevice::DrmDevice(DrmDevice &&other) 113bf215546Sopenharmony_ci : fd {other.fd} 114bf215546Sopenharmony_ci , gpu_num {other.gpu_num} 115bf215546Sopenharmony_ci , name {std::move(other.name)} 116bf215546Sopenharmony_ci{ 117bf215546Sopenharmony_ci other.fd = -1; 118bf215546Sopenharmony_ci other.gpu_num = -1; 119bf215546Sopenharmony_ci} 120bf215546Sopenharmony_ci 121bf215546Sopenharmony_ciDrmDevice &DrmDevice::operator=(DrmDevice &&other) 122bf215546Sopenharmony_ci{ 123bf215546Sopenharmony_ci std::swap(fd, other.fd); 124bf215546Sopenharmony_ci std::swap(gpu_num, other.gpu_num); 125bf215546Sopenharmony_ci std::swap(name, other.name); 126bf215546Sopenharmony_ci return *this; 127bf215546Sopenharmony_ci} 128bf215546Sopenharmony_ci 129bf215546Sopenharmony_ciDrmDevice::~DrmDevice() 130bf215546Sopenharmony_ci{ 131bf215546Sopenharmony_ci if (fd >= 0) { 132bf215546Sopenharmony_ci close(fd); 133bf215546Sopenharmony_ci } 134bf215546Sopenharmony_ci} 135bf215546Sopenharmony_ci 136bf215546Sopenharmony_ciDrmDevice::operator bool() const 137bf215546Sopenharmony_ci{ 138bf215546Sopenharmony_ci return !name.empty(); 139bf215546Sopenharmony_ci} 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ci} // namespace pps 142