diff options
author | Matthieu Herrb <matthieu.herrb@laas.fr> | 2012-11-16 14:35:58 +0000 |
---|---|---|
committer | Matthieu Herrb <matthieu.herrb@laas.fr> | 2012-11-16 14:35:58 +0000 |
commit | 1625c61d5a9e5a27fb53e877668127a04859c91f (patch) | |
tree | 3352294e7406c7a97edb2488db617dd26366b5e8 | |
parent | 816907576b29a496836a8ea757d6d9745416c6cc (diff) |
Add libkms
-rw-r--r-- | lib/libdrm/libkms/Makefile | 42 | ||||
-rw-r--r-- | lib/libdrm/libkms/Makefile.inc | 2 | ||||
-rw-r--r-- | lib/libdrm/libkms/api.c | 138 | ||||
-rw-r--r-- | lib/libdrm/libkms/dumb.c | 221 | ||||
-rw-r--r-- | lib/libdrm/libkms/intel.c | 238 | ||||
-rw-r--r-- | lib/libdrm/libkms/internal.h | 77 | ||||
-rw-r--r-- | lib/libdrm/libkms/libkms.h | 74 | ||||
-rw-r--r-- | lib/libdrm/libkms/libkms.pc.in | 10 | ||||
-rw-r--r-- | lib/libdrm/libkms/linux.c | 226 | ||||
-rw-r--r-- | lib/libdrm/libkms/nouveau.c | 220 | ||||
-rw-r--r-- | lib/libdrm/libkms/radeon.c | 242 | ||||
-rw-r--r-- | lib/libdrm/libkms/shlib_version | 2 | ||||
-rw-r--r-- | lib/libdrm/libkms/vmwgfx.c | 207 |
13 files changed, 1699 insertions, 0 deletions
diff --git a/lib/libdrm/libkms/Makefile b/lib/libdrm/libkms/Makefile new file mode 100644 index 000000000..26b27ee1a --- /dev/null +++ b/lib/libdrm/libkms/Makefile @@ -0,0 +1,42 @@ +# $OpenBSD: Makefile,v 1.7 2012/08/29 12:51:04 mpi Exp $ +.include <bsd.xconf.mk> +.include "${.CURDIR}/Makefile.inc" + +LIB= kms + +INCSDIR= ${X11BASE}/include/ + +CPP= cpp -notraditional +DEBUG?= + +CPPFLAGS+= -I${.CURDIR} \ + -I${X11BASE}/include \ + -I/usr/include/dev/pci/drm \ + -DX_PRIVSEP + +INCS= libkms.h + +SRCS= api.c \ + dumb.c \ + intel.c \ + linux.c \ + radeon.c + +includes: _SUBDIRUSE + cd ${.CURDIR}; for i in ${INCS}; do \ + j="cmp -s $$i ${DESTDIR}${INCSDIR}/$$i || \ + ${INSTALL_DATA} $$i ${DESTDIR}${INCSDIR}/"; \ + echo "\tinstalling $$i"; \ + eval "$$j"; \ + done + +NOPROFILE = + +PKGCONFIG= libkms.pc + +obj: _xenocara_obj + +.include <bsd.lib.mk> +.include <bsd.xorg.mk> + +.include <bsd.subdir.mk> diff --git a/lib/libdrm/libkms/Makefile.inc b/lib/libdrm/libkms/Makefile.inc new file mode 100644 index 000000000..62d5e984e --- /dev/null +++ b/lib/libdrm/libkms/Makefile.inc @@ -0,0 +1,2 @@ +PACKAGE_VERSION= 2.4.31 + diff --git a/lib/libdrm/libkms/api.c b/lib/libdrm/libkms/api.c new file mode 100644 index 000000000..db5f9cca8 --- /dev/null +++ b/lib/libdrm/libkms/api.c @@ -0,0 +1,138 @@ +/************************************************************************** + * + * 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. + * + **************************************************************************/ + + +//#include <config.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include "internal.h" + +int kms_create(int fd, struct kms_driver **out) +{ + return linux_create(fd, out); +} + +int kms_get_prop(struct kms_driver *kms, unsigned key, unsigned *out) +{ + switch (key) { + case KMS_BO_TYPE: + break; + default: + return -EINVAL; + } + return kms->get_prop(kms, key, out); +} + +int kms_destroy(struct kms_driver **kms) +{ + if (!(*kms)) + return 0; + + free(*kms); + *kms = NULL; + return 0; +} + +int kms_bo_create(struct kms_driver *kms, const unsigned *attr, struct kms_bo **out) +{ + unsigned width = 0; + unsigned height = 0; + enum kms_bo_type type = KMS_BO_TYPE_SCANOUT_X8R8G8B8; + int i; + + for (i = 0; attr[i];) { + unsigned key = attr[i++]; + unsigned value = attr[i++]; + + switch (key) { + case KMS_WIDTH: + width = value; + break; + case KMS_HEIGHT: + height = value; + break; + case KMS_BO_TYPE: + type = value; + break; + default: + return EINVAL; + } + } + + if (width == 0 || height == 0) + return -EINVAL; + + /* XXX sanity check type */ + + if (type == KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8 && + (width != 64 || height != 64)) + return -EINVAL; + + return kms->bo_create(kms, width, height, type, attr, out); +} + +int kms_bo_get_prop(struct kms_bo *bo, unsigned key, unsigned *out) +{ + switch (key) { + case KMS_PITCH: + *out = bo->pitch; + break; + case KMS_HANDLE: + *out = bo->handle; + break; + default: + return -EINVAL; + } + + return 0; +} + +int kms_bo_map(struct kms_bo *bo, void **out) +{ + return bo->kms->bo_map(bo, out); +} + +int kms_bo_unmap(struct kms_bo *bo) +{ + return bo->kms->bo_unmap(bo); +} + +int kms_bo_destroy(struct kms_bo **bo) +{ + int ret; + + if (!(*bo)) + return 0; + + ret = (*bo)->kms->bo_destroy(*bo); + if (ret) + return ret; + + *bo = NULL; + return 0; +} diff --git a/lib/libdrm/libkms/dumb.c b/lib/libdrm/libkms/dumb.c new file mode 100644 index 000000000..440efb310 --- /dev/null +++ b/lib/libdrm/libkms/dumb.c @@ -0,0 +1,221 @@ +/************************************************************************** + * + * 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 <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "internal.h" + +#include <sys/mman.h> +#include <sys/ioctl.h> +#include "xf86drm.h" + +#include "i915_drm.h" + +struct dumb_bo +{ + struct kms_bo base; + unsigned map_count; +}; + +static int +dumb_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 +dumb_destroy(struct kms_driver *kms) +{ + free(kms); + return 0; +} + +static int +dumb_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_mode_create_dumb arg; + struct dumb_bo *bo; + int i, ret; + + for (i = 0; attr[i]; i += 2) { + switch (attr[i]) { + case KMS_WIDTH: + case KMS_HEIGHT: + break; + case KMS_BO_TYPE: + break; + default: + return -EINVAL; + } + } + + bo = calloc(1, sizeof(*bo)); + if (!bo) + return -ENOMEM; + + memset(&arg, 0, sizeof(arg)); + + /* All BO_TYPE currently are 32bpp formats */ + arg.bpp = 32; + arg.width = width; + arg.height = height; + + ret = drmIoctl(kms->fd, DRM_IOCTL_MODE_CREATE_DUMB, &arg); + if (ret) + goto err_free; + + bo->base.kms = kms; + bo->base.handle = arg.handle; + bo->base.size = arg.size; + bo->base.pitch = arg.pitch; + + *out = &bo->base; + + return 0; + +err_free: + free(bo); + return ret; +} + +static int +dumb_bo_get_prop(struct kms_bo *bo, unsigned key, unsigned *out) +{ + switch (key) { + default: + return -EINVAL; + } +} + +static int +dumb_bo_map(struct kms_bo *_bo, void **out) +{ + struct dumb_bo *bo = (struct dumb_bo *)_bo; + struct drm_mode_map_dumb 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 = drmIoctl(bo->base.kms->fd, DRM_IOCTL_MODE_MAP_DUMB, &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 +dumb_bo_unmap(struct kms_bo *_bo) +{ + struct dumb_bo *bo = (struct dumb_bo *)_bo; + bo->map_count--; + return 0; +} + +static int +dumb_bo_destroy(struct kms_bo *_bo) +{ + struct dumb_bo *bo = (struct dumb_bo *)_bo; + struct drm_mode_destroy_dumb 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_MODE_DESTROY_DUMB, &arg); + if (ret) + return -errno; + + free(bo); + return 0; +} + +int +dumb_create(int fd, struct kms_driver **out) +{ + struct kms_driver *kms; + int ret; + uint64_t cap = 0; + + ret = drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &cap); + if (ret || cap == 0) + return -EINVAL; + + kms = calloc(1, sizeof(*kms)); + if (!kms) + return -ENOMEM; + + kms->fd = fd; + + kms->bo_create = dumb_bo_create; + kms->bo_map = dumb_bo_map; + kms->bo_unmap = dumb_bo_unmap; + kms->bo_get_prop = dumb_bo_get_prop; + kms->bo_destroy = dumb_bo_destroy; + kms->get_prop = dumb_get_prop; + kms->destroy = dumb_destroy; + *out = kms; + + return 0; +} diff --git a/lib/libdrm/libkms/intel.c b/lib/libdrm/libkms/intel.c new file mode 100644 index 000000000..8b8249b18 --- /dev/null +++ b/lib/libdrm/libkms/intel.c @@ -0,0 +1,238 @@ +/************************************************************************** + * + * 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 <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "internal.h" + +#include <sys/mman.h> +#include <sys/ioctl.h> +#include "xf86drm.h" + +#include "i915_drm.h" + +struct intel_bo +{ + struct kms_bo base; + unsigned map_count; +}; + +static int +intel_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 +intel_destroy(struct kms_driver *kms) +{ + free(kms); + return 0; +} + +static int +intel_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_i915_gem_create arg; + unsigned size, pitch; + struct intel_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_I915_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; + if (type == KMS_BO_TYPE_SCANOUT_X8R8G8B8 && pitch > 512) { + struct drm_i915_gem_set_tiling tile; + + memset(&tile, 0, sizeof(tile)); + tile.handle = bo->base.handle; + tile.tiling_mode = I915_TILING_X; + tile.stride = bo->base.pitch; + + ret = drmCommandWriteRead(kms->fd, DRM_I915_GEM_SET_TILING, &tile, sizeof(tile)); +#if 0 + if (ret) { + kms_bo_destroy(out); + return ret; + } +#endif + } + + return 0; + +err_free: + free(bo); + return ret; +} + +static int +intel_bo_get_prop(struct kms_bo *bo, unsigned key, unsigned *out) +{ + switch (key) { + default: + return -EINVAL; + } +} + +static int +intel_bo_map(struct kms_bo *_bo, void **out) +{ + struct intel_bo *bo = (struct intel_bo *)_bo; + struct drm_i915_gem_mmap_gtt 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_I915_GEM_MMAP_GTT, &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 +intel_bo_unmap(struct kms_bo *_bo) +{ + struct intel_bo *bo = (struct intel_bo *)_bo; + bo->map_count--; + return 0; +} + +static int +intel_bo_destroy(struct kms_bo *_bo) +{ + struct intel_bo *bo = (struct intel_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 +intel_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 = intel_bo_create; + kms->bo_map = intel_bo_map; + kms->bo_unmap = intel_bo_unmap; + kms->bo_get_prop = intel_bo_get_prop; + kms->bo_destroy = intel_bo_destroy; + kms->get_prop = intel_get_prop; + kms->destroy = intel_destroy; + *out = kms; + + return 0; +} diff --git a/lib/libdrm/libkms/internal.h b/lib/libdrm/libkms/internal.h new file mode 100644 index 000000000..5e2501e4d --- /dev/null +++ b/lib/libdrm/libkms/internal.h @@ -0,0 +1,77 @@ +/************************************************************************** + * + * 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. + * + **************************************************************************/ + + +#ifndef INTERNAL_H_ +#define INTERNAL_H_ + +#include "libkms.h" + +struct kms_driver +{ + int (*get_prop)(struct kms_driver *kms, const unsigned key, + unsigned *out); + int (*destroy)(struct kms_driver *kms); + + int (*bo_create)(struct kms_driver *kms, + unsigned width, + unsigned height, + enum kms_bo_type type, + const unsigned *attr, + struct kms_bo **out); + int (*bo_get_prop)(struct kms_bo *bo, const unsigned key, + unsigned *out); + int (*bo_map)(struct kms_bo *bo, void **out); + int (*bo_unmap)(struct kms_bo *bo); + int (*bo_destroy)(struct kms_bo *bo); + + int fd; +}; + +struct kms_bo +{ + struct kms_driver *kms; + void *ptr; + size_t size; + size_t offset; + size_t pitch; + unsigned handle; +}; + +int linux_create(int fd, struct kms_driver **out); + +int vmwgfx_create(int fd, struct kms_driver **out); + +int intel_create(int fd, struct kms_driver **out); + +int dumb_create(int fd, struct kms_driver **out); + +int nouveau_create(int fd, struct kms_driver **out); + +int radeon_create(int fd, struct kms_driver **out); + +#endif diff --git a/lib/libdrm/libkms/libkms.h b/lib/libdrm/libkms/libkms.h new file mode 100644 index 000000000..46644429f --- /dev/null +++ b/lib/libdrm/libkms/libkms.h @@ -0,0 +1,74 @@ +/************************************************************************** + * + * 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. + * + **************************************************************************/ + + +#ifndef _LIBKMS_H_ +#define _LIBKMS_H_ + +/** + * \file + * + */ + +struct kms_driver; +struct kms_bo; + +enum kms_attrib +{ + KMS_TERMINATE_PROP_LIST, +#define KMS_TERMINATE_PROP_LIST KMS_TERMINATE_PROP_LIST + KMS_BO_TYPE, +#define KMS_BO_TYPE KMS_BO_TYPE + KMS_WIDTH, +#define KMS_WIDTH KMS_WIDTH + KMS_HEIGHT, +#define KMS_HEIGHT KMS_HEIGHT + KMS_PITCH, +#define KMS_PITCH KMS_PITCH + KMS_HANDLE, +#define KMS_HANDLE KMS_HANDLE +}; + +enum kms_bo_type +{ + KMS_BO_TYPE_SCANOUT_X8R8G8B8 = (1 << 0), +#define KMS_BO_TYPE_SCANOUT_X8R8G8B8 KMS_BO_TYPE_SCANOUT_X8R8G8B8 + KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8 = (1 << 1), +#define KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8 KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8 +}; + +int kms_create(int fd, struct kms_driver **out); +int kms_get_prop(struct kms_driver *kms, unsigned key, unsigned *out); +int kms_destroy(struct kms_driver **kms); + +int kms_bo_create(struct kms_driver *kms, const unsigned *attr, struct kms_bo **out); +int kms_bo_get_prop(struct kms_bo *bo, unsigned key, unsigned *out); +int kms_bo_map(struct kms_bo *bo, void **out); +int kms_bo_unmap(struct kms_bo *bo); +int kms_bo_destroy(struct kms_bo **bo); + +#endif diff --git a/lib/libdrm/libkms/libkms.pc.in b/lib/libdrm/libkms/libkms.pc.in new file mode 100644 index 000000000..511535ad5 --- /dev/null +++ b/lib/libdrm/libkms/libkms.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libkms +Description: Library that abstract aways the different mm interface for kernel drivers +Version: 1.0.0 +Libs: -L${libdir} -lkms +Cflags: -I${includedir}/libkms diff --git a/lib/libdrm/libkms/linux.c b/lib/libdrm/libkms/linux.c new file mode 100644 index 000000000..72963adb4 --- /dev/null +++ b/lib/libdrm/libkms/linux.c @@ -0,0 +1,226 @@ +/************************************************************************** + * + * 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. + * + **************************************************************************/ +/* + * Thanks to krh and jcristau for the tips on + * going from fd to pci id via fstat and udev. + */ + + +//#include "config.h" +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <xf86drm.h> +#include <string.h> +#include <unistd.h> + +#include <sys/stat.h> + +#include "internal.h" + +#define PATH_SIZE 512 + +static int +linux_name_from_sysfs(int fd, char **out) +{ + char path[PATH_SIZE+1] = ""; /* initialize to please valgrind */ + char link[PATH_SIZE+1] = ""; + struct stat buffer; + unsigned maj, min; + char* slash_name; + int ret; + + /* + * Inside the sysfs directory for the device there is a symlink + * to the directory representing the driver module, that path + * happens to hold the name of the driver. + * + * So lets get the symlink for the drm device. Then read the link + * and filter out the last directory which happens to be the name + * of the driver, which we can use to load the correct interface. + * + * Thanks to Ray Strode of Plymouth for the code. + */ + + ret = fstat(fd, &buffer); + if (ret) + return ret; + + if (!S_ISCHR(buffer.st_mode)) + return -EINVAL; + + maj = major(buffer.st_rdev); + min = minor(buffer.st_rdev); + + snprintf(path, PATH_SIZE, "/sys/dev/char/%d:%d/device/driver", maj, min); + + if (readlink(path, link, PATH_SIZE) < 0) + return -EINVAL; + + /* link looks something like this: ../../../bus/pci/drivers/intel */ + slash_name = strrchr(link, '/'); + if (!slash_name) + return -EINVAL; + + /* copy name and at the same time remove the slash */ + *out = strdup(slash_name + 1); + return 0; +} + +static int +linux_from_sysfs(int fd, struct kms_driver **out) +{ + char *name; + int ret; + + ret = linux_name_from_sysfs(fd, &name); + if (ret) + return ret; + + if (!strcmp(name, "intel")) + ret = intel_create(fd, out); +#ifdef HAVE_VMWGFX + else if (!strcmp(name, "vmwgfx")) + ret = vmwgfx_create(fd, out); +#endif +#ifdef HAVE_NOUVEAU + else if (!strcmp(name, "nouveau")) + ret = nouveau_create(fd, out); +#endif +#ifdef HAVE_RADEON + else if (!strcmp(name, "radeon")) + ret = radeon_create(fd, out); +#endif + else + ret = -ENOSYS; + + free(name); + return ret; +} + +#if 0 +#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE +#include <libudev.h> + +struct create_record +{ + unsigned vendor; + unsigned chip; + int (*func)(int fd, struct kms_driver **out); +}; + +static struct create_record table[] = { + { 0x8086, 0x2a42, intel_create }, /* i965 */ +#ifdef HAVE_VMWGFX + { 0x15ad, 0x0405, vmwgfx_create }, /* VMware vGPU */ +#endif + { 0, 0, NULL }, +}; + +static int +linux_get_pciid_from_fd(int fd, unsigned *vendor_id, unsigned *chip_id) +{ + struct udev *udev; + struct udev_device *device; + struct udev_device *parent; + const char *pci_id; + struct stat buffer; + int ret; + + ret = fstat(fd, &buffer); + if (ret) + return -EINVAL; + + if (!S_ISCHR(buffer.st_mode)) + return -EINVAL; + + udev = udev_new(); + if (!udev) + return -ENOMEM; + + device = udev_device_new_from_devnum(udev, 'c', buffer.st_rdev); + if (!device) + goto err_free_udev; + + parent = udev_device_get_parent(device); + if (!parent) + goto err_free_device; + + pci_id = udev_device_get_property_value(parent, "PCI_ID"); + if (!pci_id) + goto err_free_device; + + if (sscanf(pci_id, "%x:%x", vendor_id, chip_id) != 2) + goto err_free_device; + + udev_device_unref(device); + udev_unref(udev); + + return 0; + +err_free_device: + udev_device_unref(device); +err_free_udev: + udev_unref(udev); + return -EINVAL; +} + +static int +linux_from_udev(int fd, struct kms_driver **out) +{ + unsigned vendor_id, chip_id; + int ret, i; + + ret = linux_get_pciid_from_fd(fd, &vendor_id, &chip_id); + if (ret) + return ret; + + for (i = 0; table[i].func; i++) + if (table[i].vendor == vendor_id && table[i].chip == chip_id) + return table[i].func(fd, out); + + return -ENOSYS; +} +#else +static int +linux_from_udev(int fd, struct kms_driver **out) +{ + return -ENOSYS; +} +#endif + +int +linux_create(int fd, struct kms_driver **out) +{ + if (!dumb_create(fd, out)) + return 0; + + if (!linux_from_udev(fd, out)) + return 0; + + return linux_from_sysfs(fd, out); +} diff --git a/lib/libdrm/libkms/nouveau.c b/lib/libdrm/libkms/nouveau.c new file mode 100644 index 000000000..0e24a155f --- /dev/null +++ b/lib/libdrm/libkms/nouveau.c @@ -0,0 +1,220 @@ +/************************************************************************** + * + * 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 <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "internal.h" + +#include <sys/mman.h> +#include <sys/ioctl.h> +#include "xf86drm.h" + +#include "nouveau_drm.h" + +struct nouveau_bo +{ + struct kms_bo base; + uint64_t map_handle; + unsigned map_count; +}; + +static int +nouveau_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 +nouveau_destroy(struct kms_driver *kms) +{ + free(kms); + return 0; +} + +static int +nouveau_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_nouveau_gem_new arg; + unsigned size, pitch; + struct nouveau_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; + } else { + return -EINVAL; + } + + memset(&arg, 0, sizeof(arg)); + arg.info.size = size; + arg.info.domain = NOUVEAU_GEM_DOMAIN_MAPPABLE | NOUVEAU_GEM_DOMAIN_VRAM; + arg.info.tile_mode = 0; + arg.info.tile_flags = 0; + arg.align = 512; + arg.channel_hint = 0; + + ret = drmCommandWriteRead(kms->fd, DRM_NOUVEAU_GEM_NEW, &arg, sizeof(arg)); + if (ret) + goto err_free; + + bo->base.kms = kms; + bo->base.handle = arg.info.handle; + bo->base.size = size; + bo->base.pitch = pitch; + bo->map_handle = arg.info.map_handle; + + *out = &bo->base; + + return 0; + +err_free: + free(bo); + return ret; +} + +static int +nouveau_bo_get_prop(struct kms_bo *bo, unsigned key, unsigned *out) +{ + switch (key) { + default: + return -EINVAL; + } +} + +static int +nouveau_bo_map(struct kms_bo *_bo, void **out) +{ + struct nouveau_bo *bo = (struct nouveau_bo *)_bo; + void *map = NULL; + + if (bo->base.ptr) { + bo->map_count++; + *out = bo->base.ptr; + return 0; + } + + map = mmap(0, bo->base.size, PROT_READ | PROT_WRITE, MAP_SHARED, bo->base.kms->fd, bo->map_handle); + if (map == MAP_FAILED) + return -errno; + + bo->base.ptr = map; + bo->map_count++; + *out = bo->base.ptr; + + return 0; +} + +static int +nouveau_bo_unmap(struct kms_bo *_bo) +{ + struct nouveau_bo *bo = (struct nouveau_bo *)_bo; + bo->map_count--; + return 0; +} + +static int +nouveau_bo_destroy(struct kms_bo *_bo) +{ + struct nouveau_bo *bo = (struct nouveau_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 +nouveau_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 = nouveau_bo_create; + kms->bo_map = nouveau_bo_map; + kms->bo_unmap = nouveau_bo_unmap; + kms->bo_get_prop = nouveau_bo_get_prop; + kms->bo_destroy = nouveau_bo_destroy; + kms->get_prop = nouveau_get_prop; + kms->destroy = nouveau_destroy; + *out = kms; + + return 0; +} diff --git a/lib/libdrm/libkms/radeon.c b/lib/libdrm/libkms/radeon.c new file mode 100644 index 000000000..f5e382ae4 --- /dev/null +++ b/lib/libdrm/libkms/radeon.c @@ -0,0 +1,242 @@ +/************************************************************************** + * + * 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 <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "internal.h" + +#include <sys/mman.h> +#include <sys/ioctl.h> +#include "xf86drm.h" + +#include "radeon_drm.h" + + +#define ALIGNMENT 512 + +struct radeon_bo +{ + struct kms_bo base; + unsigned map_count; +}; + +static int +radeon_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 +radeon_destroy(struct kms_driver *kms) +{ + free(kms); + return 0; +} + +static int +radeon_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_radeon_gem_create arg; + unsigned size, pitch; + struct radeon_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; + } + } + + switch (type) { + case KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8: + pitch = 4 * 64; + size = 4 * 64 * 64; + break; + case KMS_BO_TYPE_SCANOUT_X8R8G8B8: + pitch = width * 4; + pitch = (pitch + ALIGNMENT - 1) & ~(ALIGNMENT - 1); + size = pitch * height; + break; + default: + return -EINVAL; + } + + bo = calloc(1, sizeof(*bo)); + if (!bo) + return -ENOMEM; + + memset(&arg, 0, sizeof(arg)); + arg.size = size; + arg.alignment = ALIGNMENT; + arg.initial_domain = RADEON_GEM_DOMAIN_CPU; + arg.flags = 0; + arg.handle = 0; + + ret = drmCommandWriteRead(kms->fd, DRM_RADEON_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; + bo->base.offset = 0; + bo->map_count = 0; + + *out = &bo->base; + + return 0; + +err_free: + free(bo); + return ret; +} + +static int +radeon_bo_get_prop(struct kms_bo *bo, unsigned key, unsigned *out) +{ + switch (key) { + default: + return -EINVAL; + } +} + +static int +radeon_bo_map(struct kms_bo *_bo, void **out) +{ + struct radeon_bo *bo = (struct radeon_bo *)_bo; + struct drm_radeon_gem_mmap 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; + arg.offset = bo->base.offset; + arg.size = (uint64_t)bo->base.size; + + ret = drmCommandWriteRead(bo->base.kms->fd, DRM_RADEON_GEM_MMAP, + &arg, sizeof(arg)); + if (ret) + return -errno; + + map = mmap(0, arg.size, PROT_READ | PROT_WRITE, MAP_SHARED, + bo->base.kms->fd, arg.addr_ptr); + if (map == MAP_FAILED) + return -errno; + + bo->base.ptr = map; + bo->map_count++; + *out = bo->base.ptr; + + return 0; +} + +static int +radeon_bo_unmap(struct kms_bo *_bo) +{ + struct radeon_bo *bo = (struct radeon_bo *)_bo; + if (--bo->map_count == 0) { + munmap(bo->base.ptr, bo->base.size); + bo->base.ptr = NULL; + } + return 0; +} + +static int +radeon_bo_destroy(struct kms_bo *_bo) +{ + struct radeon_bo *bo = (struct radeon_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 +radeon_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 = radeon_bo_create; + kms->bo_map = radeon_bo_map; + kms->bo_unmap = radeon_bo_unmap; + kms->bo_get_prop = radeon_bo_get_prop; + kms->bo_destroy = radeon_bo_destroy; + kms->get_prop = radeon_get_prop; + kms->destroy = radeon_destroy; + *out = kms; + + return 0; +} diff --git a/lib/libdrm/libkms/shlib_version b/lib/libdrm/libkms/shlib_version new file mode 100644 index 000000000..97c9f92d6 --- /dev/null +++ b/lib/libdrm/libkms/shlib_version @@ -0,0 +1,2 @@ +major=0 +minor=0 diff --git a/lib/libdrm/libkms/vmwgfx.c b/lib/libdrm/libkms/vmwgfx.c new file mode 100644 index 000000000..d594b3bd1 --- /dev/null +++ b/lib/libdrm/libkms/vmwgfx.c @@ -0,0 +1,207 @@ +/************************************************************************** + * + * 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 <errno.h> +#include <stdlib.h> +#include <string.h> +#include "internal.h" + +#include <sys/mman.h> +#include "xf86drm.h" +#include "vmwgfx_drm.h" + +struct vmwgfx_bo +{ + struct kms_bo base; + uint64_t map_handle; + unsigned map_count; +}; + +static int +vmwgfx_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 +vmwgfx_destroy(struct kms_driver *kms) +{ + free(kms); + return 0; +} + +static int +vmwgfx_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 vmwgfx_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 -EINVAL; + + { + union drm_vmw_alloc_dmabuf_arg arg; + struct drm_vmw_alloc_dmabuf_req *req = &arg.req; + struct drm_vmw_dmabuf_rep *rep = &arg.rep; + + memset(&arg, 0, sizeof(arg)); + req->size = width * height * 4; + bo->base.size = req->size; + bo->base.pitch = width * 4; + bo->base.kms = kms; + + do { + ret = drmCommandWriteRead(bo->base.kms->fd, + DRM_VMW_ALLOC_DMABUF, + &arg, sizeof(arg)); + } while (ret == -ERESTART); + + if (ret) + goto err_free; + + bo->base.handle = rep->handle; + bo->map_handle = rep->map_handle; + bo->base.handle = rep->cur_gmr_id; + bo->base.offset = rep->cur_gmr_offset; + } + + *out = &bo->base; + + return 0; + +err_free: + free(bo); + return ret; +} + +static int +vmwgfx_bo_get_prop(struct kms_bo *bo, unsigned key, unsigned *out) +{ + switch (key) { + default: + return -EINVAL; + } +} + +static int +vmwgfx_bo_map(struct kms_bo *_bo, void **out) +{ + struct vmwgfx_bo *bo = (struct vmwgfx_bo *)_bo; + void *map; + + if (bo->base.ptr) { + bo->map_count++; + *out = bo->base.ptr; + return 0; + } + + map = mmap(NULL, bo->base.size, PROT_READ | PROT_WRITE, MAP_SHARED, bo->base.kms->fd, bo->map_handle); + if (map == MAP_FAILED) + return -errno; + + bo->base.ptr = map; + bo->map_count++; + *out = bo->base.ptr; + + return 0; +} + +static int +vmwgfx_bo_unmap(struct kms_bo *_bo) +{ + struct vmwgfx_bo *bo = (struct vmwgfx_bo *)_bo; + bo->map_count--; + return 0; +} + +static int +vmwgfx_bo_destroy(struct kms_bo *_bo) +{ + struct vmwgfx_bo *bo = (struct vmwgfx_bo *)_bo; + struct drm_vmw_unref_dmabuf_arg arg; + + 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; + drmCommandWrite(bo->base.kms->fd, DRM_VMW_UNREF_DMABUF, &arg, sizeof(arg)); + + free(bo); + return 0; +} + +int +vmwgfx_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 = vmwgfx_bo_create; + kms->bo_map = vmwgfx_bo_map; + kms->bo_unmap = vmwgfx_bo_unmap; + kms->bo_get_prop = vmwgfx_bo_get_prop; + kms->bo_destroy = vmwgfx_bo_destroy; + kms->get_prop = vmwgfx_get_prop; + kms->destroy = vmwgfx_destroy; + *out = kms; + return 0; +} |