1 /*
2  * Copyright © 2011 Intel Corporation
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,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  *
24  * Authors:
25  *    Kristian Høgsberg <krh@bitplanet.net>
26  *    Benjamin Franzke <benjaminfranzke@googlemail.com>
27  */
28 
29 #include <stdio.h>
30 #include <string.h>
31 
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <unistd.h>
35 
36 #include "egl_dri2.h"
37 
38 #ifdef HAVE_LIBUDEV
39 
40 #define DRIVER_MAP_DRI2_ONLY
41 #include "pci_ids/pci_id_driver_map.h"
42 
43 #include <libudev.h>
44 
45 static struct udev_device *
dri2_udev_device_new_from_fd(struct udev * udev,int fd)46 dri2_udev_device_new_from_fd(struct udev *udev, int fd)
47 {
48    struct udev_device *device;
49    struct stat buf;
50 
51    if (fstat(fd, &buf) < 0) {
52       _eglLog(_EGL_WARNING, "EGL-DRI2: failed to stat fd %d", fd);
53       return NULL;
54    }
55 
56    device = udev_device_new_from_devnum(udev, 'c', buf.st_rdev);
57    if (device == NULL) {
58       _eglLog(_EGL_WARNING,
59               "EGL-DRI2: could not create udev device for fd %d", fd);
60       return NULL;
61    }
62 
63    return device;
64 }
65 
66 char *
dri2_get_device_name_for_fd(int fd)67 dri2_get_device_name_for_fd(int fd)
68 {
69    struct udev *udev;
70    struct udev_device *device;
71    const char *const_device_name;
72    char *device_name = NULL;
73 
74    udev = udev_new();
75    device = dri2_udev_device_new_from_fd(udev, fd);
76    if (device == NULL)
77       return NULL;
78 
79    const_device_name = udev_device_get_devnode(device);
80    if (!const_device_name)
81       goto out;
82    device_name = strdup(const_device_name);
83 
84 out:
85    udev_device_unref(device);
86    udev_unref(udev);
87 
88    return device_name;
89 }
90 
91 char *
dri2_get_driver_for_fd(int fd)92 dri2_get_driver_for_fd(int fd)
93 {
94    struct udev *udev;
95    struct udev_device *device, *parent;
96    const char *pci_id;
97    char *driver = NULL;
98    int vendor_id, chip_id, i, j;
99 
100    udev = udev_new();
101    device = dri2_udev_device_new_from_fd(udev, fd);
102    if (device == NULL)
103       return NULL;
104 
105    parent = udev_device_get_parent(device);
106    if (parent == NULL) {
107       _eglLog(_EGL_WARNING, "DRI2: could not get parent device");
108       goto out;
109    }
110 
111    pci_id = udev_device_get_property_value(parent, "PCI_ID");
112    if (pci_id == NULL ||
113        sscanf(pci_id, "%x:%x", &vendor_id, &chip_id) != 2) {
114       _eglLog(_EGL_WARNING, "EGL-DRI2: malformed or no PCI ID");
115       goto out;
116    }
117 
118    for (i = 0; driver_map[i].driver; i++) {
119       if (vendor_id != driver_map[i].vendor_id)
120          continue;
121       if (driver_map[i].num_chips_ids == -1) {
122          driver = strdup(driver_map[i].driver);
123          _eglLog(_EGL_DEBUG, "pci id for %d: %04x:%04x, driver %s",
124                  fd, vendor_id, chip_id, driver);
125          goto out;
126       }
127 
128       for (j = 0; j < driver_map[i].num_chips_ids; j++)
129          if (driver_map[i].chip_ids[j] == chip_id) {
130             driver = strdup(driver_map[i].driver);
131             _eglLog(_EGL_DEBUG, "pci id for %d: %04x:%04x, driver %s",
132                     fd, vendor_id, chip_id, driver);
133             goto out;
134          }
135    }
136 
137 out:
138    udev_device_unref(device);
139    udev_unref(udev);
140 
141    return driver;
142 }
143 
144 #endif /* HAVE_LIBUDEV */
145