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