gallium/auxiliary/pipe-loader: Fix usage of anonymous union.
[mesa.git] / src / gallium / auxiliary / pipe-loader / pipe_loader_drm.c
1 /**************************************************************************
2 *
3 * Copyright 2011 Intel Corporation
4 * Copyright 2012 Francisco Jerez
5 * All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
17 * of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 * Authors:
28 * Kristian Høgsberg <krh@bitplanet.net>
29 * Benjamin Franzke <benjaminfranzke@googlemail.com>
30 *
31 **************************************************************************/
32
33 #include <fcntl.h>
34 #include <stdio.h>
35 #include <libudev.h>
36 #include <xf86drm.h>
37
38 #include "state_tracker/drm_driver.h"
39 #include "pipe_loader_priv.h"
40
41 #include "util/u_memory.h"
42 #include "util/u_dl.h"
43 #include "util/u_debug.h"
44
45 #define DRIVER_MAP_GALLIUM_ONLY
46 #include "pci_ids/pci_id_driver_map.h"
47
48 struct pipe_loader_drm_device {
49 struct pipe_loader_device base;
50 struct util_dl_library *lib;
51 int fd;
52 };
53
54 #define pipe_loader_drm_device(dev) ((struct pipe_loader_drm_device *)dev)
55
56 static boolean
57 find_drm_pci_id(struct pipe_loader_drm_device *ddev)
58 {
59 struct udev *udev = NULL;
60 struct udev_device *parent, *device = NULL;
61 struct stat stat;
62 const char *pci_id;
63
64 if (fstat(ddev->fd, &stat) < 0)
65 goto fail;
66
67 udev = udev_new();
68 if (!udev)
69 goto fail;
70
71 device = udev_device_new_from_devnum(udev, 'c', stat.st_rdev);
72 if (!device)
73 goto fail;
74
75 parent = udev_device_get_parent(device);
76 if (!parent)
77 goto fail;
78
79 pci_id = udev_device_get_property_value(parent, "PCI_ID");
80 if (!pci_id ||
81 sscanf(pci_id, "%x:%x", &ddev->base.u.pci.vendor_id,
82 &ddev->base.u.pci.chip_id) != 2)
83 goto fail;
84
85 return TRUE;
86
87 fail:
88 if (device)
89 udev_device_unref(device);
90 if (udev)
91 udev_unref(udev);
92
93 debug_printf("pci id for fd %d not found\n", ddev->fd);
94 return FALSE;
95 }
96
97 static boolean
98 find_drm_driver_name(struct pipe_loader_drm_device *ddev)
99 {
100 struct pipe_loader_device *dev = &ddev->base;
101 int i, j;
102
103 for (i = 0; driver_map[i].driver; i++) {
104 if (dev->u.pci.vendor_id != driver_map[i].vendor_id)
105 continue;
106
107 if (driver_map[i].num_chips_ids == -1) {
108 dev->driver_name = driver_map[i].driver;
109 goto found;
110 }
111
112 for (j = 0; j < driver_map[i].num_chips_ids; j++) {
113 if (dev->u.pci.chip_id == driver_map[i].chip_ids[j]) {
114 dev->driver_name = driver_map[i].driver;
115 goto found;
116 }
117 }
118 }
119
120 return FALSE;
121
122 found:
123 debug_printf("driver for %04x:%04x: %s\n", dev->u.pci.vendor_id,
124 dev->u.pci.chip_id, dev->driver_name);
125 return TRUE;
126 }
127
128 static struct pipe_loader_ops pipe_loader_drm_ops;
129
130 boolean
131 pipe_loader_drm_probe_fd(struct pipe_loader_device **dev, int fd)
132 {
133 struct pipe_loader_drm_device *ddev = CALLOC_STRUCT(pipe_loader_drm_device);
134
135 ddev->base.type = PIPE_LOADER_DEVICE_PCI;
136 ddev->base.ops = &pipe_loader_drm_ops;
137 ddev->fd = fd;
138
139 if (!find_drm_pci_id(ddev))
140 goto fail;
141
142 if (!find_drm_driver_name(ddev))
143 goto fail;
144
145 *dev = &ddev->base;
146 return TRUE;
147
148 fail:
149 FREE(ddev);
150 return FALSE;
151 }
152
153 static int
154 open_drm_minor(int minor)
155 {
156 char path[PATH_MAX];
157 snprintf(path, sizeof(path), DRM_DEV_NAME, DRM_DIR_NAME, minor);
158 return open(path, O_RDWR, 0);
159 }
160
161 int
162 pipe_loader_drm_probe(struct pipe_loader_device **devs, int ndev)
163 {
164 int i, j, fd;
165
166 for (i = 0, j = 0; i < DRM_MAX_MINOR; i++) {
167 fd = open_drm_minor(i);
168 if (fd < 0)
169 continue;
170
171 if (j >= ndev || !pipe_loader_drm_probe_fd(&devs[j], fd))
172 close(fd);
173
174 j++;
175 }
176
177 return j;
178 }
179
180 static void
181 pipe_loader_drm_release(struct pipe_loader_device **dev)
182 {
183 struct pipe_loader_drm_device *ddev = pipe_loader_drm_device(*dev);
184
185 if (ddev->lib)
186 util_dl_close(ddev->lib);
187
188 close(ddev->fd);
189 FREE(ddev);
190 *dev = NULL;
191 }
192
193 static struct pipe_screen *
194 pipe_loader_drm_create_screen(struct pipe_loader_device *dev,
195 const char *library_paths)
196 {
197 struct pipe_loader_drm_device *ddev = pipe_loader_drm_device(dev);
198 const struct drm_driver_descriptor *dd;
199
200 if (!ddev->lib)
201 ddev->lib = pipe_loader_find_module(dev, library_paths);
202 if (!ddev->lib)
203 return NULL;
204
205 dd = (const struct drm_driver_descriptor *)
206 util_dl_get_proc_address(ddev->lib, "driver_descriptor");
207
208 /* sanity check on the name */
209 if (!dd || strcmp(dd->name, ddev->base.driver_name) != 0)
210 return NULL;
211
212 return dd->create_screen(ddev->fd);
213 }
214
215 static struct pipe_loader_ops pipe_loader_drm_ops = {
216 .create_screen = pipe_loader_drm_create_screen,
217 .release = pipe_loader_drm_release
218 };