xf86drm: mark DRM_MAX_MINOR as deprecated
[platform/upstream/libdrm.git] / xf86drmMode.c
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 <assert.h>
37 #include <limits.h>
38 #include <stdint.h>
39 #include <stdlib.h>
40 #include <sys/ioctl.h>
41 #if HAVE_SYS_SYSCTL_H
42 #ifdef __FreeBSD__
43 #include <sys/types.h>
44 #endif
45 #include <sys/sysctl.h>
46 #endif
47 #include <stdio.h>
48 #include <stdbool.h>
49
50 #include "libdrm_macros.h"
51 #include "xf86drmMode.h"
52 #include "xf86drm.h"
53 #include <drm.h>
54 #include <drm_fourcc.h>
55 #include <string.h>
56 #include <dirent.h>
57 #include <unistd.h>
58 #include <errno.h>
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 static inline int DRM_IOCTL(int fd, unsigned long cmd, void *arg)
66 {
67         int ret = drmIoctl(fd, cmd, arg);
68         return ret < 0 ? -errno : ret;
69 }
70
71 /*
72  * Util functions
73  */
74
75 static void* drmAllocCpy(char *array, int count, int entry_size)
76 {
77         char *r;
78         int i;
79
80         if (!count || !array || !entry_size)
81                 return 0;
82
83         if (!(r = drmMalloc(count*entry_size)))
84                 return 0;
85
86         for (i = 0; i < count; i++)
87                 memcpy(r+(entry_size*i), array+(entry_size*i), entry_size);
88
89         return r;
90 }
91
92 /*
93  * A couple of free functions.
94  */
95
96 drm_public void drmModeFreeModeInfo(drmModeModeInfoPtr ptr)
97 {
98         if (!ptr)
99                 return;
100
101         drmFree(ptr);
102 }
103
104 drm_public void drmModeFreeResources(drmModeResPtr ptr)
105 {
106         if (!ptr)
107                 return;
108
109         drmFree(ptr->fbs);
110         drmFree(ptr->crtcs);
111         drmFree(ptr->connectors);
112         drmFree(ptr->encoders);
113         drmFree(ptr);
114 }
115
116 drm_public void drmModeFreeFB(drmModeFBPtr ptr)
117 {
118         if (!ptr)
119                 return;
120
121         /* we might add more frees later. */
122         drmFree(ptr);
123 }
124
125 drm_public void drmModeFreeCrtc(drmModeCrtcPtr ptr)
126 {
127         if (!ptr)
128                 return;
129
130         drmFree(ptr);
131 }
132
133 drm_public void drmModeFreeConnector(drmModeConnectorPtr ptr)
134 {
135         if (!ptr)
136                 return;
137
138         drmFree(ptr->encoders);
139         drmFree(ptr->prop_values);
140         drmFree(ptr->props);
141         drmFree(ptr->modes);
142         drmFree(ptr);
143 }
144
145 drm_public void drmModeFreeEncoder(drmModeEncoderPtr ptr)
146 {
147         drmFree(ptr);
148 }
149
150 /*
151  * ModeSetting functions.
152  */
153
154 drm_public int drmIsKMS(int fd)
155 {
156         struct drm_mode_card_res res = {0};
157
158         if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res) != 0)
159                 return 0;
160
161         return res.count_crtcs > 0 && res.count_connectors > 0 && res.count_encoders > 0;
162 }
163
164 drm_public drmModeResPtr drmModeGetResources(int fd)
165 {
166         struct drm_mode_card_res res, counts;
167         drmModeResPtr r = 0;
168
169 retry:
170         memclear(res);
171         if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
172                 return 0;
173
174         counts = res;
175
176         if (res.count_fbs) {
177                 res.fb_id_ptr = VOID2U64(drmMalloc(res.count_fbs*sizeof(uint32_t)));
178                 if (!res.fb_id_ptr)
179                         goto err_allocs;
180         }
181         if (res.count_crtcs) {
182                 res.crtc_id_ptr = VOID2U64(drmMalloc(res.count_crtcs*sizeof(uint32_t)));
183                 if (!res.crtc_id_ptr)
184                         goto err_allocs;
185         }
186         if (res.count_connectors) {
187                 res.connector_id_ptr = VOID2U64(drmMalloc(res.count_connectors*sizeof(uint32_t)));
188                 if (!res.connector_id_ptr)
189                         goto err_allocs;
190         }
191         if (res.count_encoders) {
192                 res.encoder_id_ptr = VOID2U64(drmMalloc(res.count_encoders*sizeof(uint32_t)));
193                 if (!res.encoder_id_ptr)
194                         goto err_allocs;
195         }
196
197         if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
198                 goto err_allocs;
199
200         /* The number of available connectors and etc may have changed with a
201          * hotplug event in between the ioctls, in which case the field is
202          * silently ignored by the kernel.
203          */
204         if (counts.count_fbs < res.count_fbs ||
205             counts.count_crtcs < res.count_crtcs ||
206             counts.count_connectors < res.count_connectors ||
207             counts.count_encoders < res.count_encoders)
208         {
209                 drmFree(U642VOID(res.fb_id_ptr));
210                 drmFree(U642VOID(res.crtc_id_ptr));
211                 drmFree(U642VOID(res.connector_id_ptr));
212                 drmFree(U642VOID(res.encoder_id_ptr));
213
214                 goto retry;
215         }
216
217         /*
218          * return
219          */
220         if (!(r = drmMalloc(sizeof(*r))))
221                 goto err_allocs;
222
223         r->min_width     = res.min_width;
224         r->max_width     = res.max_width;
225         r->min_height    = res.min_height;
226         r->max_height    = res.max_height;
227         r->count_fbs     = res.count_fbs;
228         r->count_crtcs   = res.count_crtcs;
229         r->count_connectors = res.count_connectors;
230         r->count_encoders = res.count_encoders;
231
232         r->fbs        = drmAllocCpy(U642VOID(res.fb_id_ptr), res.count_fbs, sizeof(uint32_t));
233         r->crtcs      = drmAllocCpy(U642VOID(res.crtc_id_ptr), res.count_crtcs, sizeof(uint32_t));
234         r->connectors = drmAllocCpy(U642VOID(res.connector_id_ptr), res.count_connectors, sizeof(uint32_t));
235         r->encoders   = drmAllocCpy(U642VOID(res.encoder_id_ptr), res.count_encoders, sizeof(uint32_t));
236         if ((res.count_fbs && !r->fbs) ||
237             (res.count_crtcs && !r->crtcs) ||
238             (res.count_connectors && !r->connectors) ||
239             (res.count_encoders && !r->encoders))
240         {
241                 drmFree(r->fbs);
242                 drmFree(r->crtcs);
243                 drmFree(r->connectors);
244                 drmFree(r->encoders);
245                 drmFree(r);
246                 r = 0;
247         }
248
249 err_allocs:
250         drmFree(U642VOID(res.fb_id_ptr));
251         drmFree(U642VOID(res.crtc_id_ptr));
252         drmFree(U642VOID(res.connector_id_ptr));
253         drmFree(U642VOID(res.encoder_id_ptr));
254
255         return r;
256 }
257
258
259 drm_public int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth,
260                             uint8_t bpp, uint32_t pitch, uint32_t bo_handle,
261                             uint32_t *buf_id)
262 {
263         struct drm_mode_fb_cmd f;
264         int ret;
265
266         memclear(f);
267         f.width  = width;
268         f.height = height;
269         f.pitch  = pitch;
270         f.bpp    = bpp;
271         f.depth  = depth;
272         f.handle = bo_handle;
273
274         if ((ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_ADDFB, &f)))
275                 return ret;
276
277         *buf_id = f.fb_id;
278         return 0;
279 }
280
281 drm_public int drmModeAddFB2WithModifiers(int fd, uint32_t width,
282                 uint32_t height, uint32_t pixel_format, const uint32_t bo_handles[4],
283                 const uint32_t pitches[4], const uint32_t offsets[4],
284                 const uint64_t modifier[4], uint32_t *buf_id, uint32_t flags)
285 {
286         struct drm_mode_fb_cmd2 f;
287         int ret;
288
289         memclear(f);
290         f.width  = width;
291         f.height = height;
292         f.pixel_format = pixel_format;
293         f.flags = flags;
294         memcpy(f.handles, bo_handles, 4 * sizeof(bo_handles[0]));
295         memcpy(f.pitches, pitches, 4 * sizeof(pitches[0]));
296         memcpy(f.offsets, offsets, 4 * sizeof(offsets[0]));
297         if (modifier)
298                 memcpy(f.modifier, modifier, 4 * sizeof(modifier[0]));
299
300         if ((ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_ADDFB2, &f)))
301                 return ret;
302
303         *buf_id = f.fb_id;
304         return 0;
305 }
306
307 drm_public int drmModeAddFB2(int fd, uint32_t width, uint32_t height,
308                 uint32_t pixel_format, const uint32_t bo_handles[4],
309                 const uint32_t pitches[4], const uint32_t offsets[4],
310                 uint32_t *buf_id, uint32_t flags)
311 {
312         return drmModeAddFB2WithModifiers(fd, width, height,
313                                           pixel_format, bo_handles,
314                                           pitches, offsets, NULL,
315                                           buf_id, flags);
316 }
317
318 drm_public int drmModeRmFB(int fd, uint32_t bufferId)
319 {
320         return DRM_IOCTL(fd, DRM_IOCTL_MODE_RMFB, &bufferId);
321 }
322
323 drm_public drmModeFBPtr drmModeGetFB(int fd, uint32_t buf)
324 {
325         struct drm_mode_fb_cmd info;
326         drmModeFBPtr r;
327
328         memclear(info);
329         info.fb_id = buf;
330
331         if (drmIoctl(fd, DRM_IOCTL_MODE_GETFB, &info))
332                 return NULL;
333
334         if (!(r = drmMalloc(sizeof(*r))))
335                 return NULL;
336
337         r->fb_id = info.fb_id;
338         r->width = info.width;
339         r->height = info.height;
340         r->pitch = info.pitch;
341         r->bpp = info.bpp;
342         r->handle = info.handle;
343         r->depth = info.depth;
344
345         return r;
346 }
347
348 drm_public int drmModeDirtyFB(int fd, uint32_t bufferId,
349                    drmModeClipPtr clips, uint32_t num_clips)
350 {
351         struct drm_mode_fb_dirty_cmd dirty;
352
353         memclear(dirty);
354         dirty.fb_id = bufferId;
355         dirty.clips_ptr = VOID2U64(clips);
356         dirty.num_clips = num_clips;
357
358         return DRM_IOCTL(fd, DRM_IOCTL_MODE_DIRTYFB, &dirty);
359 }
360
361 /*
362  * Crtc functions
363  */
364
365 drm_public drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId)
366 {
367         struct drm_mode_crtc crtc;
368         drmModeCrtcPtr r;
369
370         memclear(crtc);
371         crtc.crtc_id = crtcId;
372
373         if (drmIoctl(fd, DRM_IOCTL_MODE_GETCRTC, &crtc))
374                 return 0;
375
376         /*
377          * return
378          */
379
380         if (!(r = drmMalloc(sizeof(*r))))
381                 return 0;
382
383         r->crtc_id         = crtc.crtc_id;
384         r->x               = crtc.x;
385         r->y               = crtc.y;
386         r->mode_valid      = crtc.mode_valid;
387         if (r->mode_valid) {
388                 memcpy(&r->mode, &crtc.mode, sizeof(struct drm_mode_modeinfo));
389                 r->width = crtc.mode.hdisplay;
390                 r->height = crtc.mode.vdisplay;
391         }
392         r->buffer_id       = crtc.fb_id;
393         r->gamma_size      = crtc.gamma_size;
394         return r;
395 }
396
397 drm_public int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId,
398                    uint32_t x, uint32_t y, uint32_t *connectors, int count,
399                    drmModeModeInfoPtr mode)
400 {
401         struct drm_mode_crtc crtc;
402
403         memclear(crtc);
404         crtc.x             = x;
405         crtc.y             = y;
406         crtc.crtc_id       = crtcId;
407         crtc.fb_id         = bufferId;
408         crtc.set_connectors_ptr = VOID2U64(connectors);
409         crtc.count_connectors = count;
410         if (mode) {
411           memcpy(&crtc.mode, mode, sizeof(struct drm_mode_modeinfo));
412           crtc.mode_valid = 1;
413         }
414
415         return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETCRTC, &crtc);
416 }
417
418 /*
419  * Cursor manipulation
420  */
421
422 drm_public int drmModeSetCursor(int fd, uint32_t crtcId, uint32_t bo_handle,
423                                                                 uint32_t width, uint32_t height)
424 {
425         struct drm_mode_cursor arg;
426
427         memclear(arg);
428         arg.flags = DRM_MODE_CURSOR_BO;
429         arg.crtc_id = crtcId;
430         arg.width = width;
431         arg.height = height;
432         arg.handle = bo_handle;
433
434         return DRM_IOCTL(fd, DRM_IOCTL_MODE_CURSOR, &arg);
435 }
436
437 drm_public int drmModeSetCursor2(int fd, uint32_t crtcId, uint32_t bo_handle,
438                                                                  uint32_t width, uint32_t height, int32_t hot_x,
439                                                                  int32_t hot_y)
440 {
441         struct drm_mode_cursor2 arg;
442
443         memclear(arg);
444         arg.flags = DRM_MODE_CURSOR_BO;
445         arg.crtc_id = crtcId;
446         arg.width = width;
447         arg.height = height;
448         arg.handle = bo_handle;
449         arg.hot_x = hot_x;
450         arg.hot_y = hot_y;
451
452         return DRM_IOCTL(fd, DRM_IOCTL_MODE_CURSOR2, &arg);
453 }
454
455 drm_public int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y)
456 {
457         struct drm_mode_cursor arg;
458
459         memclear(arg);
460         arg.flags = DRM_MODE_CURSOR_MOVE;
461         arg.crtc_id = crtcId;
462         arg.x = x;
463         arg.y = y;
464
465         return DRM_IOCTL(fd, DRM_IOCTL_MODE_CURSOR, &arg);
466 }
467
468 /*
469  * Encoder get
470  */
471 drm_public drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id)
472 {
473         struct drm_mode_get_encoder enc;
474         drmModeEncoderPtr r = NULL;
475
476         memclear(enc);
477         enc.encoder_id = encoder_id;
478
479         if (drmIoctl(fd, DRM_IOCTL_MODE_GETENCODER, &enc))
480                 return 0;
481
482         if (!(r = drmMalloc(sizeof(*r))))
483                 return 0;
484
485         r->encoder_id = enc.encoder_id;
486         r->crtc_id = enc.crtc_id;
487         r->encoder_type = enc.encoder_type;
488         r->possible_crtcs = enc.possible_crtcs;
489         r->possible_clones = enc.possible_clones;
490
491         return r;
492 }
493
494 /*
495  * Connector manipulation
496  */
497 static drmModeConnectorPtr
498 _drmModeGetConnector(int fd, uint32_t connector_id, int probe)
499 {
500         struct drm_mode_get_connector conn, counts;
501         drmModeConnectorPtr r = NULL;
502         struct drm_mode_modeinfo stack_mode;
503
504         memclear(conn);
505         conn.connector_id = connector_id;
506         if (!probe) {
507                 conn.count_modes = 1;
508                 conn.modes_ptr = VOID2U64(&stack_mode);
509         }
510
511         if (drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))
512                 return 0;
513
514 retry:
515         counts = conn;
516
517         if (conn.count_props) {
518                 conn.props_ptr = VOID2U64(drmMalloc(conn.count_props*sizeof(uint32_t)));
519                 if (!conn.props_ptr)
520                         goto err_allocs;
521                 conn.prop_values_ptr = VOID2U64(drmMalloc(conn.count_props*sizeof(uint64_t)));
522                 if (!conn.prop_values_ptr)
523                         goto err_allocs;
524         }
525
526         if (conn.count_modes) {
527                 conn.modes_ptr = VOID2U64(drmMalloc(conn.count_modes*sizeof(struct drm_mode_modeinfo)));
528                 if (!conn.modes_ptr)
529                         goto err_allocs;
530         } else {
531                 conn.count_modes = 1;
532                 conn.modes_ptr = VOID2U64(&stack_mode);
533         }
534
535         if (conn.count_encoders) {
536                 conn.encoders_ptr = VOID2U64(drmMalloc(conn.count_encoders*sizeof(uint32_t)));
537                 if (!conn.encoders_ptr)
538                         goto err_allocs;
539         }
540
541         if (drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))
542                 goto err_allocs;
543
544         /* The number of available connectors and etc may have changed with a
545          * hotplug event in between the ioctls, in which case the field is
546          * silently ignored by the kernel.
547          */
548         if (counts.count_props < conn.count_props ||
549             counts.count_modes < conn.count_modes ||
550             counts.count_encoders < conn.count_encoders) {
551                 drmFree(U642VOID(conn.props_ptr));
552                 drmFree(U642VOID(conn.prop_values_ptr));
553                 if (U642VOID(conn.modes_ptr) != &stack_mode)
554                         drmFree(U642VOID(conn.modes_ptr));
555                 drmFree(U642VOID(conn.encoders_ptr));
556
557                 goto retry;
558         }
559
560         if(!(r = drmMalloc(sizeof(*r)))) {
561                 goto err_allocs;
562         }
563
564         r->connector_id = conn.connector_id;
565         r->encoder_id = conn.encoder_id;
566         r->connection   = conn.connection;
567         r->mmWidth      = conn.mm_width;
568         r->mmHeight     = conn.mm_height;
569         /* convert subpixel from kernel to userspace */
570         r->subpixel     = conn.subpixel + 1;
571         r->count_modes  = conn.count_modes;
572         r->count_props  = conn.count_props;
573         r->props        = drmAllocCpy(U642VOID(conn.props_ptr), conn.count_props, sizeof(uint32_t));
574         r->prop_values  = drmAllocCpy(U642VOID(conn.prop_values_ptr), conn.count_props, sizeof(uint64_t));
575         r->modes        = drmAllocCpy(U642VOID(conn.modes_ptr), conn.count_modes, sizeof(struct drm_mode_modeinfo));
576         r->count_encoders = conn.count_encoders;
577         r->encoders     = drmAllocCpy(U642VOID(conn.encoders_ptr), conn.count_encoders, sizeof(uint32_t));
578         r->connector_type  = conn.connector_type;
579         r->connector_type_id = conn.connector_type_id;
580
581         if ((r->count_props && !r->props) ||
582             (r->count_props && !r->prop_values) ||
583             (r->count_modes && !r->modes) ||
584             (r->count_encoders && !r->encoders)) {
585                 drmFree(r->props);
586                 drmFree(r->prop_values);
587                 drmFree(r->modes);
588                 drmFree(r->encoders);
589                 drmFree(r);
590                 r = 0;
591         }
592
593 err_allocs:
594         drmFree(U642VOID(conn.prop_values_ptr));
595         drmFree(U642VOID(conn.props_ptr));
596         if (U642VOID(conn.modes_ptr) != &stack_mode)
597                 drmFree(U642VOID(conn.modes_ptr));
598         drmFree(U642VOID(conn.encoders_ptr));
599
600         return r;
601 }
602
603 drm_public drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id)
604 {
605         return _drmModeGetConnector(fd, connector_id, 1);
606 }
607
608 drm_public drmModeConnectorPtr drmModeGetConnectorCurrent(int fd, uint32_t connector_id)
609 {
610         return _drmModeGetConnector(fd, connector_id, 0);
611 }
612
613 drm_public uint32_t drmModeConnectorGetPossibleCrtcs(int fd,
614                                                      const drmModeConnector *connector)
615 {
616         drmModeEncoder *encoder;
617         int i;
618         uint32_t possible_crtcs;
619
620         possible_crtcs = 0;
621         for (i = 0; i < connector->count_encoders; i++) {
622                 encoder = drmModeGetEncoder(fd, connector->encoders[i]);
623                 if (!encoder) {
624                         return 0;
625                 }
626
627                 possible_crtcs |= encoder->possible_crtcs;
628                 drmModeFreeEncoder(encoder);
629         }
630
631         if (possible_crtcs == 0)
632                 errno = ENOENT;
633         return possible_crtcs;
634 }
635
636 drm_public int drmModeAttachMode(int fd, uint32_t connector_id, drmModeModeInfoPtr mode_info)
637 {
638         struct drm_mode_mode_cmd res;
639
640         memclear(res);
641         memcpy(&res.mode, mode_info, sizeof(struct drm_mode_modeinfo));
642         res.connector_id = connector_id;
643
644         return DRM_IOCTL(fd, DRM_IOCTL_MODE_ATTACHMODE, &res);
645 }
646
647 drm_public int drmModeDetachMode(int fd, uint32_t connector_id, drmModeModeInfoPtr mode_info)
648 {
649         struct drm_mode_mode_cmd res;
650
651         memclear(res);
652         memcpy(&res.mode, mode_info, sizeof(struct drm_mode_modeinfo));
653         res.connector_id = connector_id;
654
655         return DRM_IOCTL(fd, DRM_IOCTL_MODE_DETACHMODE, &res);
656 }
657
658 drm_public drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id)
659 {
660         struct drm_mode_get_property prop;
661         drmModePropertyPtr r;
662
663         memclear(prop);
664         prop.prop_id = property_id;
665
666         if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop))
667                 return 0;
668
669         if (prop.count_values)
670                 prop.values_ptr = VOID2U64(drmMalloc(prop.count_values * sizeof(uint64_t)));
671
672         if (prop.count_enum_blobs && (prop.flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)))
673                 prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(struct drm_mode_property_enum)));
674
675         if (prop.count_enum_blobs && (prop.flags & DRM_MODE_PROP_BLOB)) {
676                 prop.values_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(uint32_t)));
677                 prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(uint32_t)));
678         }
679
680         if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop)) {
681                 r = NULL;
682                 goto err_allocs;
683         }
684
685         if (!(r = drmMalloc(sizeof(*r))))
686                 goto err_allocs;
687
688         r->prop_id = prop.prop_id;
689         r->count_values = prop.count_values;
690
691         r->flags = prop.flags;
692         if (prop.count_values)
693                 r->values = drmAllocCpy(U642VOID(prop.values_ptr), prop.count_values, sizeof(uint64_t));
694         if (prop.flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) {
695                 r->count_enums = prop.count_enum_blobs;
696                 r->enums = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(struct drm_mode_property_enum));
697         } else if (prop.flags & DRM_MODE_PROP_BLOB) {
698                 r->values = drmAllocCpy(U642VOID(prop.values_ptr), prop.count_enum_blobs, sizeof(uint32_t));
699                 r->blob_ids = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(uint32_t));
700                 r->count_blobs = prop.count_enum_blobs;
701         }
702         strncpy(r->name, prop.name, DRM_PROP_NAME_LEN);
703         r->name[DRM_PROP_NAME_LEN-1] = 0;
704
705 err_allocs:
706         drmFree(U642VOID(prop.values_ptr));
707         drmFree(U642VOID(prop.enum_blob_ptr));
708
709         return r;
710 }
711
712 drm_public void drmModeFreeProperty(drmModePropertyPtr ptr)
713 {
714         if (!ptr)
715                 return;
716
717         drmFree(ptr->values);
718         drmFree(ptr->enums);
719         drmFree(ptr->blob_ids);
720         drmFree(ptr);
721 }
722
723 drm_public drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd,
724                                                                                                                  uint32_t blob_id)
725 {
726         struct drm_mode_get_blob blob;
727         drmModePropertyBlobPtr r;
728
729         memclear(blob);
730         blob.blob_id = blob_id;
731
732         if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
733                 return NULL;
734
735         if (blob.length)
736                 blob.data = VOID2U64(drmMalloc(blob.length));
737
738         if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob)) {
739                 r = NULL;
740                 goto err_allocs;
741         }
742
743         if (!(r = drmMalloc(sizeof(*r))))
744                 goto err_allocs;
745
746         r->id = blob.blob_id;
747         r->length = blob.length;
748         r->data = drmAllocCpy(U642VOID(blob.data), 1, blob.length);
749
750 err_allocs:
751         drmFree(U642VOID(blob.data));
752         return r;
753 }
754
755 static inline const uint32_t *
756 get_formats_ptr(const struct drm_format_modifier_blob *blob)
757 {
758         return (const uint32_t *)(((uint8_t *)blob) + blob->formats_offset);
759 }
760
761 static inline const struct drm_format_modifier *
762 get_modifiers_ptr(const struct drm_format_modifier_blob *blob)
763 {
764         return (const struct drm_format_modifier *)(((uint8_t *)blob) +
765                                                     blob->modifiers_offset);
766 }
767
768 static bool _drmModeFormatModifierGetNext(const drmModePropertyBlobRes *blob,
769                                           drmModeFormatModifierIterator *iter)
770 {
771         const struct drm_format_modifier *blob_modifiers, *mod;
772         const struct drm_format_modifier_blob *fmt_mod_blob;
773         const uint32_t *blob_formats;
774
775         assert(blob && iter);
776
777         fmt_mod_blob = blob->data;
778         blob_modifiers = get_modifiers_ptr(fmt_mod_blob);
779         blob_formats = get_formats_ptr(fmt_mod_blob);
780
781         /* fmt_idx and mod_idx designate the number of processed formats
782          * and modifiers.
783          */
784         if (iter->fmt_idx >= fmt_mod_blob->count_formats ||
785             iter->mod_idx >= fmt_mod_blob->count_modifiers)
786                 return false;
787
788         iter->fmt = blob_formats[iter->fmt_idx];
789         iter->mod = DRM_FORMAT_MOD_INVALID;
790
791         /* From the latest valid found, get the next valid modifier */
792         while (iter->mod_idx < fmt_mod_blob->count_modifiers) {
793                 mod = &blob_modifiers[iter->mod_idx++];
794
795                 /* Check if the format that fmt_idx designates, belongs to
796                  * this modifier 64-bit window selected via mod->offset.
797                  */
798                 if (iter->fmt_idx < mod->offset ||
799                     iter->fmt_idx >= mod->offset + 64)
800                         continue;
801                 if (!(mod->formats & (1 << (iter->fmt_idx - mod->offset))))
802                         continue;
803
804                 iter->mod = mod->modifier;
805                 break;
806         }
807
808         if (iter->mod_idx == fmt_mod_blob->count_modifiers) {
809                 iter->mod_idx = 0;
810                 iter->fmt_idx++;
811         }
812
813         /* Since mod_idx reset, in order for the caller to iterate over
814          * the last modifier of the last format, always return true here
815          * and early return from the next call.
816          */
817         return true;
818 }
819
820 /**
821  * Iterate over formats first and then over modifiers. On each call, iter->fmt
822  * is retained until all associated modifiers are returned. Then, either update
823  * iter->fmt with the next format, or exit if there aren't any left.
824  *
825  * NOTE: clients should not make any assumption on mod_idx and fmt_idx values
826  *
827  * @blob: valid kernel blob holding formats and modifiers
828  * @iter: input and output iterator data. Iter data must be initialised to zero
829  * @return: false, on error or there aren't any further formats or modifiers left.
830  *          true, on success and there are more formats or modifiers.
831  */
832 drm_public bool drmModeFormatModifierBlobIterNext(const drmModePropertyBlobRes *blob,
833                                                   drmModeFormatModifierIterator *iter)
834 {
835         drmModeFormatModifierIterator tmp;
836         bool has_fmt;
837
838         if (!blob || !iter)
839                 return false;
840
841         tmp.fmt_idx = iter->fmt_idx;
842         tmp.mod_idx = iter->mod_idx;
843
844         /* With the current state of things, DRM/KMS drivers are allowed to
845          * construct blobs having formats and no modifiers. Userspace can't
846          * legitimately abort in such cases.
847          *
848          * While waiting for the kernel to perhaps disallow formats with no
849          * modifiers in IN_FORMATS blobs, skip the format altogether.
850          */
851         do {
852                 has_fmt = _drmModeFormatModifierGetNext(blob, &tmp);
853                 if (has_fmt && tmp.mod != DRM_FORMAT_MOD_INVALID)
854                         *iter = tmp;
855
856         } while (has_fmt && tmp.mod == DRM_FORMAT_MOD_INVALID);
857
858         return has_fmt;
859 }
860
861 drm_public void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr)
862 {
863         if (!ptr)
864                 return;
865
866         drmFree(ptr->data);
867         drmFree(ptr);
868 }
869
870 drm_public int drmModeConnectorSetProperty(int fd, uint32_t connector_id,
871                                                                                    uint32_t property_id,
872                                                                                    uint64_t value)
873 {
874         struct drm_mode_connector_set_property osp;
875
876         memclear(osp);
877         osp.connector_id = connector_id;
878         osp.prop_id = property_id;
879         osp.value = value;
880
881         return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETPROPERTY, &osp);
882 }
883
884 /*
885  * checks if a modesetting capable driver has attached to the pci id
886  * returns 0 if modesetting supported.
887  *  -EINVAL or invalid bus id
888  *  -ENOSYS if no modesetting support
889 */
890 drm_public int drmCheckModesettingSupported(const char *busid)
891 {
892 #if defined (__linux__)
893         char pci_dev_dir[1024];
894         int domain, bus, dev, func;
895         DIR *sysdir;
896         struct dirent *dent;
897         int found = 0, ret;
898
899         ret = sscanf(busid, "pci:%04x:%02x:%02x.%d", &domain, &bus, &dev, &func);
900         if (ret != 4)
901                 return -EINVAL;
902
903         sprintf(pci_dev_dir, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/drm",
904                 domain, bus, dev, func);
905
906         sysdir = opendir(pci_dev_dir);
907         if (sysdir) {
908                 dent = readdir(sysdir);
909                 while (dent) {
910                         if (!strncmp(dent->d_name, "controlD", 8)) {
911                                 found = 1;
912                                 break;
913                         }
914
915                         dent = readdir(sysdir);
916                 }
917                 closedir(sysdir);
918                 if (found)
919                         return 0;
920         }
921
922         sprintf(pci_dev_dir, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/",
923                 domain, bus, dev, func);
924
925         sysdir = opendir(pci_dev_dir);
926         if (!sysdir)
927                 return -EINVAL;
928
929         dent = readdir(sysdir);
930         while (dent) {
931                 if (!strncmp(dent->d_name, "drm:controlD", 12)) {
932                         found = 1;
933                         break;
934                 }
935
936                 dent = readdir(sysdir);
937         }
938
939         closedir(sysdir);
940         if (found)
941                 return 0;
942 #elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
943         char sbusid[1024];
944         char oid[128];
945         int i, modesetting, ret;
946         size_t len;
947
948         /* How many GPUs do we expect in the machine ? */
949         for (i = 0; i < 10; i++) {
950                 snprintf(oid, sizeof(oid), "hw.dri.%d.busid", i);
951                 len = sizeof(sbusid);
952                 ret = sysctlbyname(oid, sbusid, &len, NULL, 0);
953                 if (ret == -1) {
954                         if (errno == ENOENT)
955                                 continue;
956                         return -EINVAL;
957                 }
958                 if (strcmp(sbusid, busid) != 0)
959                         continue;
960                 snprintf(oid, sizeof(oid), "hw.dri.%d.modesetting", i);
961                 len = sizeof(modesetting);
962                 ret = sysctlbyname(oid, &modesetting, &len, NULL, 0);
963                 if (ret == -1 || len != sizeof(modesetting))
964                         return -EINVAL;
965                 return (modesetting ? 0 : -ENOSYS);
966         }
967 #elif defined(__DragonFly__)
968         return 0;
969 #elif defined(__OpenBSD__)
970         int     fd;
971         struct drm_mode_card_res res;
972         drmModeResPtr r = 0;
973
974         if ((fd = drmOpen(NULL, busid)) < 0)
975                 return -EINVAL;
976
977         memset(&res, 0, sizeof(struct drm_mode_card_res));
978
979         if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) {
980                 drmClose(fd);
981                 return -errno;
982         }
983
984         drmClose(fd);
985         return 0;
986 #endif
987         return -ENOSYS;
988 }
989
990 drm_public int drmModeCrtcGetGamma(int fd, uint32_t crtc_id, uint32_t size,
991                                                                    uint16_t *red, uint16_t *green,
992                                                                    uint16_t *blue)
993 {
994         struct drm_mode_crtc_lut l;
995
996         memclear(l);
997         l.crtc_id = crtc_id;
998         l.gamma_size = size;
999         l.red = VOID2U64(red);
1000         l.green = VOID2U64(green);
1001         l.blue = VOID2U64(blue);
1002
1003         return DRM_IOCTL(fd, DRM_IOCTL_MODE_GETGAMMA, &l);
1004 }
1005
1006 drm_public int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size,
1007                                                                    const uint16_t *red, const uint16_t *green,
1008                                                                    const uint16_t *blue)
1009 {
1010         struct drm_mode_crtc_lut l;
1011
1012         memclear(l);
1013         l.crtc_id = crtc_id;
1014         l.gamma_size = size;
1015         l.red = VOID2U64(red);
1016         l.green = VOID2U64(green);
1017         l.blue = VOID2U64(blue);
1018
1019         return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETGAMMA, &l);
1020 }
1021
1022 drm_public int drmHandleEvent(int fd, drmEventContextPtr evctx)
1023 {
1024         char buffer[1024];
1025         int len, i;
1026         struct drm_event *e;
1027         struct drm_event_vblank *vblank;
1028         struct drm_event_crtc_sequence *seq;
1029         void *user_data;
1030
1031         /* The DRM read semantics guarantees that we always get only
1032          * complete events. */
1033
1034         len = read(fd, buffer, sizeof buffer);
1035         if (len == 0)
1036                 return 0;
1037         if (len < (int)sizeof *e)
1038                 return -1;
1039
1040         i = 0;
1041         while (i < len) {
1042                 e = (struct drm_event *)(buffer + i);
1043                 switch (e->type) {
1044                 case DRM_EVENT_VBLANK:
1045                         if (evctx->version < 1 ||
1046                             evctx->vblank_handler == NULL)
1047                                 break;
1048                         vblank = (struct drm_event_vblank *) e;
1049                         evctx->vblank_handler(fd,
1050                                               vblank->sequence,
1051                                               vblank->tv_sec,
1052                                               vblank->tv_usec,
1053                                               U642VOID (vblank->user_data));
1054                         break;
1055                 case DRM_EVENT_FLIP_COMPLETE:
1056                         vblank = (struct drm_event_vblank *) e;
1057                         user_data = U642VOID (vblank->user_data);
1058
1059                         if (evctx->version >= 3 && evctx->page_flip_handler2)
1060                                 evctx->page_flip_handler2(fd,
1061                                                          vblank->sequence,
1062                                                          vblank->tv_sec,
1063                                                          vblank->tv_usec,
1064                                                          vblank->crtc_id,
1065                                                          user_data);
1066                         else if (evctx->version >= 2 && evctx->page_flip_handler)
1067                                 evctx->page_flip_handler(fd,
1068                                                          vblank->sequence,
1069                                                          vblank->tv_sec,
1070                                                          vblank->tv_usec,
1071                                                          user_data);
1072                         break;
1073                 case DRM_EVENT_CRTC_SEQUENCE:
1074                         seq = (struct drm_event_crtc_sequence *) e;
1075                         if (evctx->version >= 4 && evctx->sequence_handler)
1076                                 evctx->sequence_handler(fd,
1077                                                         seq->sequence,
1078                                                         seq->time_ns,
1079                                                         seq->user_data);
1080                         break;
1081                 default:
1082                         break;
1083                 }
1084                 i += e->length;
1085         }
1086
1087         return 0;
1088 }
1089
1090 drm_public int drmModePageFlip(int fd, uint32_t crtc_id, uint32_t fb_id,
1091                     uint32_t flags, void *user_data)
1092 {
1093         struct drm_mode_crtc_page_flip flip;
1094
1095         memclear(flip);
1096         flip.fb_id = fb_id;
1097         flip.crtc_id = crtc_id;
1098         flip.user_data = VOID2U64(user_data);
1099         flip.flags = flags;
1100
1101         return DRM_IOCTL(fd, DRM_IOCTL_MODE_PAGE_FLIP, &flip);
1102 }
1103
1104 drm_public int drmModePageFlipTarget(int fd, uint32_t crtc_id, uint32_t fb_id,
1105                           uint32_t flags, void *user_data,
1106                           uint32_t target_vblank)
1107 {
1108         struct drm_mode_crtc_page_flip_target flip_target;
1109
1110         memclear(flip_target);
1111         flip_target.fb_id = fb_id;
1112         flip_target.crtc_id = crtc_id;
1113         flip_target.user_data = VOID2U64(user_data);
1114         flip_target.flags = flags;
1115         flip_target.sequence = target_vblank;
1116
1117         return DRM_IOCTL(fd, DRM_IOCTL_MODE_PAGE_FLIP, &flip_target);
1118 }
1119
1120 drm_public int drmModeSetPlane(int fd, uint32_t plane_id, uint32_t crtc_id,
1121                     uint32_t fb_id, uint32_t flags,
1122                     int32_t crtc_x, int32_t crtc_y,
1123                     uint32_t crtc_w, uint32_t crtc_h,
1124                     uint32_t src_x, uint32_t src_y,
1125                     uint32_t src_w, uint32_t src_h)
1126 {
1127         struct drm_mode_set_plane s;
1128
1129         memclear(s);
1130         s.plane_id = plane_id;
1131         s.crtc_id = crtc_id;
1132         s.fb_id = fb_id;
1133         s.flags = flags;
1134         s.crtc_x = crtc_x;
1135         s.crtc_y = crtc_y;
1136         s.crtc_w = crtc_w;
1137         s.crtc_h = crtc_h;
1138         s.src_x = src_x;
1139         s.src_y = src_y;
1140         s.src_w = src_w;
1141         s.src_h = src_h;
1142
1143         return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETPLANE, &s);
1144 }
1145
1146 drm_public drmModePlanePtr drmModeGetPlane(int fd, uint32_t plane_id)
1147 {
1148         struct drm_mode_get_plane ovr, counts;
1149         drmModePlanePtr r = 0;
1150
1151 retry:
1152         memclear(ovr);
1153         ovr.plane_id = plane_id;
1154         if (drmIoctl(fd, DRM_IOCTL_MODE_GETPLANE, &ovr))
1155                 return 0;
1156
1157         counts = ovr;
1158
1159         if (ovr.count_format_types) {
1160                 ovr.format_type_ptr = VOID2U64(drmMalloc(ovr.count_format_types *
1161                                                          sizeof(uint32_t)));
1162                 if (!ovr.format_type_ptr)
1163                         goto err_allocs;
1164         }
1165
1166         if (drmIoctl(fd, DRM_IOCTL_MODE_GETPLANE, &ovr))
1167                 goto err_allocs;
1168
1169         if (counts.count_format_types < ovr.count_format_types) {
1170                 drmFree(U642VOID(ovr.format_type_ptr));
1171                 goto retry;
1172         }
1173
1174         if (!(r = drmMalloc(sizeof(*r))))
1175                 goto err_allocs;
1176
1177         r->count_formats = ovr.count_format_types;
1178         r->plane_id = ovr.plane_id;
1179         r->crtc_id = ovr.crtc_id;
1180         r->fb_id = ovr.fb_id;
1181         r->possible_crtcs = ovr.possible_crtcs;
1182         r->gamma_size = ovr.gamma_size;
1183         r->formats = drmAllocCpy(U642VOID(ovr.format_type_ptr),
1184                                  ovr.count_format_types, sizeof(uint32_t));
1185         if (ovr.count_format_types && !r->formats) {
1186                 drmFree(r->formats);
1187                 drmFree(r);
1188                 r = 0;
1189         }
1190
1191 err_allocs:
1192         drmFree(U642VOID(ovr.format_type_ptr));
1193
1194         return r;
1195 }
1196
1197 drm_public void drmModeFreePlane(drmModePlanePtr ptr)
1198 {
1199         if (!ptr)
1200                 return;
1201
1202         drmFree(ptr->formats);
1203         drmFree(ptr);
1204 }
1205
1206 drm_public drmModePlaneResPtr drmModeGetPlaneResources(int fd)
1207 {
1208         struct drm_mode_get_plane_res res, counts;
1209         drmModePlaneResPtr r = 0;
1210
1211 retry:
1212         memclear(res);
1213         if (drmIoctl(fd, DRM_IOCTL_MODE_GETPLANERESOURCES, &res))
1214                 return 0;
1215
1216         counts = res;
1217
1218         if (res.count_planes) {
1219                 res.plane_id_ptr = VOID2U64(drmMalloc(res.count_planes *
1220                                                         sizeof(uint32_t)));
1221                 if (!res.plane_id_ptr)
1222                         goto err_allocs;
1223         }
1224
1225         if (drmIoctl(fd, DRM_IOCTL_MODE_GETPLANERESOURCES, &res))
1226                 goto err_allocs;
1227
1228         if (counts.count_planes < res.count_planes) {
1229                 drmFree(U642VOID(res.plane_id_ptr));
1230                 goto retry;
1231         }
1232
1233         if (!(r = drmMalloc(sizeof(*r))))
1234                 goto err_allocs;
1235
1236         r->count_planes = res.count_planes;
1237         r->planes = drmAllocCpy(U642VOID(res.plane_id_ptr),
1238                                   res.count_planes, sizeof(uint32_t));
1239         if (res.count_planes && !r->planes) {
1240                 drmFree(r->planes);
1241                 drmFree(r);
1242                 r = 0;
1243         }
1244
1245 err_allocs:
1246         drmFree(U642VOID(res.plane_id_ptr));
1247
1248         return r;
1249 }
1250
1251 drm_public void drmModeFreePlaneResources(drmModePlaneResPtr ptr)
1252 {
1253         if (!ptr)
1254                 return;
1255
1256         drmFree(ptr->planes);
1257         drmFree(ptr);
1258 }
1259
1260 drm_public drmModeObjectPropertiesPtr drmModeObjectGetProperties(int fd,
1261                                                       uint32_t object_id,
1262                                                       uint32_t object_type)
1263 {
1264         struct drm_mode_obj_get_properties properties;
1265         drmModeObjectPropertiesPtr ret = NULL;
1266         uint32_t count;
1267
1268 retry:
1269         memclear(properties);
1270         properties.obj_id = object_id;
1271         properties.obj_type = object_type;
1272
1273         if (drmIoctl(fd, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, &properties))
1274                 return 0;
1275
1276         count = properties.count_props;
1277
1278         if (count) {
1279                 properties.props_ptr = VOID2U64(drmMalloc(count *
1280                                                           sizeof(uint32_t)));
1281                 if (!properties.props_ptr)
1282                         goto err_allocs;
1283                 properties.prop_values_ptr = VOID2U64(drmMalloc(count *
1284                                                       sizeof(uint64_t)));
1285                 if (!properties.prop_values_ptr)
1286                         goto err_allocs;
1287         }
1288
1289         if (drmIoctl(fd, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, &properties))
1290                 goto err_allocs;
1291
1292         if (count < properties.count_props) {
1293                 drmFree(U642VOID(properties.props_ptr));
1294                 drmFree(U642VOID(properties.prop_values_ptr));
1295                 goto retry;
1296         }
1297         count = properties.count_props;
1298
1299         ret = drmMalloc(sizeof(*ret));
1300         if (!ret)
1301                 goto err_allocs;
1302
1303         ret->count_props = count;
1304         ret->props = drmAllocCpy(U642VOID(properties.props_ptr),
1305                                  count, sizeof(uint32_t));
1306         ret->prop_values = drmAllocCpy(U642VOID(properties.prop_values_ptr),
1307                                        count, sizeof(uint64_t));
1308         if (ret->count_props && (!ret->props || !ret->prop_values)) {
1309                 drmFree(ret->props);
1310                 drmFree(ret->prop_values);
1311                 drmFree(ret);
1312                 ret = NULL;
1313         }
1314
1315 err_allocs:
1316         drmFree(U642VOID(properties.props_ptr));
1317         drmFree(U642VOID(properties.prop_values_ptr));
1318         return ret;
1319 }
1320
1321 drm_public void drmModeFreeObjectProperties(drmModeObjectPropertiesPtr ptr)
1322 {
1323         if (!ptr)
1324                 return;
1325         drmFree(ptr->props);
1326         drmFree(ptr->prop_values);
1327         drmFree(ptr);
1328 }
1329
1330 drm_public int drmModeObjectSetProperty(int fd, uint32_t object_id, uint32_t object_type,
1331                              uint32_t property_id, uint64_t value)
1332 {
1333         struct drm_mode_obj_set_property prop;
1334
1335         memclear(prop);
1336         prop.value = value;
1337         prop.prop_id = property_id;
1338         prop.obj_id = object_id;
1339         prop.obj_type = object_type;
1340
1341         return DRM_IOCTL(fd, DRM_IOCTL_MODE_OBJ_SETPROPERTY, &prop);
1342 }
1343
1344 typedef struct _drmModeAtomicReqItem drmModeAtomicReqItem, *drmModeAtomicReqItemPtr;
1345
1346 struct _drmModeAtomicReqItem {
1347         uint32_t object_id;
1348         uint32_t property_id;
1349         uint64_t value;
1350         uint32_t cursor;
1351 };
1352
1353 struct _drmModeAtomicReq {
1354         uint32_t cursor;
1355         uint32_t size_items;
1356         drmModeAtomicReqItemPtr items;
1357 };
1358
1359 drm_public drmModeAtomicReqPtr drmModeAtomicAlloc(void)
1360 {
1361         drmModeAtomicReqPtr req;
1362
1363         req = drmMalloc(sizeof *req);
1364         if (!req)
1365                 return NULL;
1366
1367         req->items = NULL;
1368         req->cursor = 0;
1369         req->size_items = 0;
1370
1371         return req;
1372 }
1373
1374 drm_public drmModeAtomicReqPtr drmModeAtomicDuplicate(const drmModeAtomicReqPtr old)
1375 {
1376         drmModeAtomicReqPtr new;
1377
1378         if (!old)
1379                 return NULL;
1380
1381         new = drmMalloc(sizeof *new);
1382         if (!new)
1383                 return NULL;
1384
1385         new->cursor = old->cursor;
1386         new->size_items = old->size_items;
1387
1388         if (old->size_items) {
1389                 new->items = drmMalloc(old->size_items * sizeof(*new->items));
1390                 if (!new->items) {
1391                         free(new);
1392                         return NULL;
1393                 }
1394                 memcpy(new->items, old->items,
1395                        old->cursor * sizeof(*new->items));
1396         } else {
1397                 new->items = NULL;
1398         }
1399
1400         return new;
1401 }
1402
1403 drm_public int drmModeAtomicMerge(drmModeAtomicReqPtr base,
1404                                   const drmModeAtomicReqPtr augment)
1405 {
1406         uint32_t i;
1407
1408         if (!base)
1409                 return -EINVAL;
1410
1411         if (!augment || augment->cursor == 0)
1412                 return 0;
1413
1414         if (base->cursor + augment->cursor >= base->size_items) {
1415                 drmModeAtomicReqItemPtr new;
1416                 int saved_size = base->size_items;
1417
1418                 base->size_items = base->cursor + augment->cursor;
1419                 new = realloc(base->items,
1420                               base->size_items * sizeof(*base->items));
1421                 if (!new) {
1422                         base->size_items = saved_size;
1423                         return -ENOMEM;
1424                 }
1425                 base->items = new;
1426         }
1427
1428         memcpy(&base->items[base->cursor], augment->items,
1429                augment->cursor * sizeof(*augment->items));
1430         for (i = base->cursor; i < base->cursor + augment->cursor; i++)
1431                 base->items[i].cursor = i;
1432         base->cursor += augment->cursor;
1433
1434         return 0;
1435 }
1436
1437 drm_public int drmModeAtomicGetCursor(const drmModeAtomicReqPtr req)
1438 {
1439         if (!req)
1440                 return -EINVAL;
1441         return req->cursor;
1442 }
1443
1444 drm_public void drmModeAtomicSetCursor(drmModeAtomicReqPtr req, int cursor)
1445 {
1446         if (req)
1447                 req->cursor = cursor;
1448 }
1449
1450 drm_public int drmModeAtomicAddProperty(drmModeAtomicReqPtr req,
1451                                         uint32_t object_id,
1452                                         uint32_t property_id,
1453                                         uint64_t value)
1454 {
1455         if (!req)
1456                 return -EINVAL;
1457
1458         if (object_id == 0 || property_id == 0)
1459                 return -EINVAL;
1460
1461         if (req->cursor >= req->size_items) {
1462                 const uint32_t item_size_inc = getpagesize() / sizeof(*req->items);
1463                 drmModeAtomicReqItemPtr new;
1464
1465                 req->size_items += item_size_inc;
1466                 new = realloc(req->items, req->size_items * sizeof(*req->items));
1467                 if (!new) {
1468                         req->size_items -= item_size_inc;
1469                         return -ENOMEM;
1470                 }
1471                 req->items = new;
1472         }
1473
1474         req->items[req->cursor].object_id = object_id;
1475         req->items[req->cursor].property_id = property_id;
1476         req->items[req->cursor].value = value;
1477         req->items[req->cursor].cursor = req->cursor;
1478         req->cursor++;
1479
1480         return req->cursor;
1481 }
1482
1483 drm_public void drmModeAtomicFree(drmModeAtomicReqPtr req)
1484 {
1485         if (!req)
1486                 return;
1487
1488         if (req->items)
1489                 drmFree(req->items);
1490         drmFree(req);
1491 }
1492
1493 static int sort_req_list(const void *misc, const void *other)
1494 {
1495         const drmModeAtomicReqItem *first = misc;
1496         const drmModeAtomicReqItem *second = other;
1497
1498         if (first->object_id != second->object_id)
1499                 return first->object_id - second->object_id;
1500         else if (first->property_id != second->property_id)
1501                 return first->property_id - second->property_id;
1502         else
1503                 return first->cursor - second->cursor;
1504 }
1505
1506 drm_public int drmModeAtomicCommit(int fd, const drmModeAtomicReqPtr req,
1507                                    uint32_t flags, void *user_data)
1508 {
1509         drmModeAtomicReqPtr sorted;
1510         struct drm_mode_atomic atomic;
1511         uint32_t *objs_ptr = NULL;
1512         uint32_t *count_props_ptr = NULL;
1513         uint32_t *props_ptr = NULL;
1514         uint64_t *prop_values_ptr = NULL;
1515         uint32_t last_obj_id = 0;
1516         uint32_t i;
1517         int obj_idx = -1;
1518         int ret = -1;
1519
1520         if (!req)
1521                 return -EINVAL;
1522
1523         if (req->cursor == 0)
1524                 return 0;
1525
1526         sorted = drmModeAtomicDuplicate(req);
1527         if (sorted == NULL)
1528                 return -ENOMEM;
1529
1530         memclear(atomic);
1531
1532         /* Sort the list by object ID, then by property ID. */
1533         qsort(sorted->items, sorted->cursor, sizeof(*sorted->items),
1534               sort_req_list);
1535
1536         /* Now the list is sorted, eliminate duplicate property sets. */
1537         for (i = 0; i < sorted->cursor; i++) {
1538                 if (sorted->items[i].object_id != last_obj_id) {
1539                         atomic.count_objs++;
1540                         last_obj_id = sorted->items[i].object_id;
1541                 }
1542
1543                 if (i == sorted->cursor - 1)
1544                         continue;
1545
1546                 if (sorted->items[i].object_id != sorted->items[i + 1].object_id ||
1547                     sorted->items[i].property_id != sorted->items[i + 1].property_id)
1548                         continue;
1549
1550                 memmove(&sorted->items[i], &sorted->items[i + 1],
1551                         (sorted->cursor - i - 1) * sizeof(*sorted->items));
1552                 sorted->cursor--;
1553         }
1554
1555         for (i = 0; i < sorted->cursor; i++)
1556                 sorted->items[i].cursor = i;
1557
1558         objs_ptr = drmMalloc(atomic.count_objs * sizeof objs_ptr[0]);
1559         if (!objs_ptr) {
1560                 errno = ENOMEM;
1561                 goto out;
1562         }
1563
1564         count_props_ptr = drmMalloc(atomic.count_objs * sizeof count_props_ptr[0]);
1565         if (!count_props_ptr) {
1566                 errno = ENOMEM;
1567                 goto out;
1568         }
1569
1570         props_ptr = drmMalloc(sorted->cursor * sizeof props_ptr[0]);
1571         if (!props_ptr) {
1572                 errno = ENOMEM;
1573                 goto out;
1574         }
1575
1576         prop_values_ptr = drmMalloc(sorted->cursor * sizeof prop_values_ptr[0]);
1577         if (!prop_values_ptr) {
1578                 errno = ENOMEM;
1579                 goto out;
1580         }
1581
1582         for (i = 0, last_obj_id = 0; i < sorted->cursor; i++) {
1583                 if (sorted->items[i].object_id != last_obj_id) {
1584                         obj_idx++;
1585                         objs_ptr[obj_idx] = sorted->items[i].object_id;
1586                         last_obj_id = objs_ptr[obj_idx];
1587                 }
1588
1589                 count_props_ptr[obj_idx]++;
1590                 props_ptr[i] = sorted->items[i].property_id;
1591                 prop_values_ptr[i] = sorted->items[i].value;
1592
1593         }
1594
1595         atomic.flags = flags;
1596         atomic.objs_ptr = VOID2U64(objs_ptr);
1597         atomic.count_props_ptr = VOID2U64(count_props_ptr);
1598         atomic.props_ptr = VOID2U64(props_ptr);
1599         atomic.prop_values_ptr = VOID2U64(prop_values_ptr);
1600         atomic.user_data = VOID2U64(user_data);
1601
1602         ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_ATOMIC, &atomic);
1603
1604 out:
1605         drmFree(objs_ptr);
1606         drmFree(count_props_ptr);
1607         drmFree(props_ptr);
1608         drmFree(prop_values_ptr);
1609         drmModeAtomicFree(sorted);
1610
1611         return ret;
1612 }
1613
1614 drm_public int
1615 drmModeCreatePropertyBlob(int fd, const void *data, size_t length,
1616                                      uint32_t *id)
1617 {
1618         struct drm_mode_create_blob create;
1619         int ret;
1620
1621         if (length >= 0xffffffff)
1622                 return -ERANGE;
1623
1624         memclear(create);
1625
1626         create.length = length;
1627         create.data = (uintptr_t) data;
1628         create.blob_id = 0;
1629         *id = 0;
1630
1631         ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_CREATEPROPBLOB, &create);
1632         if (ret != 0)
1633                 return ret;
1634
1635         *id = create.blob_id;
1636         return 0;
1637 }
1638
1639 drm_public int
1640 drmModeDestroyPropertyBlob(int fd, uint32_t id)
1641 {
1642         struct drm_mode_destroy_blob destroy;
1643
1644         memclear(destroy);
1645         destroy.blob_id = id;
1646         return DRM_IOCTL(fd, DRM_IOCTL_MODE_DESTROYPROPBLOB, &destroy);
1647 }
1648
1649 drm_public int
1650 drmModeCreateLease(int fd, const uint32_t *objects, int num_objects, int flags,
1651                    uint32_t *lessee_id)
1652 {
1653         struct drm_mode_create_lease create;
1654         int ret;
1655
1656         memclear(create);
1657         create.object_ids = (uintptr_t) objects;
1658         create.object_count = num_objects;
1659         create.flags = flags;
1660
1661         ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_CREATE_LEASE, &create);
1662         if (ret == 0) {
1663                 *lessee_id = create.lessee_id;
1664                 return create.fd;
1665         }
1666         return -errno;
1667 }
1668
1669 drm_public drmModeLesseeListPtr
1670 drmModeListLessees(int fd)
1671 {
1672         struct drm_mode_list_lessees list;
1673         uint32_t count;
1674         drmModeLesseeListPtr ret;
1675
1676         memclear(list);
1677
1678         if (DRM_IOCTL(fd, DRM_IOCTL_MODE_LIST_LESSEES, &list))
1679                 return NULL;
1680
1681         count = list.count_lessees;
1682         ret = drmMalloc(sizeof (drmModeLesseeListRes) + count * sizeof (ret->lessees[0]));
1683         if (!ret)
1684                 return NULL;
1685
1686         list.lessees_ptr = VOID2U64(&ret->lessees[0]);
1687         if (DRM_IOCTL(fd, DRM_IOCTL_MODE_LIST_LESSEES, &list)) {
1688                 drmFree(ret);
1689                 return NULL;
1690         }
1691
1692         ret->count = count;
1693         return ret;
1694 }
1695
1696 drm_public drmModeObjectListPtr
1697 drmModeGetLease(int fd)
1698 {
1699         struct drm_mode_get_lease get;
1700         uint32_t count;
1701         drmModeObjectListPtr ret;
1702
1703         memclear(get);
1704
1705         if (DRM_IOCTL(fd, DRM_IOCTL_MODE_GET_LEASE, &get))
1706                 return NULL;
1707
1708         count = get.count_objects;
1709         ret = drmMalloc(sizeof (drmModeObjectListRes) + count * sizeof (ret->objects[0]));
1710         if (!ret)
1711                 return NULL;
1712
1713         get.objects_ptr = VOID2U64(&ret->objects[0]);
1714         if (DRM_IOCTL(fd, DRM_IOCTL_MODE_GET_LEASE, &get)) {
1715                 drmFree(ret);
1716                 return NULL;
1717         }
1718
1719         ret->count = count;
1720         return ret;
1721 }
1722
1723 drm_public int
1724 drmModeRevokeLease(int fd, uint32_t lessee_id)
1725 {
1726         struct drm_mode_revoke_lease revoke;
1727         int ret;
1728
1729         memclear(revoke);
1730
1731         revoke.lessee_id = lessee_id;
1732
1733         ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_REVOKE_LEASE, &revoke);
1734         if (ret == 0)
1735                 return 0;
1736         return -errno;
1737 }
1738
1739 drm_public drmModeFB2Ptr
1740 drmModeGetFB2(int fd, uint32_t fb_id)
1741 {
1742         struct drm_mode_fb_cmd2 get = {
1743                 .fb_id = fb_id,
1744         };
1745         drmModeFB2Ptr ret;
1746         int err;
1747
1748         err = DRM_IOCTL(fd, DRM_IOCTL_MODE_GETFB2, &get);
1749         if (err != 0)
1750                 return NULL;
1751
1752         ret = drmMalloc(sizeof(drmModeFB2));
1753         if (!ret)
1754                 return NULL;
1755
1756         ret->fb_id = fb_id;
1757         ret->width = get.width;
1758         ret->height = get.height;
1759         ret->pixel_format = get.pixel_format;
1760         ret->flags = get.flags;
1761         ret->modifier = get.modifier[0];
1762         memcpy(ret->handles, get.handles, sizeof(uint32_t) * 4);
1763         memcpy(ret->pitches, get.pitches, sizeof(uint32_t) * 4);
1764         memcpy(ret->offsets, get.offsets, sizeof(uint32_t) * 4);
1765
1766         return ret;
1767 }
1768
1769 drm_public void drmModeFreeFB2(drmModeFB2Ptr ptr)
1770 {
1771         drmFree(ptr);
1772 }
1773
1774 drm_public const char *
1775 drmModeGetConnectorTypeName(uint32_t connector_type)
1776 {
1777         /* Keep the strings in sync with the kernel's drm_connector_enum_list in
1778          * drm_connector.c. */
1779         switch (connector_type) {
1780         case DRM_MODE_CONNECTOR_Unknown:
1781                 return "Unknown";
1782         case DRM_MODE_CONNECTOR_VGA:
1783                 return "VGA";
1784         case DRM_MODE_CONNECTOR_DVII:
1785                 return "DVI-I";
1786         case DRM_MODE_CONNECTOR_DVID:
1787                 return "DVI-D";
1788         case DRM_MODE_CONNECTOR_DVIA:
1789                 return "DVI-A";
1790         case DRM_MODE_CONNECTOR_Composite:
1791                 return "Composite";
1792         case DRM_MODE_CONNECTOR_SVIDEO:
1793                 return "SVIDEO";
1794         case DRM_MODE_CONNECTOR_LVDS:
1795                 return "LVDS";
1796         case DRM_MODE_CONNECTOR_Component:
1797                 return "Component";
1798         case DRM_MODE_CONNECTOR_9PinDIN:
1799                 return "DIN";
1800         case DRM_MODE_CONNECTOR_DisplayPort:
1801                 return "DP";
1802         case DRM_MODE_CONNECTOR_HDMIA:
1803                 return "HDMI-A";
1804         case DRM_MODE_CONNECTOR_HDMIB:
1805                 return "HDMI-B";
1806         case DRM_MODE_CONNECTOR_TV:
1807                 return "TV";
1808         case DRM_MODE_CONNECTOR_eDP:
1809                 return "eDP";
1810         case DRM_MODE_CONNECTOR_VIRTUAL:
1811                 return "Virtual";
1812         case DRM_MODE_CONNECTOR_DSI:
1813                 return "DSI";
1814         case DRM_MODE_CONNECTOR_DPI:
1815                 return "DPI";
1816         case DRM_MODE_CONNECTOR_WRITEBACK:
1817                 return "Writeback";
1818         case DRM_MODE_CONNECTOR_SPI:
1819                 return "SPI";
1820         case DRM_MODE_CONNECTOR_USB:
1821                 return "USB";
1822         default:
1823                 return NULL;
1824         }
1825 }
1826
1827 drm_public int
1828 drmModeCreateDumbBuffer(int fd, uint32_t width, uint32_t height, uint32_t bpp,
1829                         uint32_t flags, uint32_t *handle, uint32_t *pitch,
1830                         uint64_t *size)
1831 {
1832         int ret;
1833         struct drm_mode_create_dumb create = {
1834                 .width = width,
1835                 .height = height,
1836                 .bpp = bpp,
1837                 .flags = flags,
1838         };
1839
1840         ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create);
1841         if (ret != 0)
1842                 return ret;
1843
1844         *handle = create.handle;
1845         *pitch = create.pitch;
1846         *size = create.size;
1847         return 0;
1848 }
1849
1850 drm_public int
1851 drmModeDestroyDumbBuffer(int fd, uint32_t handle)
1852 {
1853         struct drm_mode_destroy_dumb destroy = {
1854                 .handle = handle,
1855         };
1856
1857         return DRM_IOCTL(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy);
1858 }
1859
1860 drm_public int
1861 drmModeMapDumbBuffer(int fd, uint32_t handle, uint64_t *offset)
1862 {
1863         int ret;
1864         struct drm_mode_map_dumb map = {
1865                 .handle = handle,
1866         };
1867
1868         ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_MAP_DUMB, &map);
1869         if (ret != 0)
1870                 return ret;
1871
1872         *offset = map.offset;
1873         return 0;
1874 }