1 /*
2 * \file xf86drmMode.c
3 * Header for DRM modesetting interface.
4 *
5 * \author Jakob Bornecrantz <wallbraker@gmail.com>
6 *
7 * \par Acknowledgements:
8 * Feb 2007, Dave Airlie <airlied@linux.ie>
9 */
10
11 /*
12 * Copyright (c) 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas.
13 * Copyright (c) 2007-2008 Dave Airlie <airlied@linux.ie>
14 * Copyright (c) 2007-2008 Jakob Bornecrantz <wallbraker@gmail.com>
15 *
16 * Permission is hereby granted, free of charge, to any person obtaining a
17 * copy of this software and associated documentation files (the "Software"),
18 * to deal in the Software without restriction, including without limitation
19 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
20 * and/or sell copies of the Software, and to permit persons to whom the
21 * Software is furnished to do so, subject to the following conditions:
22 *
23 * The above copyright notice and this permission notice shall be included in
24 * all copies or substantial portions of the Software.
25 *
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
31 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
32 * IN THE SOFTWARE.
33 *
34 */
35
36 #include <stdint.h>
37 #include <sys/ioctl.h>
38 #include <stdio.h>
39
40 #ifdef HAVE_CONFIG_H
41 #include "config.h"
42 #endif
43
44 #include "xf86drmMode.h"
45 #include "xf86drm.h"
46 #include "drm.h"
47 #include <string.h>
48 #include <dirent.h>
49 #include <unistd.h>
50 #include <errno.h>
51
52 #ifdef HAVE_VALGRIND
53 #include <valgrind.h>
54 #include <memcheck.h>
55 #define VG(x) x
56 #else
57 #define VG(x)
58 #endif
59
60 #define memclear(s) memset(&s, 0, sizeof(s))
61
62 #define U642VOID(x) ((void *)(unsigned long)(x))
63 #define VOID2U64(x) ((uint64_t)(unsigned long)(x))
64
65 /*
66 * Util functions
67 */
68
drmAllocCpy(char * array,int count,int entry_size)69 static void* drmAllocCpy(char *array, int count, int entry_size)
70 {
71 char *r;
72 int i;
73
74 if (!count || !array || !entry_size)
75 return 0;
76
77 if (!(r = (char *)drmMalloc(count*entry_size)))
78 return 0;
79
80 for (i = 0; i < count; i++)
81 memcpy(r+(entry_size*i), array+(entry_size*i), entry_size);
82
83 return r;
84 }
85
drmModeFreeResources(drmModeResPtr ptr)86 void drmModeFreeResources(drmModeResPtr ptr)
87 {
88 if (!ptr)
89 return;
90
91 drmFree(ptr->fbs);
92 drmFree(ptr->crtcs);
93 drmFree(ptr->connectors);
94 drmFree(ptr->encoders);
95 drmFree(ptr);
96
97 }
98
99 /*
100 * ModeSetting functions.
101 */
102
drmModeGetResources(int fd)103 drmModeResPtr drmModeGetResources(int fd)
104 {
105 struct drm_mode_card_res res, counts;
106 drmModeResPtr r = 0;
107
108 retry:
109 memclear(res);
110 if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
111 return 0;
112
113 counts = res;
114
115 if (res.count_fbs) {
116 res.fb_id_ptr = VOID2U64(drmMalloc(res.count_fbs*sizeof(uint32_t)));
117 if (!res.fb_id_ptr)
118 goto err_allocs;
119 }
120 if (res.count_crtcs) {
121 res.crtc_id_ptr = VOID2U64(drmMalloc(res.count_crtcs*sizeof(uint32_t)));
122 if (!res.crtc_id_ptr)
123 goto err_allocs;
124 }
125 if (res.count_connectors) {
126 res.connector_id_ptr = VOID2U64(drmMalloc(res.count_connectors*sizeof(uint32_t)));
127 if (!res.connector_id_ptr)
128 goto err_allocs;
129 }
130 if (res.count_encoders) {
131 res.encoder_id_ptr = VOID2U64(drmMalloc(res.count_encoders*sizeof(uint32_t)));
132 if (!res.encoder_id_ptr)
133 goto err_allocs;
134 }
135
136 if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
137 goto err_allocs;
138
139 /* The number of available connectors and etc may have changed with a
140 * hotplug event in between the ioctls, in which case the field is
141 * silently ignored by the kernel.
142 */
143 if (counts.count_fbs < res.count_fbs ||
144 counts.count_crtcs < res.count_crtcs ||
145 counts.count_connectors < res.count_connectors ||
146 counts.count_encoders < res.count_encoders)
147 {
148 drmFree(U642VOID(res.fb_id_ptr));
149 drmFree(U642VOID(res.crtc_id_ptr));
150 drmFree(U642VOID(res.connector_id_ptr));
151 drmFree(U642VOID(res.encoder_id_ptr));
152
153 goto retry;
154 }
155
156 /*
157 * return
158 */
159 if (!(r = (drmModeResPtr)drmMalloc(sizeof(*r))))
160 goto err_allocs;
161
162 r->min_width = res.min_width;
163 r->max_width = res.max_width;
164 r->min_height = res.min_height;
165 r->max_height = res.max_height;
166 r->count_fbs = res.count_fbs;
167 r->count_crtcs = res.count_crtcs;
168 r->count_connectors = res.count_connectors;
169 r->count_encoders = res.count_encoders;
170
171 r->fbs = (uint32_t*)drmAllocCpy((char *)U642VOID(res.fb_id_ptr), res.count_fbs, sizeof(uint32_t));
172 r->crtcs = (uint32_t*)drmAllocCpy((char *)U642VOID(res.crtc_id_ptr), res.count_crtcs, sizeof(uint32_t));
173 r->connectors = (uint32_t*)drmAllocCpy((char *)U642VOID(res.connector_id_ptr), res.count_connectors, sizeof(uint32_t));
174 r->encoders = (uint32_t*)drmAllocCpy((char *)U642VOID(res.encoder_id_ptr), res.count_encoders, sizeof(uint32_t));
175 if ((res.count_fbs && !r->fbs) ||
176 (res.count_crtcs && !r->crtcs) ||
177 (res.count_connectors && !r->connectors) ||
178 (res.count_encoders && !r->encoders))
179 {
180 drmFree(r->fbs);
181 drmFree(r->crtcs);
182 drmFree(r->connectors);
183 drmFree(r->encoders);
184 drmFree(r);
185 r = 0;
186 }
187
188 err_allocs:
189 drmFree(U642VOID(res.fb_id_ptr));
190 drmFree(U642VOID(res.crtc_id_ptr));
191 drmFree(U642VOID(res.connector_id_ptr));
192 drmFree(U642VOID(res.encoder_id_ptr));
193
194 return r;
195 }
196
drmModeGetProperty(int fd,uint32_t property_id)197 drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id)
198 {
199 struct drm_mode_get_property prop;
200 drmModePropertyPtr r;
201
202 memclear(prop);
203 prop.prop_id = property_id;
204
205 if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop))
206 return 0;
207
208 if (prop.count_values)
209 prop.values_ptr = VOID2U64(drmMalloc(prop.count_values * sizeof(uint64_t)));
210
211 if (prop.count_enum_blobs && (prop.flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)))
212 prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(struct drm_mode_property_enum)));
213
214 if (prop.count_enum_blobs && (prop.flags & DRM_MODE_PROP_BLOB)) {
215 prop.values_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(uint32_t)));
216 prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(uint32_t)));
217 }
218
219 if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop)) {
220 r = nullptr;
221 goto err_allocs;
222 }
223
224 if (!(r = (drmModePropertyPtr)drmMalloc(sizeof(*r))))
225 return nullptr;
226
227 r->prop_id = prop.prop_id;
228 r->count_values = prop.count_values;
229
230 r->flags = prop.flags;
231 if (prop.count_values)
232 r->values = (uint64_t *)drmAllocCpy((char *)U642VOID(prop.values_ptr), prop.count_values, sizeof(uint64_t));
233 if (prop.flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) {
234 r->count_enums = prop.count_enum_blobs;
235 r->enums = (struct drm_mode_property_enum*)drmAllocCpy((char*)U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(struct drm_mode_property_enum));
236 } else if (prop.flags & DRM_MODE_PROP_BLOB) {
237 r->values = (uint64_t *)drmAllocCpy((char *)U642VOID(prop.values_ptr), prop.count_enum_blobs, sizeof(uint32_t));
238 r->blob_ids = (uint32_t *)drmAllocCpy((char *)U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(uint32_t));
239 r->count_blobs = prop.count_enum_blobs;
240 }
241 strncpy(r->name, prop.name, DRM_PROP_NAME_LEN);
242 r->name[DRM_PROP_NAME_LEN-1] = 0;
243
244 err_allocs:
245 drmFree(U642VOID(prop.values_ptr));
246 drmFree(U642VOID(prop.enum_blob_ptr));
247
248 return r;
249 }
250
drmModeFreeProperty(drmModePropertyPtr ptr)251 void drmModeFreeProperty(drmModePropertyPtr ptr)
252 {
253 if (!ptr)
254 return;
255
256 drmFree(ptr->values);
257 drmFree(ptr->enums);
258 drmFree(ptr);
259 }
260
drmModeObjectGetProperties(int fd,uint32_t object_id,uint32_t object_type)261 drmModeObjectPropertiesPtr drmModeObjectGetProperties(int fd,
262 uint32_t object_id,
263 uint32_t object_type)
264 {
265 struct drm_mode_obj_get_properties properties;
266 drmModeObjectPropertiesPtr ret = nullptr;
267 uint32_t count;
268
269 retry:
270 memclear(properties);
271 properties.obj_id = object_id;
272 properties.obj_type = object_type;
273
274 if (drmIoctl(fd, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, &properties))
275 return 0;
276
277 count = properties.count_props;
278
279 if (count) {
280 properties.props_ptr = VOID2U64(drmMalloc(count *
281 sizeof(uint32_t)));
282 if (!properties.props_ptr)
283 goto err_allocs;
284 properties.prop_values_ptr = VOID2U64(drmMalloc(count *
285 sizeof(uint64_t)));
286 if (!properties.prop_values_ptr)
287 goto err_allocs;
288 }
289
290 if (drmIoctl(fd, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, &properties))
291 goto err_allocs;
292
293 if (count < properties.count_props) {
294 drmFree(U642VOID(properties.props_ptr));
295 drmFree(U642VOID(properties.prop_values_ptr));
296 goto retry;
297 }
298 count = properties.count_props;
299
300 ret = (drmModeObjectPropertiesPtr)drmMalloc(sizeof(*ret));
301 if (!ret)
302 goto err_allocs;
303
304 ret->count_props = count;
305 ret->props = (uint32_t *)drmAllocCpy((char *)U642VOID(properties.props_ptr),
306 count, sizeof(uint32_t));
307 ret->prop_values = (uint64_t *)drmAllocCpy((char *)U642VOID(properties.prop_values_ptr),
308 count, sizeof(uint64_t));
309 if (ret->count_props && (!ret->props || !ret->prop_values)) {
310 drmFree(ret->props);
311 drmFree(ret->prop_values);
312 drmFree(ret);
313 ret = nullptr;
314 }
315
316 err_allocs:
317 drmFree(U642VOID(properties.props_ptr));
318 drmFree(U642VOID(properties.prop_values_ptr));
319 return ret;
320 }
321
drmModeFreeObjectProperties(drmModeObjectPropertiesPtr ptr)322 void drmModeFreeObjectProperties(drmModeObjectPropertiesPtr ptr)
323 {
324 if (!ptr)
325 return;
326 drmFree(ptr->props);
327 drmFree(ptr->prop_values);
328 drmFree(ptr);
329 }
330