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>
76 #ifndef __NOT_HAVE_DRM_H
81 #include "pci_id_driver_map.h"
83 static void default_logger(int level
, const char *fmt
, ...)
85 if (level
<= _LOADER_WARNING
) {
88 vfprintf(stderr
, fmt
, args
);
93 static void (*log_
)(int level
, const char *fmt
, ...) = default_logger
;
98 static void *udev_handle
= NULL
;
101 udev_dlopen_handle(void)
104 udev_handle
= dlopen("libudev.so.1", RTLD_LOCAL
| RTLD_LAZY
);
107 /* libudev.so.1 changed the return types of the two unref functions
108 * from voids to pointers. We don't use those return values, and the
109 * only ABI I've heard that cares about this kind of change (calling
110 * a function with a void * return that actually only returns void)
113 udev_handle
= dlopen("libudev.so.0", RTLD_LOCAL
| RTLD_LAZY
);
116 log_(_LOADER_FATAL
, "Couldn't dlopen libudev.so.1 or libudev.so.0, "
117 "driver detection may be broken.\n");
126 asserted_dlsym(void *dlopen_handle
, const char *name
)
128 void *result
= dlsym(dlopen_handle
, name
);
133 #define UDEV_SYMBOL(ret, name, args) \
134 ret (*name) args = asserted_dlsym(udev_dlopen_handle(), #name);
137 static inline struct udev_device
*
138 udev_device_new_from_fd(struct udev
*udev
, int fd
)
140 struct udev_device
*device
;
142 UDEV_SYMBOL(struct udev_device
*, udev_device_new_from_devnum
,
143 (struct udev
*udev
, char type
, dev_t devnum
));
145 if (fstat(fd
, &buf
) < 0) {
146 log_(_LOADER_WARNING
, "MESA-LOADER: failed to stat fd %d\n", fd
);
150 device
= udev_device_new_from_devnum(udev
, 'c', buf
.st_rdev
);
151 if (device
== NULL
) {
152 log_(_LOADER_WARNING
,
153 "MESA-LOADER: could not create udev device for fd %d\n", fd
);
161 loader_get_pci_id_for_fd(int fd
, int *vendor_id
, int *chip_id
)
163 struct udev
*udev
= NULL
;
164 struct udev_device
*device
= NULL
, *parent
;
166 UDEV_SYMBOL(struct udev
*, udev_new
, (void));
167 UDEV_SYMBOL(struct udev_device
*, udev_device_get_parent
,
168 (struct udev_device
*));
169 UDEV_SYMBOL(const char *, udev_device_get_property_value
,
170 (struct udev_device
*, const char *));
171 UDEV_SYMBOL(struct udev_device
*, udev_device_unref
,
172 (struct udev_device
*));
173 UDEV_SYMBOL(struct udev
*, udev_unref
, (struct udev
*));
178 device
= udev_device_new_from_fd(udev
, fd
);
182 parent
= udev_device_get_parent(device
);
183 if (parent
== NULL
) {
184 log_(_LOADER_WARNING
, "MESA-LOADER: could not get parent device\n");
188 pci_id
= udev_device_get_property_value(parent
, "PCI_ID");
189 if (pci_id
== NULL
||
190 sscanf(pci_id
, "%x:%x", vendor_id
, chip_id
) != 2) {
191 log_(_LOADER_WARNING
, "MESA-LOADER: malformed or no PCI ID\n");
198 udev_device_unref(device
);
202 return (*chip_id
>= 0);
205 #elif !defined(__NOT_HAVE_DRM_H)
208 #include <i915_drm.h>
210 #include <radeon_drm.h>
213 loader_get_pci_id_for_fd(int fd
, int *vendor_id
, int *chip_id
)
215 drmVersionPtr version
;
219 version
= drmGetVersion(fd
);
221 log_(_LOADER_WARNING
, "MESA-LOADER: invalid drm fd\n");
224 if (!version
->name
) {
225 log_(_LOADER_WARNING
, "MESA-LOADER: unable to determine the driver name\n");
226 drmFreeVersion(version
);
230 if (strcmp(version
->name
, "i915") == 0) {
231 struct drm_i915_getparam gp
;
236 memset(&gp
, 0, sizeof(gp
));
237 gp
.param
= I915_PARAM_CHIPSET_ID
;
239 ret
= drmCommandWriteRead(fd
, DRM_I915_GETPARAM
, &gp
, sizeof(gp
));
241 log_(_LOADER_WARNING
, "MESA-LOADER: failed to get param for i915\n");
245 else if (strcmp(version
->name
, "radeon") == 0) {
246 struct drm_radeon_info info
;
251 memset(&info
, 0, sizeof(info
));
252 info
.request
= RADEON_INFO_DEVICE_ID
;
253 info
.value
= (unsigned long) chip_id
;
254 ret
= drmCommandWriteRead(fd
, DRM_RADEON_INFO
, &info
, sizeof(info
));
256 log_(_LOADER_WARNING
, "MESA-LOADER: failed to get info for radeon\n");
260 else if (strcmp(version
->name
, "nouveau") == 0) {
265 else if (strcmp(version
->name
, "vmwgfx") == 0) {
271 drmFreeVersion(version
);
273 return (*chip_id
>= 0);
279 loader_get_pci_id_for_fd(int fd
, int *vendor_id
, int *chip_id
)
288 loader_get_device_name_for_fd(int fd
)
290 char *device_name
= NULL
;
293 struct udev_device
*device
;
294 const char *const_device_name
;
295 UDEV_SYMBOL(struct udev
*, udev_new
, (void));
296 UDEV_SYMBOL(const char *, udev_device_get_devnode
,
297 (struct udev_device
*));
298 UDEV_SYMBOL(struct udev_device
*, udev_device_unref
,
299 (struct udev_device
*));
300 UDEV_SYMBOL(struct udev
*, udev_unref
, (struct udev
*));
303 device
= udev_device_new_from_fd(udev
, fd
);
307 const_device_name
= udev_device_get_devnode(device
);
308 if (!const_device_name
)
310 device_name
= strdup(const_device_name
);
313 udev_device_unref(device
);
320 loader_get_driver_for_fd(int fd
, unsigned driver_types
)
322 int vendor_id
, chip_id
, i
, j
;
326 driver_types
= _LOADER_GALLIUM
| _LOADER_DRI
;
328 if (!loader_get_pci_id_for_fd(fd
, &vendor_id
, &chip_id
)) {
330 #ifndef __NOT_HAVE_DRM_H
331 /* fallback to drmGetVersion(): */
332 drmVersionPtr version
= drmGetVersion(fd
);
335 log_(_LOADER_WARNING
, "failed to get driver name for fd %d\n", fd
);
339 driver
= strndup(version
->name
, version
->name_len
);
340 log_(_LOADER_INFO
, "using driver %s for %d\n", driver
, fd
);
342 drmFreeVersion(version
);
348 for (i
= 0; driver_map
[i
].driver
; i
++) {
349 if (vendor_id
!= driver_map
[i
].vendor_id
)
352 if (!(driver_types
& driver_map
[i
].driver_types
))
355 if (driver_map
[i
].predicate
&& !driver_map
[i
].predicate(fd
))
358 if (driver_map
[i
].num_chips_ids
== -1) {
359 driver
= strdup(driver_map
[i
].driver
);
363 for (j
= 0; j
< driver_map
[i
].num_chips_ids
; j
++)
364 if (driver_map
[i
].chip_ids
[j
] == chip_id
) {
365 driver
= strdup(driver_map
[i
].driver
);
371 log_(driver
? _LOADER_DEBUG
: _LOADER_WARNING
,
372 "pci id for fd %d: %04x:%04x, driver %s\n",
373 fd
, vendor_id
, chip_id
, driver
);
378 loader_set_logger(void (*logger
)(int level
, const char *fmt
, ...))