1/* 2 * Copyright © 2019 Red Hat 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23#include "macros.h" 24#include <wayland-client.h> 25#include "wayland-drm-client-protocol.h" 26#include "device_select.h" 27#include <string.h> 28#include <stdio.h> 29#include <unistd.h> 30#include <fcntl.h> 31#include <xf86drm.h> 32struct device_select_wayland_info { 33 struct wl_drm *wl_drm; 34 drmDevicePtr dev_info; 35 bool info_is_set; 36}; 37 38static void 39device_select_drm_handle_device(void *data, struct wl_drm *drm, const char *device) 40{ 41 struct device_select_wayland_info *info = data; 42 43 int fd = open(device, O_RDWR | O_CLOEXEC); 44 if (fd == -1) 45 return; 46 47 int ret = drmGetDevice2(fd, 0, &info->dev_info); 48 if (ret >= 0) 49 info->info_is_set = true; 50 close(fd); 51 return; 52} 53 54static void 55device_select_drm_handle_format(void *data, struct wl_drm *drm, uint32_t format) 56{ 57 58} 59 60static void 61device_select_drm_handle_authenticated(void *data, struct wl_drm *drm) 62{ 63 64} 65 66 67static void 68device_select_drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t value) 69{ 70 71} 72 73 74static const struct wl_drm_listener ds_drm_listener = { 75 .device = device_select_drm_handle_device, 76 .format = device_select_drm_handle_format, 77 .authenticated = device_select_drm_handle_authenticated, 78 .capabilities = device_select_drm_handle_capabilities 79}; 80 81static void 82device_select_registry_global(void *data, struct wl_registry *registry, uint32_t name, 83 const char *interface, uint32_t version) 84{ 85 struct device_select_wayland_info *info = data; 86 if (strcmp(interface, "wl_drm") == 0) { 87 info->wl_drm = wl_registry_bind(registry, name, &wl_drm_interface, MIN2(version, 2)); 88 wl_drm_add_listener(info->wl_drm, &ds_drm_listener, data); 89 } 90} 91 92static void 93device_select_registry_global_remove_cb(void *data, struct wl_registry *registry, 94 uint32_t name) 95{ 96 97} 98 99int device_select_find_wayland_pci_default(struct device_pci_info *devices, uint32_t device_count) 100{ 101 struct wl_display *display; 102 struct wl_registry *registry = NULL; 103 unsigned default_idx = -1; 104 struct device_select_wayland_info info = {}; 105 106 display = wl_display_connect(NULL); 107 if (!display) 108 goto out; 109 110 registry = wl_display_get_registry(display); 111 if (!registry) { 112 wl_display_disconnect(display); 113 goto out; 114 } 115 116 static const struct wl_registry_listener registry_listener = 117 { device_select_registry_global, device_select_registry_global_remove_cb }; 118 119 wl_registry_add_listener(registry, ®istry_listener, &info); 120 wl_display_dispatch(display); 121 wl_display_roundtrip(display); 122 123 124 if (info.info_is_set) { 125 for (unsigned i = 0; i < device_count; i++) { 126 if (devices[i].has_bus_info) { 127 if (info.dev_info->businfo.pci->domain == devices[i].bus_info.domain && 128 info.dev_info->businfo.pci->bus == devices[i].bus_info.bus && 129 info.dev_info->businfo.pci->dev == devices[i].bus_info.dev && 130 info.dev_info->businfo.pci->func == devices[i].bus_info.func) 131 default_idx = i; 132 } else { 133 if (info.dev_info->deviceinfo.pci->vendor_id == devices[i].dev_info.vendor_id && 134 info.dev_info->deviceinfo.pci->device_id == devices[i].dev_info.device_id) 135 default_idx = i; 136 } 137 if (default_idx != -1) 138 break; 139 } 140 } 141 142 if (info.wl_drm) 143 wl_drm_destroy(info.wl_drm); 144 wl_registry_destroy(registry); 145 wl_display_disconnect(display); 146 out: 147 return default_idx; 148} 149