X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=xf86drm.c;h=953fc76203f2caad394a46b1a09c256c00f5c124;hb=def955c09ecec3789b03dfdedc1761ad65ab8eb2;hp=f306c9b7ee8f0d81f7f17a423e170ea77ed94be7;hpb=5226b52773e0a9972cd1e0dade55cb9ae869941c;p=android-x86%2Fexternal-libdrm.git diff --git a/xf86drm.c b/xf86drm.c index f306c9b7..953fc762 100644 --- a/xf86drm.c +++ b/xf86drm.c @@ -31,9 +31,6 @@ * DEALINGS IN THE SOFTWARE. */ -#ifdef HAVE_CONFIG_H -# include -#endif #include #include #include @@ -62,6 +59,8 @@ #endif #include +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + /* Not all systems have MAP_FAILED defined */ #ifndef MAP_FAILED #define MAP_FAILED ((void *)-1) @@ -102,7 +101,7 @@ #define DRM_MAJOR 226 /* Linux */ #endif -#ifdef __OpenBSD__ +#if defined(__OpenBSD__) || defined(__DragonFly__) struct drm_pciinfo { uint16_t domain; uint8_t bus; @@ -124,7 +123,7 @@ struct drm_pciinfo { static drmServerInfoPtr drm_server_info; -void drmSetServerInfo(drmServerInfoPtr info) +drm_public void drmSetServerInfo(drmServerInfoPtr info) { drm_server_info = info; } @@ -144,7 +143,7 @@ drmDebugPrint(const char *format, va_list ap) return vfprintf(stderr, format, ap); } -void +drm_public void drmMsg(const char *format, ...) { va_list ap; @@ -164,25 +163,25 @@ drmMsg(const char *format, ...) static void *drmHashTable = NULL; /* Context switch callbacks */ -void *drmGetHashTable(void) +drm_public void *drmGetHashTable(void) { return drmHashTable; } -void *drmMalloc(int size) +drm_public void *drmMalloc(int size) { return calloc(1, size); } -void drmFree(void *pt) +drm_public void drmFree(void *pt) { free(pt); } /** - * Call ioctl, restarting if it is interupted + * Call ioctl, restarting if it is interrupted */ -int +drm_public int drmIoctl(int fd, unsigned long request, void *arg) { int ret; @@ -202,7 +201,7 @@ static unsigned long drmGetKeyFromFd(int fd) return st.st_rdev; } -drmHashEntry *drmGetEntry(int fd) +drm_public drmHashEntry *drmGetEntry(int fd) { unsigned long key = drmGetKeyFromFd(fd); void *value; @@ -290,10 +289,10 @@ static int drmMatchBusID(const char *id1, const char *id2, int pci_domain_ok) * * \internal * Checks for failure. If failure was caused by signal call chown again. - * If any other failure happened then it will output error mesage using + * If any other failure happened then it will output error message using * drmMsg() call. */ -#if !defined(UDEV) +#if !UDEV static int chown_check_return(const char *path, uid_t owner, gid_t group) { int rv; @@ -332,7 +331,7 @@ static int drmOpenDevice(dev_t dev, int minor, int type) int fd; mode_t devmode = DRM_DEV_MODE, serv_mode; gid_t serv_group; -#if !defined(UDEV) +#if !UDEV int isroot = !geteuid(); uid_t user = DRM_DEV_UID; gid_t group = DRM_DEV_GID; @@ -361,7 +360,7 @@ static int drmOpenDevice(dev_t dev, int minor, int type) devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH); } -#if !defined(UDEV) +#if !UDEV if (stat(DRM_DIR_NAME, &st)) { if (!isroot) return DRM_ERR_NOT_ROOT; @@ -408,13 +407,13 @@ wait_for_udev: } #endif - fd = open(buf, O_RDWR, 0); + fd = open(buf, O_RDWR | O_CLOEXEC, 0); drmMsg("drmOpenDevice: open result is %d, (%s)\n", fd, fd < 0 ? strerror(errno) : "OK"); if (fd >= 0) return fd; -#if !defined(UDEV) +#if !UDEV /* Check if the device node is not what we expect it to be, and recreate it * and try again if so. */ @@ -428,7 +427,7 @@ wait_for_udev: chmod(buf, devmode); } } - fd = open(buf, O_RDWR, 0); + fd = open(buf, O_RDWR | O_CLOEXEC, 0); drmMsg("drmOpenDevice: open result is %d, (%s)\n", fd, fd < 0 ? strerror(errno) : "OK"); if (fd >= 0) @@ -477,7 +476,7 @@ static int drmOpenMinor(int minor, int create, int type) }; sprintf(buf, dev_name, DRM_DIR_NAME, minor); - if ((fd = open(buf, O_RDWR, 0)) >= 0) + if ((fd = open(buf, O_RDWR | O_CLOEXEC, 0)) >= 0) return fd; return -errno; } @@ -493,7 +492,7 @@ static int drmOpenMinor(int minor, int create, int type) * minor and get version information. For backward compatibility with older * Linux implementations, /proc/dri is also checked. */ -int drmAvailable(void) +drm_public int drmAvailable(void) { drmVersionPtr version; int retval = 0; @@ -728,7 +727,7 @@ static int drmOpenByName(const char *name, int type) * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName() * otherwise. */ -int drmOpen(const char *name, const char *busid) +drm_public int drmOpen(const char *name, const char *busid) { return drmOpenWithType(name, busid, DRM_NODE_PRIMARY); } @@ -749,10 +748,10 @@ int drmOpen(const char *name, const char *busid) * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName() * otherwise. */ -int drmOpenWithType(const char *name, const char *busid, int type) +drm_public int drmOpenWithType(const char *name, const char *busid, int type) { - if (!drmAvailable() && name != NULL && drm_server_info && - drm_server_info->load_module) { + if (name != NULL && drm_server_info && + drm_server_info->load_module && !drmAvailable()) { /* try to load the kernel module */ if (!drm_server_info->load_module(name)) { drmMsg("[drm] failed to load kernel module \"%s\"\n", name); @@ -772,12 +771,12 @@ int drmOpenWithType(const char *name, const char *busid, int type) return -1; } -int drmOpenControl(int minor) +drm_public int drmOpenControl(int minor) { return drmOpenMinor(minor, 0, DRM_NODE_CONTROL); } -int drmOpenRender(int minor) +drm_public int drmOpenRender(int minor) { return drmOpenMinor(minor, 0, DRM_NODE_RENDER); } @@ -791,7 +790,7 @@ int drmOpenRender(int minor) * It frees the memory pointed by \p %v as well as all the non-null strings * pointers in it. */ -void drmFreeVersion(drmVersionPtr v) +drm_public void drmFreeVersion(drmVersionPtr v) { if (!v) return; @@ -861,7 +860,7 @@ static void drmCopyVersion(drmVersionPtr d, const drm_version_t *s) * first with zeros to get the string lengths, and then the actually strings. * It also null-terminates them since they might not be already. */ -drmVersionPtr drmGetVersion(int fd) +drm_public drmVersionPtr drmGetVersion(int fd) { drmVersionPtr retval; drm_version_t *version = drmMalloc(sizeof(*version)); @@ -909,7 +908,7 @@ drmVersionPtr drmGetVersion(int fd) * This function allocates and fills a drm_version structure with a hard coded * version number. */ -drmVersionPtr drmGetLibVersion(int fd) +drm_public drmVersionPtr drmGetLibVersion(int fd) { drm_version_t *version = drmMalloc(sizeof(*version)); @@ -930,7 +929,7 @@ drmVersionPtr drmGetLibVersion(int fd) return (drmVersionPtr)version; } -int drmGetCap(int fd, uint64_t capability, uint64_t *value) +drm_public int drmGetCap(int fd, uint64_t capability, uint64_t *value) { struct drm_get_cap cap; int ret; @@ -946,7 +945,7 @@ int drmGetCap(int fd, uint64_t capability, uint64_t *value) return 0; } -int drmSetClientCap(int fd, uint64_t capability, uint64_t value) +drm_public int drmSetClientCap(int fd, uint64_t capability, uint64_t value) { struct drm_set_client_cap cap; @@ -965,7 +964,7 @@ int drmSetClientCap(int fd, uint64_t capability, uint64_t value) * \internal * This function is just frees the memory pointed by \p busid. */ -void drmFreeBusid(const char *busid) +drm_public void drmFreeBusid(const char *busid) { drmFree((void *)busid); } @@ -983,7 +982,7 @@ void drmFreeBusid(const char *busid) * get the string length and data, passing the arguments in a drm_unique * structure. */ -char *drmGetBusid(int fd) +drm_public char *drmGetBusid(int fd) { drm_unique_t u; @@ -1014,7 +1013,7 @@ char *drmGetBusid(int fd) * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing * the arguments in a drm_unique structure. */ -int drmSetBusid(int fd, const char *busid) +drm_public int drmSetBusid(int fd, const char *busid) { drm_unique_t u; @@ -1028,7 +1027,7 @@ int drmSetBusid(int fd, const char *busid) return 0; } -int drmGetMagic(int fd, drm_magic_t * magic) +drm_public int drmGetMagic(int fd, drm_magic_t * magic) { drm_auth_t auth; @@ -1041,7 +1040,7 @@ int drmGetMagic(int fd, drm_magic_t * magic) return 0; } -int drmAuthMagic(int fd, drm_magic_t magic) +drm_public int drmAuthMagic(int fd, drm_magic_t magic) { drm_auth_t auth; @@ -1102,8 +1101,8 @@ int drmAuthMagic(int fd, drm_magic_t magic) * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing * the arguments in a drm_map structure. */ -int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type, - drmMapFlags flags, drm_handle_t *handle) +drm_public int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type, + drmMapFlags flags, drm_handle_t *handle) { drm_map_t map; @@ -1119,7 +1118,7 @@ int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type, return 0; } -int drmRmMap(int fd, drm_handle_t handle) +drm_public int drmRmMap(int fd, drm_handle_t handle) { drm_map_t map; @@ -1147,8 +1146,8 @@ int drmRmMap(int fd, drm_handle_t handle) * * \sa drm_buf_desc. */ -int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags, - int agp_offset) +drm_public int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags, + int agp_offset) { drm_buf_desc_t request; @@ -1163,7 +1162,7 @@ int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags, return request.count; } -int drmMarkBufs(int fd, double low, double high) +drm_public int drmMarkBufs(int fd, double low, double high) { drm_buf_info_t info; int i; @@ -1214,7 +1213,7 @@ int drmMarkBufs(int fd, double low, double high) * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing * the arguments in a drm_buf_free structure. */ -int drmFreeBufs(int fd, int count, int *list) +drm_public int drmFreeBufs(int fd, int count, int *list) { drm_buf_free_t request; @@ -1235,7 +1234,7 @@ int drmFreeBufs(int fd, int count, int *list) * \internal * This function closes the file descriptor. */ -int drmClose(int fd) +drm_public int drmClose(int fd) { unsigned long key = drmGetKeyFromFd(fd); drmHashEntry *entry = drmGetEntry(fd); @@ -1266,7 +1265,8 @@ int drmClose(int fd) * \internal * This function is a wrapper for mmap(). */ -int drmMap(int fd, drm_handle_t handle, drmSize size, drmAddressPtr address) +drm_public int drmMap(int fd, drm_handle_t handle, drmSize size, + drmAddressPtr address) { static unsigned long pagesize_mask = 0; @@ -1296,12 +1296,12 @@ int drmMap(int fd, drm_handle_t handle, drmSize size, drmAddressPtr address) * \internal * This function is a wrapper for munmap(). */ -int drmUnmap(drmAddress address, drmSize size) +drm_public int drmUnmap(drmAddress address, drmSize size) { return drm_munmap(address, size); } -drmBufInfoPtr drmGetBufInfo(int fd) +drm_public drmBufInfoPtr drmGetBufInfo(int fd) { drm_buf_info_t info; drmBufInfoPtr retval; @@ -1351,7 +1351,7 @@ drmBufInfoPtr drmGetBufInfo(int fd) * information about the buffers in a drm_buf_map structure into the * client-visible data structures. */ -drmBufMapPtr drmMapBufs(int fd) +drm_public drmBufMapPtr drmMapBufs(int fd) { drm_buf_map_t bufs; drmBufMapPtr retval; @@ -1396,7 +1396,7 @@ drmBufMapPtr drmMapBufs(int fd) * Calls munmap() for every buffer stored in \p bufs and frees the * memory allocated by drmMapBufs(). */ -int drmUnmapBufs(drmBufMapPtr bufs) +drm_public int drmUnmapBufs(drmBufMapPtr bufs) { int i; @@ -1424,7 +1424,7 @@ int drmUnmapBufs(drmBufMapPtr bufs) * Assemble the arguments into a drm_dma structure and keeps issuing the * DRM_IOCTL_DMA ioctl until success or until maximum number of retries. */ -int drmDMA(int fd, drmDMAReqPtr request) +drm_public int drmDMA(int fd, drmDMAReqPtr request) { drm_dma_t dma; int ret, i = 0; @@ -1458,7 +1458,7 @@ int drmDMA(int fd, drmDMAReqPtr request) * * \param fd file descriptor. * \param context context. - * \param flags flags that determine the sate of the hardware when the function + * \param flags flags that determine the state of the hardware when the function * returns. * * \return always zero. @@ -1467,7 +1467,7 @@ int drmDMA(int fd, drmDMAReqPtr request) * This function translates the arguments into a drm_lock structure and issue * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired. */ -int drmGetLock(int fd, drm_context_t context, drmLockFlags flags) +drm_public int drmGetLock(int fd, drm_context_t context, drmLockFlags flags) { drm_lock_t lock; @@ -1498,7 +1498,7 @@ int drmGetLock(int fd, drm_context_t context, drmLockFlags flags) * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the * argument in a drm_lock structure. */ -int drmUnlock(int fd, drm_context_t context) +drm_public int drmUnlock(int fd, drm_context_t context) { drm_lock_t lock; @@ -1507,7 +1507,7 @@ int drmUnlock(int fd, drm_context_t context) return drmIoctl(fd, DRM_IOCTL_UNLOCK, &lock); } -drm_context_t *drmGetReservedContextList(int fd, int *count) +drm_public drm_context_t *drmGetReservedContextList(int fd, int *count) { drm_ctx_res_t res; drm_ctx_t *list; @@ -1544,7 +1544,7 @@ err_free_context: return NULL; } -void drmFreeReservedContextList(drm_context_t *pt) +drm_public void drmFreeReservedContextList(drm_context_t *pt) { drmFree(pt); } @@ -1567,7 +1567,7 @@ void drmFreeReservedContextList(drm_context_t *pt) * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the * argument in a drm_ctx structure. */ -int drmCreateContext(int fd, drm_context_t *handle) +drm_public int drmCreateContext(int fd, drm_context_t *handle) { drm_ctx_t ctx; @@ -1578,7 +1578,7 @@ int drmCreateContext(int fd, drm_context_t *handle) return 0; } -int drmSwitchToContext(int fd, drm_context_t context) +drm_public int drmSwitchToContext(int fd, drm_context_t context) { drm_ctx_t ctx; @@ -1589,7 +1589,8 @@ int drmSwitchToContext(int fd, drm_context_t context) return 0; } -int drmSetContextFlags(int fd, drm_context_t context, drm_context_tFlags flags) +drm_public int drmSetContextFlags(int fd, drm_context_t context, + drm_context_tFlags flags) { drm_ctx_t ctx; @@ -1610,8 +1611,8 @@ int drmSetContextFlags(int fd, drm_context_t context, drm_context_tFlags flags) return 0; } -int drmGetContextFlags(int fd, drm_context_t context, - drm_context_tFlagsPtr flags) +drm_public int drmGetContextFlags(int fd, drm_context_t context, + drm_context_tFlagsPtr flags) { drm_ctx_t ctx; @@ -1644,7 +1645,7 @@ int drmGetContextFlags(int fd, drm_context_t context, * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the * argument in a drm_ctx structure. */ -int drmDestroyContext(int fd, drm_context_t handle) +drm_public int drmDestroyContext(int fd, drm_context_t handle) { drm_ctx_t ctx; @@ -1655,7 +1656,7 @@ int drmDestroyContext(int fd, drm_context_t handle) return 0; } -int drmCreateDrawable(int fd, drm_drawable_t *handle) +drm_public int drmCreateDrawable(int fd, drm_drawable_t *handle) { drm_draw_t draw; @@ -1666,7 +1667,7 @@ int drmCreateDrawable(int fd, drm_drawable_t *handle) return 0; } -int drmDestroyDrawable(int fd, drm_drawable_t handle) +drm_public int drmDestroyDrawable(int fd, drm_drawable_t handle) { drm_draw_t draw; @@ -1677,9 +1678,9 @@ int drmDestroyDrawable(int fd, drm_drawable_t handle) return 0; } -int drmUpdateDrawableInfo(int fd, drm_drawable_t handle, - drm_drawable_info_type_t type, unsigned int num, - void *data) +drm_public int drmUpdateDrawableInfo(int fd, drm_drawable_t handle, + drm_drawable_info_type_t type, + unsigned int num, void *data) { drm_update_draw_t update; @@ -1695,6 +1696,46 @@ int drmUpdateDrawableInfo(int fd, drm_drawable_t handle, return 0; } +drm_public int drmCrtcGetSequence(int fd, uint32_t crtcId, uint64_t *sequence, + uint64_t *ns) +{ + struct drm_crtc_get_sequence get_seq; + int ret; + + memclear(get_seq); + get_seq.crtc_id = crtcId; + ret = drmIoctl(fd, DRM_IOCTL_CRTC_GET_SEQUENCE, &get_seq); + if (ret) + return ret; + + if (sequence) + *sequence = get_seq.sequence; + if (ns) + *ns = get_seq.sequence_ns; + return 0; +} + +drm_public int drmCrtcQueueSequence(int fd, uint32_t crtcId, uint32_t flags, + uint64_t sequence, + uint64_t *sequence_queued, + uint64_t user_data) +{ + struct drm_crtc_queue_sequence queue_seq; + int ret; + + memclear(queue_seq); + queue_seq.crtc_id = crtcId; + queue_seq.flags = flags; + queue_seq.sequence = sequence; + queue_seq.user_data = user_data; + + ret = drmIoctl(fd, DRM_IOCTL_CRTC_QUEUE_SEQUENCE, &queue_seq); + if (ret == 0 && sequence_queued) + *sequence_queued = queue_seq.sequence; + + return ret; +} + /** * Acquire the AGP device. * @@ -1707,7 +1748,7 @@ int drmUpdateDrawableInfo(int fd, drm_drawable_t handle, * \internal * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl. */ -int drmAgpAcquire(int fd) +drm_public int drmAgpAcquire(int fd) { if (drmIoctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL)) return -errno; @@ -1725,7 +1766,7 @@ int drmAgpAcquire(int fd) * \internal * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl. */ -int drmAgpRelease(int fd) +drm_public int drmAgpRelease(int fd) { if (drmIoctl(fd, DRM_IOCTL_AGP_RELEASE, NULL)) return -errno; @@ -1745,7 +1786,7 @@ int drmAgpRelease(int fd) * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the * argument in a drm_agp_mode structure. */ -int drmAgpEnable(int fd, unsigned long mode) +drm_public int drmAgpEnable(int fd, unsigned long mode) { drm_agp_mode_t m; @@ -1773,8 +1814,8 @@ int drmAgpEnable(int fd, unsigned long mode) * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the * arguments in a drm_agp_buffer structure. */ -int drmAgpAlloc(int fd, unsigned long size, unsigned long type, - unsigned long *address, drm_handle_t *handle) +drm_public int drmAgpAlloc(int fd, unsigned long size, unsigned long type, + unsigned long *address, drm_handle_t *handle) { drm_agp_buffer_t b; @@ -1803,7 +1844,7 @@ int drmAgpAlloc(int fd, unsigned long size, unsigned long type, * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the * argument in a drm_agp_buffer structure. */ -int drmAgpFree(int fd, drm_handle_t handle) +drm_public int drmAgpFree(int fd, drm_handle_t handle) { drm_agp_buffer_t b; @@ -1828,7 +1869,7 @@ int drmAgpFree(int fd, drm_handle_t handle) * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the * argument in a drm_agp_binding structure. */ -int drmAgpBind(int fd, drm_handle_t handle, unsigned long offset) +drm_public int drmAgpBind(int fd, drm_handle_t handle, unsigned long offset) { drm_agp_binding_t b; @@ -1853,7 +1894,7 @@ int drmAgpBind(int fd, drm_handle_t handle, unsigned long offset) * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing * the argument in a drm_agp_binding structure. */ -int drmAgpUnbind(int fd, drm_handle_t handle) +drm_public int drmAgpUnbind(int fd, drm_handle_t handle) { drm_agp_binding_t b; @@ -1876,7 +1917,7 @@ int drmAgpUnbind(int fd, drm_handle_t handle) * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the * necessary information in a drm_agp_info structure. */ -int drmAgpVersionMajor(int fd) +drm_public int drmAgpVersionMajor(int fd) { drm_agp_info_t i; @@ -1899,7 +1940,7 @@ int drmAgpVersionMajor(int fd) * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the * necessary information in a drm_agp_info structure. */ -int drmAgpVersionMinor(int fd) +drm_public int drmAgpVersionMinor(int fd) { drm_agp_info_t i; @@ -1922,7 +1963,7 @@ int drmAgpVersionMinor(int fd) * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the * necessary information in a drm_agp_info structure. */ -unsigned long drmAgpGetMode(int fd) +drm_public unsigned long drmAgpGetMode(int fd) { drm_agp_info_t i; @@ -1945,7 +1986,7 @@ unsigned long drmAgpGetMode(int fd) * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the * necessary information in a drm_agp_info structure. */ -unsigned long drmAgpBase(int fd) +drm_public unsigned long drmAgpBase(int fd) { drm_agp_info_t i; @@ -1968,7 +2009,7 @@ unsigned long drmAgpBase(int fd) * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the * necessary information in a drm_agp_info structure. */ -unsigned long drmAgpSize(int fd) +drm_public unsigned long drmAgpSize(int fd) { drm_agp_info_t i; @@ -1991,7 +2032,7 @@ unsigned long drmAgpSize(int fd) * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the * necessary information in a drm_agp_info structure. */ -unsigned long drmAgpMemoryUsed(int fd) +drm_public unsigned long drmAgpMemoryUsed(int fd) { drm_agp_info_t i; @@ -2014,7 +2055,7 @@ unsigned long drmAgpMemoryUsed(int fd) * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the * necessary information in a drm_agp_info structure. */ -unsigned long drmAgpMemoryAvail(int fd) +drm_public unsigned long drmAgpMemoryAvail(int fd) { drm_agp_info_t i; @@ -2037,7 +2078,7 @@ unsigned long drmAgpMemoryAvail(int fd) * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the * necessary information in a drm_agp_info structure. */ -unsigned int drmAgpVendorId(int fd) +drm_public unsigned int drmAgpVendorId(int fd) { drm_agp_info_t i; @@ -2060,7 +2101,7 @@ unsigned int drmAgpVendorId(int fd) * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the * necessary information in a drm_agp_info structure. */ -unsigned int drmAgpDeviceId(int fd) +drm_public unsigned int drmAgpDeviceId(int fd) { drm_agp_info_t i; @@ -2071,7 +2112,8 @@ unsigned int drmAgpDeviceId(int fd) return i.id_device; } -int drmScatterGatherAlloc(int fd, unsigned long size, drm_handle_t *handle) +drm_public int drmScatterGatherAlloc(int fd, unsigned long size, + drm_handle_t *handle) { drm_scatter_gather_t sg; @@ -2085,7 +2127,7 @@ int drmScatterGatherAlloc(int fd, unsigned long size, drm_handle_t *handle) return 0; } -int drmScatterGatherFree(int fd, drm_handle_t handle) +drm_public int drmScatterGatherFree(int fd, drm_handle_t handle) { drm_scatter_gather_t sg; @@ -2107,7 +2149,7 @@ int drmScatterGatherFree(int fd, drm_handle_t handle) * \internal * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl. */ -int drmWaitVBlank(int fd, drmVBlankPtr vbl) +drm_public int drmWaitVBlank(int fd, drmVBlankPtr vbl) { struct timespec timeout, cur; int ret; @@ -2139,7 +2181,7 @@ out: return ret; } -int drmError(int err, const char *label) +drm_public int drmError(int err, const char *label) { switch (err) { case DRM_ERR_NO_DEVICE: @@ -2176,7 +2218,7 @@ int drmError(int err, const char *label) * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the * argument in a drm_control structure. */ -int drmCtlInstHandler(int fd, int irq) +drm_public int drmCtlInstHandler(int fd, int irq) { drm_control_t ctl; @@ -2200,7 +2242,7 @@ int drmCtlInstHandler(int fd, int irq) * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the * argument in a drm_control structure. */ -int drmCtlUninstHandler(int fd) +drm_public int drmCtlUninstHandler(int fd) { drm_control_t ctl; @@ -2212,7 +2254,7 @@ int drmCtlUninstHandler(int fd) return 0; } -int drmFinish(int fd, int context, drmLockFlags flags) +drm_public int drmFinish(int fd, int context, drmLockFlags flags) { drm_lock_t lock; @@ -2243,7 +2285,8 @@ int drmFinish(int fd, int context, drmLockFlags flags) * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the * arguments in a drm_irq_busid structure. */ -int drmGetInterruptFromBusID(int fd, int busnum, int devnum, int funcnum) +drm_public int drmGetInterruptFromBusID(int fd, int busnum, int devnum, + int funcnum) { drm_irq_busid_t p; @@ -2256,7 +2299,7 @@ int drmGetInterruptFromBusID(int fd, int busnum, int devnum, int funcnum) return p.irq; } -int drmAddContextTag(int fd, drm_context_t context, void *tag) +drm_public int drmAddContextTag(int fd, drm_context_t context, void *tag) { drmHashEntry *entry = drmGetEntry(fd); @@ -2267,14 +2310,14 @@ int drmAddContextTag(int fd, drm_context_t context, void *tag) return 0; } -int drmDelContextTag(int fd, drm_context_t context) +drm_public int drmDelContextTag(int fd, drm_context_t context) { drmHashEntry *entry = drmGetEntry(fd); return drmHashDelete(entry->tagTable, context); } -void *drmGetContextTag(int fd, drm_context_t context) +drm_public void *drmGetContextTag(int fd, drm_context_t context) { drmHashEntry *entry = drmGetEntry(fd); void *value; @@ -2285,8 +2328,8 @@ void *drmGetContextTag(int fd, drm_context_t context) return value; } -int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id, - drm_handle_t handle) +drm_public int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id, + drm_handle_t handle) { drm_ctx_priv_map_t map; @@ -2299,8 +2342,8 @@ int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id, return 0; } -int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id, - drm_handle_t *handle) +drm_public int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id, + drm_handle_t *handle) { drm_ctx_priv_map_t map; @@ -2315,9 +2358,9 @@ int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id, return 0; } -int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size, - drmMapType *type, drmMapFlags *flags, drm_handle_t *handle, - int *mtrr) +drm_public int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size, + drmMapType *type, drmMapFlags *flags, + drm_handle_t *handle, int *mtrr) { drm_map_t map; @@ -2334,8 +2377,8 @@ int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size, return 0; } -int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid, - unsigned long *magic, unsigned long *iocs) +drm_public int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid, + unsigned long *magic, unsigned long *iocs) { drm_client_t client; @@ -2351,7 +2394,7 @@ int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid, return 0; } -int drmGetStats(int fd, drmStatsT *stats) +drm_public int drmGetStats(int fd, drmStatsT *stats) { drm_stats_t s; unsigned i; @@ -2489,7 +2532,7 @@ int drmGetStats(int fd, drmStatsT *stats) * It issues a read-write ioctl given by * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. */ -int drmSetInterfaceVersion(int fd, drmSetVersion *version) +drm_public int drmSetInterfaceVersion(int fd, drmSetVersion *version) { int retcode = 0; drm_set_version_t sv; @@ -2524,7 +2567,7 @@ int drmSetInterfaceVersion(int fd, drmSetVersion *version) * It issues a ioctl given by * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. */ -int drmCommandNone(int fd, unsigned long drmCommandIndex) +drm_public int drmCommandNone(int fd, unsigned long drmCommandIndex) { unsigned long request; @@ -2551,8 +2594,8 @@ int drmCommandNone(int fd, unsigned long drmCommandIndex) * It issues a read ioctl given by * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. */ -int drmCommandRead(int fd, unsigned long drmCommandIndex, void *data, - unsigned long size) +drm_public int drmCommandRead(int fd, unsigned long drmCommandIndex, + void *data, unsigned long size) { unsigned long request; @@ -2580,8 +2623,8 @@ int drmCommandRead(int fd, unsigned long drmCommandIndex, void *data, * It issues a write ioctl given by * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. */ -int drmCommandWrite(int fd, unsigned long drmCommandIndex, void *data, - unsigned long size) +drm_public int drmCommandWrite(int fd, unsigned long drmCommandIndex, + void *data, unsigned long size) { unsigned long request; @@ -2609,8 +2652,8 @@ int drmCommandWrite(int fd, unsigned long drmCommandIndex, void *data, * It issues a read-write ioctl given by * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. */ -int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, void *data, - unsigned long size) +drm_public int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, + void *data, unsigned long size) { unsigned long request; @@ -2632,14 +2675,13 @@ static struct { static int nr_fds = 0; -int drmOpenOnce(void *unused, - const char *BusID, - int *newlyopened) +drm_public int drmOpenOnce(void *unused, const char *BusID, int *newlyopened) { return drmOpenOnceWithType(BusID, newlyopened, DRM_NODE_PRIMARY); } -int drmOpenOnceWithType(const char *BusID, int *newlyopened, int type) +drm_public int drmOpenOnceWithType(const char *BusID, int *newlyopened, + int type) { int i; int fd; @@ -2672,7 +2714,7 @@ int drmOpenOnceWithType(const char *BusID, int *newlyopened, int type) return fd; } -void drmCloseOnce(int fd) +drm_public void drmCloseOnce(int fd) { int i; @@ -2691,17 +2733,35 @@ void drmCloseOnce(int fd) } } -int drmSetMaster(int fd) +drm_public int drmSetMaster(int fd) { return drmIoctl(fd, DRM_IOCTL_SET_MASTER, NULL); } -int drmDropMaster(int fd) +drm_public int drmDropMaster(int fd) { return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL); } -char *drmGetDeviceNameFromFd(int fd) +drm_public int drmIsMaster(int fd) +{ + /* Detect master by attempting something that requires master. + * + * Authenticating magic tokens requires master and 0 is an + * internal kernel detail which we could use. Attempting this on + * a master fd would fail therefore fail with EINVAL because 0 + * is invalid. + * + * A non-master fd will fail with EACCES, as the kernel checks + * for master before attempting to do anything else. + * + * Since we don't want to leak implementation details, use + * EACCES. + */ + return drmAuthMagic(fd, 0) != -EACCES; +} + +drm_public char *drmGetDeviceNameFromFd(int fd) { char name[128]; struct stat sbuf; @@ -2727,7 +2787,21 @@ char *drmGetDeviceNameFromFd(int fd) return strdup(name); } -int drmGetNodeTypeFromFd(int fd) +static bool drmNodeIsDRM(int maj, int min) +{ +#ifdef __linux__ + char path[64]; + struct stat sbuf; + + snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device/drm", + maj, min); + return stat(path, &sbuf) == 0; +#else + return maj == DRM_MAJOR; +#endif +} + +drm_public int drmGetNodeTypeFromFd(int fd) { struct stat sbuf; int maj, min, type; @@ -2738,7 +2812,7 @@ int drmGetNodeTypeFromFd(int fd) maj = major(sbuf.st_rdev); min = minor(sbuf.st_rdev); - if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) { + if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) { errno = EINVAL; return -1; } @@ -2749,7 +2823,8 @@ int drmGetNodeTypeFromFd(int fd) return type; } -int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, int *prime_fd) +drm_public int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, + int *prime_fd) { struct drm_prime_handle args; int ret; @@ -2766,7 +2841,7 @@ int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, int *prime_fd) return 0; } -int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle) +drm_public int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle) { struct drm_prime_handle args; int ret; @@ -2785,12 +2860,11 @@ static char *drmGetMinorNameForFD(int fd, int type) { #ifdef __linux__ DIR *sysdir; - struct dirent *pent, *ent; + struct dirent *ent; struct stat sbuf; const char *name = drmGetMinorName(type); int len; char dev_name[64], buf[64]; - long name_max; int maj, min; if (!name) @@ -2804,7 +2878,7 @@ static char *drmGetMinorNameForFD(int fd, int type) maj = major(sbuf.st_rdev); min = minor(sbuf.st_rdev); - if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) + if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) return NULL; snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/drm", maj, min); @@ -2813,30 +2887,18 @@ static char *drmGetMinorNameForFD(int fd, int type) if (!sysdir) return NULL; - name_max = fpathconf(dirfd(sysdir), _PC_NAME_MAX); - if (name_max == -1) - goto out_close_dir; - - pent = malloc(offsetof(struct dirent, d_name) + name_max + 1); - if (pent == NULL) - goto out_close_dir; - - while (readdir_r(sysdir, pent, &ent) == 0 && ent != NULL) { + while ((ent = readdir(sysdir))) { if (strncmp(ent->d_name, name, len) == 0) { snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s", ent->d_name); - free(pent); closedir(sysdir); - return strdup(dev_name); } } - free(pent); - -out_close_dir: closedir(sysdir); + return NULL; #else struct stat sbuf; char buf[PATH_MAX + 1]; @@ -2850,7 +2912,7 @@ out_close_dir: maj = major(sbuf.st_rdev); min = minor(sbuf.st_rdev); - if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) + if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) return NULL; switch (type) { @@ -2877,15 +2939,14 @@ out_close_dir: return strdup(buf); #endif - return NULL; } -char *drmGetPrimaryDeviceNameFromFd(int fd) +drm_public char *drmGetPrimaryDeviceNameFromFd(int fd) { return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY); } -char *drmGetRenderDeviceNameFromFd(int fd) +drm_public char *drmGetRenderDeviceNameFromFd(int fd) { return drmGetMinorNameForFD(fd, DRM_NODE_RENDER); } @@ -2934,12 +2995,26 @@ sysfs_uevent_get(const char *path, const char *fmt, ...) } #endif +/* Little white lie to avoid major rework of the existing code */ +#define DRM_BUS_VIRTIO 0x10 + static int drmParseSubsystemType(int maj, int min) { #ifdef __linux__ char path[PATH_MAX + 1]; char link[PATH_MAX + 1] = ""; char *name; + struct { + const char *name; + int bus_type; + } bus_types[] = { + { "/pci", DRM_BUS_PCI }, + { "/usb", DRM_BUS_USB }, + { "/platform", DRM_BUS_PLATFORM }, + { "/spi", DRM_BUS_PLATFORM }, + { "/host1x", DRM_BUS_HOST1X }, + { "/virtio", DRM_BUS_VIRTIO }, + }; snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/subsystem", maj, min); @@ -2951,20 +3026,13 @@ static int drmParseSubsystemType(int maj, int min) if (!name) return -EINVAL; - if (strncmp(name, "/pci", 4) == 0) - return DRM_BUS_PCI; - - if (strncmp(name, "/usb", 4) == 0) - return DRM_BUS_USB; - - if (strncmp(name, "/platform", 9) == 0) - return DRM_BUS_PLATFORM; - - if (strncmp(name, "/host1x", 7) == 0) - return DRM_BUS_HOST1X; + for (unsigned i = 0; i < ARRAY_SIZE(bus_types); i++) { + if (strncmp(name, bus_types[i].name, strlen(bus_types[i].name)) == 0) + return bus_types[i].bus_type; + } return -EINVAL; -#elif defined(__OpenBSD__) +#elif defined(__OpenBSD__) || defined(__DragonFly__) return DRM_BUS_PCI; #else #warning "Missing implementation of drmParseSubsystemType" @@ -2972,16 +3040,32 @@ static int drmParseSubsystemType(int maj, int min) #endif } +static void +get_pci_path(int maj, int min, char *pci_path) +{ + char path[PATH_MAX + 1], *term; + + snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); + if (!realpath(path, pci_path)) { + strcpy(pci_path, path); + return; + } + + term = strrchr(pci_path, '/'); + if (term && strncmp(term, "/virtio", 7) == 0) + *term = 0; +} + static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info) { #ifdef __linux__ unsigned int domain, bus, dev, func; - char path[PATH_MAX + 1], *value; + char pci_path[PATH_MAX + 1], *value; int num; - snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); + get_pci_path(maj, min, pci_path); - value = sysfs_uevent_get(path, "PCI_SLOT_NAME"); + value = sysfs_uevent_get(pci_path, "PCI_SLOT_NAME"); if (!value) return -ENOENT; @@ -2997,7 +3081,7 @@ static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info) info->func = func; return 0; -#elif defined(__OpenBSD__) +#elif defined(__OpenBSD__) || defined(__DragonFly__) struct drm_pciinfo pinfo; int fd, type; @@ -3027,7 +3111,7 @@ static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info) #endif } -int drmDevicesEqual(drmDevicePtr a, drmDevicePtr b) +drm_public int drmDevicesEqual(drmDevicePtr a, drmDevicePtr b) { if (a == NULL || b == NULL) return 0; @@ -3086,7 +3170,6 @@ static int parse_separate_sysfs_files(int maj, int min, drmPciDeviceInfoPtr device, bool ignore_revision) { -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) static const char *attrs[] = { "revision", /* Older kernels are missing the file, so check for it first */ "vendor", @@ -3094,14 +3177,15 @@ static int parse_separate_sysfs_files(int maj, int min, "subsystem_vendor", "subsystem_device", }; - char path[PATH_MAX + 1]; + char path[PATH_MAX + 1], pci_path[PATH_MAX + 1]; unsigned int data[ARRAY_SIZE(attrs)]; FILE *fp; int ret; + get_pci_path(maj, min, pci_path); + for (unsigned i = ignore_revision ? 1 : 0; i < ARRAY_SIZE(attrs); i++) { - snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/%s", maj, min, - attrs[i]); + snprintf(path, PATH_MAX, "%s/%s", pci_path, attrs[i]); fp = fopen(path, "r"); if (!fp) return -errno; @@ -3125,11 +3209,13 @@ static int parse_separate_sysfs_files(int maj, int min, static int parse_config_sysfs_file(int maj, int min, drmPciDeviceInfoPtr device) { - char path[PATH_MAX + 1]; + char path[PATH_MAX + 1], pci_path[PATH_MAX + 1]; unsigned char config[64]; int fd, ret; - snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/config", maj, min); + get_pci_path(maj, min, pci_path); + + snprintf(path, PATH_MAX, "%s/config", pci_path); fd = open(path, O_RDONLY); if (fd < 0) return -errno; @@ -3161,7 +3247,7 @@ static int drmParsePciDeviceInfo(int maj, int min, return parse_config_sysfs_file(maj, min, device); return 0; -#elif defined(__OpenBSD__) +#elif defined(__OpenBSD__) || defined(__DragonFly__) struct drm_pciinfo pinfo; int fd, type; @@ -3224,7 +3310,7 @@ static void drmFreeHost1xDevice(drmDevicePtr device) } } -void drmFreeDevice(drmDevicePtr *device) +drm_public void drmFreeDevice(drmDevicePtr *device) { if (device == NULL) return; @@ -3245,7 +3331,7 @@ void drmFreeDevice(drmDevicePtr *device) *device = NULL; } -void drmFreeDevices(drmDevicePtr devices[], int count) +drm_public void drmFreeDevices(drmDevicePtr devices[], int count) { int i; @@ -3442,69 +3528,97 @@ free_device: return ret; } -static int drmParsePlatformBusInfo(int maj, int min, drmPlatformBusInfoPtr info) +static int drmParseOFBusInfo(int maj, int min, char *fullname) { #ifdef __linux__ - char path[PATH_MAX + 1], *name; + char path[PATH_MAX + 1], *name, *tmp_name; snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); name = sysfs_uevent_get(path, "OF_FULLNAME"); - if (!name) - return -ENOENT; + tmp_name = name; + if (!name) { + /* If the device lacks OF data, pick the MODALIAS info */ + name = sysfs_uevent_get(path, "MODALIAS"); + if (!name) + return -ENOENT; + + /* .. and strip the MODALIAS=[platform,usb...]: part. */ + tmp_name = strrchr(name, ':'); + if (!tmp_name) { + free(name); + return -ENOENT; + } + tmp_name++; + } - strncpy(info->fullname, name, DRM_PLATFORM_DEVICE_NAME_LEN); - info->fullname[DRM_PLATFORM_DEVICE_NAME_LEN - 1] = '\0'; + strncpy(fullname, tmp_name, DRM_PLATFORM_DEVICE_NAME_LEN); + fullname[DRM_PLATFORM_DEVICE_NAME_LEN - 1] = '\0'; free(name); return 0; #else -#warning "Missing implementation of drmParsePlatformBusInfo" +#warning "Missing implementation of drmParseOFBusInfo" return -EINVAL; #endif } -static int drmParsePlatformDeviceInfo(int maj, int min, - drmPlatformDeviceInfoPtr info) +static int drmParseOFDeviceInfo(int maj, int min, char ***compatible) { #ifdef __linux__ - char path[PATH_MAX + 1], *value; + char path[PATH_MAX + 1], *value, *tmp_name; unsigned int count, i; int err; snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); value = sysfs_uevent_get(path, "OF_COMPATIBLE_N"); - if (!value) - return -ENOENT; - - sscanf(value, "%u", &count); - free(value); + if (value) { + sscanf(value, "%u", &count); + free(value); + } else { + /* Assume one entry if the device lack OF data */ + count = 1; + } - info->compatible = calloc(count + 1, sizeof(*info->compatible)); - if (!info->compatible) + *compatible = calloc(count + 1, sizeof(char *)); + if (!*compatible) return -ENOMEM; for (i = 0; i < count; i++) { value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i); + tmp_name = value; if (!value) { - err = -ENOENT; - goto free; + /* If the device lacks OF data, pick the MODALIAS info */ + value = sysfs_uevent_get(path, "MODALIAS"); + if (!value) { + err = -ENOENT; + goto free; + } + + /* .. and strip the MODALIAS=[platform,usb...]: part. */ + tmp_name = strrchr(value, ':'); + if (!tmp_name) { + free(value); + return -ENOENT; + } + tmp_name = strdup(tmp_name + 1); + free(value); } - info->compatible[i] = value; + (*compatible)[i] = tmp_name; } return 0; free: while (i--) - free(info->compatible[i]); + free((*compatible)[i]); - free(info->compatible); + free(*compatible); return err; #else -#warning "Missing implementation of drmParsePlatformDeviceInfo" +#warning "Missing implementation of drmParseOFDeviceInfo" return -EINVAL; #endif } @@ -3527,7 +3641,7 @@ static int drmProcessPlatformDevice(drmDevicePtr *device, dev->businfo.platform = (drmPlatformBusInfoPtr)ptr; - ret = drmParsePlatformBusInfo(maj, min, dev->businfo.platform); + ret = drmParseOFBusInfo(maj, min, dev->businfo.platform->fullname); if (ret < 0) goto free_device; @@ -3535,7 +3649,7 @@ static int drmProcessPlatformDevice(drmDevicePtr *device, ptr += sizeof(drmPlatformBusInfo); dev->deviceinfo.platform = (drmPlatformDeviceInfoPtr)ptr; - ret = drmParsePlatformDeviceInfo(maj, min, dev->deviceinfo.platform); + ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.platform->compatible); if (ret < 0) goto free_device; } @@ -3549,73 +3663,6 @@ free_device: return ret; } -static int drmParseHost1xBusInfo(int maj, int min, drmHost1xBusInfoPtr info) -{ -#ifdef __linux__ - char path[PATH_MAX + 1], *name; - - snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); - - name = sysfs_uevent_get(path, "OF_FULLNAME"); - if (!name) - return -ENOENT; - - strncpy(info->fullname, name, DRM_HOST1X_DEVICE_NAME_LEN); - info->fullname[DRM_HOST1X_DEVICE_NAME_LEN - 1] = '\0'; - free(name); - - return 0; -#else -#warning "Missing implementation of drmParseHost1xBusInfo" - return -EINVAL; -#endif -} - -static int drmParseHost1xDeviceInfo(int maj, int min, - drmHost1xDeviceInfoPtr info) -{ -#ifdef __linux__ - char path[PATH_MAX + 1], *value; - unsigned int count, i; - int err; - - snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); - - value = sysfs_uevent_get(path, "OF_COMPATIBLE_N"); - if (!value) - return -ENOENT; - - sscanf(value, "%u", &count); - free(value); - - info->compatible = calloc(count + 1, sizeof(*info->compatible)); - if (!info->compatible) - return -ENOMEM; - - for (i = 0; i < count; i++) { - value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i); - if (!value) { - err = -ENOENT; - goto free; - } - - info->compatible[i] = value; - } - - return 0; - -free: - while (i--) - free(info->compatible[i]); - - free(info->compatible); - return err; -#else -#warning "Missing implementation of drmParseHost1xDeviceInfo" - return -EINVAL; -#endif -} - static int drmProcessHost1xDevice(drmDevicePtr *device, const char *node, int node_type, int maj, int min, bool fetch_deviceinfo, @@ -3634,7 +3681,7 @@ static int drmProcessHost1xDevice(drmDevicePtr *device, dev->businfo.host1x = (drmHost1xBusInfoPtr)ptr; - ret = drmParseHost1xBusInfo(maj, min, dev->businfo.host1x); + ret = drmParseOFBusInfo(maj, min, dev->businfo.host1x->fullname); if (ret < 0) goto free_device; @@ -3642,7 +3689,7 @@ static int drmProcessHost1xDevice(drmDevicePtr *device, ptr += sizeof(drmHost1xBusInfo); dev->deviceinfo.host1x = (drmHost1xDeviceInfoPtr)ptr; - ret = drmParseHost1xDeviceInfo(maj, min, dev->deviceinfo.host1x); + ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.host1x->compatible); if (ret < 0) goto free_device; } @@ -3656,6 +3703,53 @@ free_device: return ret; } +static int +process_device(drmDevicePtr *device, const char *d_name, + int req_subsystem_type, + bool fetch_deviceinfo, uint32_t flags) +{ + struct stat sbuf; + char node[PATH_MAX + 1]; + int node_type, subsystem_type; + unsigned int maj, min; + + node_type = drmGetNodeType(d_name); + if (node_type < 0) + return -1; + + snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, d_name); + if (stat(node, &sbuf)) + return -1; + + maj = major(sbuf.st_rdev); + min = minor(sbuf.st_rdev); + + if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) + return -1; + + subsystem_type = drmParseSubsystemType(maj, min); + if (req_subsystem_type != -1 && req_subsystem_type != subsystem_type) + return -1; + + switch (subsystem_type) { + case DRM_BUS_PCI: + case DRM_BUS_VIRTIO: + return drmProcessPciDevice(device, node, node_type, maj, min, + fetch_deviceinfo, flags); + case DRM_BUS_USB: + return drmProcessUsbDevice(device, node, node_type, maj, min, + fetch_deviceinfo, flags); + case DRM_BUS_PLATFORM: + return drmProcessPlatformDevice(device, node, node_type, maj, min, + fetch_deviceinfo, flags); + case DRM_BUS_HOST1X: + return drmProcessHost1xDevice(device, node, node_type, maj, min, + fetch_deviceinfo, flags); + default: + return -1; + } +} + /* Consider devices located on the same bus as duplicate and fold the respective * entries into a single one. * @@ -3685,6 +3779,28 @@ drm_device_validate_flags(uint32_t flags) return (flags & ~DRM_DEVICE_GET_PCI_REVISION); } +static bool +drm_device_has_rdev(drmDevicePtr device, dev_t find_rdev) +{ + struct stat sbuf; + + for (int i = 0; i < DRM_NODE_MAX; i++) { + if (device->available_nodes & 1 << i) { + if (stat(device->nodes[i], &sbuf) == 0 && + sbuf.st_rdev == find_rdev) + return true; + } + } + return false; +} + +/* + * The kernel drm core has a number of places that assume maximum of + * 3x64 devices nodes. That's 64 for each of primary, control and + * render nodes. Rounded it up to 256 for simplicity. + */ +#define MAX_DRM_NODES 256 + /** * Get information about the opened drm device * @@ -3698,7 +3814,7 @@ drm_device_validate_flags(uint32_t flags) * \note Unlike drmGetDevice it does not retrieve the pci device revision field * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set. */ -int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device) +drm_public int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device) { #ifdef __OpenBSD__ /* @@ -3722,7 +3838,7 @@ int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device) maj = major(sbuf.st_rdev); min = minor(sbuf.st_rdev); - if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) + if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) return -EINVAL; node_type = drmGetMinorType(min); @@ -3765,16 +3881,14 @@ int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device) return 0; #else - drmDevicePtr *local_devices; + drmDevicePtr local_devices[MAX_DRM_NODES]; drmDevicePtr d; DIR *sysdir; struct dirent *dent; struct stat sbuf; - char node[PATH_MAX + 1]; - int node_type, subsystem_type; + int subsystem_type; int maj, min; int ret, i, node_count; - int max_count = 16; dev_t find_rdev; if (drm_device_validate_flags(flags)) @@ -3790,112 +3904,52 @@ int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device) maj = major(sbuf.st_rdev); min = minor(sbuf.st_rdev); - if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) + if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) return -EINVAL; subsystem_type = drmParseSubsystemType(maj, min); - - local_devices = calloc(max_count, sizeof(drmDevicePtr)); - if (local_devices == NULL) - return -ENOMEM; + if (subsystem_type < 0) + return subsystem_type; sysdir = opendir(DRM_DIR_NAME); - if (!sysdir) { - ret = -errno; - goto free_locals; - } + if (!sysdir) + return -errno; i = 0; while ((dent = readdir(sysdir))) { - node_type = drmGetNodeType(dent->d_name); - if (node_type < 0) - continue; - - snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, dent->d_name); - if (stat(node, &sbuf)) - continue; - - maj = major(sbuf.st_rdev); - min = minor(sbuf.st_rdev); - - if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) - continue; - - if (drmParseSubsystemType(maj, min) != subsystem_type) + ret = process_device(&d, dent->d_name, subsystem_type, true, flags); + if (ret) continue; - switch (subsystem_type) { - case DRM_BUS_PCI: - ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags); - if (ret) - continue; - + if (i >= MAX_DRM_NODES) { + fprintf(stderr, "More than %d drm nodes detected. " + "Please report a bug - that should not happen.\n" + "Skipping extra nodes\n", MAX_DRM_NODES); break; - - case DRM_BUS_USB: - ret = drmProcessUsbDevice(&d, node, node_type, maj, min, true, flags); - if (ret) - continue; - - break; - - case DRM_BUS_PLATFORM: - ret = drmProcessPlatformDevice(&d, node, node_type, maj, min, true, flags); - if (ret) - continue; - - break; - - case DRM_BUS_HOST1X: - ret = drmProcessHost1xDevice(&d, node, node_type, maj, min, true, flags); - if (ret) - continue; - - break; - - default: - continue; - } - - if (i >= max_count) { - drmDevicePtr *temp; - - max_count += 16; - temp = realloc(local_devices, max_count * sizeof(drmDevicePtr)); - if (!temp) - goto free_devices; - local_devices = temp; } - - /* store target at local_devices[0] for ease to use below */ - if (find_rdev == sbuf.st_rdev && i) { - local_devices[i] = local_devices[0]; - local_devices[0] = d; - } - else - local_devices[i] = d; + local_devices[i] = d; i++; } node_count = i; drmFoldDuplicatedDevices(local_devices, node_count); - *device = local_devices[0]; - drmFreeDevices(&local_devices[1], node_count - 1); + *device = NULL; + + for (i = 0; i < node_count; i++) { + if (!local_devices[i]) + continue; + + if (drm_device_has_rdev(local_devices[i], find_rdev)) + *device = local_devices[i]; + else + drmFreeDevice(&local_devices[i]); + } closedir(sysdir); - free(local_devices); if (*device == NULL) return -ENODEV; return 0; - -free_devices: - drmFreeDevices(local_devices, i); - closedir(sysdir); - -free_locals: - free(local_devices); - return ret; #endif } @@ -3908,7 +3962,7 @@ free_locals: * * \return zero on success, negative error code otherwise. */ -int drmGetDevice(int fd, drmDevicePtr *device) +drm_public int drmGetDevice(int fd, drmDevicePtr *device) { return drmGetDevice2(fd, DRM_DEVICE_GET_PCI_REVISION, device); } @@ -3929,100 +3983,34 @@ int drmGetDevice(int fd, drmDevicePtr *device) * \note Unlike drmGetDevices it does not retrieve the pci device revision field * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set. */ -int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], int max_devices) +drm_public int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], + int max_devices) { - drmDevicePtr *local_devices; + drmDevicePtr local_devices[MAX_DRM_NODES]; drmDevicePtr device; DIR *sysdir; struct dirent *dent; - struct stat sbuf; - char node[PATH_MAX + 1]; - int node_type, subsystem_type; - int maj, min; int ret, i, node_count, device_count; - int max_count = 16; if (drm_device_validate_flags(flags)) return -EINVAL; - local_devices = calloc(max_count, sizeof(drmDevicePtr)); - if (local_devices == NULL) - return -ENOMEM; - sysdir = opendir(DRM_DIR_NAME); - if (!sysdir) { - ret = -errno; - goto free_locals; - } + if (!sysdir) + return -errno; i = 0; while ((dent = readdir(sysdir))) { - node_type = drmGetNodeType(dent->d_name); - if (node_type < 0) - continue; - - snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, dent->d_name); - if (stat(node, &sbuf)) - continue; - - maj = major(sbuf.st_rdev); - min = minor(sbuf.st_rdev); - - if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) - continue; - - subsystem_type = drmParseSubsystemType(maj, min); - - if (subsystem_type < 0) + ret = process_device(&device, dent->d_name, -1, devices != NULL, flags); + if (ret) continue; - switch (subsystem_type) { - case DRM_BUS_PCI: - ret = drmProcessPciDevice(&device, node, node_type, - maj, min, devices != NULL, flags); - if (ret) - continue; - - break; - - case DRM_BUS_USB: - ret = drmProcessUsbDevice(&device, node, node_type, maj, min, - devices != NULL, flags); - if (ret) - goto free_devices; - - break; - - case DRM_BUS_PLATFORM: - ret = drmProcessPlatformDevice(&device, node, node_type, maj, min, - devices != NULL, flags); - if (ret) - continue; - - break; - - case DRM_BUS_HOST1X: - ret = drmProcessHost1xDevice(&device, node, node_type, maj, min, - devices != NULL, flags); - if (ret) - continue; - + if (i >= MAX_DRM_NODES) { + fprintf(stderr, "More than %d drm nodes detected. " + "Please report a bug - that should not happen.\n" + "Skipping extra nodes\n", MAX_DRM_NODES); break; - - default: - continue; } - - if (i >= max_count) { - drmDevicePtr *temp; - - max_count += 16; - temp = realloc(local_devices, max_count * sizeof(drmDevicePtr)); - if (!temp) - goto free_devices; - local_devices = temp; - } - local_devices[i] = device; i++; } @@ -4044,16 +4032,7 @@ int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], int max_devices) } closedir(sysdir); - free(local_devices); return device_count; - -free_devices: - drmFreeDevices(local_devices, i); - closedir(sysdir); - -free_locals: - free(local_devices); - return ret; } /** @@ -4068,12 +4047,12 @@ free_locals: * alternatively the number of devices stored in devices[], which is * capped by the max_devices. */ -int drmGetDevices(drmDevicePtr devices[], int max_devices) +drm_public int drmGetDevices(drmDevicePtr devices[], int max_devices) { return drmGetDevices2(DRM_DEVICE_GET_PCI_REVISION, devices, max_devices); } -char *drmGetDeviceNameFromFd2(int fd) +drm_public char *drmGetDeviceNameFromFd2(int fd) { #ifdef __linux__ struct stat sbuf; @@ -4086,7 +4065,7 @@ char *drmGetDeviceNameFromFd2(int fd) maj = major(sbuf.st_rdev); min = minor(sbuf.st_rdev); - if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) + if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) return NULL; snprintf(path, sizeof(path), "/sys/dev/char/%d:%d", maj, min); @@ -4112,7 +4091,7 @@ char *drmGetDeviceNameFromFd2(int fd) maj = major(sbuf.st_rdev); min = minor(sbuf.st_rdev); - if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) + if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) return NULL; node_type = drmGetMinorType(min); @@ -4145,7 +4124,7 @@ char *drmGetDeviceNameFromFd2(int fd) #endif } -int drmSyncobjCreate(int fd, uint32_t flags, uint32_t *handle) +drm_public int drmSyncobjCreate(int fd, uint32_t flags, uint32_t *handle) { struct drm_syncobj_create args; int ret; @@ -4155,12 +4134,12 @@ int drmSyncobjCreate(int fd, uint32_t flags, uint32_t *handle) args.handle = 0; ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &args); if (ret) - return ret; + return ret; *handle = args.handle; return 0; } -int drmSyncobjDestroy(int fd, uint32_t handle) +drm_public int drmSyncobjDestroy(int fd, uint32_t handle) { struct drm_syncobj_destroy args; @@ -4169,7 +4148,7 @@ int drmSyncobjDestroy(int fd, uint32_t handle) return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_DESTROY, &args); } -int drmSyncobjHandleToFD(int fd, uint32_t handle, int *obj_fd) +drm_public int drmSyncobjHandleToFD(int fd, uint32_t handle, int *obj_fd) { struct drm_syncobj_handle args; int ret; @@ -4179,12 +4158,12 @@ int drmSyncobjHandleToFD(int fd, uint32_t handle, int *obj_fd) args.handle = handle; ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args); if (ret) - return ret; + return ret; *obj_fd = args.fd; return 0; } -int drmSyncobjFDToHandle(int fd, int obj_fd, uint32_t *handle) +drm_public int drmSyncobjFDToHandle(int fd, int obj_fd, uint32_t *handle) { struct drm_syncobj_handle args; int ret; @@ -4194,12 +4173,13 @@ int drmSyncobjFDToHandle(int fd, int obj_fd, uint32_t *handle) args.handle = 0; ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args); if (ret) - return ret; + return ret; *handle = args.handle; return 0; } -int drmSyncobjImportSyncFile(int fd, uint32_t handle, int sync_file_fd) +drm_public int drmSyncobjImportSyncFile(int fd, uint32_t handle, + int sync_file_fd) { struct drm_syncobj_handle args; @@ -4210,7 +4190,8 @@ int drmSyncobjImportSyncFile(int fd, uint32_t handle, int sync_file_fd) return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args); } -int drmSyncobjExportSyncFile(int fd, uint32_t handle, int *sync_file_fd) +drm_public int drmSyncobjExportSyncFile(int fd, uint32_t handle, + int *sync_file_fd) { struct drm_syncobj_handle args; int ret; @@ -4221,7 +4202,134 @@ int drmSyncobjExportSyncFile(int fd, uint32_t handle, int *sync_file_fd) args.flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE; ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args); if (ret) - return ret; + return ret; *sync_file_fd = args.fd; return 0; } + +drm_public int drmSyncobjWait(int fd, uint32_t *handles, unsigned num_handles, + int64_t timeout_nsec, unsigned flags, + uint32_t *first_signaled) +{ + struct drm_syncobj_wait args; + int ret; + + memclear(args); + args.handles = (uintptr_t)handles; + args.timeout_nsec = timeout_nsec; + args.count_handles = num_handles; + args.flags = flags; + + ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_WAIT, &args); + if (ret < 0) + return -errno; + + if (first_signaled) + *first_signaled = args.first_signaled; + return ret; +} + +drm_public int drmSyncobjReset(int fd, const uint32_t *handles, + uint32_t handle_count) +{ + struct drm_syncobj_array args; + int ret; + + memclear(args); + args.handles = (uintptr_t)handles; + args.count_handles = handle_count; + + ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_RESET, &args); + return ret; +} + +drm_public int drmSyncobjSignal(int fd, const uint32_t *handles, + uint32_t handle_count) +{ + struct drm_syncobj_array args; + int ret; + + memclear(args); + args.handles = (uintptr_t)handles; + args.count_handles = handle_count; + + ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &args); + return ret; +} + +drm_public int drmSyncobjTimelineSignal(int fd, const uint32_t *handles, + uint64_t *points, uint32_t handle_count) +{ + struct drm_syncobj_timeline_array args; + int ret; + + memclear(args); + args.handles = (uintptr_t)handles; + args.points = (uintptr_t)points; + args.count_handles = handle_count; + + ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, &args); + return ret; +} + +drm_public int drmSyncobjTimelineWait(int fd, uint32_t *handles, uint64_t *points, + unsigned num_handles, + int64_t timeout_nsec, unsigned flags, + uint32_t *first_signaled) +{ + struct drm_syncobj_timeline_wait args; + int ret; + + memclear(args); + args.handles = (uintptr_t)handles; + args.points = (uintptr_t)points; + args.timeout_nsec = timeout_nsec; + args.count_handles = num_handles; + args.flags = flags; + + ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, &args); + if (ret < 0) + return -errno; + + if (first_signaled) + *first_signaled = args.first_signaled; + return ret; +} + + +drm_public int drmSyncobjQuery(int fd, uint32_t *handles, uint64_t *points, + uint32_t handle_count) +{ + struct drm_syncobj_timeline_array args; + int ret; + + memclear(args); + args.handles = (uintptr_t)handles; + args.points = (uintptr_t)points; + args.count_handles = handle_count; + + ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args); + if (ret) + return ret; + return 0; +} + +drm_public int drmSyncobjTransfer(int fd, + uint32_t dst_handle, uint64_t dst_point, + uint32_t src_handle, uint64_t src_point, + uint32_t flags) +{ + struct drm_syncobj_transfer args; + int ret; + + memclear(args); + args.src_handle = src_handle; + args.dst_handle = dst_handle; + args.src_point = src_point; + args.dst_point = dst_point; + args.flags = flags; + + ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TRANSFER, &args); + + return ret; +}