diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2014-08-10 04:10:31 +1000 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2014-08-10 05:26:59 +1000 |
commit | 19ae6962b47db91803f3100e9cab6f43ef348fc7 (patch) | |
tree | 6d4f2831f2e0f42a7496c049517b3ea04406561d /lib | |
parent | 565bf0ec3ba22fc14671dcf0b7372ef585feba80 (diff) |
drm: expose the full object/event interfaces to userspace
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makefile.am | 8 | ||||
-rw-r--r-- | lib/kern.c | 218 |
2 files changed, 223 insertions, 3 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am index 9eef51dc..00f8088b 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -2,9 +2,11 @@ noinst_LTLIBRARIES = libpciaccessos.la libpciaccessos_la_CPPFLAGS = -I${top_srcdir}/nvkm/include \ -I${top_srcdir}/nvkm \ - -I${top_srcdir} + -I${top_srcdir} \ + -I/usr/include/libdrm libpciaccessos_la_CFLAGS = @PCIACCESS_CFLAGS@ -libpciaccessos_la_LIBADD = @PCIACCESS_LIBS@ -lpthread \ +libpciaccessos_la_LIBADD = @PCIACCESS_LIBS@ -lpthread -ldrm \ $(top_srcdir)/nvkm/libnvkm.la libpciaccessos_la_SOURCES = intr.c \ - main.c + main.c \ + kern.c diff --git a/lib/kern.c b/lib/kern.c new file mode 100644 index 00000000..47725862 --- /dev/null +++ b/lib/kern.c @@ -0,0 +1,218 @@ +/* + * Copyright 2014 Red Hat Inc. + * + * 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, sublicense, + * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + * Authors: Ben Skeggs <bskeggs@redhat.com> + */ + +#include <sys/mman.h> +#include <sys/ioctl.h> + +#include <xf86drm.h> + +#include <nvif/client.h> +#include <nvif/driver.h> +#include <nvif/notify.h> +#include <nvif/unpack.h> +#include <nvif/event.h> +#include <nvif/ioctl.h> + +#include <drm/uapi/drm/nouveau_drm.h> + +struct drm_client_priv { + int fd; + u32 version; + pthread_t event; + bool done; +}; + +static void +drm_client_unmap(void *priv, void *ptr, u32 size) +{ +} + +static void * +drm_client_map(void *priv, u64 handle, u32 size) +{ + return NULL; +} + +static int +drm_client_ioctl(void *priv, bool super, void *data, u32 size, void **hack) +{ + const unsigned long request = DRM_IOC(DRM_IOC_READWRITE, DRM_IOCTL_BASE, + DRM_COMMAND_BASE + + DRM_NOUVEAU_NVIF, size); + struct drm_client_priv *drm = priv; + int ret = ioctl(drm->fd, request, data); + if (ret < 0) + return -errno; + return ret; +} + +static int +drm_client_resume(void *priv) +{ + return -EINVAL; +} + +static int +drm_client_suspend(void *priv) +{ + return -ENOSYS; +} + +static void +drm_client_notify(void *repv, u32 repc) +{ + union { + struct nvif_notify_rep_v0 v0; + } *rep = repv; + void *data = repv; + u32 size = repc; + u64 token; + u8 route; + int ret; + + printf("notify %d\n", repc); + + if (nvif_unpack(rep->v0, 0, 0, true)) { + token = rep->v0.token; + route = rep->v0.route; + } else + assert(0); + + switch (route) { + case NVIF_NOTIFY_V0_ROUTE_NVIF: { + struct nvif_notify *notify = (void *)(unsigned long)token; + assert(notify); + nvif_notify(repv, sizeof(rep->v0), data, size); + } + break; + default: + assert(0); + break; + } +} + +static void * +drm_client_event(void *arg) +{ + struct drm_client_priv *drm = arg; + struct drm_event *e; + char data[1024]; + ssize_t size; + int i; + + while (1) { + if ((size = read(drm->fd, data, sizeof(data))) <= 0) + continue; + + for (i = 0; e = (void *)&data[i], i < size; i += e->length) { + u32 size = e->length - sizeof(*e); + u8 *data = (u8 *)e + sizeof(*e); + switch (e->type) { + case DRM_NOUVEAU_EVENT_NVIF: + drm_client_notify(data, size); + continue; + default: + break; + } + fprintf(stderr, "event %08x, %d\n", e->type, size); + } + } + + return NULL; +} + +static void +drm_client_fini(void *priv) +{ + struct drm_client_priv *drm = priv; + if (drm) { + if (drm->fd >= 0) { + if (drm->done) { + pthread_cancel(drm->event); + pthread_join(drm->event, NULL); + } + close(drm->fd); + } + free(drm); + } +} + +#define DRM_RENDER_PATH "/dev/dri/renderD" +#define DRM_RENDER_MIN 128 +#define DRM_RENDER_MAX (128 + 63) +static int +drm_client_init(const char *name, u64 device, const char *cfg, + const char *dbg, void **ppriv) +{ + struct drm_client_priv *drm; + drmVersionPtr ver; + int ret, minor; + char path[128]; + + if (ret = -ENOMEM, !(drm = *ppriv = malloc(sizeof(*drm)))) + goto fail; + + for (minor = DRM_RENDER_MIN; minor <= DRM_RENDER_MAX; minor++) { + snprintf(path, sizeof(path), "/dev/dri/renderD%d", minor); + if ((drm->fd = open(path, O_RDWR, 0)) < 0) + continue; + if ((ver = drmGetVersion(drm->fd)) == NULL) + continue; + if (!strcmp(ver->name, "nouveau")) + break; + free(ver); + } + + if (ret = -ENODEV, minor > DRM_RENDER_MAX) + goto fail; + + drm->version = (ver->version_major << 24) | + (ver->version_minor << 8) | + ver->version_patchlevel; + free(ver); + if (ret = -ENOSYS, drm->version < 0x01000200) + goto fail; + + if ((ret = pthread_create(&drm->event, NULL, drm_client_event, drm))) + goto fail; + + drm->done = true; + return 0; +fail: + drm_client_fini(drm); + return ret; +} + +const struct nvif_driver +nvif_driver_drm = { + .name = "drm", + .init = drm_client_init, + .fini = drm_client_fini, + .suspend = drm_client_suspend, + .resume = drm_client_resume, + .ioctl = drm_client_ioctl, + .map = drm_client_map, + .unmap = drm_client_unmap, + .keep = true, +}; |