1/*
2 * va_wayland_drm.c - Wayland/DRM helpers
3 *
4 * Copyright (c) 2012 Intel Corporation. All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL INTEL AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27#include "sysdeps.h"
28#include <unistd.h>
29#include <errno.h>
30#include <fcntl.h>
31#include <dlfcn.h>
32#include <sys/stat.h>
33#include <xf86drm.h>
34#include "va_drmcommon.h"
35#include "drm/va_drm_utils.h"
36#include "va_wayland_drm.h"
37#include "va_wayland_private.h"
38#include "wayland-drm-client-protocol.h"
39
40/* XXX: Wayland/DRM support currently lives in Mesa libEGL.so.* library */
41#define LIBWAYLAND_DRM_NAME "libEGL.so.1"
42
43typedef struct va_wayland_drm_context {
44    struct va_wayland_context   base;
45    void                       *handle;
46    struct wl_drm              *drm;
47    struct wl_registry         *registry;
48    void                       *drm_interface;
49    unsigned int                is_authenticated        : 1;
50} VADisplayContextWaylandDRM;
51
52static void
53drm_handle_device(void *data, struct wl_drm *drm, const char *device)
54{
55    VADisplayContextP const pDisplayContext = data;
56    VADriverContextP const ctx = pDisplayContext->pDriverContext;
57    VADisplayContextWaylandDRM * const wl_drm_ctx = pDisplayContext->opaque;
58    struct drm_state * const drm_state = ctx->drm_state;
59    drm_magic_t magic;
60    struct stat st;
61
62    if (stat(device, &st) < 0) {
63        va_wayland_error("failed to identify %s: %s (errno %d)",
64                         device, strerror(errno), errno);
65        return;
66    }
67
68    if (!S_ISCHR(st.st_mode)) {
69        va_wayland_error("%s is not a device", device);
70        return;
71    }
72
73    drm_state->fd = open(device, O_RDWR);
74    if (drm_state->fd < 0) {
75        va_wayland_error("failed to open %s: %s (errno %d)",
76                         device, strerror(errno), errno);
77        return;
78    }
79
80    drmGetMagic(drm_state->fd, &magic);
81    wl_drm_authenticate(wl_drm_ctx->drm, magic);
82}
83
84static void
85drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)
86{
87}
88
89static void
90drm_handle_authenticated(void *data, struct wl_drm *drm)
91{
92    VADisplayContextP const pDisplayContext = data;
93    VADriverContextP const ctx = pDisplayContext->pDriverContext;
94    VADisplayContextWaylandDRM * const wl_drm_ctx = pDisplayContext->opaque;
95    struct drm_state * const drm_state = ctx->drm_state;
96
97    wl_drm_ctx->is_authenticated = 1;
98    drm_state->auth_type         = VA_DRM_AUTH_CUSTOM;
99}
100
101static const struct wl_drm_listener drm_listener = {
102    drm_handle_device,
103    drm_handle_format,
104    drm_handle_authenticated
105};
106
107static VAStatus
108va_DisplayContextGetDriverName(
109    VADisplayContextP pDisplayContext,
110    char            **driver_name_ptr
111)
112{
113    VADriverContextP const ctx = pDisplayContext->pDriverContext;
114
115    return VA_DRM_GetDriverName(ctx, driver_name_ptr);
116}
117
118void
119va_wayland_drm_destroy(VADisplayContextP pDisplayContext)
120{
121    VADriverContextP const ctx = pDisplayContext->pDriverContext;
122    struct va_wayland_drm_context * const wl_drm_ctx = pDisplayContext->opaque;
123    struct drm_state * const drm_state = ctx->drm_state;
124
125    if (wl_drm_ctx->drm) {
126        wl_drm_destroy(wl_drm_ctx->drm);
127        wl_drm_ctx->drm = NULL;
128    }
129    wl_drm_ctx->is_authenticated = 0;
130
131    if (wl_drm_ctx->handle) {
132        dlclose(wl_drm_ctx->handle);
133        wl_drm_ctx->handle = NULL;
134    }
135
136    if (drm_state) {
137        if (drm_state->fd >= 0) {
138            close(drm_state->fd);
139            drm_state->fd = -1;
140        }
141        free(ctx->drm_state);
142        ctx->drm_state = NULL;
143    }
144}
145
146static void
147registry_handle_global(
148    void               *data,
149    struct wl_registry *registry,
150    uint32_t            id,
151    const char         *interface,
152    uint32_t            version
153)
154{
155    struct va_wayland_drm_context *wl_drm_ctx = data;
156
157    if (strcmp(interface, "wl_drm") == 0) {
158        wl_drm_ctx->drm =
159            wl_registry_bind(wl_drm_ctx->registry, id, wl_drm_ctx->drm_interface, 1);
160    }
161}
162
163static const struct wl_registry_listener registry_listener = {
164    registry_handle_global,
165    NULL,
166};
167
168bool
169va_wayland_drm_create(VADisplayContextP pDisplayContext)
170{
171    VADriverContextP const ctx = pDisplayContext->pDriverContext;
172    struct va_wayland_drm_context *wl_drm_ctx;
173    struct drm_state *drm_state;
174    uint32_t id;
175
176    wl_drm_ctx = malloc(sizeof(*wl_drm_ctx));
177    if (!wl_drm_ctx)
178        return false;
179    wl_drm_ctx->base.destroy            = va_wayland_drm_destroy;
180    wl_drm_ctx->handle                  = NULL;
181    wl_drm_ctx->drm                     = NULL;
182    wl_drm_ctx->drm_interface           = NULL;
183    wl_drm_ctx->is_authenticated        = 0;
184    pDisplayContext->opaque             = wl_drm_ctx;
185    pDisplayContext->vaGetDriverName    = va_DisplayContextGetDriverName;
186
187    drm_state = calloc(1, sizeof(struct drm_state));
188    if (!drm_state)
189        return false;
190    drm_state->fd        = -1;
191    drm_state->auth_type = 0;
192    ctx->drm_state       = drm_state;
193
194    wl_drm_ctx->handle = dlopen(LIBWAYLAND_DRM_NAME, RTLD_LAZY|RTLD_LOCAL);
195    if (!wl_drm_ctx->handle)
196        return false;
197
198    wl_drm_ctx->drm_interface =
199        dlsym(wl_drm_ctx->handle, "wl_drm_interface");
200    if (!wl_drm_ctx->drm_interface)
201        return false;
202
203    wl_drm_ctx->registry = wl_display_get_registry(ctx->native_dpy);
204    wl_registry_add_listener(wl_drm_ctx->registry, &registry_listener, wl_drm_ctx);
205    wl_display_roundtrip(ctx->native_dpy);
206
207    /* registry_handle_global should have been called by the
208     * wl_display_roundtrip above
209     */
210
211    if (!wl_drm_ctx->drm)
212        return false;
213
214    wl_drm_add_listener(wl_drm_ctx->drm, &drm_listener, pDisplayContext);
215    wl_display_roundtrip(ctx->native_dpy);
216    if (drm_state->fd < 0)
217        return false;
218
219    wl_display_roundtrip(ctx->native_dpy);
220    if (!wl_drm_ctx->is_authenticated)
221        return false;
222    return true;
223}
224