summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2014-08-10 04:10:31 +1000
committerBen Skeggs <bskeggs@redhat.com>2014-08-10 05:26:59 +1000
commit19ae6962b47db91803f3100e9cab6f43ef348fc7 (patch)
tree6d4f2831f2e0f42a7496c049517b3ea04406561d /lib
parent565bf0ec3ba22fc14671dcf0b7372ef585feba80 (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.am8
-rw-r--r--lib/kern.c218
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,
+};