Home | History | Annotate | Download | only in exynos
      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 (at) samsung.com>
     25  */
     26 
     27 #include <stdlib.h>
     28 #include <stdio.h>
     29 #include <string.h>
     30 #include <errno.h>
     31 #include <unistd.h>
     32 
     33 #include <sys/mman.h>
     34 #include <linux/stddef.h>
     35 
     36 #include <xf86drm.h>
     37 
     38 #include "libdrm_macros.h"
     39 #include "exynos_drm.h"
     40 #include "exynos_drmif.h"
     41 
     42 #define U642VOID(x) ((void *)(unsigned long)(x))
     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  */
     51 struct 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  */
     72 void 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  */
     90 struct 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 
    125 err_free_bo:
    126 	free(bo);
    127 fail:
    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  */
    144 int 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  */
    170 void 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  */
    202 struct exynos_bo *
    203 exynos_bo_from_name(struct exynos_device *dev, uint32_t name)
    204 {
    205 	struct exynos_bo *bo;
    206 	struct drm_gem_open req = {
    207 		.name = name,
    208 	};
    209 
    210 	bo = calloc(sizeof(*bo), 1);
    211 	if (!bo) {
    212 		fprintf(stderr, "failed to allocate bo[%s].\n",
    213 				strerror(errno));
    214 		return NULL;
    215 	}
    216 
    217 	if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) {
    218 		fprintf(stderr, "failed to open gem object[%s].\n",
    219 				strerror(errno));
    220 		goto err_free_bo;
    221 	}
    222 
    223 	bo->dev = dev;
    224 	bo->name = name;
    225 	bo->handle = req.handle;
    226 
    227 	return bo;
    228 
    229 err_free_bo:
    230 	free(bo);
    231 	return NULL;
    232 }
    233 
    234 /*
    235  * Get a gem global object name from a gem object handle.
    236  *
    237  * @bo: a exynos buffer object including gem handle.
    238  * @name: a gem global object name to be got by kernel driver.
    239  *
    240  * this interface is used to get a gem global object name from a gem object
    241  * handle to a buffer that wants to share it with another process.
    242  *
    243  * if true, return 0 else negative.
    244  */
    245 int exynos_bo_get_name(struct exynos_bo *bo, uint32_t *name)
    246 {
    247 	if (!bo->name) {
    248 		struct drm_gem_flink req = {
    249 			.handle = bo->handle,
    250 		};
    251 		int ret;
    252 
    253 		ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req);
    254 		if (ret) {
    255 			fprintf(stderr, "failed to get gem global name[%s].\n",
    256 					strerror(errno));
    257 			return ret;
    258 		}
    259 
    260 		bo->name = req.name;
    261 	}
    262 
    263 	*name = bo->name;
    264 
    265 	return 0;
    266 }
    267 
    268 uint32_t exynos_bo_handle(struct exynos_bo *bo)
    269 {
    270 	return bo->handle;
    271 }
    272 
    273 /*
    274  * Mmap a buffer to user space.
    275  *
    276  * @bo: a exynos buffer object including a gem object handle to be mmapped
    277  *	to user space.
    278  *
    279  * if true, user pointer mmaped else NULL.
    280  */
    281 void *exynos_bo_map(struct exynos_bo *bo)
    282 {
    283 	if (!bo->vaddr) {
    284 		struct exynos_device *dev = bo->dev;
    285 		struct drm_mode_map_dumb arg;
    286 		void *map = NULL;
    287 		int ret;
    288 
    289 		memset(&arg, 0, sizeof(arg));
    290 		arg.handle = bo->handle;
    291 
    292 		ret = drmIoctl(dev->fd, DRM_IOCTL_MODE_MAP_DUMB, &arg);
    293 		if (ret) {
    294 			fprintf(stderr, "failed to map dumb buffer[%s].\n",
    295 				strerror(errno));
    296 			return NULL;
    297 		}
    298 
    299 		map = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
    300 				dev->fd, arg.offset);
    301 
    302 		if (map != MAP_FAILED)
    303 			bo->vaddr = map;
    304 	}
    305 
    306 	return bo->vaddr;
    307 }
    308 
    309 /*
    310  * Export gem object to dmabuf as file descriptor.
    311  *
    312  * @dev: exynos device object
    313  * @handle: gem handle to export as file descriptor of dmabuf
    314  * @fd: file descriptor returned from kernel
    315  *
    316  * @return: 0 on success, -1 on error, and errno will be set
    317  */
    318 int
    319 exynos_prime_handle_to_fd(struct exynos_device *dev, uint32_t handle, int *fd)
    320 {
    321 	return drmPrimeHandleToFD(dev->fd, handle, 0, fd);
    322 }
    323 
    324 /*
    325  * Import file descriptor into gem handle.
    326  *
    327  * @dev: exynos device object
    328  * @fd: file descriptor of dmabuf to import
    329  * @handle: gem handle returned from kernel
    330  *
    331  * @return: 0 on success, -1 on error, and errno will be set
    332  */
    333 int
    334 exynos_prime_fd_to_handle(struct exynos_device *dev, int fd, uint32_t *handle)
    335 {
    336 	return drmPrimeFDToHandle(dev->fd, fd, handle);
    337 }
    338 
    339 
    340 
    341 /*
    342  * Request Wireless Display connection or disconnection.
    343  *
    344  * @dev: a exynos device object.
    345  * @connect: indicate whether connectoin or disconnection request.
    346  * @ext: indicate whether edid data includes extensions data or not.
    347  * @edid: a pointer to edid data from Wireless Display device.
    348  *
    349  * this interface is used to request Virtual Display driver connection or
    350  * disconnection. for this, user should get a edid data from the Wireless
    351  * Display device and then send that data to kernel driver with connection
    352  * request
    353  *
    354  * if true, return 0 else negative.
    355  */
    356 int
    357 exynos_vidi_connection(struct exynos_device *dev, uint32_t connect,
    358 		       uint32_t ext, void *edid)
    359 {
    360 	struct drm_exynos_vidi_connection req = {
    361 		.connection	= connect,
    362 		.extensions	= ext,
    363 		.edid		= (uint64_t)(uintptr_t)edid,
    364 	};
    365 	int ret;
    366 
    367 	ret = drmIoctl(dev->fd, DRM_IOCTL_EXYNOS_VIDI_CONNECTION, &req);
    368 	if (ret) {
    369 		fprintf(stderr, "failed to request vidi connection[%s].\n",
    370 				strerror(errno));
    371 		return ret;
    372 	}
    373 
    374 	return 0;
    375 }
    376 
    377 static void
    378 exynos_handle_vendor(int fd, struct drm_event *e, void *ctx)
    379 {
    380 	struct drm_exynos_g2d_event *g2d;
    381 	struct exynos_event_context *ectx = ctx;
    382 
    383 	switch (e->type) {
    384 		case DRM_EXYNOS_G2D_EVENT:
    385 			if (ectx->version < 1 || ectx->g2d_event_handler == NULL)
    386 				break;
    387 			g2d = (struct drm_exynos_g2d_event *)e;
    388 			ectx->g2d_event_handler(fd, g2d->cmdlist_no, g2d->tv_sec,
    389 						g2d->tv_usec, U642VOID(g2d->user_data));
    390 			break;
    391 
    392 		default:
    393 			break;
    394 	}
    395 }
    396 
    397 int
    398 exynos_handle_event(struct exynos_device *dev, struct exynos_event_context *ctx)
    399 {
    400 	char buffer[1024];
    401 	int len, i;
    402 	struct drm_event *e;
    403 	struct drm_event_vblank *vblank;
    404 	drmEventContextPtr evctx = &ctx->base;
    405 
    406 	/* The DRM read semantics guarantees that we always get only
    407 	 * complete events. */
    408 	len = read(dev->fd, buffer, sizeof buffer);
    409 	if (len == 0)
    410 		return 0;
    411 	if (len < (int)sizeof *e)
    412 		return -1;
    413 
    414 	i = 0;
    415 	while (i < len) {
    416 		e = (struct drm_event *)(buffer + i);
    417 		switch (e->type) {
    418 		case DRM_EVENT_VBLANK:
    419 			if (evctx->version < 1 ||
    420 			    evctx->vblank_handler == NULL)
    421 				break;
    422 			vblank = (struct drm_event_vblank *) e;
    423 			evctx->vblank_handler(dev->fd,
    424 					      vblank->sequence,
    425 					      vblank->tv_sec,
    426 					      vblank->tv_usec,
    427 					      U642VOID (vblank->user_data));
    428 			break;
    429 		case DRM_EVENT_FLIP_COMPLETE:
    430 			if (evctx->version < 2 ||
    431 			    evctx->page_flip_handler == NULL)
    432 				break;
    433 			vblank = (struct drm_event_vblank *) e;
    434 			evctx->page_flip_handler(dev->fd,
    435 						 vblank->sequence,
    436 						 vblank->tv_sec,
    437 						 vblank->tv_usec,
    438 						 U642VOID (vblank->user_data));
    439 			break;
    440 		default:
    441 			exynos_handle_vendor(dev->fd, e, evctx);
    442 			break;
    443 		}
    444 		i += e->length;
    445 	}
    446 
    447 	return 0;
    448 }
    449