loader.c revision 848b8605
1848b8605Smrg/* 2848b8605Smrg * Copyright (C) 2013 Rob Clark <robclark@freedesktop.org> 3848b8605Smrg * 4848b8605Smrg * This code is derived from the following files. 5848b8605Smrg * 6848b8605Smrg * * src/glx/dri3_common.c 7848b8605Smrg * Copyright © 2013 Keith Packard 8848b8605Smrg * 9848b8605Smrg * * src/egl/drivers/dri2/common.c 10848b8605Smrg * * src/gbm/backends/dri/driver_name.c 11848b8605Smrg * Copyright © 2011 Intel Corporation 12848b8605Smrg * 13848b8605Smrg * Authors: 14848b8605Smrg * Kristian Høgsberg <krh@bitplanet.net> 15848b8605Smrg * Benjamin Franzke <benjaminfranzke@googlemail.com> 16848b8605Smrg * 17848b8605Smrg * * src/gallium/targets/egl-static/egl.c 18848b8605Smrg * Copyright (C) 2010-2011 LunarG Inc. 19848b8605Smrg * 20848b8605Smrg * Authors: 21848b8605Smrg * Chia-I Wu <olv@lunarg.com> 22848b8605Smrg * 23848b8605Smrg * * src/gallium/state_trackers/egl/drm/native_drm.c 24848b8605Smrg * Copyright (C) 2010 Chia-I Wu <olv@0xlab.org> 25848b8605Smrg * 26848b8605Smrg * * src/egl/drivers/dri2/platform_android.c 27848b8605Smrg * 28848b8605Smrg * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com> 29848b8605Smrg * Copyright (C) 2010-2011 LunarG Inc. 30848b8605Smrg * 31848b8605Smrg * Based on platform_x11, which has 32848b8605Smrg * 33848b8605Smrg * Copyright © 2011 Intel Corporation 34848b8605Smrg * 35848b8605Smrg * * src/gallium/auxiliary/pipe-loader/pipe_loader_drm.c 36848b8605Smrg * Copyright 2011 Intel Corporation 37848b8605Smrg * Copyright 2012 Francisco Jerez 38848b8605Smrg * All Rights Reserved. 39848b8605Smrg * 40848b8605Smrg * Authors: 41848b8605Smrg * Kristian Høgsberg <krh@bitplanet.net> 42848b8605Smrg * Benjamin Franzke <benjaminfranzke@googlemail.com> 43848b8605Smrg * 44848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 45848b8605Smrg * copy of this software and associated documentation files (the "Software"), 46848b8605Smrg * to deal in the Software without restriction, including without limitation 47848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 48848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 49848b8605Smrg * Software is furnished to do so, subject to the following conditions: 50848b8605Smrg * 51848b8605Smrg * The above copyright notice and this permission notice (including the next 52848b8605Smrg * paragraph) shall be included in all copies or substantial portions of the 53848b8605Smrg * Software. 54848b8605Smrg * 55848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 56848b8605Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 57848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 58848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 59848b8605Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 60848b8605Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 61848b8605Smrg * SOFTWARE. 62848b8605Smrg * 63848b8605Smrg * Authors: 64848b8605Smrg * Rob Clark <robclark@freedesktop.org> 65848b8605Smrg */ 66848b8605Smrg 67848b8605Smrg#include <stdarg.h> 68848b8605Smrg#include <stdio.h> 69848b8605Smrg#include <string.h> 70848b8605Smrg#ifdef HAVE_LIBUDEV 71848b8605Smrg#include <assert.h> 72848b8605Smrg#include <dlfcn.h> 73848b8605Smrg#include <fcntl.h> 74848b8605Smrg#include <unistd.h> 75848b8605Smrg#include <stdlib.h> 76848b8605Smrg#include <errno.h> 77848b8605Smrg#ifdef USE_DRICONF 78848b8605Smrg#include "xmlconfig.h" 79848b8605Smrg#include "xmlpool.h" 80848b8605Smrg#endif 81848b8605Smrg#endif 82848b8605Smrg#ifdef HAVE_SYSFS 83848b8605Smrg#include <sys/stat.h> 84848b8605Smrg#include <sys/types.h> 85848b8605Smrg#endif 86848b8605Smrg#include "loader.h" 87848b8605Smrg 88848b8605Smrg#ifndef __NOT_HAVE_DRM_H 89848b8605Smrg#include <xf86drm.h> 90848b8605Smrg#endif 91848b8605Smrg 92848b8605Smrg#define __IS_LOADER 93848b8605Smrg#include "pci_id_driver_map.h" 94848b8605Smrg 95848b8605Smrgstatic void default_logger(int level, const char *fmt, ...) 96848b8605Smrg{ 97848b8605Smrg if (level <= _LOADER_WARNING) { 98848b8605Smrg va_list args; 99848b8605Smrg va_start(args, fmt); 100848b8605Smrg vfprintf(stderr, fmt, args); 101848b8605Smrg va_end(args); 102848b8605Smrg } 103848b8605Smrg} 104848b8605Smrg 105848b8605Smrgstatic void (*log_)(int level, const char *fmt, ...) = default_logger; 106848b8605Smrg 107848b8605Smrg#ifdef HAVE_LIBUDEV 108848b8605Smrg#include <libudev.h> 109848b8605Smrg 110848b8605Smrgstatic void *udev_handle = NULL; 111848b8605Smrg 112848b8605Smrgstatic void * 113848b8605Smrgudev_dlopen_handle(void) 114848b8605Smrg{ 115848b8605Smrg if (!udev_handle) { 116848b8605Smrg udev_handle = dlopen("libudev.so.1", RTLD_LOCAL | RTLD_LAZY); 117848b8605Smrg 118848b8605Smrg if (!udev_handle) { 119848b8605Smrg /* libudev.so.1 changed the return types of the two unref functions 120848b8605Smrg * from voids to pointers. We don't use those return values, and the 121848b8605Smrg * only ABI I've heard that cares about this kind of change (calling 122848b8605Smrg * a function with a void * return that actually only returns void) 123848b8605Smrg * might be ia64. 124848b8605Smrg */ 125848b8605Smrg udev_handle = dlopen("libudev.so.0", RTLD_LOCAL | RTLD_LAZY); 126848b8605Smrg 127848b8605Smrg if (!udev_handle) { 128848b8605Smrg log_(_LOADER_WARNING, "Couldn't dlopen libudev.so.1 or " 129848b8605Smrg "libudev.so.0, driver detection may be broken.\n"); 130848b8605Smrg } 131848b8605Smrg } 132848b8605Smrg } 133848b8605Smrg 134848b8605Smrg return udev_handle; 135848b8605Smrg} 136848b8605Smrg 137848b8605Smrgstatic int dlsym_failed = 0; 138848b8605Smrg 139848b8605Smrgstatic void * 140848b8605Smrgchecked_dlsym(void *dlopen_handle, const char *name) 141848b8605Smrg{ 142848b8605Smrg void *result = dlsym(dlopen_handle, name); 143848b8605Smrg if (!result) 144848b8605Smrg dlsym_failed = 1; 145848b8605Smrg return result; 146848b8605Smrg} 147848b8605Smrg 148848b8605Smrg#define UDEV_SYMBOL(ret, name, args) \ 149848b8605Smrg ret (*name) args = checked_dlsym(udev_dlopen_handle(), #name); 150848b8605Smrg 151848b8605Smrg 152848b8605Smrgstatic inline struct udev_device * 153848b8605Smrgudev_device_new_from_fd(struct udev *udev, int fd) 154848b8605Smrg{ 155848b8605Smrg struct udev_device *device; 156848b8605Smrg struct stat buf; 157848b8605Smrg UDEV_SYMBOL(struct udev_device *, udev_device_new_from_devnum, 158848b8605Smrg (struct udev *udev, char type, dev_t devnum)); 159848b8605Smrg 160848b8605Smrg if (dlsym_failed) 161848b8605Smrg return NULL; 162848b8605Smrg 163848b8605Smrg if (fstat(fd, &buf) < 0) { 164848b8605Smrg log_(_LOADER_WARNING, "MESA-LOADER: failed to stat fd %d\n", fd); 165848b8605Smrg return NULL; 166848b8605Smrg } 167848b8605Smrg 168848b8605Smrg device = udev_device_new_from_devnum(udev, 'c', buf.st_rdev); 169848b8605Smrg if (device == NULL) { 170848b8605Smrg log_(_LOADER_WARNING, 171848b8605Smrg "MESA-LOADER: could not create udev device for fd %d\n", fd); 172848b8605Smrg return NULL; 173848b8605Smrg } 174848b8605Smrg 175848b8605Smrg return device; 176848b8605Smrg} 177848b8605Smrg 178848b8605Smrgstatic int 179848b8605Smrglibudev_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id) 180848b8605Smrg{ 181848b8605Smrg struct udev *udev = NULL; 182848b8605Smrg struct udev_device *device = NULL, *parent; 183848b8605Smrg const char *pci_id; 184848b8605Smrg UDEV_SYMBOL(struct udev *, udev_new, (void)); 185848b8605Smrg UDEV_SYMBOL(struct udev_device *, udev_device_get_parent, 186848b8605Smrg (struct udev_device *)); 187848b8605Smrg UDEV_SYMBOL(const char *, udev_device_get_property_value, 188848b8605Smrg (struct udev_device *, const char *)); 189848b8605Smrg UDEV_SYMBOL(struct udev_device *, udev_device_unref, 190848b8605Smrg (struct udev_device *)); 191848b8605Smrg UDEV_SYMBOL(struct udev *, udev_unref, (struct udev *)); 192848b8605Smrg 193848b8605Smrg *chip_id = -1; 194848b8605Smrg 195848b8605Smrg if (dlsym_failed) 196848b8605Smrg return 0; 197848b8605Smrg 198848b8605Smrg udev = udev_new(); 199848b8605Smrg device = udev_device_new_from_fd(udev, fd); 200848b8605Smrg if (!device) 201848b8605Smrg goto out; 202848b8605Smrg 203848b8605Smrg parent = udev_device_get_parent(device); 204848b8605Smrg if (parent == NULL) { 205848b8605Smrg log_(_LOADER_WARNING, "MESA-LOADER: could not get parent device\n"); 206848b8605Smrg goto out; 207848b8605Smrg } 208848b8605Smrg 209848b8605Smrg pci_id = udev_device_get_property_value(parent, "PCI_ID"); 210848b8605Smrg if (pci_id == NULL || 211848b8605Smrg sscanf(pci_id, "%x:%x", vendor_id, chip_id) != 2) { 212848b8605Smrg log_(_LOADER_WARNING, "MESA-LOADER: malformed or no PCI ID\n"); 213848b8605Smrg *chip_id = -1; 214848b8605Smrg goto out; 215848b8605Smrg } 216848b8605Smrg 217848b8605Smrgout: 218848b8605Smrg if (device) 219848b8605Smrg udev_device_unref(device); 220848b8605Smrg if (udev) 221848b8605Smrg udev_unref(udev); 222848b8605Smrg 223848b8605Smrg return (*chip_id >= 0); 224848b8605Smrg} 225848b8605Smrg 226848b8605Smrgstatic char * 227848b8605Smrgget_render_node_from_id_path_tag(struct udev *udev, 228848b8605Smrg char *id_path_tag, 229848b8605Smrg char another_tag) 230848b8605Smrg{ 231848b8605Smrg struct udev_device *device; 232848b8605Smrg struct udev_enumerate *e; 233848b8605Smrg struct udev_list_entry *entry; 234848b8605Smrg const char *path, *id_path_tag_tmp; 235848b8605Smrg char *path_res; 236848b8605Smrg char found = 0; 237848b8605Smrg UDEV_SYMBOL(struct udev_enumerate *, udev_enumerate_new, 238848b8605Smrg (struct udev *)); 239848b8605Smrg UDEV_SYMBOL(int, udev_enumerate_add_match_subsystem, 240848b8605Smrg (struct udev_enumerate *, const char *)); 241848b8605Smrg UDEV_SYMBOL(int, udev_enumerate_add_match_sysname, 242848b8605Smrg (struct udev_enumerate *, const char *)); 243848b8605Smrg UDEV_SYMBOL(int, udev_enumerate_scan_devices, 244848b8605Smrg (struct udev_enumerate *)); 245848b8605Smrg UDEV_SYMBOL(struct udev_list_entry *, udev_enumerate_get_list_entry, 246848b8605Smrg (struct udev_enumerate *)); 247848b8605Smrg UDEV_SYMBOL(struct udev_list_entry *, udev_list_entry_get_next, 248848b8605Smrg (struct udev_list_entry *)); 249848b8605Smrg UDEV_SYMBOL(const char *, udev_list_entry_get_name, 250848b8605Smrg (struct udev_list_entry *)); 251848b8605Smrg UDEV_SYMBOL(struct udev_device *, udev_device_new_from_syspath, 252848b8605Smrg (struct udev *, const char *)); 253848b8605Smrg UDEV_SYMBOL(const char *, udev_device_get_property_value, 254848b8605Smrg (struct udev_device *, const char *)); 255848b8605Smrg UDEV_SYMBOL(const char *, udev_device_get_devnode, 256848b8605Smrg (struct udev_device *)); 257848b8605Smrg UDEV_SYMBOL(struct udev_device *, udev_device_unref, 258848b8605Smrg (struct udev_device *)); 259848b8605Smrg 260848b8605Smrg e = udev_enumerate_new(udev); 261848b8605Smrg udev_enumerate_add_match_subsystem(e, "drm"); 262848b8605Smrg udev_enumerate_add_match_sysname(e, "render*"); 263848b8605Smrg 264848b8605Smrg udev_enumerate_scan_devices(e); 265848b8605Smrg udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) { 266848b8605Smrg path = udev_list_entry_get_name(entry); 267848b8605Smrg device = udev_device_new_from_syspath(udev, path); 268848b8605Smrg if (!device) 269848b8605Smrg continue; 270848b8605Smrg id_path_tag_tmp = udev_device_get_property_value(device, "ID_PATH_TAG"); 271848b8605Smrg if (id_path_tag_tmp) { 272848b8605Smrg if ((!another_tag && !strcmp(id_path_tag, id_path_tag_tmp)) || 273848b8605Smrg (another_tag && strcmp(id_path_tag, id_path_tag_tmp))) { 274848b8605Smrg found = 1; 275848b8605Smrg break; 276848b8605Smrg } 277848b8605Smrg } 278848b8605Smrg udev_device_unref(device); 279848b8605Smrg } 280848b8605Smrg 281848b8605Smrg if (found) { 282848b8605Smrg path_res = strdup(udev_device_get_devnode(device)); 283848b8605Smrg udev_device_unref(device); 284848b8605Smrg return path_res; 285848b8605Smrg } 286848b8605Smrg return NULL; 287848b8605Smrg} 288848b8605Smrg 289848b8605Smrgstatic char * 290848b8605Smrgget_id_path_tag_from_fd(struct udev *udev, int fd) 291848b8605Smrg{ 292848b8605Smrg struct udev_device *device; 293848b8605Smrg const char *id_path_tag_tmp; 294848b8605Smrg char *id_path_tag; 295848b8605Smrg UDEV_SYMBOL(const char *, udev_device_get_property_value, 296848b8605Smrg (struct udev_device *, const char *)); 297848b8605Smrg UDEV_SYMBOL(struct udev_device *, udev_device_unref, 298848b8605Smrg (struct udev_device *)); 299848b8605Smrg 300848b8605Smrg device = udev_device_new_from_fd(udev, fd); 301848b8605Smrg if (!device) 302848b8605Smrg return NULL; 303848b8605Smrg 304848b8605Smrg id_path_tag_tmp = udev_device_get_property_value(device, "ID_PATH_TAG"); 305848b8605Smrg if (!id_path_tag_tmp) 306848b8605Smrg return NULL; 307848b8605Smrg 308848b8605Smrg id_path_tag = strdup(id_path_tag_tmp); 309848b8605Smrg 310848b8605Smrg udev_device_unref(device); 311848b8605Smrg return id_path_tag; 312848b8605Smrg} 313848b8605Smrg 314848b8605Smrgstatic int 315848b8605Smrgdrm_open_device(const char *device_name) 316848b8605Smrg{ 317848b8605Smrg int fd; 318848b8605Smrg#ifdef O_CLOEXEC 319848b8605Smrg fd = open(device_name, O_RDWR | O_CLOEXEC); 320848b8605Smrg if (fd == -1 && errno == EINVAL) 321848b8605Smrg#endif 322848b8605Smrg { 323848b8605Smrg fd = open(device_name, O_RDWR); 324848b8605Smrg if (fd != -1) 325848b8605Smrg fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); 326848b8605Smrg } 327848b8605Smrg return fd; 328848b8605Smrg} 329848b8605Smrg 330848b8605Smrg#ifdef USE_DRICONF 331848b8605Smrgconst char __driConfigOptionsLoader[] = 332848b8605SmrgDRI_CONF_BEGIN 333848b8605Smrg DRI_CONF_SECTION_INITIALIZATION 334848b8605Smrg DRI_CONF_DEVICE_ID_PATH_TAG() 335848b8605Smrg DRI_CONF_SECTION_END 336848b8605SmrgDRI_CONF_END; 337848b8605Smrg#endif 338848b8605Smrg 339848b8605Smrgint loader_get_user_preferred_fd(int default_fd, int *different_device) 340848b8605Smrg{ 341848b8605Smrg struct udev *udev; 342848b8605Smrg#ifdef USE_DRICONF 343848b8605Smrg driOptionCache defaultInitOptions; 344848b8605Smrg driOptionCache userInitOptions; 345848b8605Smrg#endif 346848b8605Smrg const char *dri_prime = getenv("DRI_PRIME"); 347848b8605Smrg char *prime = NULL; 348848b8605Smrg int is_different_device = 0, fd = default_fd; 349848b8605Smrg char *default_device_id_path_tag; 350848b8605Smrg char *device_name = NULL; 351848b8605Smrg char another_tag = 0; 352848b8605Smrg UDEV_SYMBOL(struct udev *, udev_new, (void)); 353848b8605Smrg UDEV_SYMBOL(struct udev *, udev_unref, (struct udev *)); 354848b8605Smrg 355848b8605Smrg if (dri_prime) 356848b8605Smrg prime = strdup(dri_prime); 357848b8605Smrg#ifdef USE_DRICONF 358848b8605Smrg else { 359848b8605Smrg driParseOptionInfo(&defaultInitOptions, __driConfigOptionsLoader); 360848b8605Smrg driParseConfigFiles(&userInitOptions, &defaultInitOptions, 0, "loader"); 361848b8605Smrg if (driCheckOption(&userInitOptions, "device_id", DRI_STRING)) 362848b8605Smrg prime = strdup(driQueryOptionstr(&userInitOptions, "device_id")); 363848b8605Smrg driDestroyOptionCache(&userInitOptions); 364848b8605Smrg driDestroyOptionInfo(&defaultInitOptions); 365848b8605Smrg } 366848b8605Smrg#endif 367848b8605Smrg 368848b8605Smrg if (prime == NULL) { 369848b8605Smrg *different_device = 0; 370848b8605Smrg return default_fd; 371848b8605Smrg } 372848b8605Smrg 373848b8605Smrg udev = udev_new(); 374848b8605Smrg if (!udev) 375848b8605Smrg goto prime_clean; 376848b8605Smrg 377848b8605Smrg default_device_id_path_tag = get_id_path_tag_from_fd(udev, default_fd); 378848b8605Smrg if (!default_device_id_path_tag) 379848b8605Smrg goto udev_clean; 380848b8605Smrg 381848b8605Smrg is_different_device = 1; 382848b8605Smrg /* two format are supported: 383848b8605Smrg * "1": choose any other card than the card used by default. 384848b8605Smrg * id_path_tag: (for example "pci-0000_02_00_0") choose the card 385848b8605Smrg * with this id_path_tag. 386848b8605Smrg */ 387848b8605Smrg if (!strcmp(prime,"1")) { 388848b8605Smrg free(prime); 389848b8605Smrg prime = strdup(default_device_id_path_tag); 390848b8605Smrg /* request a card with a different card than the default card */ 391848b8605Smrg another_tag = 1; 392848b8605Smrg } else if (!strcmp(default_device_id_path_tag, prime)) 393848b8605Smrg /* we are to get a new fd (render-node) of the same device */ 394848b8605Smrg is_different_device = 0; 395848b8605Smrg 396848b8605Smrg device_name = get_render_node_from_id_path_tag(udev, 397848b8605Smrg prime, 398848b8605Smrg another_tag); 399848b8605Smrg if (device_name == NULL) { 400848b8605Smrg is_different_device = 0; 401848b8605Smrg goto default_device_clean; 402848b8605Smrg } 403848b8605Smrg 404848b8605Smrg fd = drm_open_device(device_name); 405848b8605Smrg if (fd > 0) { 406848b8605Smrg close(default_fd); 407848b8605Smrg } else { 408848b8605Smrg fd = default_fd; 409848b8605Smrg is_different_device = 0; 410848b8605Smrg } 411848b8605Smrg free(device_name); 412848b8605Smrg 413848b8605Smrg default_device_clean: 414848b8605Smrg free(default_device_id_path_tag); 415848b8605Smrg udev_clean: 416848b8605Smrg udev_unref(udev); 417848b8605Smrg prime_clean: 418848b8605Smrg free(prime); 419848b8605Smrg 420848b8605Smrg *different_device = is_different_device; 421848b8605Smrg return fd; 422848b8605Smrg} 423848b8605Smrg#else 424848b8605Smrgint loader_get_user_preferred_fd(int default_fd, int *different_device) 425848b8605Smrg{ 426848b8605Smrg *different_device = 0; 427848b8605Smrg return default_fd; 428848b8605Smrg} 429848b8605Smrg#endif 430848b8605Smrg 431848b8605Smrg#if defined(HAVE_SYSFS) 432848b8605Smrgstatic int 433848b8605Smrgdev_node_from_fd(int fd, unsigned int *maj, unsigned int *min) 434848b8605Smrg{ 435848b8605Smrg struct stat buf; 436848b8605Smrg 437848b8605Smrg if (fstat(fd, &buf) < 0) { 438848b8605Smrg log_(_LOADER_WARNING, "MESA-LOADER: failed to stat fd %d\n", fd); 439848b8605Smrg return -1; 440848b8605Smrg } 441848b8605Smrg 442848b8605Smrg if (!S_ISCHR(buf.st_mode)) { 443848b8605Smrg log_(_LOADER_WARNING, "MESA-LOADER: fd %d not a character device\n", fd); 444848b8605Smrg return -1; 445848b8605Smrg } 446848b8605Smrg 447848b8605Smrg *maj = major(buf.st_rdev); 448848b8605Smrg *min = minor(buf.st_rdev); 449848b8605Smrg 450848b8605Smrg return 0; 451848b8605Smrg} 452848b8605Smrg 453848b8605Smrgstatic int 454848b8605Smrgsysfs_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id) 455848b8605Smrg{ 456848b8605Smrg unsigned int maj, min; 457848b8605Smrg FILE *f; 458848b8605Smrg char buf[0x40]; 459848b8605Smrg 460848b8605Smrg if (dev_node_from_fd(fd, &maj, &min) < 0) { 461848b8605Smrg *chip_id = -1; 462848b8605Smrg return 0; 463848b8605Smrg } 464848b8605Smrg 465848b8605Smrg snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/vendor", maj, min); 466848b8605Smrg if (!(f = fopen(buf, "r"))) { 467848b8605Smrg *chip_id = -1; 468848b8605Smrg return 0; 469848b8605Smrg } 470848b8605Smrg if (fscanf(f, "%x", vendor_id) != 1) { 471848b8605Smrg *chip_id = -1; 472848b8605Smrg fclose(f); 473848b8605Smrg return 0; 474848b8605Smrg } 475848b8605Smrg fclose(f); 476848b8605Smrg snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/device", maj, min); 477848b8605Smrg if (!(f = fopen(buf, "r"))) { 478848b8605Smrg *chip_id = -1; 479848b8605Smrg return 0; 480848b8605Smrg } 481848b8605Smrg if (fscanf(f, "%x", chip_id) != 1) { 482848b8605Smrg *chip_id = -1; 483848b8605Smrg fclose(f); 484848b8605Smrg return 0; 485848b8605Smrg } 486848b8605Smrg fclose(f); 487848b8605Smrg return 1; 488848b8605Smrg} 489848b8605Smrg#endif 490848b8605Smrg 491848b8605Smrg#if !defined(__NOT_HAVE_DRM_H) 492848b8605Smrg/* for i915 */ 493848b8605Smrg#include <i915_drm.h> 494848b8605Smrg/* for radeon */ 495848b8605Smrg#include <radeon_drm.h> 496848b8605Smrg 497848b8605Smrgstatic int 498848b8605Smrgdrm_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id) 499848b8605Smrg{ 500848b8605Smrg drmVersionPtr version; 501848b8605Smrg 502848b8605Smrg *chip_id = -1; 503848b8605Smrg 504848b8605Smrg version = drmGetVersion(fd); 505848b8605Smrg if (!version) { 506848b8605Smrg log_(_LOADER_WARNING, "MESA-LOADER: invalid drm fd\n"); 507848b8605Smrg return 0; 508848b8605Smrg } 509848b8605Smrg if (!version->name) { 510848b8605Smrg log_(_LOADER_WARNING, "MESA-LOADER: unable to determine the driver name\n"); 511848b8605Smrg drmFreeVersion(version); 512848b8605Smrg return 0; 513848b8605Smrg } 514848b8605Smrg 515848b8605Smrg if (strcmp(version->name, "i915") == 0) { 516848b8605Smrg struct drm_i915_getparam gp; 517848b8605Smrg int ret; 518848b8605Smrg 519848b8605Smrg *vendor_id = 0x8086; 520848b8605Smrg 521848b8605Smrg memset(&gp, 0, sizeof(gp)); 522848b8605Smrg gp.param = I915_PARAM_CHIPSET_ID; 523848b8605Smrg gp.value = chip_id; 524848b8605Smrg ret = drmCommandWriteRead(fd, DRM_I915_GETPARAM, &gp, sizeof(gp)); 525848b8605Smrg if (ret) { 526848b8605Smrg log_(_LOADER_WARNING, "MESA-LOADER: failed to get param for i915\n"); 527848b8605Smrg *chip_id = -1; 528848b8605Smrg } 529848b8605Smrg } 530848b8605Smrg else if (strcmp(version->name, "radeon") == 0) { 531848b8605Smrg struct drm_radeon_info info; 532848b8605Smrg int ret; 533848b8605Smrg 534848b8605Smrg *vendor_id = 0x1002; 535848b8605Smrg 536848b8605Smrg memset(&info, 0, sizeof(info)); 537848b8605Smrg info.request = RADEON_INFO_DEVICE_ID; 538848b8605Smrg info.value = (unsigned long) chip_id; 539848b8605Smrg ret = drmCommandWriteRead(fd, DRM_RADEON_INFO, &info, sizeof(info)); 540848b8605Smrg if (ret) { 541848b8605Smrg log_(_LOADER_WARNING, "MESA-LOADER: failed to get info for radeon\n"); 542848b8605Smrg *chip_id = -1; 543848b8605Smrg } 544848b8605Smrg } 545848b8605Smrg else if (strcmp(version->name, "nouveau") == 0) { 546848b8605Smrg *vendor_id = 0x10de; 547848b8605Smrg /* not used */ 548848b8605Smrg *chip_id = 0; 549848b8605Smrg } 550848b8605Smrg else if (strcmp(version->name, "vmwgfx") == 0) { 551848b8605Smrg *vendor_id = 0x15ad; 552848b8605Smrg /* assume SVGA II */ 553848b8605Smrg *chip_id = 0x0405; 554848b8605Smrg } 555848b8605Smrg 556848b8605Smrg drmFreeVersion(version); 557848b8605Smrg 558848b8605Smrg return (*chip_id >= 0); 559848b8605Smrg} 560848b8605Smrg#endif 561848b8605Smrg 562848b8605Smrg 563848b8605Smrgint 564848b8605Smrgloader_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id) 565848b8605Smrg{ 566848b8605Smrg#if HAVE_LIBUDEV 567848b8605Smrg if (libudev_get_pci_id_for_fd(fd, vendor_id, chip_id)) 568848b8605Smrg return 1; 569848b8605Smrg#endif 570848b8605Smrg#if HAVE_SYSFS 571848b8605Smrg if (sysfs_get_pci_id_for_fd(fd, vendor_id, chip_id)) 572848b8605Smrg return 1; 573848b8605Smrg#endif 574848b8605Smrg#if !defined(__NOT_HAVE_DRM_H) 575848b8605Smrg if (drm_get_pci_id_for_fd(fd, vendor_id, chip_id)) 576848b8605Smrg return 1; 577848b8605Smrg#endif 578848b8605Smrg return 0; 579848b8605Smrg} 580848b8605Smrg 581848b8605Smrg 582848b8605Smrg#ifdef HAVE_LIBUDEV 583848b8605Smrgstatic char * 584848b8605Smrglibudev_get_device_name_for_fd(int fd) 585848b8605Smrg{ 586848b8605Smrg char *device_name = NULL; 587848b8605Smrg struct udev *udev; 588848b8605Smrg struct udev_device *device; 589848b8605Smrg const char *const_device_name; 590848b8605Smrg UDEV_SYMBOL(struct udev *, udev_new, (void)); 591848b8605Smrg UDEV_SYMBOL(const char *, udev_device_get_devnode, 592848b8605Smrg (struct udev_device *)); 593848b8605Smrg UDEV_SYMBOL(struct udev_device *, udev_device_unref, 594848b8605Smrg (struct udev_device *)); 595848b8605Smrg UDEV_SYMBOL(struct udev *, udev_unref, (struct udev *)); 596848b8605Smrg 597848b8605Smrg udev = udev_new(); 598848b8605Smrg device = udev_device_new_from_fd(udev, fd); 599848b8605Smrg if (device == NULL) 600848b8605Smrg return NULL; 601848b8605Smrg 602848b8605Smrg const_device_name = udev_device_get_devnode(device); 603848b8605Smrg if (!const_device_name) 604848b8605Smrg goto out; 605848b8605Smrg device_name = strdup(const_device_name); 606848b8605Smrg 607848b8605Smrgout: 608848b8605Smrg udev_device_unref(device); 609848b8605Smrg udev_unref(udev); 610848b8605Smrg return device_name; 611848b8605Smrg} 612848b8605Smrg#endif 613848b8605Smrg 614848b8605Smrg 615848b8605Smrg#if HAVE_SYSFS 616848b8605Smrgstatic char * 617848b8605Smrgsysfs_get_device_name_for_fd(int fd) 618848b8605Smrg{ 619848b8605Smrg char *device_name = NULL; 620848b8605Smrg unsigned int maj, min; 621848b8605Smrg FILE *f; 622848b8605Smrg char buf[0x40]; 623848b8605Smrg static const char match[9] = "\0DEVNAME="; 624848b8605Smrg int expected = 1; 625848b8605Smrg 626848b8605Smrg if (dev_node_from_fd(fd, &maj, &min) < 0) 627848b8605Smrg return NULL; 628848b8605Smrg 629848b8605Smrg snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/uevent", maj, min); 630848b8605Smrg if (!(f = fopen(buf, "r"))) 631848b8605Smrg return NULL; 632848b8605Smrg 633848b8605Smrg while (expected < sizeof(match)) { 634848b8605Smrg int c = getc(f); 635848b8605Smrg 636848b8605Smrg if (c == EOF) { 637848b8605Smrg fclose(f); 638848b8605Smrg return NULL; 639848b8605Smrg } else if (c == match[expected] ) 640848b8605Smrg expected++; 641848b8605Smrg else 642848b8605Smrg expected = 0; 643848b8605Smrg } 644848b8605Smrg 645848b8605Smrg strcpy(buf, "/dev/"); 646848b8605Smrg if (fgets(buf + 5, sizeof(buf) - 5, f)) 647848b8605Smrg device_name = strdup(buf); 648848b8605Smrg 649848b8605Smrg fclose(f); 650848b8605Smrg return device_name; 651848b8605Smrg} 652848b8605Smrg#endif 653848b8605Smrg 654848b8605Smrg 655848b8605Smrgchar * 656848b8605Smrgloader_get_device_name_for_fd(int fd) 657848b8605Smrg{ 658848b8605Smrg char *result = NULL; 659848b8605Smrg 660848b8605Smrg#if HAVE_LIBUDEV 661848b8605Smrg if ((result = libudev_get_device_name_for_fd(fd))) 662848b8605Smrg return result; 663848b8605Smrg#endif 664848b8605Smrg#if HAVE_SYSFS 665848b8605Smrg if ((result = sysfs_get_device_name_for_fd(fd))) 666848b8605Smrg return result; 667848b8605Smrg#endif 668848b8605Smrg return result; 669848b8605Smrg} 670848b8605Smrg 671848b8605Smrgchar * 672848b8605Smrgloader_get_driver_for_fd(int fd, unsigned driver_types) 673848b8605Smrg{ 674848b8605Smrg int vendor_id, chip_id, i, j; 675848b8605Smrg char *driver = NULL; 676848b8605Smrg 677848b8605Smrg if (!driver_types) 678848b8605Smrg driver_types = _LOADER_GALLIUM | _LOADER_DRI; 679848b8605Smrg 680848b8605Smrg if (!loader_get_pci_id_for_fd(fd, &vendor_id, &chip_id)) { 681848b8605Smrg 682848b8605Smrg#ifndef __NOT_HAVE_DRM_H 683848b8605Smrg /* fallback to drmGetVersion(): */ 684848b8605Smrg drmVersionPtr version = drmGetVersion(fd); 685848b8605Smrg 686848b8605Smrg if (!version) { 687848b8605Smrg log_(_LOADER_WARNING, "failed to get driver name for fd %d\n", fd); 688848b8605Smrg return NULL; 689848b8605Smrg } 690848b8605Smrg 691848b8605Smrg driver = strndup(version->name, version->name_len); 692848b8605Smrg log_(_LOADER_INFO, "using driver %s for %d\n", driver, fd); 693848b8605Smrg 694848b8605Smrg drmFreeVersion(version); 695848b8605Smrg#endif 696848b8605Smrg 697848b8605Smrg return driver; 698848b8605Smrg } 699848b8605Smrg 700848b8605Smrg for (i = 0; driver_map[i].driver; i++) { 701848b8605Smrg if (vendor_id != driver_map[i].vendor_id) 702848b8605Smrg continue; 703848b8605Smrg 704848b8605Smrg if (!(driver_types & driver_map[i].driver_types)) 705848b8605Smrg continue; 706848b8605Smrg 707848b8605Smrg if (driver_map[i].predicate && !driver_map[i].predicate(fd)) 708848b8605Smrg continue; 709848b8605Smrg 710848b8605Smrg if (driver_map[i].num_chips_ids == -1) { 711848b8605Smrg driver = strdup(driver_map[i].driver); 712848b8605Smrg goto out; 713848b8605Smrg } 714848b8605Smrg 715848b8605Smrg for (j = 0; j < driver_map[i].num_chips_ids; j++) 716848b8605Smrg if (driver_map[i].chip_ids[j] == chip_id) { 717848b8605Smrg driver = strdup(driver_map[i].driver); 718848b8605Smrg goto out; 719848b8605Smrg } 720848b8605Smrg } 721848b8605Smrg 722848b8605Smrgout: 723848b8605Smrg log_(driver ? _LOADER_DEBUG : _LOADER_WARNING, 724848b8605Smrg "pci id for fd %d: %04x:%04x, driver %s\n", 725848b8605Smrg fd, vendor_id, chip_id, driver); 726848b8605Smrg return driver; 727848b8605Smrg} 728848b8605Smrg 729848b8605Smrgvoid 730848b8605Smrgloader_set_logger(void (*logger)(int level, const char *fmt, ...)) 731848b8605Smrg{ 732848b8605Smrg log_ = logger; 733848b8605Smrg} 734