diff --git a/include/drm/drm.h b/include/drm/drm.h index 1666e91b..c183fcc0 100644 --- a/include/drm/drm.h +++ b/include/drm/drm.h @@ -806,6 +806,13 @@ struct drm_gem_change_handle { * commits. */ #define DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP 0x15 +/** + * DRM_CAP_ATOMIC_ERROR_REPORTING + * + * If set to 1, the driver supports reporting of failure codes on error in + * atomic ioctl(). + */ +#define DRM_CAP_ATOMIC_ERROR_REPORTING 0x16 /* DRM_IOCTL_GET_CAP ioctl argument type */ struct drm_get_cap { diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h index cbbbfc1d..71e91d4f 100644 --- a/include/drm/drm_mode.h +++ b/include/drm/drm_mode.h @@ -45,6 +45,7 @@ extern "C" { #define DRM_CONNECTOR_NAME_LEN 32 #define DRM_DISPLAY_MODE_LEN 32 #define DRM_PROP_NAME_LEN 32 +#define DRM_MODE_ATOMIC_FAILURE_STRING_LEN 128 #define DRM_MODE_TYPE_BUILTIN (1<<0) /* deprecated */ #define DRM_MODE_TYPE_CLOCK_C ((1<<1) | DRM_MODE_TYPE_BUILTIN) /* deprecated */ @@ -166,6 +167,10 @@ extern "C" { #define DRM_MODE_LINK_STATUS_GOOD 0 #define DRM_MODE_LINK_STATUS_BAD 1 +/* Panel type property */ +#define DRM_MODE_PANEL_TYPE_UNKNOWN 0 +#define DRM_MODE_PANEL_TYPE_OLED 1 + /* * DRM_MODE_ROTATE_ * @@ -1339,6 +1344,42 @@ struct drm_mode_destroy_dumb { DRM_MODE_ATOMIC_NONBLOCK |\ DRM_MODE_ATOMIC_ALLOW_MODESET) +/** + * enum drm_mode_atomic_failure_codes - error codes for failures in atomic_ioctl + * @DRM_MODE_ATOMIC_INVALID_API_USAGE: invallid API usage(DRM_ATOMIC not + * enabled, invalid falg, page_flip event + * with test-only, etc) + * @DRM_MODE_ATOMIC_CRTC_NEED_FULL_MODESET: Need full modeset on this crtc + * @DRM_MODE_ATOMIC_NEED_FULL_MODESET: Need full modeset on all connected crtc's + * @DRM_MODE_ATOMIC_ASYNC_PROP_CHANGED: Property changed in async flip + */ +enum drm_mode_atomic_failure_codes { + DRM_MODE_ATOMIC_INVALID_API_USAGE, + DRM_MODE_ATOMIC_CRTC_NEED_FULL_MODESET, + DRM_MODE_ATOMIC_NEED_FULL_MODESET, + DRM_MODE_ATOMIC_ASYNC_PROP_CHANGED, +}; + +/** + * struct drm_mode_atomic_err_code - struct to store the error code + * + * pointer to this struct will be stored in reserved variable of + * struct drm_mode_atomic to report the failure cause to the user. + * + * @failure_code: error codes defined in enum drm_moide_atomic_failure_code + * @failure_objs_ptr: pointer to the drm_object that caused error + * @reserved: reserved for future use + * @count_objs: count of drm_objects if multiple drm_objects caused error + * @failure_string: user readable error message string + */ +struct drm_mode_atomic_err_code { + __u64 failure_code; + __u64 failure_objs_ptr; + __u64 reserved; + __u32 count_objs; + char failure_string[DRM_MODE_ATOMIC_FAILURE_STRING_LEN]; +}; + struct drm_mode_atomic { __u32 flags; __u32 count_objs; diff --git a/xf86drmMode.c b/xf86drmMode.c index a4873a0f..fb97dcc5 100644 --- a/xf86drmMode.c +++ b/xf86drmMode.c @@ -1363,9 +1363,15 @@ struct _drmModeAtomicReqItem { struct _drmModeAtomicReq { uint32_t cursor; uint32_t size_items; + struct drm_mode_atomic_err_code *err_code_ptr; drmModeAtomicReqItemPtr items; }; +drm_public const struct drm_mode_atomic_err_code * drmModeAtomicGetErrorCode(drmModeAtomicReqPtr req) +{ + return req->err_code_ptr; +} + drm_public drmModeAtomicReqPtr drmModeAtomicAlloc(void) { drmModeAtomicReqPtr req; @@ -1377,6 +1383,9 @@ drm_public drmModeAtomicReqPtr drmModeAtomicAlloc(void) req->items = NULL; req->cursor = 0; req->size_items = 0; + req->err_code_ptr = drmMalloc(sizeof(struct drm_mode_atomic_err_code)); + if (!req->err_code_ptr) + return NULL; return req; } @@ -1395,9 +1404,21 @@ drm_public drmModeAtomicReqPtr drmModeAtomicDuplicate(const drmModeAtomicReqPtr new->cursor = old->cursor; new->size_items = old->size_items; + if (old->err_code_ptr) { + new->err_code_ptr = drmMalloc(sizeof(struct drm_mode_atomic_err_code)); + if (!new->err_code_ptr) { + free(new); + return NULL; + } + memcpy(new->err_code_ptr, old->err_code_ptr, sizeof(struct drm_mode_atomic_err_code)); + } else + new->err_code_ptr = NULL; + if (old->size_items) { new->items = drmMalloc(old->size_items * sizeof(*new->items)); if (!new->items) { + if (new->err_code_ptr) + free(new->err_code_ptr); free(new); return NULL; } @@ -1441,6 +1462,10 @@ drm_public int drmModeAtomicMerge(drmModeAtomicReqPtr base, base->items[i].cursor = i; base->cursor += augment->cursor; + if (base->err_code_ptr) + memcpy(base->err_code_ptr, augment->err_code_ptr, + sizeof(struct drm_mode_atomic_err_code)); + return 0; } @@ -1497,6 +1522,10 @@ drm_public void drmModeAtomicFree(drmModeAtomicReqPtr req) if (req->items) drmFree(req->items); + if (req->err_code_ptr) { + drmFree(req->err_code_ptr); + } + drmFree(req); } @@ -1518,6 +1547,7 @@ drm_public int drmModeAtomicCommit(int fd, const drmModeAtomicReqPtr req, { drmModeAtomicReqPtr sorted; struct drm_mode_atomic atomic; + uint64_t err_reporting = 0; uint32_t *objs_ptr = NULL; uint32_t *count_props_ptr = NULL; uint32_t *props_ptr = NULL; @@ -1609,8 +1639,15 @@ drm_public int drmModeAtomicCommit(int fd, const drmModeAtomicReqPtr req, atomic.prop_values_ptr = VOID2U64(prop_values_ptr); atomic.user_data = VOID2U64(user_data); - ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_ATOMIC, &atomic); + /* TODO: This capability has to read on init once and retrived on each commit */ + /* Check if atomic error reporting is available */ + drmGetCap(fd, DRM_CAP_ATOMIC_ERROR_REPORTING, &err_reporting); + if (err_reporting) + atomic.reserved = (uintptr_t)req->err_code_ptr; + else + atomic.reserved = 0; + ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_ATOMIC, &atomic); out: drmFree(objs_ptr); drmFree(count_props_ptr); diff --git a/xf86drmMode.h b/xf86drmMode.h index 08487887..e7612064 100644 --- a/xf86drmMode.h +++ b/xf86drmMode.h @@ -536,6 +536,8 @@ drmModeDestroyDumbBuffer(int fd, uint32_t handle); extern int drmModeMapDumbBuffer(int fd, uint32_t handle, uint64_t *offset); +extern const struct drm_mode_atomic_err_code * drmModeAtomicGetErrorCode(drmModeAtomicReqPtr req); + #if defined(__cplusplus) } #endif