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