X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=xf86drmMode.c;h=bca5a91001a9a46cdad0ad7e3dd6e6c96e8ad09f;hb=c7ed900d0188d72084fe30a57d111872d12462ad;hp=04fdf1ff04c907dbc5c36995aaf6006948064f3b;hpb=7b228e900f59cda3cafb60692be9dd7aced6ad96;p=platform%2Fupstream%2Flibdrm.git diff --git a/xf86drmMode.c b/xf86drmMode.c index 04fdf1f..bca5a91 100644 --- a/xf86drmMode.c +++ b/xf86drmMode.c @@ -34,13 +34,21 @@ */ /* - * TODO the types we are after are defined in diffrent headers on diffrent + * TODO the types we are after are defined in different headers on different * platforms find which headers to include to get uint32_t */ + +#include #include +#include #include +#if HAVE_SYS_SYSCTL_H +#include +#endif #include +#include +#include "libdrm_macros.h" #include "xf86drmMode.h" #include "xf86drm.h" #include @@ -49,6 +57,8 @@ #include #include +#define memclear(s) memset(&s, 0, sizeof(s)) + #define U642VOID(x) ((void *)(unsigned long)(x)) #define VOID2U64(x) ((uint64_t)(unsigned long)(x)) @@ -62,7 +72,7 @@ static inline int DRM_IOCTL(int fd, unsigned long cmd, void *arg) * Util functions */ -void* drmAllocCpy(void *array, int count, int entry_size) +static void* drmAllocCpy(char *array, int count, int entry_size) { char *r; int i; @@ -83,7 +93,7 @@ void* drmAllocCpy(void *array, int count, int entry_size) * A couple of free functions. */ -void drmModeFreeModeInfo(drmModeModeInfoPtr ptr) +drm_public void drmModeFreeModeInfo(drmModeModeInfoPtr ptr) { if (!ptr) return; @@ -91,7 +101,7 @@ void drmModeFreeModeInfo(drmModeModeInfoPtr ptr) drmFree(ptr); } -void drmModeFreeResources(drmModeResPtr ptr) +drm_public void drmModeFreeResources(drmModeResPtr ptr) { if (!ptr) return; @@ -101,10 +111,9 @@ void drmModeFreeResources(drmModeResPtr ptr) drmFree(ptr->connectors); drmFree(ptr->encoders); drmFree(ptr); - } -void drmModeFreeFB(drmModeFBPtr ptr) +drm_public void drmModeFreeFB(drmModeFBPtr ptr) { if (!ptr) return; @@ -113,16 +122,15 @@ void drmModeFreeFB(drmModeFBPtr ptr) drmFree(ptr); } -void drmModeFreeCrtc(drmModeCrtcPtr ptr) +drm_public void drmModeFreeCrtc(drmModeCrtcPtr ptr) { if (!ptr) return; drmFree(ptr); - } -void drmModeFreeConnector(drmModeConnectorPtr ptr) +drm_public void drmModeFreeConnector(drmModeConnectorPtr ptr) { if (!ptr) return; @@ -132,10 +140,9 @@ void drmModeFreeConnector(drmModeConnectorPtr ptr) drmFree(ptr->props); drmFree(ptr->modes); drmFree(ptr); - } -void drmModeFreeEncoder(drmModeEncoderPtr ptr) +drm_public void drmModeFreeEncoder(drmModeEncoderPtr ptr) { drmFree(ptr); } @@ -144,13 +151,13 @@ void drmModeFreeEncoder(drmModeEncoderPtr ptr) * ModeSetting functions. */ -drmModeResPtr drmModeGetResources(int fd) +drm_public drmModeResPtr drmModeGetResources(int fd) { struct drm_mode_card_res res, counts; drmModeResPtr r = 0; retry: - memset(&res, 0, sizeof(struct drm_mode_card_res)); + memclear(res); if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) return 0; @@ -238,13 +245,15 @@ err_allocs: return r; } -int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth, - uint8_t bpp, uint32_t pitch, uint32_t bo_handle, - uint32_t *buf_id) + +drm_public int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth, + uint8_t bpp, uint32_t pitch, uint32_t bo_handle, + uint32_t *buf_id) { struct drm_mode_fb_cmd f; int ret; + memclear(f); f.width = width; f.height = height; f.pitch = pitch; @@ -259,14 +268,15 @@ int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth, return 0; } -int drmModeAddFB2(int fd, uint32_t width, uint32_t height, - uint32_t pixel_format, uint32_t bo_handles[4], - uint32_t pitches[4], uint32_t offsets[4], - uint32_t *buf_id, uint32_t flags) +drm_public int drmModeAddFB2WithModifiers(int fd, uint32_t width, + uint32_t height, uint32_t pixel_format, const uint32_t bo_handles[4], + const uint32_t pitches[4], const uint32_t offsets[4], + const uint64_t modifier[4], uint32_t *buf_id, uint32_t flags) { struct drm_mode_fb_cmd2 f; int ret; + memclear(f); f.width = width; f.height = height; f.pixel_format = pixel_format; @@ -274,6 +284,8 @@ int drmModeAddFB2(int fd, uint32_t width, uint32_t height, memcpy(f.handles, bo_handles, 4 * sizeof(bo_handles[0])); memcpy(f.pitches, pitches, 4 * sizeof(pitches[0])); memcpy(f.offsets, offsets, 4 * sizeof(offsets[0])); + if (modifier) + memcpy(f.modifier, modifier, 4 * sizeof(modifier[0])); if ((ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_ADDFB2, &f))) return ret; @@ -282,18 +294,28 @@ int drmModeAddFB2(int fd, uint32_t width, uint32_t height, return 0; } -int drmModeRmFB(int fd, uint32_t bufferId) +drm_public int drmModeAddFB2(int fd, uint32_t width, uint32_t height, + uint32_t pixel_format, const uint32_t bo_handles[4], + const uint32_t pitches[4], const uint32_t offsets[4], + uint32_t *buf_id, uint32_t flags) { - return DRM_IOCTL(fd, DRM_IOCTL_MODE_RMFB, &bufferId); - + return drmModeAddFB2WithModifiers(fd, width, height, + pixel_format, bo_handles, + pitches, offsets, NULL, + buf_id, flags); +} +drm_public int drmModeRmFB(int fd, uint32_t bufferId) +{ + return DRM_IOCTL(fd, DRM_IOCTL_MODE_RMFB, &bufferId); } -drmModeFBPtr drmModeGetFB(int fd, uint32_t buf) +drm_public drmModeFBPtr drmModeGetFB(int fd, uint32_t buf) { struct drm_mode_fb_cmd info; drmModeFBPtr r; + memclear(info); info.fb_id = buf; if (drmIoctl(fd, DRM_IOCTL_MODE_GETFB, &info)) @@ -313,11 +335,12 @@ drmModeFBPtr drmModeGetFB(int fd, uint32_t buf) return r; } -int drmModeDirtyFB(int fd, uint32_t bufferId, +drm_public int drmModeDirtyFB(int fd, uint32_t bufferId, drmModeClipPtr clips, uint32_t num_clips) { - struct drm_mode_fb_dirty_cmd dirty = { 0 }; + struct drm_mode_fb_dirty_cmd dirty; + memclear(dirty); dirty.fb_id = bufferId; dirty.clips_ptr = VOID2U64(clips); dirty.num_clips = num_clips; @@ -325,16 +348,16 @@ int drmModeDirtyFB(int fd, uint32_t bufferId, return DRM_IOCTL(fd, DRM_IOCTL_MODE_DIRTYFB, &dirty); } - /* * Crtc functions */ -drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId) +drm_public drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId) { struct drm_mode_crtc crtc; drmModeCrtcPtr r; + memclear(crtc); crtc.crtc_id = crtcId; if (drmIoctl(fd, DRM_IOCTL_MODE_GETCRTC, &crtc)) @@ -351,20 +374,23 @@ drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId) r->x = crtc.x; r->y = crtc.y; r->mode_valid = crtc.mode_valid; - if (r->mode_valid) + if (r->mode_valid) { memcpy(&r->mode, &crtc.mode, sizeof(struct drm_mode_modeinfo)); + r->width = crtc.mode.hdisplay; + r->height = crtc.mode.vdisplay; + } r->buffer_id = crtc.fb_id; r->gamma_size = crtc.gamma_size; return r; } - -int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, - uint32_t x, uint32_t y, uint32_t *connectors, int count, +drm_public int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, + uint32_t x, uint32_t y, uint32_t *connectors, int count, drmModeModeInfoPtr mode) { struct drm_mode_crtc crtc; + memclear(crtc); crtc.x = x; crtc.y = y; crtc.crtc_id = crtcId; @@ -374,8 +400,7 @@ int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, if (mode) { memcpy(&crtc.mode, mode, sizeof(struct drm_mode_modeinfo)); crtc.mode_valid = 1; - } else - crtc.mode_valid = 0; + } return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETCRTC, &crtc); } @@ -384,10 +409,12 @@ int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, * Cursor manipulation */ -int drmModeSetCursor(int fd, uint32_t crtcId, uint32_t bo_handle, uint32_t width, uint32_t height) +drm_public int drmModeSetCursor(int fd, uint32_t crtcId, uint32_t bo_handle, + uint32_t width, uint32_t height) { struct drm_mode_cursor arg; + memclear(arg); arg.flags = DRM_MODE_CURSOR_BO; arg.crtc_id = crtcId; arg.width = width; @@ -397,10 +424,29 @@ int drmModeSetCursor(int fd, uint32_t crtcId, uint32_t bo_handle, uint32_t width return DRM_IOCTL(fd, DRM_IOCTL_MODE_CURSOR, &arg); } -int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y) +drm_public int drmModeSetCursor2(int fd, uint32_t crtcId, uint32_t bo_handle, + uint32_t width, uint32_t height, int32_t hot_x, + int32_t hot_y) +{ + struct drm_mode_cursor2 arg; + + memclear(arg); + arg.flags = DRM_MODE_CURSOR_BO; + arg.crtc_id = crtcId; + arg.width = width; + arg.height = height; + arg.handle = bo_handle; + arg.hot_x = hot_x; + arg.hot_y = hot_y; + + return DRM_IOCTL(fd, DRM_IOCTL_MODE_CURSOR2, &arg); +} + +drm_public int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y) { struct drm_mode_cursor arg; + memclear(arg); arg.flags = DRM_MODE_CURSOR_MOVE; arg.crtc_id = crtcId; arg.x = x; @@ -412,15 +458,13 @@ int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y) /* * Encoder get */ -drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id) +drm_public drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id) { struct drm_mode_get_encoder enc; drmModeEncoderPtr r = NULL; + memclear(enc); enc.encoder_id = encoder_id; - enc.encoder_type = 0; - enc.possible_crtcs = 0; - enc.possible_clones = 0; if (drmIoctl(fd, DRM_IOCTL_MODE_GETENCODER, &enc)) return 0; @@ -440,19 +484,24 @@ drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id) /* * Connector manipulation */ - -drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id) +static drmModeConnectorPtr +_drmModeGetConnector(int fd, uint32_t connector_id, int probe) { struct drm_mode_get_connector conn, counts; drmModeConnectorPtr r = NULL; + struct drm_mode_modeinfo stack_mode; -retry: - memset(&conn, 0, sizeof(struct drm_mode_get_connector)); + memclear(conn); conn.connector_id = connector_id; + if (!probe) { + conn.count_modes = 1; + conn.modes_ptr = VOID2U64(&stack_mode); + } if (drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn)) return 0; +retry: counts = conn; if (conn.count_props) { @@ -468,6 +517,9 @@ retry: conn.modes_ptr = VOID2U64(drmMalloc(conn.count_modes*sizeof(struct drm_mode_modeinfo))); if (!conn.modes_ptr) goto err_allocs; + } else { + conn.count_modes = 1; + conn.modes_ptr = VOID2U64(&stack_mode); } if (conn.count_encoders) { @@ -488,7 +540,8 @@ retry: counts.count_encoders < conn.count_encoders) { drmFree(U642VOID(conn.props_ptr)); drmFree(U642VOID(conn.prop_values_ptr)); - drmFree(U642VOID(conn.modes_ptr)); + if (U642VOID(conn.modes_ptr) != &stack_mode) + drmFree(U642VOID(conn.modes_ptr)); drmFree(U642VOID(conn.encoders_ptr)); goto retry; @@ -530,44 +583,52 @@ retry: err_allocs: drmFree(U642VOID(conn.prop_values_ptr)); drmFree(U642VOID(conn.props_ptr)); - drmFree(U642VOID(conn.modes_ptr)); + if (U642VOID(conn.modes_ptr) != &stack_mode) + drmFree(U642VOID(conn.modes_ptr)); drmFree(U642VOID(conn.encoders_ptr)); return r; } -int drmModeAttachMode(int fd, uint32_t connector_id, drmModeModeInfoPtr mode_info) +drm_public drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id) +{ + return _drmModeGetConnector(fd, connector_id, 1); +} + +drm_public drmModeConnectorPtr drmModeGetConnectorCurrent(int fd, uint32_t connector_id) +{ + return _drmModeGetConnector(fd, connector_id, 0); +} + +drm_public int drmModeAttachMode(int fd, uint32_t connector_id, drmModeModeInfoPtr mode_info) { struct drm_mode_mode_cmd res; + memclear(res); memcpy(&res.mode, mode_info, sizeof(struct drm_mode_modeinfo)); res.connector_id = connector_id; return DRM_IOCTL(fd, DRM_IOCTL_MODE_ATTACHMODE, &res); } -int drmModeDetachMode(int fd, uint32_t connector_id, drmModeModeInfoPtr mode_info) +drm_public int drmModeDetachMode(int fd, uint32_t connector_id, drmModeModeInfoPtr mode_info) { struct drm_mode_mode_cmd res; + memclear(res); memcpy(&res.mode, mode_info, sizeof(struct drm_mode_modeinfo)); res.connector_id = connector_id; return DRM_IOCTL(fd, DRM_IOCTL_MODE_DETACHMODE, &res); } - -drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id) +drm_public drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id) { struct drm_mode_get_property prop; drmModePropertyPtr r; + memclear(prop); prop.prop_id = property_id; - prop.count_enum_blobs = 0; - prop.count_values = 0; - prop.flags = 0; - prop.enum_blob_ptr = 0; - prop.values_ptr = 0; if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop)) return 0; @@ -589,7 +650,7 @@ drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id) } if (!(r = drmMalloc(sizeof(*r)))) - return NULL; + goto err_allocs; r->prop_id = prop.prop_id; r->count_values = prop.count_values; @@ -615,23 +676,24 @@ err_allocs: return r; } -void drmModeFreeProperty(drmModePropertyPtr ptr) +drm_public void drmModeFreeProperty(drmModePropertyPtr ptr) { if (!ptr) return; drmFree(ptr->values); drmFree(ptr->enums); + drmFree(ptr->blob_ids); drmFree(ptr); } -drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, uint32_t blob_id) +drm_public drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, + uint32_t blob_id) { struct drm_mode_get_blob blob; drmModePropertyBlobPtr r; - blob.length = 0; - blob.data = 0; + memclear(blob); blob.blob_id = blob_id; if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob)) @@ -657,7 +719,7 @@ err_allocs: return r; } -void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr) +drm_public void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr) { if (!ptr) return; @@ -666,11 +728,13 @@ void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr) drmFree(ptr); } -int drmModeConnectorSetProperty(int fd, uint32_t connector_id, uint32_t property_id, - uint64_t value) +drm_public int drmModeConnectorSetProperty(int fd, uint32_t connector_id, + uint32_t property_id, + uint64_t value) { struct drm_mode_connector_set_property osp; + memclear(osp); osp.connector_id = connector_id; osp.prop_id = property_id; osp.value = value; @@ -684,9 +748,9 @@ int drmModeConnectorSetProperty(int fd, uint32_t connector_id, uint32_t property * -EINVAL or invalid bus id * -ENOSYS if no modesetting support */ -int drmCheckModesettingSupported(const char *busid) +drm_public int drmCheckModesettingSupported(const char *busid) { -#ifdef __linux__ +#if defined (__linux__) char pci_dev_dir[1024]; int domain, bus, dev, func; DIR *sysdir; @@ -736,16 +800,61 @@ int drmCheckModesettingSupported(const char *busid) closedir(sysdir); if (found) return 0; +#elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__) + char sbusid[1024]; + char oid[128]; + int i, modesetting, ret; + size_t len; + + /* How many GPUs do we expect in the machine ? */ + for (i = 0; i < 10; i++) { + snprintf(oid, sizeof(oid), "hw.dri.%d.busid", i); + len = sizeof(sbusid); + ret = sysctlbyname(oid, sbusid, &len, NULL, 0); + if (ret == -1) { + if (errno == ENOENT) + continue; + return -EINVAL; + } + if (strcmp(sbusid, busid) != 0) + continue; + snprintf(oid, sizeof(oid), "hw.dri.%d.modesetting", i); + len = sizeof(modesetting); + ret = sysctlbyname(oid, &modesetting, &len, NULL, 0); + if (ret == -1 || len != sizeof(modesetting)) + return -EINVAL; + return (modesetting ? 0 : -ENOSYS); + } +#elif defined(__DragonFly__) + return 0; +#elif defined(__OpenBSD__) + int fd; + struct drm_mode_card_res res; + drmModeResPtr r = 0; + + if ((fd = drmOpen(NULL, busid)) < 0) + return -EINVAL; + + memset(&res, 0, sizeof(struct drm_mode_card_res)); + + if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) { + drmClose(fd); + return -errno; + } + + drmClose(fd); + return 0; #endif return -ENOSYS; - } -int drmModeCrtcGetGamma(int fd, uint32_t crtc_id, uint32_t size, - uint16_t *red, uint16_t *green, uint16_t *blue) +drm_public int drmModeCrtcGetGamma(int fd, uint32_t crtc_id, uint32_t size, + uint16_t *red, uint16_t *green, + uint16_t *blue) { struct drm_mode_crtc_lut l; + memclear(l); l.crtc_id = crtc_id; l.gamma_size = size; l.red = VOID2U64(red); @@ -755,11 +864,13 @@ int drmModeCrtcGetGamma(int fd, uint32_t crtc_id, uint32_t size, return DRM_IOCTL(fd, DRM_IOCTL_MODE_GETGAMMA, &l); } -int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size, - uint16_t *red, uint16_t *green, uint16_t *blue) +drm_public int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size, + uint16_t *red, uint16_t *green, + uint16_t *blue) { struct drm_mode_crtc_lut l; + memclear(l); l.crtc_id = crtc_id; l.gamma_size = size; l.red = VOID2U64(red); @@ -769,25 +880,84 @@ int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size, return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETGAMMA, &l); } -int drmHandleEvent(int fd, drmEventContextPtr evctx) +#ifdef TIZEN_USE_USER_HANDLER +#include "libdrm_lists.h" +#include + +struct drm_user_handler_data { + int fd; + drm_user_handler handler; + drmMMListHead link; +}; + +static drmMMListHead user_handler_list; +static int user_handler_list_init = 0; + +drm_public int +drmAddUserHandler(int fd, drm_user_handler handler) +{ + struct drm_user_handler_data *data = malloc(sizeof(struct drm_user_handler_data)); + + if (!data) + return -1; + + data->fd = fd; + data->handler = handler; + + if (!user_handler_list_init) + { + user_handler_list_init = 1; + DRMINITLISTHEAD(&user_handler_list); + } + + DRMLISTADDTAIL(&data->link, &user_handler_list); + + return 0; +} + +drm_public void +drmRemoveUserHandler(int fd, drm_user_handler handler) +{ + struct drm_user_handler_data *data; + + if (!user_handler_list_init) + { + user_handler_list_init = 1; + DRMINITLISTHEAD(&user_handler_list); + } + + DRMLISTFOREACHENTRY(data, &user_handler_list, link) { + if (data->fd == fd && data->handler == handler) + { + DRMLISTDEL(&data->link); + free(data); + return; + } + } +} +#endif + +drm_public int drmHandleEvent(int fd, drmEventContextPtr evctx) { char buffer[1024]; int len, i; struct drm_event *e; struct drm_event_vblank *vblank; - + struct drm_event_crtc_sequence *seq; + void *user_data; + /* The DRM read semantics guarantees that we always get only * complete events. */ len = read(fd, buffer, sizeof buffer); if (len == 0) return 0; - if (len < sizeof *e) + if (len < (int)sizeof *e) return -1; i = 0; while (i < len) { - e = (struct drm_event *) &buffer[i]; + e = (struct drm_event *)(buffer + i); switch (e->type) { case DRM_EVENT_VBLANK: if (evctx->version < 1 || @@ -795,23 +965,54 @@ int drmHandleEvent(int fd, drmEventContextPtr evctx) break; vblank = (struct drm_event_vblank *) e; evctx->vblank_handler(fd, - vblank->sequence, + vblank->sequence, vblank->tv_sec, vblank->tv_usec, U642VOID (vblank->user_data)); break; case DRM_EVENT_FLIP_COMPLETE: - if (evctx->version < 2 || - evctx->page_flip_handler == NULL) - break; vblank = (struct drm_event_vblank *) e; - evctx->page_flip_handler(fd, - vblank->sequence, - vblank->tv_sec, - vblank->tv_usec, - U642VOID (vblank->user_data)); + user_data = U642VOID (vblank->user_data); + + if (evctx->version >= 3 && evctx->page_flip_handler2) + evctx->page_flip_handler2(fd, + vblank->sequence, + vblank->tv_sec, + vblank->tv_usec, + vblank->crtc_id, + user_data); + else if (evctx->version >= 2 && evctx->page_flip_handler) + evctx->page_flip_handler(fd, + vblank->sequence, + vblank->tv_sec, + vblank->tv_usec, + user_data); + break; + case DRM_EVENT_CRTC_SEQUENCE: + seq = (struct drm_event_crtc_sequence *) e; + if (evctx->version >= 4 && evctx->sequence_handler) + evctx->sequence_handler(fd, + seq->sequence, + seq->time_ns, + seq->user_data); break; default: +#ifdef TIZEN_USE_USER_HANDLER + { + struct drm_user_handler_data *data; + int ret = -1; + if (!user_handler_list_init) + break; + DRMLISTFOREACHENTRY(data, &user_handler_list, link) { + if (data->handler) + { + ret = data->handler(e); + if (ret == 0) + break; + } + } + } +#endif break; } i += e->length; @@ -820,30 +1021,46 @@ int drmHandleEvent(int fd, drmEventContextPtr evctx) return 0; } -int drmModePageFlip(int fd, uint32_t crtc_id, uint32_t fb_id, +drm_public int drmModePageFlip(int fd, uint32_t crtc_id, uint32_t fb_id, uint32_t flags, void *user_data) { struct drm_mode_crtc_page_flip flip; + memclear(flip); flip.fb_id = fb_id; flip.crtc_id = crtc_id; flip.user_data = VOID2U64(user_data); flip.flags = flags; - flip.reserved = 0; return DRM_IOCTL(fd, DRM_IOCTL_MODE_PAGE_FLIP, &flip); } -int drmModeSetPlane(int fd, uint32_t plane_id, uint32_t crtc_id, +drm_public int drmModePageFlipTarget(int fd, uint32_t crtc_id, uint32_t fb_id, + uint32_t flags, void *user_data, + uint32_t target_vblank) +{ + struct drm_mode_crtc_page_flip_target flip_target; + + memclear(flip_target); + flip_target.fb_id = fb_id; + flip_target.crtc_id = crtc_id; + flip_target.user_data = VOID2U64(user_data); + flip_target.flags = flags; + flip_target.sequence = target_vblank; + + return DRM_IOCTL(fd, DRM_IOCTL_MODE_PAGE_FLIP, &flip_target); +} + +drm_public int drmModeSetPlane(int fd, uint32_t plane_id, uint32_t crtc_id, uint32_t fb_id, uint32_t flags, - uint32_t crtc_x, uint32_t crtc_y, + int32_t crtc_x, int32_t crtc_y, uint32_t crtc_w, uint32_t crtc_h, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h) - { struct drm_mode_set_plane s; + memclear(s); s.plane_id = plane_id; s.crtc_id = crtc_id; s.fb_id = fb_id; @@ -860,14 +1077,13 @@ int drmModeSetPlane(int fd, uint32_t plane_id, uint32_t crtc_id, return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETPLANE, &s); } - -drmModePlanePtr drmModeGetPlane(int fd, uint32_t plane_id) +drm_public drmModePlanePtr drmModeGetPlane(int fd, uint32_t plane_id) { struct drm_mode_get_plane ovr, counts; drmModePlanePtr r = 0; retry: - memset(&ovr, 0, sizeof(struct drm_mode_get_plane)); + memclear(ovr); ovr.plane_id = plane_id; if (drmIoctl(fd, DRM_IOCTL_MODE_GETPLANE, &ovr)) return 0; @@ -912,7 +1128,7 @@ err_allocs: return r; } -void drmModeFreePlane(drmModePlanePtr ptr) +drm_public void drmModeFreePlane(drmModePlanePtr ptr) { if (!ptr) return; @@ -921,13 +1137,13 @@ void drmModeFreePlane(drmModePlanePtr ptr) drmFree(ptr); } -drmModePlaneResPtr drmModeGetPlaneResources(int fd) +drm_public drmModePlaneResPtr drmModeGetPlaneResources(int fd) { struct drm_mode_get_plane_res res, counts; drmModePlaneResPtr r = 0; retry: - memset(&res, 0, sizeof(struct drm_mode_get_plane_res)); + memclear(res); if (drmIoctl(fd, DRM_IOCTL_MODE_GETPLANERESOURCES, &res)) return 0; @@ -966,7 +1182,7 @@ err_allocs: return r; } -void drmModeFreePlaneResources(drmModePlaneResPtr ptr) +drm_public void drmModeFreePlaneResources(drmModePlaneResPtr ptr) { if (!ptr) return; @@ -975,7 +1191,7 @@ void drmModeFreePlaneResources(drmModePlaneResPtr ptr) drmFree(ptr); } -drmModeObjectPropertiesPtr drmModeObjectGetProperties(int fd, +drm_public drmModeObjectPropertiesPtr drmModeObjectGetProperties(int fd, uint32_t object_id, uint32_t object_type) { @@ -984,7 +1200,7 @@ drmModeObjectPropertiesPtr drmModeObjectGetProperties(int fd, uint32_t count; retry: - memset(&properties, 0, sizeof(struct drm_mode_obj_get_properties)); + memclear(properties); properties.obj_id = object_id; properties.obj_type = object_type; @@ -1036,7 +1252,7 @@ err_allocs: return ret; } -void drmModeFreeObjectProperties(drmModeObjectPropertiesPtr ptr) +drm_public void drmModeFreeObjectProperties(drmModeObjectPropertiesPtr ptr) { if (!ptr) return; @@ -1045,11 +1261,12 @@ void drmModeFreeObjectProperties(drmModeObjectPropertiesPtr ptr) drmFree(ptr); } -int drmModeObjectSetProperty(int fd, uint32_t object_id, uint32_t object_type, +drm_public int drmModeObjectSetProperty(int fd, uint32_t object_id, uint32_t object_type, uint32_t property_id, uint64_t value) { struct drm_mode_obj_set_property prop; + memclear(prop); prop.value = value; prop.prop_id = property_id; prop.obj_id = object_id; @@ -1057,3 +1274,424 @@ int drmModeObjectSetProperty(int fd, uint32_t object_id, uint32_t object_type, return DRM_IOCTL(fd, DRM_IOCTL_MODE_OBJ_SETPROPERTY, &prop); } + +typedef struct _drmModeAtomicReqItem drmModeAtomicReqItem, *drmModeAtomicReqItemPtr; + +struct _drmModeAtomicReqItem { + uint32_t object_id; + uint32_t property_id; + uint64_t value; +}; + +struct _drmModeAtomicReq { + uint32_t cursor; + uint32_t size_items; + drmModeAtomicReqItemPtr items; +}; + +drm_public drmModeAtomicReqPtr drmModeAtomicAlloc(void) +{ + drmModeAtomicReqPtr req; + + req = drmMalloc(sizeof *req); + if (!req) + return NULL; + + req->items = NULL; + req->cursor = 0; + req->size_items = 0; + + return req; +} + +drm_public drmModeAtomicReqPtr drmModeAtomicDuplicate(drmModeAtomicReqPtr old) +{ + drmModeAtomicReqPtr new; + + if (!old) + return NULL; + + new = drmMalloc(sizeof *new); + if (!new) + return NULL; + + new->cursor = old->cursor; + new->size_items = old->size_items; + + if (old->size_items) { + new->items = drmMalloc(old->size_items * sizeof(*new->items)); + if (!new->items) { + free(new); + return NULL; + } + memcpy(new->items, old->items, + old->cursor * sizeof(*new->items)); + } else { + new->items = NULL; + } + + return new; +} + +drm_public int drmModeAtomicMerge(drmModeAtomicReqPtr base, + drmModeAtomicReqPtr augment) +{ + if (!base) + return -EINVAL; + + if (!augment || augment->cursor == 0) + return 0; + + if (base->cursor + augment->cursor >= base->size_items) { + drmModeAtomicReqItemPtr new; + int saved_size = base->size_items; + + base->size_items = base->cursor + augment->cursor; + new = realloc(base->items, + base->size_items * sizeof(*base->items)); + if (!new) { + base->size_items = saved_size; + return -ENOMEM; + } + base->items = new; + } + + memcpy(&base->items[base->cursor], augment->items, + augment->cursor * sizeof(*augment->items)); + base->cursor += augment->cursor; + + return 0; +} + +drm_public int drmModeAtomicGetCursor(drmModeAtomicReqPtr req) +{ + if (!req) + return -EINVAL; + return req->cursor; +} + +drm_public void drmModeAtomicSetCursor(drmModeAtomicReqPtr req, int cursor) +{ + if (req) + req->cursor = cursor; +} + +drm_public int drmModeAtomicAddProperty(drmModeAtomicReqPtr req, + uint32_t object_id, + uint32_t property_id, + uint64_t value) +{ + if (!req) + return -EINVAL; + + if (object_id == 0 || property_id == 0) + return -EINVAL; + + if (req->cursor >= req->size_items) { + const uint32_t item_size_inc = getpagesize() / sizeof(*req->items); + drmModeAtomicReqItemPtr new; + + req->size_items += item_size_inc; + new = realloc(req->items, req->size_items * sizeof(*req->items)); + if (!new) { + req->size_items -= item_size_inc; + return -ENOMEM; + } + req->items = new; + } + + req->items[req->cursor].object_id = object_id; + req->items[req->cursor].property_id = property_id; + req->items[req->cursor].value = value; + req->cursor++; + + return req->cursor; +} + +drm_public void drmModeAtomicFree(drmModeAtomicReqPtr req) +{ + if (!req) + return; + + if (req->items) + drmFree(req->items); + drmFree(req); +} + +static int sort_req_list(const void *misc, const void *other) +{ + const drmModeAtomicReqItem *first = misc; + const drmModeAtomicReqItem *second = other; + + if (first->object_id < second->object_id) + return -1; + else if (first->object_id > second->object_id) + return 1; + else + return second->property_id - first->property_id; +} + +drm_public int drmModeAtomicCommit(int fd, drmModeAtomicReqPtr req, + uint32_t flags, void *user_data) +{ + drmModeAtomicReqPtr sorted; + struct drm_mode_atomic atomic; + uint32_t *objs_ptr = NULL; + uint32_t *count_props_ptr = NULL; + uint32_t *props_ptr = NULL; + uint64_t *prop_values_ptr = NULL; + uint32_t last_obj_id = 0; + uint32_t i; + int obj_idx = -1; + int ret = -1; + + if (!req) + return -EINVAL; + + if (req->cursor == 0) + return 0; + + sorted = drmModeAtomicDuplicate(req); + if (sorted == NULL) + return -ENOMEM; + + memclear(atomic); + + /* Sort the list by object ID, then by property ID. */ + qsort(sorted->items, sorted->cursor, sizeof(*sorted->items), + sort_req_list); + + /* Now the list is sorted, eliminate duplicate property sets. */ + for (i = 0; i < sorted->cursor; i++) { + if (sorted->items[i].object_id != last_obj_id) { + atomic.count_objs++; + last_obj_id = sorted->items[i].object_id; + } + + if (i == sorted->cursor - 1) + continue; + + if (sorted->items[i].object_id != sorted->items[i + 1].object_id || + sorted->items[i].property_id != sorted->items[i + 1].property_id) + continue; + + memmove(&sorted->items[i], &sorted->items[i + 1], + (sorted->cursor - i - 1) * sizeof(*sorted->items)); + sorted->cursor--; + } + + objs_ptr = drmMalloc(atomic.count_objs * sizeof objs_ptr[0]); + if (!objs_ptr) { + errno = ENOMEM; + goto out; + } + + count_props_ptr = drmMalloc(atomic.count_objs * sizeof count_props_ptr[0]); + if (!count_props_ptr) { + errno = ENOMEM; + goto out; + } + + props_ptr = drmMalloc(sorted->cursor * sizeof props_ptr[0]); + if (!props_ptr) { + errno = ENOMEM; + goto out; + } + + prop_values_ptr = drmMalloc(sorted->cursor * sizeof prop_values_ptr[0]); + if (!prop_values_ptr) { + errno = ENOMEM; + goto out; + } + + for (i = 0, last_obj_id = 0; i < sorted->cursor; i++) { + if (sorted->items[i].object_id != last_obj_id) { + obj_idx++; + objs_ptr[obj_idx] = sorted->items[i].object_id; + last_obj_id = objs_ptr[obj_idx]; + } + + count_props_ptr[obj_idx]++; + props_ptr[i] = sorted->items[i].property_id; + prop_values_ptr[i] = sorted->items[i].value; + + } + + atomic.flags = flags; + atomic.objs_ptr = VOID2U64(objs_ptr); + atomic.count_props_ptr = VOID2U64(count_props_ptr); + atomic.props_ptr = VOID2U64(props_ptr); + atomic.prop_values_ptr = VOID2U64(prop_values_ptr); + atomic.user_data = VOID2U64(user_data); + + ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_ATOMIC, &atomic); + +out: + drmFree(objs_ptr); + drmFree(count_props_ptr); + drmFree(props_ptr); + drmFree(prop_values_ptr); + drmModeAtomicFree(sorted); + + return ret; +} + +drm_public int +drmModeCreatePropertyBlob(int fd, const void *data, size_t length, + uint32_t *id) +{ + struct drm_mode_create_blob create; + int ret; + + if (length >= 0xffffffff) + return -ERANGE; + + memclear(create); + + create.length = length; + create.data = (uintptr_t) data; + create.blob_id = 0; + *id = 0; + + ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_CREATEPROPBLOB, &create); + if (ret != 0) + return ret; + + *id = create.blob_id; + return 0; +} + +drm_public int +drmModeDestroyPropertyBlob(int fd, uint32_t id) +{ + struct drm_mode_destroy_blob destroy; + + memclear(destroy); + destroy.blob_id = id; + return DRM_IOCTL(fd, DRM_IOCTL_MODE_DESTROYPROPBLOB, &destroy); +} + +drm_public int +drmModeCreateLease(int fd, const uint32_t *objects, int num_objects, int flags, + uint32_t *lessee_id) +{ + struct drm_mode_create_lease create; + int ret; + + memclear(create); + create.object_ids = (uintptr_t) objects; + create.object_count = num_objects; + create.flags = flags; + + ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_CREATE_LEASE, &create); + if (ret == 0) { + *lessee_id = create.lessee_id; + return create.fd; + } + return -errno; +} + +drm_public drmModeLesseeListPtr +drmModeListLessees(int fd) +{ + struct drm_mode_list_lessees list; + uint32_t count; + drmModeLesseeListPtr ret; + + memclear(list); + + if (DRM_IOCTL(fd, DRM_IOCTL_MODE_LIST_LESSEES, &list)) + return NULL; + + count = list.count_lessees; + ret = drmMalloc(sizeof (drmModeLesseeListRes) + count * sizeof (ret->lessees[0])); + if (!ret) + return NULL; + + list.lessees_ptr = VOID2U64(&ret->lessees[0]); + if (DRM_IOCTL(fd, DRM_IOCTL_MODE_LIST_LESSEES, &list)) { + drmFree(ret); + return NULL; + } + + ret->count = count; + return ret; +} + +drm_public drmModeObjectListPtr +drmModeGetLease(int fd) +{ + struct drm_mode_get_lease get; + uint32_t count; + drmModeObjectListPtr ret; + + memclear(get); + + if (DRM_IOCTL(fd, DRM_IOCTL_MODE_GET_LEASE, &get)) + return NULL; + + count = get.count_objects; + ret = drmMalloc(sizeof (drmModeObjectListRes) + count * sizeof (ret->objects[0])); + if (!ret) + return NULL; + + get.objects_ptr = VOID2U64(&ret->objects[0]); + if (DRM_IOCTL(fd, DRM_IOCTL_MODE_GET_LEASE, &get)) { + drmFree(ret); + return NULL; + } + + ret->count = count; + return ret; +} + +drm_public int +drmModeRevokeLease(int fd, uint32_t lessee_id) +{ + struct drm_mode_revoke_lease revoke; + int ret; + + memclear(revoke); + + revoke.lessee_id = lessee_id; + + ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_REVOKE_LEASE, &revoke); + if (ret == 0) + return 0; + return -errno; +} + +drm_public drmModeFB2Ptr +drmModeGetFB2(int fd, uint32_t fb_id) +{ + struct drm_mode_fb_cmd2 get = { + .fb_id = fb_id, + }; + drmModeFB2Ptr ret; + int err; + + err = DRM_IOCTL(fd, DRM_IOCTL_MODE_GETFB2, &get); + if (err != 0) + return NULL; + + ret = drmMalloc(sizeof(drmModeFB2)); + if (!ret) + return NULL; + + ret->fb_id = fb_id; + ret->width = get.width; + ret->height = get.height; + ret->pixel_format = get.pixel_format; + ret->flags = get.flags; + ret->modifier = get.modifier[0]; + memcpy(ret->handles, get.handles, sizeof(uint32_t) * 4); + memcpy(ret->pitches, get.pitches, sizeof(uint32_t) * 4); + memcpy(ret->offsets, get.offsets, sizeof(uint32_t) * 4); + + return ret; +} + +drm_public void drmModeFreeFB2(drmModeFB2Ptr ptr) +{ + drmFree(ptr); +}