diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index c1d173c4..2cb9c9e9 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -271,6 +271,7 @@ typedef struct _drmTextureRegion { typedef enum { DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + DRM_VBLANK_EVENT = 0x4000000, /**< Send event instead of blocking */ DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */ DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ @@ -667,4 +668,22 @@ extern void drmMsg(const char *format, ...); extern int drmSetMaster(int fd); extern int drmDropMaster(int fd); +#define DRM_EVENT_CONTEXT_VERSION 1 + +typedef struct _drmEventContext { + + /* This struct is versioned so we can add more pointers if we + * add more events. */ + int version; + + void (*vblank_handler)(int fd, + unsigned int sequence, + unsigned int tv_sec, + unsigned int tv_usec, + void *user_data); + +} drmEventContext, *drmEventContextPtr; + +extern int drmHandleEvent(int fd, drmEventContextPtr evctx); + #endif diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index 88b4fe3a..6d85113a 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #define U642VOID(x) ((void *)(unsigned long)(x)) @@ -667,3 +668,45 @@ int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size, return 0; } + +int drmHandleEvent(int fd, drmEventContextPtr evctx) +{ + char buffer[1024]; + int len, i; + struct drm_event *e; + struct drm_event_vblank *vblank; + + /* 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) + return -1; + + i = 0; + while (i < len) { + e = (struct drm_event *) &buffer[i]; + switch (e->type) { + case DRM_EVENT_VBLANK: + if (evctx->version < 1 || + evctx->vblank_handler == NULL) + break; + vblank = (struct drm_event_vblank *) e; + evctx->vblank_handler(fd, + vblank->sequence, + vblank->tv_sec, + vblank->tv_usec, + U642VOID (vblank->user_data)); + break; + + default: + break; + } + i += e->length; + } + + return 0; +} + diff --git a/shared-core/drm.h b/shared-core/drm.h index d97844f8..089e184a 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -809,6 +809,34 @@ struct drm_gem_open { #define DRM_COMMAND_BASE 0x40 #define DRM_COMMAND_END 0xA0 +/** + * Header for events written back to userspace on the drm fd. The + * type defines the type of event, the length specifies the total + * length of the event (including the header), and user_data is + * typically a 64 bit value passed with the ioctl that triggered the + * event. A read on the drm fd will always only return complete + * events, that is, if for example the read buffer is 100 bytes, and + * there are two 64 byte events pending, only one will be returned. + * + * Event types 0 - 0x7fffffff are generic drm events, 0x80000000 and + * up are chipset specific. + */ +struct drm_event { + uint32_t type; + uint32_t length; +}; + +#define DRM_EVENT_VBLANK 0x01 + +struct drm_event_vblank { + struct drm_event base; + uint64_t user_data; + uint32_t tv_sec; + uint32_t tv_usec; + uint32_t sequence; + uint32_t reserved; +}; + /* typedef area */ #ifndef __KERNEL__ typedef struct drm_clip_rect drm_clip_rect_t;