exynos_drm.c revision e88f27b3
1/*
2 * Copyright (C) 2012 Samsung Electronics Co., Ltd.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors:
24 *    Inki Dae <inki.dae@samsung.com>
25 */
26
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#include <stdlib.h>
32#include <stdio.h>
33#include <string.h>
34#include <errno.h>
35
36#include <sys/mman.h>
37#include <linux/stddef.h>
38
39#include <xf86drm.h>
40
41#include "exynos_drm.h"
42#include "exynos_drmif.h"
43
44/*
45 * Create exynos drm device object.
46 *
47 * @fd: file descriptor to exynos drm driver opened.
48 *
49 * if true, return the device object else NULL.
50 */
51struct exynos_device * exynos_device_create(int fd)
52{
53	struct exynos_device *dev;
54
55	dev = calloc(sizeof(*dev), 1);
56	if (!dev) {
57		fprintf(stderr, "failed to create device[%s].\n",
58				strerror(errno));
59		return NULL;
60	}
61
62	dev->fd = fd;
63
64	return dev;
65}
66
67/*
68 * Destroy exynos drm device object
69 *
70 * @dev: exynos drm device object.
71 */
72void exynos_device_destroy(struct exynos_device *dev)
73{
74	free(dev);
75}
76
77/*
78 * Create a exynos buffer object to exynos drm device.
79 *
80 * @dev: exynos drm device object.
81 * @size: user-desired size.
82 * flags: user-desired memory type.
83 *	user can set one or more types among several types to memory
84 *	allocation and cache attribute types. and as default,
85 *	EXYNOS_BO_NONCONTIG and EXYNOS-BO_NONCACHABLE types would
86 *	be used.
87 *
88 * if true, return a exynos buffer object else NULL.
89 */
90struct exynos_bo * exynos_bo_create(struct exynos_device *dev,
91						size_t size, uint32_t flags)
92{
93	struct exynos_bo *bo;
94	struct drm_exynos_gem_create req = {
95		.size = size,
96		.flags = flags,
97	};
98
99	if (size == 0) {
100		fprintf(stderr, "invalid size.\n");
101		goto fail;
102	}
103
104	bo = calloc(sizeof(*bo), 1);
105	if (!bo) {
106		fprintf(stderr, "failed to create bo[%s].\n",
107				strerror(errno));
108		goto err_free_bo;
109	}
110
111	bo->dev = dev;
112
113	if (drmIoctl(dev->fd, DRM_IOCTL_EXYNOS_GEM_CREATE, &req)){
114		fprintf(stderr, "failed to create gem object[%s].\n",
115				strerror(errno));
116		goto err_free_bo;
117	}
118
119	bo->handle = req.handle;
120	bo->size = size;
121	bo->flags = flags;
122
123	return bo;
124
125err_free_bo:
126	free(bo);
127fail:
128	return NULL;
129}
130
131/*
132 * Get information to gem region allocated.
133 *
134 * @dev: exynos drm device object.
135 * @handle: gem handle to request gem info.
136 * @size: size to gem object and returned by kernel side.
137 * @flags: gem flags to gem object and returned by kernel side.
138 *
139 * with this function call, you can get flags and size to gem handle
140 * through bo object.
141 *
142 * if true, return 0 else negative.
143 */
144int exynos_bo_get_info(struct exynos_device *dev, uint32_t handle,
145			size_t *size, uint32_t *flags)
146{
147	int ret;
148	struct drm_exynos_gem_info req = {
149		.handle = handle,
150	};
151
152	ret = drmIoctl(dev->fd, DRM_IOCTL_EXYNOS_GEM_GET, &req);
153	if (ret < 0) {
154		fprintf(stderr, "failed to get gem object information[%s].\n",
155				strerror(errno));
156		return ret;
157	}
158
159	*size = req.size;
160	*flags = req.flags;
161
162	return 0;
163}
164
165/*
166 * Destroy a exynos buffer object.
167 *
168 * @bo: a exynos buffer object to be destroyed.
169 */
170void exynos_bo_destroy(struct exynos_bo *bo)
171{
172	if (!bo)
173		return;
174
175	if (bo->vaddr)
176		munmap(bo->vaddr, bo->size);
177
178	if (bo->handle) {
179		struct drm_gem_close req = {
180			.handle = bo->handle,
181		};
182
183		drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_CLOSE, &req);
184	}
185
186	free(bo);
187}
188
189
190/*
191 * Get a exynos buffer object from a gem global object name.
192 *
193 * @dev: a exynos device object.
194 * @name: a gem global object name exported by another process.
195 *
196 * this interface is used to get a exynos buffer object from a gem
197 * global object name sent by another process for buffer sharing.
198 *
199 * if true, return a exynos buffer object else NULL.
200 *
201 */
202struct exynos_bo * exynos_bo_from_name(struct exynos_device *dev, uint32_t name)
203{
204	struct exynos_bo *bo;
205	struct drm_gem_open req = {
206		.name = name,
207	};
208
209	bo = calloc(sizeof(*bo), 1);
210	if (!bo) {
211		fprintf(stderr, "failed to allocate bo[%s].\n",
212				strerror(errno));
213		return NULL;
214	}
215
216	if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) {
217		fprintf(stderr, "failed to open gem object[%s].\n",
218				strerror(errno));
219		goto err_free_bo;
220	}
221
222	bo->dev = dev;
223	bo->name = name;
224	bo->handle = req.handle;
225
226	return bo;
227
228err_free_bo:
229	free(bo);
230	return NULL;
231}
232
233/*
234 * Get a gem global object name from a gem object handle.
235 *
236 * @bo: a exynos buffer object including gem handle.
237 * @name: a gem global object name to be got by kernel driver.
238 *
239 * this interface is used to get a gem global object name from a gem object
240 * handle to a buffer that wants to share it with another process.
241 *
242 * if true, return 0 else negative.
243 */
244int exynos_bo_get_name(struct exynos_bo *bo, uint32_t *name)
245{
246	if (!bo->name) {
247		struct drm_gem_flink req = {
248			.handle = bo->handle,
249		};
250		int ret;
251
252		ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req);
253		if (ret) {
254			fprintf(stderr, "failed to get gem global name[%s].\n",
255					strerror(errno));
256			return ret;
257		}
258
259		bo->name = req.name;
260	}
261
262	*name = bo->name;
263
264	return 0;
265}
266
267uint32_t exynos_bo_handle(struct exynos_bo *bo)
268{
269	return bo->handle;
270}
271
272/*
273 * Mmap a buffer to user space.
274 *
275 * @bo: a exynos buffer object including a gem object handle to be mmapped
276 *	to user space.
277 *
278 * if true, user pointer mmaped else NULL.
279 */
280void *exynos_bo_map(struct exynos_bo *bo)
281{
282	if (!bo->vaddr) {
283		struct exynos_device *dev = bo->dev;
284		struct drm_exynos_gem_mmap req = {
285			.handle = bo->handle,
286			.size	= bo->size,
287		};
288		int ret;
289
290		ret = drmIoctl(dev->fd, DRM_IOCTL_EXYNOS_GEM_MMAP, &req);
291		if (ret) {
292			fprintf(stderr, "failed to mmap[%s].\n",
293				strerror(errno));
294			return NULL;
295		}
296
297		bo->vaddr = req.mapped;
298	}
299
300	return bo->vaddr;
301}
302
303/*
304 * Export gem object to dmabuf as file descriptor.
305 *
306 * @dev: a exynos device object.
307 * @handle: gem handle to be exported into dmabuf as file descriptor.
308 * @fd: file descriptor to dmabuf exported from gem handle and
309 *	returned by kernel side.
310 *
311 * if true, return 0 else negative.
312 */
313int exynos_prime_handle_to_fd(struct exynos_device *dev, uint32_t handle,
314					int *fd)
315{
316	int ret;
317	struct drm_prime_handle req = {
318		.handle	= handle,
319	};
320
321	ret = drmIoctl(dev->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &req);
322	if (ret) {
323		fprintf(stderr, "failed to mmap[%s].\n",
324			strerror(errno));
325		return ret;
326	}
327
328	*fd = req.fd;
329	return 0;
330}
331
332/*
333 * Import file descriptor into gem handle.
334 *
335 * @dev: a exynos device object.
336 * @fd: file descriptor exported into dmabuf.
337 * @handle: gem handle to gem object imported from file descriptor
338 *	and returned by kernel side.
339 *
340 * if true, return 0 else negative.
341 */
342int exynos_prime_fd_to_handle(struct exynos_device *dev, int fd,
343					uint32_t *handle)
344{
345	int ret;
346	struct drm_prime_handle req = {
347		.fd	= fd,
348	};
349
350	ret = drmIoctl(dev->fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &req);
351	if (ret) {
352		fprintf(stderr, "failed to mmap[%s].\n",
353			strerror(errno));
354		return ret;
355	}
356
357	*handle = req.handle;
358	return 0;
359}
360
361
362
363/*
364 * Request Wireless Display connection or disconnection.
365 *
366 * @dev: a exynos device object.
367 * @connect: indicate whether connectoin or disconnection request.
368 * @ext: indicate whether edid data includes extentions data or not.
369 * @edid: a pointer to edid data from Wireless Display device.
370 *
371 * this interface is used to request Virtual Display driver connection or
372 * disconnection. for this, user should get a edid data from the Wireless
373 * Display device and then send that data to kernel driver with connection
374 * request
375 *
376 * if true, return 0 else negative.
377 */
378int exynos_vidi_connection(struct exynos_device *dev, uint32_t connect,
379				uint32_t ext, void *edid)
380{
381	struct drm_exynos_vidi_connection req = {
382		.connection	= connect,
383		.extensions	= ext,
384		.edid		= edid,
385	};
386	int ret;
387
388	ret = drmIoctl(dev->fd, DRM_IOCTL_EXYNOS_VIDI_CONNECTION, &req);
389	if (ret) {
390		fprintf(stderr, "failed to request vidi connection[%s].\n",
391				strerror(errno));
392		return ret;
393	}
394
395	return 0;
396}
397