3 * Header for DRM modesetting interface.
5 * \author Jakob Bornecrantz <wallbraker@gmail.com>
7 * \par Acknowledgements:
8 * Feb 2007, Dave Airlie <airlied@linux.ie>
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>
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:
23 * The above copyright notice and this permission notice shall be included in
24 * all copies or substantial portions of the Software.
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
39 #include <sys/ioctl.h>
42 #include <sys/types.h>
44 #include <sys/sysctl.h>
49 #include "libdrm_macros.h"
50 #include "xf86drmMode.h"
58 #define memclear(s) memset(&s, 0, sizeof(s))
60 #define U642VOID(x) ((void *)(unsigned long)(x))
61 #define VOID2U64(x) ((uint64_t)(unsigned long)(x))
63 static inline int DRM_IOCTL(int fd
, unsigned long cmd
, void *arg
)
65 int ret
= drmIoctl(fd
, cmd
, arg
);
66 return ret
< 0 ? -errno
: ret
;
73 static void* drmAllocCpy(char *array
, int count
, int entry_size
)
78 if (!count
|| !array
|| !entry_size
)
81 if (!(r
= drmMalloc(count
*entry_size
)))
84 for (i
= 0; i
< count
; i
++)
85 memcpy(r
+(entry_size
*i
), array
+(entry_size
*i
), entry_size
);
91 * A couple of free functions.
94 drm_public
void drmModeFreeModeInfo(drmModeModeInfoPtr ptr
)
102 drm_public
void drmModeFreeResources(drmModeResPtr ptr
)
109 drmFree(ptr
->connectors
);
110 drmFree(ptr
->encoders
);
114 drm_public
void drmModeFreeFB(drmModeFBPtr ptr
)
119 /* we might add more frees later. */
123 drm_public
void drmModeFreeCrtc(drmModeCrtcPtr ptr
)
131 drm_public
void drmModeFreeConnector(drmModeConnectorPtr ptr
)
136 drmFree(ptr
->encoders
);
137 drmFree(ptr
->prop_values
);
143 drm_public
void drmModeFreeEncoder(drmModeEncoderPtr ptr
)
149 * ModeSetting functions.
152 drm_public
int drmIsKMS(int fd
)
154 struct drm_mode_card_res res
= {0};
156 if (drmIoctl(fd
, DRM_IOCTL_MODE_GETRESOURCES
, &res
) != 0)
159 return res
.count_crtcs
> 0 && res
.count_connectors
> 0 && res
.count_encoders
> 0;
162 drm_public drmModeResPtr
drmModeGetResources(int fd
)
164 struct drm_mode_card_res res
, counts
;
169 if (drmIoctl(fd
, DRM_IOCTL_MODE_GETRESOURCES
, &res
))
175 res
.fb_id_ptr
= VOID2U64(drmMalloc(res
.count_fbs
*sizeof(uint32_t)));
179 if (res
.count_crtcs
) {
180 res
.crtc_id_ptr
= VOID2U64(drmMalloc(res
.count_crtcs
*sizeof(uint32_t)));
181 if (!res
.crtc_id_ptr
)
184 if (res
.count_connectors
) {
185 res
.connector_id_ptr
= VOID2U64(drmMalloc(res
.count_connectors
*sizeof(uint32_t)));
186 if (!res
.connector_id_ptr
)
189 if (res
.count_encoders
) {
190 res
.encoder_id_ptr
= VOID2U64(drmMalloc(res
.count_encoders
*sizeof(uint32_t)));
191 if (!res
.encoder_id_ptr
)
195 if (drmIoctl(fd
, DRM_IOCTL_MODE_GETRESOURCES
, &res
))
198 /* The number of available connectors and etc may have changed with a
199 * hotplug event in between the ioctls, in which case the field is
200 * silently ignored by the kernel.
202 if (counts
.count_fbs
< res
.count_fbs
||
203 counts
.count_crtcs
< res
.count_crtcs
||
204 counts
.count_connectors
< res
.count_connectors
||
205 counts
.count_encoders
< res
.count_encoders
)
207 drmFree(U642VOID(res
.fb_id_ptr
));
208 drmFree(U642VOID(res
.crtc_id_ptr
));
209 drmFree(U642VOID(res
.connector_id_ptr
));
210 drmFree(U642VOID(res
.encoder_id_ptr
));
218 if (!(r
= drmMalloc(sizeof(*r
))))
221 r
->min_width
= res
.min_width
;
222 r
->max_width
= res
.max_width
;
223 r
->min_height
= res
.min_height
;
224 r
->max_height
= res
.max_height
;
225 r
->count_fbs
= res
.count_fbs
;
226 r
->count_crtcs
= res
.count_crtcs
;
227 r
->count_connectors
= res
.count_connectors
;
228 r
->count_encoders
= res
.count_encoders
;
230 r
->fbs
= drmAllocCpy(U642VOID(res
.fb_id_ptr
), res
.count_fbs
, sizeof(uint32_t));
231 r
->crtcs
= drmAllocCpy(U642VOID(res
.crtc_id_ptr
), res
.count_crtcs
, sizeof(uint32_t));
232 r
->connectors
= drmAllocCpy(U642VOID(res
.connector_id_ptr
), res
.count_connectors
, sizeof(uint32_t));
233 r
->encoders
= drmAllocCpy(U642VOID(res
.encoder_id_ptr
), res
.count_encoders
, sizeof(uint32_t));
234 if ((res
.count_fbs
&& !r
->fbs
) ||
235 (res
.count_crtcs
&& !r
->crtcs
) ||
236 (res
.count_connectors
&& !r
->connectors
) ||
237 (res
.count_encoders
&& !r
->encoders
))
241 drmFree(r
->connectors
);
242 drmFree(r
->encoders
);
248 drmFree(U642VOID(res
.fb_id_ptr
));
249 drmFree(U642VOID(res
.crtc_id_ptr
));
250 drmFree(U642VOID(res
.connector_id_ptr
));
251 drmFree(U642VOID(res
.encoder_id_ptr
));
257 drm_public
int drmModeAddFB(int fd
, uint32_t width
, uint32_t height
, uint8_t depth
,
258 uint8_t bpp
, uint32_t pitch
, uint32_t bo_handle
,
261 struct drm_mode_fb_cmd f
;
270 f
.handle
= bo_handle
;
272 if ((ret
= DRM_IOCTL(fd
, DRM_IOCTL_MODE_ADDFB
, &f
)))
279 drm_public
int drmModeAddFB2WithModifiers(int fd
, uint32_t width
,
280 uint32_t height
, uint32_t pixel_format
, const uint32_t bo_handles
[4],
281 const uint32_t pitches
[4], const uint32_t offsets
[4],
282 const uint64_t modifier
[4], uint32_t *buf_id
, uint32_t flags
)
284 struct drm_mode_fb_cmd2 f
;
290 f
.pixel_format
= pixel_format
;
292 memcpy(f
.handles
, bo_handles
, 4 * sizeof(bo_handles
[0]));
293 memcpy(f
.pitches
, pitches
, 4 * sizeof(pitches
[0]));
294 memcpy(f
.offsets
, offsets
, 4 * sizeof(offsets
[0]));
296 memcpy(f
.modifier
, modifier
, 4 * sizeof(modifier
[0]));
298 if ((ret
= DRM_IOCTL(fd
, DRM_IOCTL_MODE_ADDFB2
, &f
)))
305 drm_public
int drmModeAddFB2(int fd
, uint32_t width
, uint32_t height
,
306 uint32_t pixel_format
, const uint32_t bo_handles
[4],
307 const uint32_t pitches
[4], const uint32_t offsets
[4],
308 uint32_t *buf_id
, uint32_t flags
)
310 return drmModeAddFB2WithModifiers(fd
, width
, height
,
311 pixel_format
, bo_handles
,
312 pitches
, offsets
, NULL
,
316 drm_public
int drmModeRmFB(int fd
, uint32_t bufferId
)
318 return DRM_IOCTL(fd
, DRM_IOCTL_MODE_RMFB
, &bufferId
);
321 drm_public drmModeFBPtr
drmModeGetFB(int fd
, uint32_t buf
)
323 struct drm_mode_fb_cmd info
;
329 if (drmIoctl(fd
, DRM_IOCTL_MODE_GETFB
, &info
))
332 if (!(r
= drmMalloc(sizeof(*r
))))
335 r
->fb_id
= info
.fb_id
;
336 r
->width
= info
.width
;
337 r
->height
= info
.height
;
338 r
->pitch
= info
.pitch
;
340 r
->handle
= info
.handle
;
341 r
->depth
= info
.depth
;
346 drm_public
int drmModeDirtyFB(int fd
, uint32_t bufferId
,
347 drmModeClipPtr clips
, uint32_t num_clips
)
349 struct drm_mode_fb_dirty_cmd dirty
;
352 dirty
.fb_id
= bufferId
;
353 dirty
.clips_ptr
= VOID2U64(clips
);
354 dirty
.num_clips
= num_clips
;
356 return DRM_IOCTL(fd
, DRM_IOCTL_MODE_DIRTYFB
, &dirty
);
363 drm_public drmModeCrtcPtr
drmModeGetCrtc(int fd
, uint32_t crtcId
)
365 struct drm_mode_crtc crtc
;
369 crtc
.crtc_id
= crtcId
;
371 if (drmIoctl(fd
, DRM_IOCTL_MODE_GETCRTC
, &crtc
))
378 if (!(r
= drmMalloc(sizeof(*r
))))
381 r
->crtc_id
= crtc
.crtc_id
;
384 r
->mode_valid
= crtc
.mode_valid
;
386 memcpy(&r
->mode
, &crtc
.mode
, sizeof(struct drm_mode_modeinfo
));
387 r
->width
= crtc
.mode
.hdisplay
;
388 r
->height
= crtc
.mode
.vdisplay
;
390 r
->buffer_id
= crtc
.fb_id
;
391 r
->gamma_size
= crtc
.gamma_size
;
395 drm_public
int drmModeSetCrtc(int fd
, uint32_t crtcId
, uint32_t bufferId
,
396 uint32_t x
, uint32_t y
, uint32_t *connectors
, int count
,
397 drmModeModeInfoPtr mode
)
399 struct drm_mode_crtc crtc
;
404 crtc
.crtc_id
= crtcId
;
405 crtc
.fb_id
= bufferId
;
406 crtc
.set_connectors_ptr
= VOID2U64(connectors
);
407 crtc
.count_connectors
= count
;
409 memcpy(&crtc
.mode
, mode
, sizeof(struct drm_mode_modeinfo
));
413 return DRM_IOCTL(fd
, DRM_IOCTL_MODE_SETCRTC
, &crtc
);
417 * Cursor manipulation
420 drm_public
int drmModeSetCursor(int fd
, uint32_t crtcId
, uint32_t bo_handle
,
421 uint32_t width
, uint32_t height
)
423 struct drm_mode_cursor arg
;
426 arg
.flags
= DRM_MODE_CURSOR_BO
;
427 arg
.crtc_id
= crtcId
;
430 arg
.handle
= bo_handle
;
432 return DRM_IOCTL(fd
, DRM_IOCTL_MODE_CURSOR
, &arg
);
435 drm_public
int drmModeSetCursor2(int fd
, uint32_t crtcId
, uint32_t bo_handle
,
436 uint32_t width
, uint32_t height
, int32_t hot_x
,
439 struct drm_mode_cursor2 arg
;
442 arg
.flags
= DRM_MODE_CURSOR_BO
;
443 arg
.crtc_id
= crtcId
;
446 arg
.handle
= bo_handle
;
450 return DRM_IOCTL(fd
, DRM_IOCTL_MODE_CURSOR2
, &arg
);
453 drm_public
int drmModeMoveCursor(int fd
, uint32_t crtcId
, int x
, int y
)
455 struct drm_mode_cursor arg
;
458 arg
.flags
= DRM_MODE_CURSOR_MOVE
;
459 arg
.crtc_id
= crtcId
;
463 return DRM_IOCTL(fd
, DRM_IOCTL_MODE_CURSOR
, &arg
);
469 drm_public drmModeEncoderPtr
drmModeGetEncoder(int fd
, uint32_t encoder_id
)
471 struct drm_mode_get_encoder enc
;
472 drmModeEncoderPtr r
= NULL
;
475 enc
.encoder_id
= encoder_id
;
477 if (drmIoctl(fd
, DRM_IOCTL_MODE_GETENCODER
, &enc
))
480 if (!(r
= drmMalloc(sizeof(*r
))))
483 r
->encoder_id
= enc
.encoder_id
;
484 r
->crtc_id
= enc
.crtc_id
;
485 r
->encoder_type
= enc
.encoder_type
;
486 r
->possible_crtcs
= enc
.possible_crtcs
;
487 r
->possible_clones
= enc
.possible_clones
;
493 * Connector manipulation
495 static drmModeConnectorPtr
496 _drmModeGetConnector(int fd
, uint32_t connector_id
, int probe
)
498 struct drm_mode_get_connector conn
, counts
;
499 drmModeConnectorPtr r
= NULL
;
500 struct drm_mode_modeinfo stack_mode
;
503 conn
.connector_id
= connector_id
;
505 conn
.count_modes
= 1;
506 conn
.modes_ptr
= VOID2U64(&stack_mode
);
509 if (drmIoctl(fd
, DRM_IOCTL_MODE_GETCONNECTOR
, &conn
))
515 if (conn
.count_props
) {
516 conn
.props_ptr
= VOID2U64(drmMalloc(conn
.count_props
*sizeof(uint32_t)));
519 conn
.prop_values_ptr
= VOID2U64(drmMalloc(conn
.count_props
*sizeof(uint64_t)));
520 if (!conn
.prop_values_ptr
)
524 if (conn
.count_modes
) {
525 conn
.modes_ptr
= VOID2U64(drmMalloc(conn
.count_modes
*sizeof(struct drm_mode_modeinfo
)));
529 conn
.count_modes
= 1;
530 conn
.modes_ptr
= VOID2U64(&stack_mode
);
533 if (conn
.count_encoders
) {
534 conn
.encoders_ptr
= VOID2U64(drmMalloc(conn
.count_encoders
*sizeof(uint32_t)));
535 if (!conn
.encoders_ptr
)
539 if (drmIoctl(fd
, DRM_IOCTL_MODE_GETCONNECTOR
, &conn
))
542 /* The number of available connectors and etc may have changed with a
543 * hotplug event in between the ioctls, in which case the field is
544 * silently ignored by the kernel.
546 if (counts
.count_props
< conn
.count_props
||
547 counts
.count_modes
< conn
.count_modes
||
548 counts
.count_encoders
< conn
.count_encoders
) {
549 drmFree(U642VOID(conn
.props_ptr
));
550 drmFree(U642VOID(conn
.prop_values_ptr
));
551 if (U642VOID(conn
.modes_ptr
) != &stack_mode
)
552 drmFree(U642VOID(conn
.modes_ptr
));
553 drmFree(U642VOID(conn
.encoders_ptr
));
558 if(!(r
= drmMalloc(sizeof(*r
)))) {
562 r
->connector_id
= conn
.connector_id
;
563 r
->encoder_id
= conn
.encoder_id
;
564 r
->connection
= conn
.connection
;
565 r
->mmWidth
= conn
.mm_width
;
566 r
->mmHeight
= conn
.mm_height
;
567 /* convert subpixel from kernel to userspace */
568 r
->subpixel
= conn
.subpixel
+ 1;
569 r
->count_modes
= conn
.count_modes
;
570 r
->count_props
= conn
.count_props
;
571 r
->props
= drmAllocCpy(U642VOID(conn
.props_ptr
), conn
.count_props
, sizeof(uint32_t));
572 r
->prop_values
= drmAllocCpy(U642VOID(conn
.prop_values_ptr
), conn
.count_props
, sizeof(uint64_t));
573 r
->modes
= drmAllocCpy(U642VOID(conn
.modes_ptr
), conn
.count_modes
, sizeof(struct drm_mode_modeinfo
));
574 r
->count_encoders
= conn
.count_encoders
;
575 r
->encoders
= drmAllocCpy(U642VOID(conn
.encoders_ptr
), conn
.count_encoders
, sizeof(uint32_t));
576 r
->connector_type
= conn
.connector_type
;
577 r
->connector_type_id
= conn
.connector_type_id
;
579 if ((r
->count_props
&& !r
->props
) ||
580 (r
->count_props
&& !r
->prop_values
) ||
581 (r
->count_modes
&& !r
->modes
) ||
582 (r
->count_encoders
&& !r
->encoders
)) {
584 drmFree(r
->prop_values
);
586 drmFree(r
->encoders
);
592 drmFree(U642VOID(conn
.prop_values_ptr
));
593 drmFree(U642VOID(conn
.props_ptr
));
594 if (U642VOID(conn
.modes_ptr
) != &stack_mode
)
595 drmFree(U642VOID(conn
.modes_ptr
));
596 drmFree(U642VOID(conn
.encoders_ptr
));
601 drm_public drmModeConnectorPtr
drmModeGetConnector(int fd
, uint32_t connector_id
)
603 return _drmModeGetConnector(fd
, connector_id
, 1);
606 drm_public drmModeConnectorPtr
drmModeGetConnectorCurrent(int fd
, uint32_t connector_id
)
608 return _drmModeGetConnector(fd
, connector_id
, 0);
611 drm_public
int drmModeAttachMode(int fd
, uint32_t connector_id
, drmModeModeInfoPtr mode_info
)
613 struct drm_mode_mode_cmd res
;
616 memcpy(&res
.mode
, mode_info
, sizeof(struct drm_mode_modeinfo
));
617 res
.connector_id
= connector_id
;
619 return DRM_IOCTL(fd
, DRM_IOCTL_MODE_ATTACHMODE
, &res
);
622 drm_public
int drmModeDetachMode(int fd
, uint32_t connector_id
, drmModeModeInfoPtr mode_info
)
624 struct drm_mode_mode_cmd res
;
627 memcpy(&res
.mode
, mode_info
, sizeof(struct drm_mode_modeinfo
));
628 res
.connector_id
= connector_id
;
630 return DRM_IOCTL(fd
, DRM_IOCTL_MODE_DETACHMODE
, &res
);
633 drm_public drmModePropertyPtr
drmModeGetProperty(int fd
, uint32_t property_id
)
635 struct drm_mode_get_property prop
;
636 drmModePropertyPtr r
;
639 prop
.prop_id
= property_id
;
641 if (drmIoctl(fd
, DRM_IOCTL_MODE_GETPROPERTY
, &prop
))
644 if (prop
.count_values
)
645 prop
.values_ptr
= VOID2U64(drmMalloc(prop
.count_values
* sizeof(uint64_t)));
647 if (prop
.count_enum_blobs
&& (prop
.flags
& (DRM_MODE_PROP_ENUM
| DRM_MODE_PROP_BITMASK
)))
648 prop
.enum_blob_ptr
= VOID2U64(drmMalloc(prop
.count_enum_blobs
* sizeof(struct drm_mode_property_enum
)));
650 if (prop
.count_enum_blobs
&& (prop
.flags
& DRM_MODE_PROP_BLOB
)) {
651 prop
.values_ptr
= VOID2U64(drmMalloc(prop
.count_enum_blobs
* sizeof(uint32_t)));
652 prop
.enum_blob_ptr
= VOID2U64(drmMalloc(prop
.count_enum_blobs
* sizeof(uint32_t)));
655 if (drmIoctl(fd
, DRM_IOCTL_MODE_GETPROPERTY
, &prop
)) {
660 if (!(r
= drmMalloc(sizeof(*r
))))
663 r
->prop_id
= prop
.prop_id
;
664 r
->count_values
= prop
.count_values
;
666 r
->flags
= prop
.flags
;
667 if (prop
.count_values
)
668 r
->values
= drmAllocCpy(U642VOID(prop
.values_ptr
), prop
.count_values
, sizeof(uint64_t));
669 if (prop
.flags
& (DRM_MODE_PROP_ENUM
| DRM_MODE_PROP_BITMASK
)) {
670 r
->count_enums
= prop
.count_enum_blobs
;
671 r
->enums
= drmAllocCpy(U642VOID(prop
.enum_blob_ptr
), prop
.count_enum_blobs
, sizeof(struct drm_mode_property_enum
));
672 } else if (prop
.flags
& DRM_MODE_PROP_BLOB
) {
673 r
->values
= drmAllocCpy(U642VOID(prop
.values_ptr
), prop
.count_enum_blobs
, sizeof(uint32_t));
674 r
->blob_ids
= drmAllocCpy(U642VOID(prop
.enum_blob_ptr
), prop
.count_enum_blobs
, sizeof(uint32_t));
675 r
->count_blobs
= prop
.count_enum_blobs
;
677 strncpy(r
->name
, prop
.name
, DRM_PROP_NAME_LEN
);
678 r
->name
[DRM_PROP_NAME_LEN
-1] = 0;
681 drmFree(U642VOID(prop
.values_ptr
));
682 drmFree(U642VOID(prop
.enum_blob_ptr
));
687 drm_public
void drmModeFreeProperty(drmModePropertyPtr ptr
)
692 drmFree(ptr
->values
);
694 drmFree(ptr
->blob_ids
);
698 drm_public drmModePropertyBlobPtr
drmModeGetPropertyBlob(int fd
,
701 struct drm_mode_get_blob blob
;
702 drmModePropertyBlobPtr r
;
705 blob
.blob_id
= blob_id
;
707 if (drmIoctl(fd
, DRM_IOCTL_MODE_GETPROPBLOB
, &blob
))
711 blob
.data
= VOID2U64(drmMalloc(blob
.length
));
713 if (drmIoctl(fd
, DRM_IOCTL_MODE_GETPROPBLOB
, &blob
)) {
718 if (!(r
= drmMalloc(sizeof(*r
))))
721 r
->id
= blob
.blob_id
;
722 r
->length
= blob
.length
;
723 r
->data
= drmAllocCpy(U642VOID(blob
.data
), 1, blob
.length
);
726 drmFree(U642VOID(blob
.data
));
730 drm_public
void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr
)
739 drm_public
int drmModeConnectorSetProperty(int fd
, uint32_t connector_id
,
740 uint32_t property_id
,
743 struct drm_mode_connector_set_property osp
;
746 osp
.connector_id
= connector_id
;
747 osp
.prop_id
= property_id
;
750 return DRM_IOCTL(fd
, DRM_IOCTL_MODE_SETPROPERTY
, &osp
);
754 * checks if a modesetting capable driver has attached to the pci id
755 * returns 0 if modesetting supported.
756 * -EINVAL or invalid bus id
757 * -ENOSYS if no modesetting support
759 drm_public
int drmCheckModesettingSupported(const char *busid
)
761 #if defined (__linux__)
762 char pci_dev_dir
[1024];
763 int domain
, bus
, dev
, func
;
768 ret
= sscanf(busid
, "pci:%04x:%02x:%02x.%d", &domain
, &bus
, &dev
, &func
);
772 sprintf(pci_dev_dir
, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/drm",
773 domain
, bus
, dev
, func
);
775 sysdir
= opendir(pci_dev_dir
);
777 dent
= readdir(sysdir
);
779 if (!strncmp(dent
->d_name
, "controlD", 8)) {
784 dent
= readdir(sysdir
);
791 sprintf(pci_dev_dir
, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/",
792 domain
, bus
, dev
, func
);
794 sysdir
= opendir(pci_dev_dir
);
798 dent
= readdir(sysdir
);
800 if (!strncmp(dent
->d_name
, "drm:controlD", 12)) {
805 dent
= readdir(sysdir
);
811 #elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
814 int i
, modesetting
, ret
;
817 /* How many GPUs do we expect in the machine ? */
818 for (i
= 0; i
< 10; i
++) {
819 snprintf(oid
, sizeof(oid
), "hw.dri.%d.busid", i
);
820 len
= sizeof(sbusid
);
821 ret
= sysctlbyname(oid
, sbusid
, &len
, NULL
, 0);
827 if (strcmp(sbusid
, busid
) != 0)
829 snprintf(oid
, sizeof(oid
), "hw.dri.%d.modesetting", i
);
830 len
= sizeof(modesetting
);
831 ret
= sysctlbyname(oid
, &modesetting
, &len
, NULL
, 0);
832 if (ret
== -1 || len
!= sizeof(modesetting
))
834 return (modesetting
? 0 : -ENOSYS
);
836 #elif defined(__DragonFly__)
838 #elif defined(__OpenBSD__)
840 struct drm_mode_card_res res
;
843 if ((fd
= drmOpen(NULL
, busid
)) < 0)
846 memset(&res
, 0, sizeof(struct drm_mode_card_res
));
848 if (drmIoctl(fd
, DRM_IOCTL_MODE_GETRESOURCES
, &res
)) {
859 drm_public
int drmModeCrtcGetGamma(int fd
, uint32_t crtc_id
, uint32_t size
,
860 uint16_t *red
, uint16_t *green
,
863 struct drm_mode_crtc_lut l
;
868 l
.red
= VOID2U64(red
);
869 l
.green
= VOID2U64(green
);
870 l
.blue
= VOID2U64(blue
);
872 return DRM_IOCTL(fd
, DRM_IOCTL_MODE_GETGAMMA
, &l
);
875 drm_public
int drmModeCrtcSetGamma(int fd
, uint32_t crtc_id
, uint32_t size
,
876 uint16_t *red
, uint16_t *green
,
879 struct drm_mode_crtc_lut l
;
884 l
.red
= VOID2U64(red
);
885 l
.green
= VOID2U64(green
);
886 l
.blue
= VOID2U64(blue
);
888 return DRM_IOCTL(fd
, DRM_IOCTL_MODE_SETGAMMA
, &l
);
891 drm_public
int drmHandleEvent(int fd
, drmEventContextPtr evctx
)
896 struct drm_event_vblank
*vblank
;
897 struct drm_event_crtc_sequence
*seq
;
900 /* The DRM read semantics guarantees that we always get only
901 * complete events. */
903 len
= read(fd
, buffer
, sizeof buffer
);
906 if (len
< (int)sizeof *e
)
911 e
= (struct drm_event
*)(buffer
+ i
);
913 case DRM_EVENT_VBLANK
:
914 if (evctx
->version
< 1 ||
915 evctx
->vblank_handler
== NULL
)
917 vblank
= (struct drm_event_vblank
*) e
;
918 evctx
->vblank_handler(fd
,
922 U642VOID (vblank
->user_data
));
924 case DRM_EVENT_FLIP_COMPLETE
:
925 vblank
= (struct drm_event_vblank
*) e
;
926 user_data
= U642VOID (vblank
->user_data
);
928 if (evctx
->version
>= 3 && evctx
->page_flip_handler2
)
929 evctx
->page_flip_handler2(fd
,
935 else if (evctx
->version
>= 2 && evctx
->page_flip_handler
)
936 evctx
->page_flip_handler(fd
,
942 case DRM_EVENT_CRTC_SEQUENCE
:
943 seq
= (struct drm_event_crtc_sequence
*) e
;
944 if (evctx
->version
>= 4 && evctx
->sequence_handler
)
945 evctx
->sequence_handler(fd
,
959 drm_public
int drmModePageFlip(int fd
, uint32_t crtc_id
, uint32_t fb_id
,
960 uint32_t flags
, void *user_data
)
962 struct drm_mode_crtc_page_flip flip
;
966 flip
.crtc_id
= crtc_id
;
967 flip
.user_data
= VOID2U64(user_data
);
970 return DRM_IOCTL(fd
, DRM_IOCTL_MODE_PAGE_FLIP
, &flip
);
973 drm_public
int drmModePageFlipTarget(int fd
, uint32_t crtc_id
, uint32_t fb_id
,
974 uint32_t flags
, void *user_data
,
975 uint32_t target_vblank
)
977 struct drm_mode_crtc_page_flip_target flip_target
;
979 memclear(flip_target
);
980 flip_target
.fb_id
= fb_id
;
981 flip_target
.crtc_id
= crtc_id
;
982 flip_target
.user_data
= VOID2U64(user_data
);
983 flip_target
.flags
= flags
;
984 flip_target
.sequence
= target_vblank
;
986 return DRM_IOCTL(fd
, DRM_IOCTL_MODE_PAGE_FLIP
, &flip_target
);
989 drm_public
int drmModeSetPlane(int fd
, uint32_t plane_id
, uint32_t crtc_id
,
990 uint32_t fb_id
, uint32_t flags
,
991 int32_t crtc_x
, int32_t crtc_y
,
992 uint32_t crtc_w
, uint32_t crtc_h
,
993 uint32_t src_x
, uint32_t src_y
,
994 uint32_t src_w
, uint32_t src_h
)
996 struct drm_mode_set_plane s
;
999 s
.plane_id
= plane_id
;
1000 s
.crtc_id
= crtc_id
;
1012 return DRM_IOCTL(fd
, DRM_IOCTL_MODE_SETPLANE
, &s
);
1015 drm_public drmModePlanePtr
drmModeGetPlane(int fd
, uint32_t plane_id
)
1017 struct drm_mode_get_plane ovr
, counts
;
1018 drmModePlanePtr r
= 0;
1022 ovr
.plane_id
= plane_id
;
1023 if (drmIoctl(fd
, DRM_IOCTL_MODE_GETPLANE
, &ovr
))
1028 if (ovr
.count_format_types
) {
1029 ovr
.format_type_ptr
= VOID2U64(drmMalloc(ovr
.count_format_types
*
1031 if (!ovr
.format_type_ptr
)
1035 if (drmIoctl(fd
, DRM_IOCTL_MODE_GETPLANE
, &ovr
))
1038 if (counts
.count_format_types
< ovr
.count_format_types
) {
1039 drmFree(U642VOID(ovr
.format_type_ptr
));
1043 if (!(r
= drmMalloc(sizeof(*r
))))
1046 r
->count_formats
= ovr
.count_format_types
;
1047 r
->plane_id
= ovr
.plane_id
;
1048 r
->crtc_id
= ovr
.crtc_id
;
1049 r
->fb_id
= ovr
.fb_id
;
1050 r
->possible_crtcs
= ovr
.possible_crtcs
;
1051 r
->gamma_size
= ovr
.gamma_size
;
1052 r
->formats
= drmAllocCpy(U642VOID(ovr
.format_type_ptr
),
1053 ovr
.count_format_types
, sizeof(uint32_t));
1054 if (ovr
.count_format_types
&& !r
->formats
) {
1055 drmFree(r
->formats
);
1061 drmFree(U642VOID(ovr
.format_type_ptr
));
1066 drm_public
void drmModeFreePlane(drmModePlanePtr ptr
)
1071 drmFree(ptr
->formats
);
1075 drm_public drmModePlaneResPtr
drmModeGetPlaneResources(int fd
)
1077 struct drm_mode_get_plane_res res
, counts
;
1078 drmModePlaneResPtr r
= 0;
1082 if (drmIoctl(fd
, DRM_IOCTL_MODE_GETPLANERESOURCES
, &res
))
1087 if (res
.count_planes
) {
1088 res
.plane_id_ptr
= VOID2U64(drmMalloc(res
.count_planes
*
1090 if (!res
.plane_id_ptr
)
1094 if (drmIoctl(fd
, DRM_IOCTL_MODE_GETPLANERESOURCES
, &res
))
1097 if (counts
.count_planes
< res
.count_planes
) {
1098 drmFree(U642VOID(res
.plane_id_ptr
));
1102 if (!(r
= drmMalloc(sizeof(*r
))))
1105 r
->count_planes
= res
.count_planes
;
1106 r
->planes
= drmAllocCpy(U642VOID(res
.plane_id_ptr
),
1107 res
.count_planes
, sizeof(uint32_t));
1108 if (res
.count_planes
&& !r
->planes
) {
1115 drmFree(U642VOID(res
.plane_id_ptr
));
1120 drm_public
void drmModeFreePlaneResources(drmModePlaneResPtr ptr
)
1125 drmFree(ptr
->planes
);
1129 drm_public drmModeObjectPropertiesPtr
drmModeObjectGetProperties(int fd
,
1131 uint32_t object_type
)
1133 struct drm_mode_obj_get_properties properties
;
1134 drmModeObjectPropertiesPtr ret
= NULL
;
1138 memclear(properties
);
1139 properties
.obj_id
= object_id
;
1140 properties
.obj_type
= object_type
;
1142 if (drmIoctl(fd
, DRM_IOCTL_MODE_OBJ_GETPROPERTIES
, &properties
))
1145 count
= properties
.count_props
;
1148 properties
.props_ptr
= VOID2U64(drmMalloc(count
*
1150 if (!properties
.props_ptr
)
1152 properties
.prop_values_ptr
= VOID2U64(drmMalloc(count
*
1154 if (!properties
.prop_values_ptr
)
1158 if (drmIoctl(fd
, DRM_IOCTL_MODE_OBJ_GETPROPERTIES
, &properties
))
1161 if (count
< properties
.count_props
) {
1162 drmFree(U642VOID(properties
.props_ptr
));
1163 drmFree(U642VOID(properties
.prop_values_ptr
));
1166 count
= properties
.count_props
;
1168 ret
= drmMalloc(sizeof(*ret
));
1172 ret
->count_props
= count
;
1173 ret
->props
= drmAllocCpy(U642VOID(properties
.props_ptr
),
1174 count
, sizeof(uint32_t));
1175 ret
->prop_values
= drmAllocCpy(U642VOID(properties
.prop_values_ptr
),
1176 count
, sizeof(uint64_t));
1177 if (ret
->count_props
&& (!ret
->props
|| !ret
->prop_values
)) {
1178 drmFree(ret
->props
);
1179 drmFree(ret
->prop_values
);
1185 drmFree(U642VOID(properties
.props_ptr
));
1186 drmFree(U642VOID(properties
.prop_values_ptr
));
1190 drm_public
void drmModeFreeObjectProperties(drmModeObjectPropertiesPtr ptr
)
1194 drmFree(ptr
->props
);
1195 drmFree(ptr
->prop_values
);
1199 drm_public
int drmModeObjectSetProperty(int fd
, uint32_t object_id
, uint32_t object_type
,
1200 uint32_t property_id
, uint64_t value
)
1202 struct drm_mode_obj_set_property prop
;
1206 prop
.prop_id
= property_id
;
1207 prop
.obj_id
= object_id
;
1208 prop
.obj_type
= object_type
;
1210 return DRM_IOCTL(fd
, DRM_IOCTL_MODE_OBJ_SETPROPERTY
, &prop
);
1213 typedef struct _drmModeAtomicReqItem drmModeAtomicReqItem
, *drmModeAtomicReqItemPtr
;
1215 struct _drmModeAtomicReqItem
{
1217 uint32_t property_id
;
1221 struct _drmModeAtomicReq
{
1223 uint32_t size_items
;
1224 drmModeAtomicReqItemPtr items
;
1227 drm_public drmModeAtomicReqPtr
drmModeAtomicAlloc(void)
1229 drmModeAtomicReqPtr req
;
1231 req
= drmMalloc(sizeof *req
);
1237 req
->size_items
= 0;
1242 drm_public drmModeAtomicReqPtr
drmModeAtomicDuplicate(drmModeAtomicReqPtr old
)
1244 drmModeAtomicReqPtr
new;
1249 new = drmMalloc(sizeof *new);
1253 new->cursor
= old
->cursor
;
1254 new->size_items
= old
->size_items
;
1256 if (old
->size_items
) {
1257 new->items
= drmMalloc(old
->size_items
* sizeof(*new->items
));
1262 memcpy(new->items
, old
->items
,
1263 old
->cursor
* sizeof(*new->items
));
1271 drm_public
int drmModeAtomicMerge(drmModeAtomicReqPtr base
,
1272 drmModeAtomicReqPtr augment
)
1277 if (!augment
|| augment
->cursor
== 0)
1280 if (base
->cursor
+ augment
->cursor
>= base
->size_items
) {
1281 drmModeAtomicReqItemPtr
new;
1282 int saved_size
= base
->size_items
;
1284 base
->size_items
= base
->cursor
+ augment
->cursor
;
1285 new = realloc(base
->items
,
1286 base
->size_items
* sizeof(*base
->items
));
1288 base
->size_items
= saved_size
;
1294 memcpy(&base
->items
[base
->cursor
], augment
->items
,
1295 augment
->cursor
* sizeof(*augment
->items
));
1296 base
->cursor
+= augment
->cursor
;
1301 drm_public
int drmModeAtomicGetCursor(drmModeAtomicReqPtr req
)
1308 drm_public
void drmModeAtomicSetCursor(drmModeAtomicReqPtr req
, int cursor
)
1311 req
->cursor
= cursor
;
1314 drm_public
int drmModeAtomicAddProperty(drmModeAtomicReqPtr req
,
1316 uint32_t property_id
,
1322 if (object_id
== 0 || property_id
== 0)
1325 if (req
->cursor
>= req
->size_items
) {
1326 const uint32_t item_size_inc
= getpagesize() / sizeof(*req
->items
);
1327 drmModeAtomicReqItemPtr
new;
1329 req
->size_items
+= item_size_inc
;
1330 new = realloc(req
->items
, req
->size_items
* sizeof(*req
->items
));
1332 req
->size_items
-= item_size_inc
;
1338 req
->items
[req
->cursor
].object_id
= object_id
;
1339 req
->items
[req
->cursor
].property_id
= property_id
;
1340 req
->items
[req
->cursor
].value
= value
;
1346 drm_public
void drmModeAtomicFree(drmModeAtomicReqPtr req
)
1352 drmFree(req
->items
);
1356 static int sort_req_list(const void *misc
, const void *other
)
1358 const drmModeAtomicReqItem
*first
= misc
;
1359 const drmModeAtomicReqItem
*second
= other
;
1361 if (first
->object_id
< second
->object_id
)
1363 else if (first
->object_id
> second
->object_id
)
1366 return second
->property_id
- first
->property_id
;
1369 drm_public
int drmModeAtomicCommit(int fd
, drmModeAtomicReqPtr req
,
1370 uint32_t flags
, void *user_data
)
1372 drmModeAtomicReqPtr sorted
;
1373 struct drm_mode_atomic atomic
;
1374 uint32_t *objs_ptr
= NULL
;
1375 uint32_t *count_props_ptr
= NULL
;
1376 uint32_t *props_ptr
= NULL
;
1377 uint64_t *prop_values_ptr
= NULL
;
1378 uint32_t last_obj_id
= 0;
1386 if (req
->cursor
== 0)
1389 sorted
= drmModeAtomicDuplicate(req
);
1395 /* Sort the list by object ID, then by property ID. */
1396 qsort(sorted
->items
, sorted
->cursor
, sizeof(*sorted
->items
),
1399 /* Now the list is sorted, eliminate duplicate property sets. */
1400 for (i
= 0; i
< sorted
->cursor
; i
++) {
1401 if (sorted
->items
[i
].object_id
!= last_obj_id
) {
1402 atomic
.count_objs
++;
1403 last_obj_id
= sorted
->items
[i
].object_id
;
1406 if (i
== sorted
->cursor
- 1)
1409 if (sorted
->items
[i
].object_id
!= sorted
->items
[i
+ 1].object_id
||
1410 sorted
->items
[i
].property_id
!= sorted
->items
[i
+ 1].property_id
)
1413 memmove(&sorted
->items
[i
], &sorted
->items
[i
+ 1],
1414 (sorted
->cursor
- i
- 1) * sizeof(*sorted
->items
));
1418 objs_ptr
= drmMalloc(atomic
.count_objs
* sizeof objs_ptr
[0]);
1424 count_props_ptr
= drmMalloc(atomic
.count_objs
* sizeof count_props_ptr
[0]);
1425 if (!count_props_ptr
) {
1430 props_ptr
= drmMalloc(sorted
->cursor
* sizeof props_ptr
[0]);
1436 prop_values_ptr
= drmMalloc(sorted
->cursor
* sizeof prop_values_ptr
[0]);
1437 if (!prop_values_ptr
) {
1442 for (i
= 0, last_obj_id
= 0; i
< sorted
->cursor
; i
++) {
1443 if (sorted
->items
[i
].object_id
!= last_obj_id
) {
1445 objs_ptr
[obj_idx
] = sorted
->items
[i
].object_id
;
1446 last_obj_id
= objs_ptr
[obj_idx
];
1449 count_props_ptr
[obj_idx
]++;
1450 props_ptr
[i
] = sorted
->items
[i
].property_id
;
1451 prop_values_ptr
[i
] = sorted
->items
[i
].value
;
1455 atomic
.flags
= flags
;
1456 atomic
.objs_ptr
= VOID2U64(objs_ptr
);
1457 atomic
.count_props_ptr
= VOID2U64(count_props_ptr
);
1458 atomic
.props_ptr
= VOID2U64(props_ptr
);
1459 atomic
.prop_values_ptr
= VOID2U64(prop_values_ptr
);
1460 atomic
.user_data
= VOID2U64(user_data
);
1462 ret
= DRM_IOCTL(fd
, DRM_IOCTL_MODE_ATOMIC
, &atomic
);
1466 drmFree(count_props_ptr
);
1468 drmFree(prop_values_ptr
);
1469 drmModeAtomicFree(sorted
);
1475 drmModeCreatePropertyBlob(int fd
, const void *data
, size_t length
,
1478 struct drm_mode_create_blob create
;
1481 if (length
>= 0xffffffff)
1486 create
.length
= length
;
1487 create
.data
= (uintptr_t) data
;
1491 ret
= DRM_IOCTL(fd
, DRM_IOCTL_MODE_CREATEPROPBLOB
, &create
);
1495 *id
= create
.blob_id
;
1500 drmModeDestroyPropertyBlob(int fd
, uint32_t id
)
1502 struct drm_mode_destroy_blob destroy
;
1505 destroy
.blob_id
= id
;
1506 return DRM_IOCTL(fd
, DRM_IOCTL_MODE_DESTROYPROPBLOB
, &destroy
);
1510 drmModeCreateLease(int fd
, const uint32_t *objects
, int num_objects
, int flags
,
1511 uint32_t *lessee_id
)
1513 struct drm_mode_create_lease create
;
1517 create
.object_ids
= (uintptr_t) objects
;
1518 create
.object_count
= num_objects
;
1519 create
.flags
= flags
;
1521 ret
= DRM_IOCTL(fd
, DRM_IOCTL_MODE_CREATE_LEASE
, &create
);
1523 *lessee_id
= create
.lessee_id
;
1529 drm_public drmModeLesseeListPtr
1530 drmModeListLessees(int fd
)
1532 struct drm_mode_list_lessees list
;
1534 drmModeLesseeListPtr ret
;
1538 if (DRM_IOCTL(fd
, DRM_IOCTL_MODE_LIST_LESSEES
, &list
))
1541 count
= list
.count_lessees
;
1542 ret
= drmMalloc(sizeof (drmModeLesseeListRes
) + count
* sizeof (ret
->lessees
[0]));
1546 list
.lessees_ptr
= VOID2U64(&ret
->lessees
[0]);
1547 if (DRM_IOCTL(fd
, DRM_IOCTL_MODE_LIST_LESSEES
, &list
)) {
1556 drm_public drmModeObjectListPtr
1557 drmModeGetLease(int fd
)
1559 struct drm_mode_get_lease get
;
1561 drmModeObjectListPtr ret
;
1565 if (DRM_IOCTL(fd
, DRM_IOCTL_MODE_GET_LEASE
, &get
))
1568 count
= get
.count_objects
;
1569 ret
= drmMalloc(sizeof (drmModeObjectListRes
) + count
* sizeof (ret
->objects
[0]));
1573 get
.objects_ptr
= VOID2U64(&ret
->objects
[0]);
1574 if (DRM_IOCTL(fd
, DRM_IOCTL_MODE_GET_LEASE
, &get
)) {
1584 drmModeRevokeLease(int fd
, uint32_t lessee_id
)
1586 struct drm_mode_revoke_lease revoke
;
1591 revoke
.lessee_id
= lessee_id
;
1593 ret
= DRM_IOCTL(fd
, DRM_IOCTL_MODE_REVOKE_LEASE
, &revoke
);
1599 drm_public drmModeFB2Ptr
1600 drmModeGetFB2(int fd
, uint32_t fb_id
)
1602 struct drm_mode_fb_cmd2 get
= {
1608 err
= DRM_IOCTL(fd
, DRM_IOCTL_MODE_GETFB2
, &get
);
1612 ret
= drmMalloc(sizeof(drmModeFB2
));
1617 ret
->width
= get
.width
;
1618 ret
->height
= get
.height
;
1619 ret
->pixel_format
= get
.pixel_format
;
1620 ret
->flags
= get
.flags
;
1621 ret
->modifier
= get
.modifier
[0];
1622 memcpy(ret
->handles
, get
.handles
, sizeof(uint32_t) * 4);
1623 memcpy(ret
->pitches
, get
.pitches
, sizeof(uint32_t) * 4);
1624 memcpy(ret
->offsets
, get
.offsets
, sizeof(uint32_t) * 4);
1629 drm_public
void drmModeFreeFB2(drmModeFB2Ptr ptr
)