From c8cc5996414ded1eba372d25d6d3ce50b0083616 Mon Sep 17 00:00:00 2001 From: Wang Quanxian Date: Fri, 1 Mar 2013 14:13:31 +0800 Subject: [PATCH] Add slp changes At the same time, Change %configure to %reconfigure since no configure script in source dir provided which cause build issue. --- Makefile.am | 6 +- configure.ac | 24 +- libkms/Makefile.am | 5 + libkms/slp.c | 222 +++++++++++++ packaging/libdrm.spec | 14 +- slp/Makefile.am | 22 ++ slp/drm_slp_bufmgr.c | 847 ++++++++++++++++++++++++++++++++++++++++++++++++++ slp/drm_slp_bufmgr.h | 201 ++++++++++++ slp/libdrm_slp.pc.in | 11 + slp/list.h | 131 ++++++++ 10 files changed, 1479 insertions(+), 4 deletions(-) create mode 100644 libkms/slp.c create mode 100644 slp/Makefile.am create mode 100644 slp/drm_slp_bufmgr.c create mode 100644 slp/drm_slp_bufmgr.h create mode 100644 slp/libdrm_slp.pc.in create mode 100644 slp/list.h diff --git a/Makefile.am b/Makefile.am index 94572d0..ee585ff 100644 --- a/Makefile.am +++ b/Makefile.am @@ -47,7 +47,11 @@ if HAVE_EXYNOS EXYNOS_SUBDIR = exynos endif -SUBDIRS = . $(LIBKMS_SUBDIR) $(INTEL_SUBDIR) $(NOUVEAU_SUBDIR) $(RADEON_SUBDIR) $(OMAP_SUBDIR) $(EXYNOS_SUBDIR) tests include man +if HAVE_SLP +SLP_SUBDIR = slp +endif + +SUBDIRS = . $(LIBKMS_SUBDIR) $(INTEL_SUBDIR) $(NOUVEAU_SUBDIR) $(RADEON_SUBDIR) $(OMAP_SUBDIR) $(EXYNOS_SUBDIR) $(SLP_SUBDIR) tests include libdrm_la_LTLIBRARIES = libdrm.la libdrm_ladir = $(libdir) diff --git a/configure.ac b/configure.ac index e2e3466..5e2fc60 100644 --- a/configure.ac +++ b/configure.ac @@ -93,6 +93,19 @@ AC_ARG_ENABLE(exynos-experimental-api, [Enable support for EXYNOS's experimental API (default: disabled)]), [EXYNOS=$enableval], [EXYNOS=no]) +AC_ARG_ENABLE(slp, + AS_HELP_STRING([--disable-slp], + [Enable support for slp's API (default: auto)]), + [SLP=$enableval], [SLP=auto]) + +AC_ARG_VAR([bufmgr_dir], [Directory of slp-bufmgr]) + +if test "x$bufmgr_dir" = xyes; then + AC_DEFINE_UNQUOTED(BUFMGR_DIR, "$bufmgr_dir", [Directory for the modules of slp_bufmgr]) +else + AC_DEFINE(BUFMGR_DIR, "/usr/lib/bufmgr", [Directory for the modules of slp_bufmgr]) +fi + dnl =========================================================================== dnl check compiler flags AC_DEFUN([LIBDRM_CC_TRY_FLAG], [ @@ -247,7 +260,7 @@ else fi AM_CONDITIONAL([HAVE_MANPAGES_STYLESHEET], [test "x$HAVE_MANPAGES_STYLESHEET" = "xyes"]) -if test "x$INTEL" != "xno" -o "x$RADEON" != "xno" -o "x$NOUVEAU" != "xno" -o "x$OMAP" != "xno"; then +if test "x$INTEL" != "xno" -o "x$RADEON" != "xno" -o "x$NOUVEAU" != "xno" -o "x$OMAP" != "xno" -o "x$SLP" != "xno"; then # Check for atomic intrinsics AC_CACHE_CHECK([for native atomic primitives], drm_cv_atomic_primitives, [ @@ -319,6 +332,10 @@ if test "x$INTEL" != "xno" -o "x$RADEON" != "xno" -o "x$NOUVEAU" != "xno" -o "x$ fi fi +if test "x$SLP" != "xno"; then + AC_DEFINE(HAVE_SLP, 1, [Have slp]) +fi + if test "x$INTEL" != "xno"; then PKG_CHECK_MODULES(PCIACCESS, [pciaccess >= 0.10]) fi @@ -330,6 +347,7 @@ if test "x$have_valgrind" = "xyes"; then AC_DEFINE([HAVE_VALGRIND], 1, [Use valgrind intrinsics to suppress false warnings]) fi +AM_CONDITIONAL(HAVE_SLP, [test "x$SLP" != "xno"]) AM_CONDITIONAL(HAVE_INTEL, [test "x$INTEL" != "xno"]) AM_CONDITIONAL(HAVE_RADEON, [test "x$RADEON" != "xno"]) AM_CONDITIONAL(HAVE_NOUVEAU, [test "x$NOUVEAU" != "xno"]) @@ -348,6 +366,8 @@ AC_CONFIG_FILES([ Makefile libkms/Makefile libkms/libkms.pc + slp/Makefile + slp/libdrm_slp.pc intel/Makefile intel/libdrm_intel.pc radeon/Makefile @@ -380,4 +400,6 @@ echo " Radeon API $RADEON" echo " Nouveau API $NOUVEAU" echo " OMAP API $OMAP" echo " EXYNOS API $EXYNOS" +echo " SLP API $SLP" +echo " SLP bufmgr_dir $bufmgr_dir" echo "" diff --git a/libkms/Makefile.am b/libkms/Makefile.am index 215450a..8bd56d5 100644 --- a/libkms/Makefile.am +++ b/libkms/Makefile.am @@ -31,6 +31,11 @@ if HAVE_RADEON libkms_la_SOURCES += radeon.c endif +if HAVE_SLP +libkms_la_SOURCES += slp.c +AM_CFLAGS += -I$(top_srcdir)/exynos +endif + libkmsincludedir = ${includedir}/libkms libkmsinclude_HEADERS = libkms.h diff --git a/libkms/slp.c b/libkms/slp.c new file mode 100644 index 0000000..263f2ab --- /dev/null +++ b/libkms/slp.c @@ -0,0 +1,222 @@ +/************************************************************************** + * + * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#define HAVE_STDINT_H +#define _FILE_OFFSET_BITS 64 + +#include +#include +#include +#include +#include "internal.h" + +#include +#include +#include "xf86drm.h" + +#include "exynos_drm.h" + +struct slp_bo +{ + struct kms_bo base; + unsigned map_count; +}; + +static int +slp_get_prop(struct kms_driver *kms, unsigned key, unsigned *out) +{ + switch (key) { + case KMS_BO_TYPE: + *out = KMS_BO_TYPE_SCANOUT_X8R8G8B8 | KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8; + break; + default: + return -EINVAL; + } + return 0; +} + +static int +slp_destroy(struct kms_driver *kms) +{ + free(kms); + return 0; +} + +static int +slp_bo_create(struct kms_driver *kms, + const unsigned width, const unsigned height, + const enum kms_bo_type type, const unsigned *attr, + struct kms_bo **out) +{ + struct drm_exynos_gem_create arg; + unsigned size, pitch; + struct slp_bo *bo; + int i, ret; + + for (i = 0; attr[i]; i += 2) { + switch (attr[i]) { + case KMS_WIDTH: + case KMS_HEIGHT: + case KMS_BO_TYPE: + break; + default: + return -EINVAL; + } + } + + bo = calloc(1, sizeof(*bo)); + if (!bo) + return -ENOMEM; + + if (type == KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8) { + pitch = 64 * 4; + size = 64 * 64 * 4; + } else if (type == KMS_BO_TYPE_SCANOUT_X8R8G8B8) { + pitch = width * 4; + pitch = (pitch + 512 - 1) & ~(512 - 1); + size = pitch * ((height + 4 - 1) & ~(4 - 1)); + } else { + return -EINVAL; + } + + memset(&arg, 0, sizeof(arg)); + arg.size = size; + + ret = drmCommandWriteRead(kms->fd, DRM_EXYNOS_GEM_CREATE, &arg, sizeof(arg)); + if (ret) + goto err_free; + + bo->base.kms = kms; + bo->base.handle = arg.handle; + bo->base.size = size; + bo->base.pitch = pitch; + + *out = &bo->base; + + return 0; + +err_free: + free(bo); + return ret; +} + +static int +slp_bo_get_prop(struct kms_bo *bo, unsigned key, unsigned *out) +{ + switch (key) { + default: + return -EINVAL; + } +} + +static int +slp_bo_map(struct kms_bo *_bo, void **out) +{ + struct slp_bo *bo = (struct slp_bo *)_bo; + struct drm_exynos_gem_map_off arg; + void *map = NULL; + int ret; + + if (bo->base.ptr) { + bo->map_count++; + *out = bo->base.ptr; + return 0; + } + + memset(&arg, 0, sizeof(arg)); + arg.handle = bo->base.handle; + + ret = drmCommandWriteRead(bo->base.kms->fd, DRM_EXYNOS_GEM_MAP_OFFSET, &arg, sizeof(arg)); + if (ret) + return ret; + + map = mmap(0, bo->base.size, PROT_READ | PROT_WRITE, MAP_SHARED, bo->base.kms->fd, arg.offset); + if (map == MAP_FAILED) + return -errno; + + bo->base.ptr = map; + bo->map_count++; + *out = bo->base.ptr; + + return 0; +} + +static int +slp_bo_unmap(struct kms_bo *_bo) +{ + struct slp_bo *bo = (struct slp_bo *)_bo; + bo->map_count--; + return 0; +} + +static int +slp_bo_destroy(struct kms_bo *_bo) +{ + struct slp_bo *bo = (struct slp_bo *)_bo; + struct drm_gem_close arg; + int ret; + + if (bo->base.ptr) { + /* XXX Sanity check map_count */ + munmap(bo->base.ptr, bo->base.size); + bo->base.ptr = NULL; + } + + memset(&arg, 0, sizeof(arg)); + arg.handle = bo->base.handle; + + ret = drmIoctl(bo->base.kms->fd, DRM_IOCTL_GEM_CLOSE, &arg); + if (ret) + return -errno; + + free(bo); + return 0; +} + +int +slp_create(int fd, struct kms_driver **out) +{ + struct kms_driver *kms; + + kms = calloc(1, sizeof(*kms)); + if (!kms) + return -ENOMEM; + + kms->fd = fd; + + kms->bo_create = slp_bo_create; + kms->bo_map = slp_bo_map; + kms->bo_unmap = slp_bo_unmap; + kms->bo_get_prop = slp_bo_get_prop; + kms->bo_destroy = slp_bo_destroy; + kms->get_prop = slp_get_prop; + kms->destroy = slp_destroy; + *out = kms; + + return 0; +} diff --git a/packaging/libdrm.spec b/packaging/libdrm.spec index f8462b0..1be459e 100644 --- a/packaging/libdrm.spec +++ b/packaging/libdrm.spec @@ -1,6 +1,6 @@ Name: libdrm Summary: Userspace interface to kernel DRM services -- runtime -Version: 2.4.37 +Version: 2.4.39 Release: 1 Group: libs License: MIT @@ -42,6 +42,13 @@ Userspace interface to kernel DRM services -- development files . This package provides the development environment for libdrm.. +%package slp1 +Summary: Userspace interface to slp-specific kernel DRM services +Group: Development/Libraries + +%description slp1 +Userspace interface to slp-specific kernel DRM services + %package -n libkms Summary: Userspace interface to kernel DRM buffer management @@ -58,7 +65,7 @@ Userspace interface to kernel DRM buffer management %setup -q -n %{name}-%{version} %build -%autogen --disable-static --enable-nouveau-experimental-api +%reconfigure --disable-static --enable-nouveau-experimental-api make %{?jobs:-j%jobs} %install @@ -90,6 +97,9 @@ rm -rf %{buildroot} %{_libdir}/lib*.so %{_libdir}/pkgconfig/* +%files slp1 +%{_libdir}/libdrm_slp*.so.* + %files -n libkms %defattr(-,root,root,-) %{_libdir}/libkms.so.* diff --git a/slp/Makefile.am b/slp/Makefile.am new file mode 100644 index 0000000..132662b --- /dev/null +++ b/slp/Makefile.am @@ -0,0 +1,22 @@ +SUBDIRS = . + +AM_CFLAGS = \ + $(WARN_CFLAGS) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/slp \ + $(PTHREADSTUBS_CFLAGS) \ + -I$(top_srcdir)/include/drm + +libdrm_slp_la_LTLIBRARIES = libdrm_slp.la +libdrm_slp_ladir = $(libdir) +libdrm_slp_la_LDFLAGS = -version-number 1:0:0 -no-undefined +libdrm_slp_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@ @CLOCK_LIB@ -ldl + +libdrm_slp_la_SOURCES = \ + drm_slp_bufmgr.c \ + drm_slp_bufmgr.h + +libdrm_slpincludedir = ${includedir}/libdrm +libdrm_slpinclude_HEADERS = drm_slp_bufmgr.h + +pkgconfig_DATA = libdrm_slp.pc diff --git a/slp/drm_slp_bufmgr.c b/slp/drm_slp_bufmgr.c new file mode 100644 index 0000000..f723ded --- /dev/null +++ b/slp/drm_slp_bufmgr.c @@ -0,0 +1,847 @@ +/************************************************************************** + +xserver-xorg-video-sec + +Copyright 2011 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: SooChan Lim , Sangjin Lee + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "drm_slp_bufmgr.h" +#include "list.h" + +#define PREFIX_LIB "libdrm_slp_" +#define SUFFIX_LIB ".so" +#define DEFAULT_LIB PREFIX_LIB"default"SUFFIX_LIB + +#define NUM_TRY_LOCK 10 +#define SEM_NAME "pixmap_1" +#define SEM_DEBUG 0 + +#define DRM_RETURN_IF_FAIL(cond) {if (!(cond)) { fprintf (stderr, "[%s] : '%s' failed.\n", __FUNCTION__, #cond); return; }} +#define DRM_RETURN_VAL_IF_FAIL(cond, val) {if (!(cond)) { fprintf (stderr, "[%s] : '%s' failed.\n", __FUNCTION__, #cond); return val; }} + +#define MGR_IS_VALID(mgr) (mgr && \ + mgr->link.next && \ + mgr->link.next->prev == &mgr->link) +#define BO_IS_VALID(bo) (bo && \ + MGR_IS_VALID(bo->bufmgr) && \ + bo->list.next && \ + bo->list.next->prev == &bo->list) + +typedef struct{ + void* data; + + int is_valid; + drm_data_free free_func ; +}drm_slp_user_data; + +static struct list_head *gBufMgrs = NULL; + +static int +_sem_wait_wrapper(sem_t* sem) +{ + int res = 0; + int num_try = NUM_TRY_LOCK; + + do + { + res = sem_wait(sem); + num_try--; + } while((res == -1) && (errno == EINTR) && (num_try >= 0)); + + if(res == -1) + { + fprintf(stderr, + "[libdrm] error %s:%d(sem:%p, num_try:%d) PID:%04d\n", + __FUNCTION__, + __LINE__, + sem, + num_try, + getpid()); + return 0; + } +#if SEM_DEBUG + else + { + fprintf(stderr, + "[libdrm] LOCK >> %s:%d(sem:%p, num_try:%d) PID:%04d\n", + __FUNCTION__, + __LINE__, + sem, + num_try, + getpid()); + } +#endif + + return 1; +} + +static int +_sem_post_wrapper(sem_t* sem) +{ + int res = 0; + int num_try = NUM_TRY_LOCK; + + do + { + res = sem_post(sem); + num_try--; + + } while((res == -1) && (errno == EINTR) && (num_try >= 0)); + + if(res == -1) + { + fprintf(stderr, + "[libdrm] error %s:%d(sem:%p, num_try:%d) PID:%04d\n", + __FUNCTION__, + __LINE__, + sem, + num_try, + getpid()); + return 0; + } +#if SEM_DEBUG + else + { + fprintf(stderr, + "[libdrm] UNLOCK << %s:%d(sem:%p, num_try:%d) PID:%04d\n", + __FUNCTION__, + __LINE__, + sem, + num_try, + getpid()); + } +#endif + + return 1; +} + +static int +_sem_open(drm_slp_bufmgr bufmgr) +{ + bufmgr->semObj.handle = sem_open(SEM_NAME, O_CREAT, 0777, 1); + if(bufmgr->semObj.handle == SEM_FAILED) + { + fprintf(stderr, + "[libdrm] error %s:%d(name:%s) PID:%04d\n", + __FUNCTION__, + __LINE__, + SEM_NAME, + getpid()); + bufmgr->semObj.handle = NULL; + return 0; + } +#if SEM_DEBUG + else + { + fprintf(stderr, + "[libdrm] OPEN %s:%d(sem:%p) PID:%04d\n", + __FUNCTION__, + __LINE__, + bufmgr->semObj.handle, + getpid()); + } +#endif + + bufmgr->semObj.status = STATUS_UNLOCK; + + return 1; +} + +static int +_sem_close(drm_slp_bufmgr bufmgr) +{ + _sem_wait_wrapper(bufmgr->semObj.handle); + sem_unlink(SEM_NAME); + return 1; +} + +static int +_sem_lock(drm_slp_bufmgr bufmgr) +{ + if(bufmgr->semObj.status != STATUS_UNLOCK) return 0; + + if(!_sem_wait_wrapper(bufmgr->semObj.handle)) return 0; + bufmgr->semObj.status = STATUS_LOCK; + return 1; +} + +static int +_sem_unlock(drm_slp_bufmgr bufmgr) +{ + if(bufmgr->semObj.status != STATUS_LOCK) return 0; + + _sem_post_wrapper(bufmgr->semObj.handle); + bufmgr->semObj.status = STATUS_UNLOCK; + return 1; +} + +static drm_slp_bufmgr +_load_bufmgr(int fd, const char *file, void *arg) +{ + char path[PATH_MAX] = {0,}; + drm_slp_bufmgr bufmgr = NULL; + int (*bufmgr_init)(drm_slp_bufmgr bufmgr, int fd, void *arg); + void *module; + + snprintf(path, sizeof(path), BUFMGR_DIR "/%s", file); + + module = dlopen(path, RTLD_LAZY); + if (!module) { + fprintf(stderr, + "[libdrm] failed to load module: %s(%s)\n", + dlerror(), file); + return NULL; + } + + bufmgr_init = dlsym(module, "init_slp_bufmgr"); + if (!bufmgr_init) { + fprintf(stderr, + "[libdrm] failed to lookup init function: %s(%s)\n", + dlerror(), file); + return NULL; + } + + bufmgr = calloc(sizeof(struct _drm_slp_bufmgr), 1); + if(!bufmgr) + { + return NULL; + } + + if(!bufmgr_init(bufmgr, fd, arg)) + { + fprintf(stderr,"[libdrm] Fail to init module(%s)\n", file); + free(bufmgr); + bufmgr = NULL; + return NULL; + } + + fprintf(stderr,"[libdrm] Success to load module(%s)\n", file); + + return bufmgr; +} + +drm_slp_bufmgr +drm_slp_bufmgr_init(int fd, void *arg) +{ + drm_slp_bufmgr bufmgr = NULL; + const char *p = NULL; + + if (fd < 0) + return NULL; + + if(gBufMgrs == NULL) + { + gBufMgrs = malloc(sizeof(struct list_head)); + LIST_INITHEAD(gBufMgrs); + } + else + { + LIST_FOR_EACH_ENTRY(bufmgr, gBufMgrs, link) + { + if(bufmgr->drm_fd == fd) + { + bufmgr->ref_count++; + fprintf(stderr, "[libdrm] bufmgr ref: fd=%d, ref_count:%d\n", fd, bufmgr->ref_count); + return bufmgr; + } + } + bufmgr = NULL; + } + fprintf(stderr, "[libdrm] bufmgr init: fd=%d\n", fd); + + p = getenv ("SLP_BUFMGR_MODULE"); + if (p) + { + char file[PATH_MAX] = {0,}; + snprintf(file, sizeof(file), PREFIX_LIB"%s"SUFFIX_LIB, p); + bufmgr = _load_bufmgr (fd, file, arg); + } + + if (!bufmgr) + bufmgr = _load_bufmgr (fd, DEFAULT_LIB, arg); + + if (!bufmgr) + { + struct dirent **namelist; + int found = 0; + int n; + + n = scandir(BUFMGR_DIR, &namelist, 0, alphasort); + if (n < 0) + fprintf(stderr,"[libdrm] no files : %s\n", BUFMGR_DIR); + else + { + while(n--) + { + if (!found && strstr (namelist[n]->d_name, PREFIX_LIB)) + { + char *p = strstr (namelist[n]->d_name, SUFFIX_LIB); + if (!strcmp (p, SUFFIX_LIB)) + { + bufmgr = _load_bufmgr (fd, namelist[n]->d_name, arg); + if (bufmgr) + found = 1; + } + } + free(namelist[n]); + } + free(namelist); + } + } + + if (!bufmgr) + { + fprintf(stderr,"[libdrm] backend is NULL.\n"); + return NULL; + } + + if (pthread_mutex_init(&bufmgr->lock, NULL) != 0) + { + bufmgr->bufmgr_destroy(bufmgr); + free(bufmgr); + return NULL; + } + + bufmgr->ref_count = 1; + bufmgr->drm_fd = fd; + + LIST_INITHEAD(&bufmgr->bos); + LIST_ADD(&bufmgr->link, gBufMgrs); + + return bufmgr; +} + +void +drm_slp_bufmgr_destroy(drm_slp_bufmgr bufmgr) +{ + DRM_RETURN_IF_FAIL(MGR_IS_VALID(bufmgr)); + + fprintf(stderr, "[DRM] bufmgr destroy: bufmgr:%p, drm_fd:%d\n", + bufmgr, bufmgr->drm_fd); + + /*Check and Free bos*/ + if(!LIST_IS_EMPTY(&bufmgr->bos)) + { + drm_slp_bo bo, tmp; + + LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &bufmgr->bos, list) + { + fprintf(stderr, "[libdrm] Un-freed bo(%p, ref:%d) \n", bo, bo->ref_cnt); + bo->ref_cnt = 1; + drm_slp_bo_unref(bo); + } + } + + LIST_DEL(&bufmgr->link); + bufmgr->bufmgr_destroy(bufmgr); + + if(bufmgr->semObj.isOpened) + { + _sem_close(bufmgr); + } + + pthread_mutex_destroy(&bufmgr->lock); + free(bufmgr); +} + +int +drm_slp_bufmgr_lock(drm_slp_bufmgr bufmgr) +{ + DRM_RETURN_VAL_IF_FAIL(MGR_IS_VALID(bufmgr), 0); + + pthread_mutex_lock(&bufmgr->lock); + + if(bufmgr->bufmgr_lock) + { + int ret; + ret = bufmgr->bufmgr_lock(bufmgr); + pthread_mutex_unlock(&bufmgr->lock); + return ret; + } + + if(!bufmgr->semObj.isOpened) + { + if(_sem_open(bufmgr) != 1) + { + pthread_mutex_unlock(&bufmgr->lock); + return 0; + } + bufmgr->semObj.isOpened = 1; + } + + if(_sem_lock(bufmgr) != 1) + { + pthread_mutex_unlock(&bufmgr->lock); + return 0; + } + + pthread_mutex_unlock(&bufmgr->lock); + + return 1; +} + +int +drm_slp_bufmgr_unlock(drm_slp_bufmgr bufmgr) +{ + DRM_RETURN_VAL_IF_FAIL(MGR_IS_VALID(bufmgr), 0); + + pthread_mutex_lock(&bufmgr->lock); + + if(bufmgr->bufmgr_unlock) + { + int ret; + ret = bufmgr->bufmgr_unlock(bufmgr); + pthread_mutex_unlock(&bufmgr->lock); + return ret; + } + + if(_sem_unlock(bufmgr) != 1) + { + pthread_mutex_unlock(&bufmgr->lock); + return 0; + } + + pthread_mutex_unlock(&bufmgr->lock); + + return 1; +} + +int +drm_slp_bufmgr_cache_flush(drm_slp_bufmgr bufmgr, drm_slp_bo bo, int flags) +{ + int ret; + + DRM_RETURN_VAL_IF_FAIL(MGR_IS_VALID(bufmgr) || BO_IS_VALID(bo), 0); + + if (!bo) + flags |= DRM_SLP_CACHE_ALL; + + if (bo) + { + DRM_RETURN_VAL_IF_FAIL(BO_IS_VALID(bo), 0); + + if(!bo->bufmgr) + return 0; + + pthread_mutex_lock(&bo->bufmgr->lock); + ret = bo->bufmgr->bufmgr_cache_flush(bufmgr, bo, flags); + pthread_mutex_unlock(&bo->bufmgr->lock); + } + else + { + pthread_mutex_lock(&bufmgr->lock); + ret = bufmgr->bufmgr_cache_flush(bufmgr, NULL, flags); + pthread_mutex_unlock(&bufmgr->lock); + } + + return ret; +} + +int +drm_slp_bo_size(drm_slp_bo bo) +{ + int size; + drm_slp_bufmgr bufmgr; + + DRM_RETURN_VAL_IF_FAIL(BO_IS_VALID(bo), 0); + + bufmgr = bo->bufmgr; + + pthread_mutex_lock(&bufmgr->lock); + size = bo->bufmgr->bo_size(bo); + pthread_mutex_unlock(&bufmgr->lock); + + return size; +} + +drm_slp_bo +drm_slp_bo_ref(drm_slp_bo bo) +{ + drm_slp_bufmgr bufmgr; + + DRM_RETURN_VAL_IF_FAIL(BO_IS_VALID(bo), NULL); + + bufmgr = bo->bufmgr; + + pthread_mutex_lock(&bufmgr->lock); + + bo->ref_cnt++; + + pthread_mutex_unlock(&bufmgr->lock); + + return bo; +} + +void +drm_slp_bo_unref(drm_slp_bo bo) +{ + drm_slp_bufmgr bufmgr; + + DRM_RETURN_IF_FAIL(BO_IS_VALID(bo)); + + bufmgr = bo->bufmgr; + + if(0 >= bo->ref_cnt) + return; + + pthread_mutex_lock(&bufmgr->lock); + + bo->ref_cnt--; + if(bo->ref_cnt == 0) + { + if(bo->user_data) + { + void* rd; + drm_slp_user_data* old_data; + unsigned long key; + + while(1==drmSLFirst(bo->user_data, &key, &rd)) + { + old_data = (drm_slp_user_data*)rd; + + if(old_data->is_valid && old_data->free_func) + { + if(old_data->data) + old_data->free_func(old_data->data); + old_data->data = NULL; + free(old_data); + } + drmSLDelete(bo->user_data, key); + } + + drmSLDestroy(bo->user_data); + bo->user_data = (void*)0; + } + + LIST_DEL(&bo->list); + bufmgr->bo_free(bo); + + free(bo); + } + + pthread_mutex_unlock(&bufmgr->lock); +} + +drm_slp_bo +drm_slp_bo_alloc(drm_slp_bufmgr bufmgr, const char * name, int size, int flags) +{ + drm_slp_bo bo=NULL; + + DRM_RETURN_VAL_IF_FAIL( MGR_IS_VALID(bufmgr) && (size > 0), NULL); + + bo = calloc(sizeof(struct _drm_slp_bo), 1); + if(!bo) + return NULL; + + bo->bufmgr = bufmgr; + + pthread_mutex_lock(&bufmgr->lock); + if(!bufmgr->bo_alloc(bo, name, size, flags)) + { + free(bo); + pthread_mutex_unlock(&bufmgr->lock); + return NULL; + } + bo->ref_cnt = 1; + LIST_ADD(&bo->list, &bufmgr->bos); + pthread_mutex_unlock(&bufmgr->lock); + + return bo; +} + +drm_slp_bo +drm_slp_bo_attach(drm_slp_bufmgr bufmgr, + const char* name, + int type, + int size, + unsigned int handle) +{ + drm_slp_bo bo; + + DRM_RETURN_VAL_IF_FAIL(MGR_IS_VALID(bufmgr), NULL); + + bo = calloc(sizeof(struct _drm_slp_bo), 1); + if(!bo) + return NULL; + + bo->bufmgr = bufmgr; + + pthread_mutex_lock(&bufmgr->lock); + if(!bufmgr->bo_attach(bo, name, type, size, handle)) + { + free(bo); + pthread_mutex_unlock(&bufmgr->lock); + return NULL; + } + bo->ref_cnt = 1; + LIST_ADD(&bo->list, &bufmgr->bos); + pthread_mutex_unlock(&bufmgr->lock); + + return bo; +} + +drm_slp_bo +drm_slp_bo_import(drm_slp_bufmgr bufmgr, unsigned int key) +{ + drm_slp_bo bo; + + DRM_RETURN_VAL_IF_FAIL(MGR_IS_VALID(bufmgr), NULL); + + bo = calloc(sizeof(struct _drm_slp_bo), 1); + if(!bo) + return NULL; + + bo->bufmgr = bufmgr; + + pthread_mutex_lock(&bufmgr->lock); + if(!bufmgr->bo_import(bo, key)) + { + free(bo); + pthread_mutex_unlock(&bufmgr->lock); + return NULL; + } + bo->ref_cnt = 1; + LIST_ADD(&bo->list, &bufmgr->bos); + pthread_mutex_unlock(&bufmgr->lock); + + return bo; +} + +unsigned int +drm_slp_bo_export(drm_slp_bo bo) +{ + int ret; + + DRM_RETURN_VAL_IF_FAIL(BO_IS_VALID(bo), 0); + + pthread_mutex_lock(&bo->bufmgr->lock); + ret = bo->bufmgr->bo_export(bo); + pthread_mutex_unlock(&bo->bufmgr->lock); + + return ret; +} + +unsigned int +drm_slp_bo_get_handle(drm_slp_bo bo, int device) +{ + unsigned int ret; + + DRM_RETURN_VAL_IF_FAIL(BO_IS_VALID(bo), 0); + + pthread_mutex_lock(&bo->bufmgr->lock); + ret = bo->bufmgr->bo_get_handle(bo, device); + pthread_mutex_unlock(&bo->bufmgr->lock); + + return ret; +} + +unsigned int +drm_slp_bo_map(drm_slp_bo bo, int device, int opt) +{ + unsigned int ret; + + DRM_RETURN_VAL_IF_FAIL(BO_IS_VALID(bo), 0); + + pthread_mutex_lock(&bo->bufmgr->lock); + if(bo->bufmgr->bo_lock) + { + bo->bufmgr->bo_lock(bo, 0, (void*)0); + } + + ret = bo->bufmgr->bo_map(bo, device, opt); + pthread_mutex_unlock(&bo->bufmgr->lock); + + return ret; +} + +int +drm_slp_bo_unmap(drm_slp_bo bo, int device) +{ + int ret; + + DRM_RETURN_VAL_IF_FAIL(BO_IS_VALID(bo), 0); + + pthread_mutex_lock(&bo->bufmgr->lock); + ret = bo->bufmgr->bo_unmap(bo, device); + + if(bo->bufmgr->bo_unlock) + { + bo->bufmgr->bo_unlock(bo); + } + pthread_mutex_unlock(&bo->bufmgr->lock); + + return 0; +} + +int +drm_slp_bo_swap(drm_slp_bo bo1, drm_slp_bo bo2) +{ + void* temp; + + DRM_RETURN_VAL_IF_FAIL(BO_IS_VALID(bo1), 0); + DRM_RETURN_VAL_IF_FAIL(BO_IS_VALID(bo2), 0); + + if(bo1->bufmgr->bo_size(bo1) != bo2->bufmgr->bo_size(bo2)) + return 0; + + pthread_mutex_lock(&bo1->bufmgr->lock); + temp = bo1->priv; + bo1->priv = bo2->priv; + bo2->priv = temp; + pthread_mutex_unlock(&bo1->bufmgr->lock); + + return 1; +} + +int +drm_slp_bo_add_user_data(drm_slp_bo bo, unsigned long key, drm_data_free data_free_func) +{ + int ret; + drm_slp_user_data* data; + + DRM_RETURN_VAL_IF_FAIL(BO_IS_VALID(bo), 0); + + if(!bo->user_data) + bo->user_data = drmSLCreate(); + + data = calloc(1, sizeof(drm_slp_user_data)); + if(!data) + return 0; + + data->free_func = data_free_func; + data->data = (void*)0; + data->is_valid = 0; + + ret = drmSLInsert(bo->user_data, key, data); + if(ret == 1) /* Already in list */ + { + free(data); + return 0; + } + + return 1; +} + +int +drm_slp_bo_set_user_data(drm_slp_bo bo, unsigned long key, void* data) +{ + void *rd; + drm_slp_user_data* old_data; + + DRM_RETURN_VAL_IF_FAIL(BO_IS_VALID(bo), 0); + + if(!bo->user_data) + return 0; + + if(drmSLLookup(bo->user_data, key, &rd)) + return 0; + + old_data = (drm_slp_user_data*)rd; + if (!old_data) + return 0; + + if(old_data->is_valid) + { + if(old_data->free_func) + { + if(old_data->data) + old_data->free_func(old_data->data); + old_data->data = NULL; + } + } + else + old_data->is_valid = 1; + + old_data->data = data; + + return 1; +} + +int +drm_slp_bo_get_user_data(drm_slp_bo bo, unsigned long key, void** data) +{ + void *rd; + drm_slp_user_data* old_data; + + DRM_RETURN_VAL_IF_FAIL(BO_IS_VALID(bo) && data && bo->user_data, 0); + + if(drmSLLookup(bo->user_data, key, &rd)) + { + *data = NULL; + return 0; + } + + old_data = (drm_slp_user_data*)rd; + if (!old_data) + { + *data = NULL; + return 0; + } + + *data = old_data->data; + + return 1; +} + +int +drm_slp_bo_delete_user_data(drm_slp_bo bo, unsigned long key) +{ + void *rd; + drm_slp_user_data* old_data=(void*)0; + + DRM_RETURN_VAL_IF_FAIL(BO_IS_VALID(bo) && bo->user_data, 0); + + if(drmSLLookup(bo->user_data, key, &rd)) + return 0; + + old_data = (drm_slp_user_data*)rd; + if (!old_data) + return 0; + + if(old_data->is_valid && old_data->free_func) + { + if(old_data->data) + old_data->free_func(old_data->data); + free(old_data); + } + drmSLDelete(bo->user_data, key); + + return 1; +} diff --git a/slp/drm_slp_bufmgr.h b/slp/drm_slp_bufmgr.h new file mode 100644 index 0000000..a4adef5 --- /dev/null +++ b/slp/drm_slp_bufmgr.h @@ -0,0 +1,201 @@ +/************************************************************************** + +xserver-xorg-video-sec + +Copyright 2011 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: SooChan Lim , Sangjin Lee + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +#ifndef _DRM_SLP_BUFMGR_H_ +#define _DRM_SLP_BUFMGR_H_ + +#include +#include +#include + +typedef struct _drm_slp_bo * drm_slp_bo; +typedef struct _drm_slp_bufmgr * drm_slp_bufmgr; + +struct list_head +{ + struct list_head *prev; + struct list_head *next; +}; + +struct _drm_slp_bo +{ + struct list_head list; + drm_slp_bufmgr bufmgr; + int ref_cnt; /*atomic count*/ + void *user_data; + + /* private data */ + void *priv; +}; + +typedef enum +{ + STATUS_UNLOCK, + STATUS_READY_TO_LOCK, + STATUS_LOCK, +} lock_status; + +struct _drm_slp_bufmgr +{ + struct list_head bos; /*list head of bo*/ + + pthread_mutex_t lock; + struct { + int isOpened; + lock_status status; + sem_t* handle; + } semObj; + + void (*bufmgr_destroy)(drm_slp_bufmgr bufmgr); + int (*bufmgr_cache_flush)(drm_slp_bufmgr bufmgr, drm_slp_bo bo, int flags); + + int (*bo_size)(drm_slp_bo bo); + + void (*bo_free)(drm_slp_bo bo); + int (*bo_alloc)(drm_slp_bo bo, + const char* name, + int size, + int flags); + int (*bo_attach)(drm_slp_bo bo, + const char* name, + int type, + int size, + unsigned int handle); + int (*bo_import)(drm_slp_bo bo, unsigned int key); + unsigned int (*bo_export)(drm_slp_bo bo); + + unsigned int (*bo_get_handle)(drm_slp_bo bo, int device); + unsigned int (*bo_map)(drm_slp_bo bo, int device, int opt); + int (*bo_unmap)(drm_slp_bo bo, int device); + + + /* Padding for future extension */ + int (*bufmgr_lock) (drm_slp_bufmgr bufmgr); + int (*bufmgr_unlock) (drm_slp_bufmgr bufmgr); + int (*bo_lock) (drm_slp_bo bo, unsigned int checkOnly, unsigned int* isLocked); + int (*bo_unlock) (drm_slp_bo bo); + void (*reserved5) (void); + void (*reserved6) (void); + + /* private data */ + void *priv; + + struct list_head link; /*link of bufmgr*/ + + int drm_fd; + int ref_count; +}; + +/* DRM_SLP_MEM_TYPE */ +#define DRM_SLP_MEM_GEM 0 +#define DRM_SLP_MEM_USERPTR 1 +#define DRM_SLP_MEM_DMABUF 2 +#define DRM_SLP_MEM_GPU 3 + +/* DRM_SLP_DEVICE_TYPE */ +#define DRM_SLP_DEVICE_DEFAULT 0 //Default handle +#define DRM_SLP_DEVICE_CPU 1 +#define DRM_SLP_DEVICE_2D 2 +#define DRM_SLP_DEVICE_3D 3 +#define DRM_SLP_DEVICE_MM 4 + +/* DRM_SLP_OPTION */ +#define DRM_SLP_OPTION_READ (1 << 0) +#define DRM_SLP_OPTION_WRITE (1 << 1) + +/* DRM_SLP_CACHE */ +#define DRM_SLP_CACHE_INV 0x01 +#define DRM_SLP_CACHE_CLN 0x02 +#define DRM_SLP_CACHE_ALL 0x10 +#define DRM_SLP_CACHE_FLUSH (DRM_SLP_CACHE_INV|DRM_SLP_CACHE_CLN) +#define DRM_SLP_CACHE_FLUSH_ALL (DRM_SLP_CACHE_FLUSH|DRM_SLP_CACHE_ALL) + +enum DRM_SLP_BO_FLAGS{ + DRM_SLP_BO_DEFAULT = 0, + DRM_SLP_BO_SCANOUT = (1<<0), + DRM_SLP_BO_NONCACHABLE = (1<<1), + DRM_SLP_BO_WC = (1<<2), +}; + +/* Functions for buffer mnager */ +drm_slp_bufmgr +drm_slp_bufmgr_init(int fd, void * arg); +void +drm_slp_bufmgr_destroy(drm_slp_bufmgr bufmgr); +int +drm_slp_bufmgr_lock(drm_slp_bufmgr bufmgr); +int +drm_slp_bufmgr_unlock(drm_slp_bufmgr bufmgr); +int +drm_slp_bufmgr_cache_flush(drm_slp_bufmgr bufmgr, drm_slp_bo bo, int flags); + + +/*Functions for bo*/ +int +drm_slp_bo_size (drm_slp_bo bo); +drm_slp_bo +drm_slp_bo_ref(drm_slp_bo bo); +void +drm_slp_bo_unref(drm_slp_bo bo); +drm_slp_bo +drm_slp_bo_alloc(drm_slp_bufmgr bufmgr, + const char* name, + int size, + int flags); +drm_slp_bo +drm_slp_bo_attach(drm_slp_bufmgr bufmgr, + const char* name, + int type, + int size, + unsigned int handle); +drm_slp_bo +drm_slp_bo_import(drm_slp_bufmgr bufmgr, unsigned int key); +unsigned int +drm_slp_bo_export(drm_slp_bo bo); +unsigned int +drm_slp_bo_get_handle(drm_slp_bo, int device); +unsigned int +drm_slp_bo_map(drm_slp_bo bo, int device, int opt); +int +drm_slp_bo_unmap(drm_slp_bo bo, int device); +int +drm_slp_bo_swap(drm_slp_bo bo1, drm_slp_bo bo2); + +/*Functions for userdata of bo*/ +typedef void (*drm_data_free)(void *); +int +drm_slp_bo_add_user_data(drm_slp_bo bo, unsigned long key, drm_data_free data_free_func); +int +drm_slp_bo_delete_user_data(drm_slp_bo bo, unsigned long key); +int +drm_slp_bo_set_user_data(drm_slp_bo bo, unsigned long key, void* data); +int +drm_slp_bo_get_user_data(drm_slp_bo bo, unsigned long key, void** data); +#endif /* _DRM_SLP_BUFMGR_H_ */ diff --git a/slp/libdrm_slp.pc.in b/slp/libdrm_slp.pc.in new file mode 100644 index 0000000..220d38b --- /dev/null +++ b/slp/libdrm_slp.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libdrm +Description: Userspace interface to kernel DRM services +Version: @PACKAGE_VERSION@ +Requires: libdrm +Libs: -L${libdir} -ldrm_slp +Cflags: -I${includedir} -I${includedir}/libdrm diff --git a/slp/list.h b/slp/list.h new file mode 100644 index 0000000..e967b93 --- /dev/null +++ b/slp/list.h @@ -0,0 +1,131 @@ +/* + * + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + */ + +/** + * \file + * List macros heavily inspired by the Linux kernel + * list handling. No list looping yet. + * + * Is not threadsafe, so common operations need to + * be protected using an external mutex. + */ +#ifndef _U_DOUBLE_LIST_H_ +#define _U_DOUBLE_LIST_H_ + +#include + +static void list_inithead(struct list_head *item) +{ + item->prev = item; + item->next = item; +} + +static inline void list_add(struct list_head *item, struct list_head *list) +{ + item->prev = list; + item->next = list->next; + list->next->prev = item; + list->next = item; +} + +static inline void list_addtail(struct list_head *item, struct list_head *list) +{ + item->next = list; + item->prev = list->prev; + list->prev->next = item; + list->prev = item; +} + +static inline void list_replace(struct list_head *from, struct list_head *to) +{ + to->prev = from->prev; + to->next = from->next; + from->next->prev = to; + from->prev->next = to; +} + +static inline void list_del(struct list_head *item) +{ + item->prev->next = item->next; + item->next->prev = item->prev; +} + +static inline void list_delinit(struct list_head *item) +{ + item->prev->next = item->next; + item->next->prev = item->prev; + item->next = item; + item->prev = item; +} + +#define LIST_INITHEAD(__item) list_inithead(__item) +#define LIST_ADD(__item, __list) list_add(__item, __list) +#define LIST_ADDTAIL(__item, __list) list_addtail(__item, __list) +#define LIST_REPLACE(__from, __to) list_replace(__from, __to) +#define LIST_DEL(__item) list_del(__item) +#define LIST_DELINIT(__item) list_delinit(__item) + +#define LIST_ENTRY(__type, __item, __field) \ + ((__type *)(((char *)(__item)) - offsetof(__type, __field))) + +#define LIST_IS_EMPTY(__list) \ + ((__list)->next == (__list)) + +#ifndef container_of +#define container_of(ptr, sample, member) \ + (void *)((char *)(ptr) \ + - ((char *)&(sample)->member - (char *)(sample))) +#endif + +#define LIST_FOR_EACH_ENTRY(pos, head, member) \ + for (pos = container_of((head)->next, pos, member); \ + &pos->member != (head); \ + pos = container_of(pos->member.next, pos, member)) + +#define LIST_FOR_EACH_ENTRY_SAFE(pos, storage, head, member) \ + for (pos = container_of((head)->next, pos, member), \ + storage = container_of(pos->member.next, pos, member); \ + &pos->member != (head); \ + pos = storage, storage = container_of(storage->member.next, storage, member)) + +#define LIST_FOR_EACH_ENTRY_SAFE_REV(pos, storage, head, member) \ + for (pos = container_of((head)->prev, pos, member), \ + storage = container_of(pos->member.prev, pos, member); \ + &pos->member != (head); \ + pos = storage, storage = container_of(storage->member.prev, storage, member)) + +#define LIST_FOR_EACH_ENTRY_FROM(pos, start, head, member) \ + for (pos = container_of((start), pos, member); \ + &pos->member != (head); \ + pos = container_of(pos->member.next, pos, member)) + +#define LIST_FOR_EACH_ENTRY_FROM_REV(pos, start, head, member) \ + for (pos = container_of((start), pos, member); \ + &pos->member != (head); \ + pos = container_of(pos->member.prev, pos, member)) + +#endif /*_U_DOUBLE_LIST_H_*/ -- 2.7.4