2 * Copyright (C) 2013 Rob Clark <robclark@freedesktop.org>
4 * This code is derived from the following files.
6 * * src/glx/dri3_common.c
7 * Copyright © 2013 Keith Packard
9 * * src/egl/drivers/dri2/common.c
10 * * src/gbm/backends/dri/driver_name.c
11 * Copyright © 2011 Intel Corporation
14 * Kristian Høgsberg <krh@bitplanet.net>
15 * Benjamin Franzke <benjaminfranzke@googlemail.com>
17 * * src/gallium/targets/egl-static/egl.c
18 * Copyright (C) 2010-2011 LunarG Inc.
21 * Chia-I Wu <olv@lunarg.com>
23 * * src/gallium/state_trackers/egl/drm/native_drm.c
24 * Copyright (C) 2010 Chia-I Wu <olv@0xlab.org>
26 * * src/egl/drivers/dri2/platform_android.c
28 * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
29 * Copyright (C) 2010-2011 LunarG Inc.
31 * Based on platform_x11, which has
33 * Copyright © 2011 Intel Corporation
35 * * src/gallium/auxiliary/pipe-loader/pipe_loader_drm.c
36 * Copyright 2011 Intel Corporation
37 * Copyright 2012 Francisco Jerez
38 * All Rights Reserved.
41 * Kristian Høgsberg <krh@bitplanet.net>
42 * Benjamin Franzke <benjaminfranzke@googlemail.com>
44 * Permission is hereby granted, free of charge, to any person obtaining a
45 * copy of this software and associated documentation files (the "Software"),
46 * to deal in the Software without restriction, including without limitation
47 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
48 * and/or sell copies of the Software, and to permit persons to whom the
49 * Software is furnished to do so, subject to the following conditions:
51 * The above copyright notice and this permission notice (including the next
52 * paragraph) shall be included in all copies or substantial portions of the
55 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
56 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
57 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
58 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
59 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
60 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
64 * Rob Clark <robclark@freedesktop.org>
79 #include "xmlconfig.h"
84 #include <sys/mkdev.h>
86 #ifdef MAJOR_IN_SYSMACROS
87 #include <sys/sysmacros.h>
96 #include "pci_id_driver_map.h"
98 static void default_logger(int level
, const char *fmt
, ...)
100 if (level
<= _LOADER_WARNING
) {
103 vfprintf(stderr
, fmt
, args
);
108 static void (*log_
)(int level
, const char *fmt
, ...) = default_logger
;
111 loader_open_device(const char *device_name
)
115 fd
= open(device_name
, O_RDWR
| O_CLOEXEC
);
116 if (fd
== -1 && errno
== EINVAL
)
119 fd
= open(device_name
, O_RDWR
);
121 fcntl(fd
, F_SETFD
, fcntl(fd
, F_GETFD
) | FD_CLOEXEC
);
129 static void *udev_handle
= NULL
;
132 udev_dlopen_handle(void)
135 unsigned flags
= RTLD_NOLOAD
| RTLD_LOCAL
| RTLD_LAZY
;
138 /* libudev.so.1 changed the return types of the two unref functions
139 * from voids to pointers. We don't use those return values, and the
140 * only ABI I've heard that cares about this kind of change (calling
141 * a function with a void * return that actually only returns void)
145 /* First try opening an already linked libudev, then try loading one */
147 for (version
= 1; version
>= 0; version
--) {
148 snprintf(name
, sizeof(name
), "libudev.so.%d", version
);
149 udev_handle
= dlopen(name
, flags
);
154 if ((flags
& RTLD_NOLOAD
) == 0)
157 flags
&= ~RTLD_NOLOAD
;
160 log_(_LOADER_WARNING
,
161 "Couldn't dlopen libudev.so.1 or "
162 "libudev.so.0, driver detection may be broken.\n");
166 static int dlsym_failed
= 0;
169 checked_dlsym(void *dlopen_handle
, const char *name
)
171 void *result
= dlsym(dlopen_handle
, name
);
177 #define UDEV_SYMBOL(ret, name, args) \
178 ret (*name) args = checked_dlsym(udev_dlopen_handle(), #name);
181 static inline struct udev_device
*
182 udev_device_new_from_fd(struct udev
*udev
, int fd
)
184 struct udev_device
*device
;
186 UDEV_SYMBOL(struct udev_device
*, udev_device_new_from_devnum
,
187 (struct udev
*udev
, char type
, dev_t devnum
));
192 if (fstat(fd
, &buf
) < 0) {
193 log_(_LOADER_WARNING
, "MESA-LOADER: failed to stat fd %d\n", fd
);
197 device
= udev_device_new_from_devnum(udev
, 'c', buf
.st_rdev
);
198 if (device
== NULL
) {
199 log_(_LOADER_WARNING
,
200 "MESA-LOADER: could not create udev device for fd %d\n", fd
);
208 libudev_get_pci_id_for_fd(int fd
, int *vendor_id
, int *chip_id
)
210 struct udev
*udev
= NULL
;
211 struct udev_device
*device
= NULL
, *parent
;
213 UDEV_SYMBOL(struct udev
*, udev_new
, (void));
214 UDEV_SYMBOL(struct udev_device
*, udev_device_get_parent
,
215 (struct udev_device
*));
216 UDEV_SYMBOL(const char *, udev_device_get_property_value
,
217 (struct udev_device
*, const char *));
218 UDEV_SYMBOL(struct udev_device
*, udev_device_unref
,
219 (struct udev_device
*));
220 UDEV_SYMBOL(struct udev
*, udev_unref
, (struct udev
*));
228 device
= udev_device_new_from_fd(udev
, fd
);
232 parent
= udev_device_get_parent(device
);
233 if (parent
== NULL
) {
234 log_(_LOADER_WARNING
, "MESA-LOADER: could not get parent device\n");
238 pci_id
= udev_device_get_property_value(parent
, "PCI_ID");
239 if (pci_id
== NULL
) {
240 log_(_LOADER_INFO
, "MESA-LOADER: no PCI ID\n");
243 } else if (sscanf(pci_id
, "%x:%x", vendor_id
, chip_id
) != 2) {
244 log_(_LOADER_WARNING
, "MESA-LOADER: malformed PCI ID\n");
251 udev_device_unref(device
);
255 return (*chip_id
>= 0);
259 get_render_node_from_id_path_tag(struct udev
*udev
,
263 struct udev_device
*device
;
264 struct udev_enumerate
*e
;
265 struct udev_list_entry
*entry
;
266 const char *path
, *id_path_tag_tmp
;
269 UDEV_SYMBOL(struct udev_enumerate
*, udev_enumerate_new
,
271 UDEV_SYMBOL(int, udev_enumerate_add_match_subsystem
,
272 (struct udev_enumerate
*, const char *));
273 UDEV_SYMBOL(int, udev_enumerate_add_match_sysname
,
274 (struct udev_enumerate
*, const char *));
275 UDEV_SYMBOL(int, udev_enumerate_scan_devices
,
276 (struct udev_enumerate
*));
277 UDEV_SYMBOL(struct udev_list_entry
*, udev_enumerate_get_list_entry
,
278 (struct udev_enumerate
*));
279 UDEV_SYMBOL(void, udev_enumerate_unref
,
280 (struct udev_enumerate
*));
281 UDEV_SYMBOL(struct udev_list_entry
*, udev_list_entry_get_next
,
282 (struct udev_list_entry
*));
283 UDEV_SYMBOL(const char *, udev_list_entry_get_name
,
284 (struct udev_list_entry
*));
285 UDEV_SYMBOL(struct udev_device
*, udev_device_new_from_syspath
,
286 (struct udev
*, const char *));
287 UDEV_SYMBOL(const char *, udev_device_get_property_value
,
288 (struct udev_device
*, const char *));
289 UDEV_SYMBOL(const char *, udev_device_get_devnode
,
290 (struct udev_device
*));
291 UDEV_SYMBOL(struct udev_device
*, udev_device_unref
,
292 (struct udev_device
*));
294 e
= udev_enumerate_new(udev
);
295 udev_enumerate_add_match_subsystem(e
, "drm");
296 udev_enumerate_add_match_sysname(e
, "render*");
298 udev_enumerate_scan_devices(e
);
299 udev_list_entry_foreach(entry
, udev_enumerate_get_list_entry(e
)) {
300 path
= udev_list_entry_get_name(entry
);
301 device
= udev_device_new_from_syspath(udev
, path
);
304 id_path_tag_tmp
= udev_device_get_property_value(device
, "ID_PATH_TAG");
305 if (id_path_tag_tmp
) {
306 if ((!another_tag
&& !strcmp(id_path_tag
, id_path_tag_tmp
)) ||
307 (another_tag
&& strcmp(id_path_tag
, id_path_tag_tmp
))) {
312 udev_device_unref(device
);
315 udev_enumerate_unref(e
);
318 path_res
= strdup(udev_device_get_devnode(device
));
319 udev_device_unref(device
);
326 get_id_path_tag_from_fd(struct udev
*udev
, int fd
)
328 struct udev_device
*device
;
329 const char *id_path_tag_tmp
;
331 UDEV_SYMBOL(const char *, udev_device_get_property_value
,
332 (struct udev_device
*, const char *));
333 UDEV_SYMBOL(struct udev_device
*, udev_device_unref
,
334 (struct udev_device
*));
336 device
= udev_device_new_from_fd(udev
, fd
);
340 id_path_tag_tmp
= udev_device_get_property_value(device
, "ID_PATH_TAG");
341 if (!id_path_tag_tmp
)
344 id_path_tag
= strdup(id_path_tag_tmp
);
346 udev_device_unref(device
);
351 const char __driConfigOptionsLoader
[] =
353 DRI_CONF_SECTION_INITIALIZATION
354 DRI_CONF_DEVICE_ID_PATH_TAG()
359 int loader_get_user_preferred_fd(int default_fd
, int *different_device
)
363 driOptionCache defaultInitOptions
;
364 driOptionCache userInitOptions
;
366 const char *dri_prime
= getenv("DRI_PRIME");
368 int is_different_device
= 0, fd
= default_fd
;
369 char *default_device_id_path_tag
;
370 char *device_name
= NULL
;
371 char another_tag
= 0;
372 UDEV_SYMBOL(struct udev
*, udev_new
, (void));
373 UDEV_SYMBOL(struct udev
*, udev_unref
, (struct udev
*));
376 prime
= strdup(dri_prime
);
379 driParseOptionInfo(&defaultInitOptions
, __driConfigOptionsLoader
);
380 driParseConfigFiles(&userInitOptions
, &defaultInitOptions
, 0, "loader");
381 if (driCheckOption(&userInitOptions
, "device_id", DRI_STRING
))
382 prime
= strdup(driQueryOptionstr(&userInitOptions
, "device_id"));
383 driDestroyOptionCache(&userInitOptions
);
384 driDestroyOptionInfo(&defaultInitOptions
);
389 *different_device
= 0;
397 default_device_id_path_tag
= get_id_path_tag_from_fd(udev
, default_fd
);
398 if (!default_device_id_path_tag
)
401 is_different_device
= 1;
402 /* two format are supported:
403 * "1": choose any other card than the card used by default.
404 * id_path_tag: (for example "pci-0000_02_00_0") choose the card
405 * with this id_path_tag.
407 if (!strcmp(prime
,"1")) {
409 prime
= strdup(default_device_id_path_tag
);
410 /* request a card with a different card than the default card */
412 } else if (!strcmp(default_device_id_path_tag
, prime
))
413 /* we are to get a new fd (render-node) of the same device */
414 is_different_device
= 0;
416 device_name
= get_render_node_from_id_path_tag(udev
,
419 if (device_name
== NULL
) {
420 is_different_device
= 0;
421 goto default_device_clean
;
424 fd
= loader_open_device(device_name
);
429 is_different_device
= 0;
433 default_device_clean
:
434 free(default_device_id_path_tag
);
440 *different_device
= is_different_device
;
444 int loader_get_user_preferred_fd(int default_fd
, int *different_device
)
446 *different_device
= 0;
451 #if defined(HAVE_SYSFS) || defined(HAVE_LIBDRM)
453 dev_node_from_fd(int fd
, unsigned int *maj
, unsigned int *min
)
457 if (fstat(fd
, &buf
) < 0) {
458 log_(_LOADER_WARNING
, "MESA-LOADER: failed to stat fd %d\n", fd
);
462 if (!S_ISCHR(buf
.st_mode
)) {
463 log_(_LOADER_WARNING
, "MESA-LOADER: fd %d not a character device\n", fd
);
467 *maj
= major(buf
.st_rdev
);
468 *min
= minor(buf
.st_rdev
);
474 #if defined(HAVE_SYSFS)
476 sysfs_get_pci_id_for_fd(int fd
, int *vendor_id
, int *chip_id
)
478 unsigned int maj
, min
;
482 if (dev_node_from_fd(fd
, &maj
, &min
) < 0) {
487 snprintf(buf
, sizeof(buf
), "/sys/dev/char/%d:%d/device/vendor", maj
, min
);
488 if (!(f
= fopen(buf
, "r"))) {
492 if (fscanf(f
, "%x", vendor_id
) != 1) {
498 snprintf(buf
, sizeof(buf
), "/sys/dev/char/%d:%d/device/device", maj
, min
);
499 if (!(f
= fopen(buf
, "r"))) {
503 if (fscanf(f
, "%x", chip_id
) != 1) {
513 #if defined(HAVE_LIBDRM)
515 #include <i915_drm.h>
517 #include <radeon_drm.h>
520 drm_get_pci_id_for_fd(int fd
, int *vendor_id
, int *chip_id
)
522 drmVersionPtr version
;
526 version
= drmGetVersion(fd
);
528 log_(_LOADER_WARNING
, "MESA-LOADER: invalid drm fd\n");
531 if (!version
->name
) {
532 log_(_LOADER_WARNING
, "MESA-LOADER: unable to determine the driver name\n");
533 drmFreeVersion(version
);
537 if (strcmp(version
->name
, "i915") == 0) {
538 struct drm_i915_getparam gp
;
543 memset(&gp
, 0, sizeof(gp
));
544 gp
.param
= I915_PARAM_CHIPSET_ID
;
546 ret
= drmCommandWriteRead(fd
, DRM_I915_GETPARAM
, &gp
, sizeof(gp
));
548 log_(_LOADER_WARNING
, "MESA-LOADER: failed to get param for i915\n");
552 else if (strcmp(version
->name
, "radeon") == 0) {
553 struct drm_radeon_info info
;
558 memset(&info
, 0, sizeof(info
));
559 info
.request
= RADEON_INFO_DEVICE_ID
;
560 info
.value
= (unsigned long) chip_id
;
561 ret
= drmCommandWriteRead(fd
, DRM_RADEON_INFO
, &info
, sizeof(info
));
563 log_(_LOADER_WARNING
, "MESA-LOADER: failed to get info for radeon\n");
567 else if (strcmp(version
->name
, "nouveau") == 0) {
572 else if (strcmp(version
->name
, "vmwgfx") == 0) {
578 drmFreeVersion(version
);
580 return (*chip_id
>= 0);
586 loader_get_pci_id_for_fd(int fd
, int *vendor_id
, int *chip_id
)
589 if (libudev_get_pci_id_for_fd(fd
, vendor_id
, chip_id
))
593 if (sysfs_get_pci_id_for_fd(fd
, vendor_id
, chip_id
))
597 if (drm_get_pci_id_for_fd(fd
, vendor_id
, chip_id
))
606 libudev_get_device_name_for_fd(int fd
)
608 char *device_name
= NULL
;
610 struct udev_device
*device
;
611 const char *const_device_name
;
612 UDEV_SYMBOL(struct udev
*, udev_new
, (void));
613 UDEV_SYMBOL(const char *, udev_device_get_devnode
,
614 (struct udev_device
*));
615 UDEV_SYMBOL(struct udev_device
*, udev_device_unref
,
616 (struct udev_device
*));
617 UDEV_SYMBOL(struct udev
*, udev_unref
, (struct udev
*));
623 device
= udev_device_new_from_fd(udev
, fd
);
627 const_device_name
= udev_device_get_devnode(device
);
628 if (!const_device_name
)
630 device_name
= strdup(const_device_name
);
633 udev_device_unref(device
);
642 sysfs_get_device_name_for_fd(int fd
)
644 char *device_name
= NULL
;
645 unsigned int maj
, min
;
648 static const char match
[9] = "\nDEVNAME=";
651 if (dev_node_from_fd(fd
, &maj
, &min
) < 0)
654 snprintf(buf
, sizeof(buf
), "/sys/dev/char/%d:%d/uevent", maj
, min
);
655 if (!(f
= fopen(buf
, "r")))
658 while (expected
< sizeof(match
)) {
664 } else if (c
== match
[expected
] )
670 strcpy(buf
, "/dev/");
671 if (fgets(buf
+ 5, sizeof(buf
) - 5, f
)) {
672 buf
[strcspn(buf
, "\n")] = '\0';
673 device_name
= strdup(buf
);
681 #if defined(HAVE_LIBDRM)
683 drm_get_device_name_for_fd(int fd
)
685 unsigned int maj
, min
;
689 if (dev_node_from_fd(fd
, &maj
, &min
) < 0)
692 n
= snprintf(buf
, sizeof(buf
), DRM_DEV_NAME
, DRM_DIR_NAME
, min
);
693 if (n
== -1 || n
>= sizeof(buf
))
701 loader_get_device_name_for_fd(int fd
)
706 if ((result
= libudev_get_device_name_for_fd(fd
)))
710 if ((result
= sysfs_get_device_name_for_fd(fd
)))
714 if ((result
= drm_get_device_name_for_fd(fd
)))
721 loader_get_driver_for_fd(int fd
, unsigned driver_types
)
723 int vendor_id
, chip_id
, i
, j
;
727 driver_types
= _LOADER_GALLIUM
| _LOADER_DRI
;
729 if (!loader_get_pci_id_for_fd(fd
, &vendor_id
, &chip_id
)) {
732 /* fallback to drmGetVersion(): */
733 drmVersionPtr version
= drmGetVersion(fd
);
736 log_(_LOADER_WARNING
, "failed to get driver name for fd %d\n", fd
);
740 driver
= strndup(version
->name
, version
->name_len
);
741 log_(_LOADER_INFO
, "using driver %s for %d\n", driver
, fd
);
743 drmFreeVersion(version
);
749 for (i
= 0; driver_map
[i
].driver
; i
++) {
750 if (vendor_id
!= driver_map
[i
].vendor_id
)
753 if (!(driver_types
& driver_map
[i
].driver_types
))
756 if (driver_map
[i
].predicate
&& !driver_map
[i
].predicate(fd
))
759 if (driver_map
[i
].num_chips_ids
== -1) {
760 driver
= strdup(driver_map
[i
].driver
);
764 for (j
= 0; j
< driver_map
[i
].num_chips_ids
; j
++)
765 if (driver_map
[i
].chip_ids
[j
] == chip_id
) {
766 driver
= strdup(driver_map
[i
].driver
);
772 log_(driver
? _LOADER_DEBUG
: _LOADER_WARNING
,
773 "pci id for fd %d: %04x:%04x, driver %s\n",
774 fd
, vendor_id
, chip_id
, driver
);
779 loader_set_logger(void (*logger
)(int level
, const char *fmt
, ...))