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#include <unistd.h> 36 37#include <sys/mman.h> 38#include <linux/stddef.h> 39 40#include <xf86drm.h> 41 42#include "libdrm_macros.h" 43#include "exynos_drm.h" 44#include "exynos_drmif.h" 45 46#define U642VOID(x) ((void *)(unsigned long)(x)) 47 48/* 49 * Create exynos drm device object. 50 * 51 * @fd: file descriptor to exynos drm driver opened. 52 * 53 * if true, return the device object else NULL. 54 */ 55struct exynos_device * exynos_device_create(int fd) 56{ 57 struct exynos_device *dev; 58 59 dev = calloc(sizeof(*dev), 1); 60 if (!dev) { 61 fprintf(stderr, "failed to create device[%s].\n", 62 strerror(errno)); 63 return NULL; 64 } 65 66 dev->fd = fd; 67 68 return dev; 69} 70 71/* 72 * Destroy exynos drm device object 73 * 74 * @dev: exynos drm device object. 75 */ 76void exynos_device_destroy(struct exynos_device *dev) 77{ 78 free(dev); 79} 80 81/* 82 * Create a exynos buffer object to exynos drm device. 83 * 84 * @dev: exynos drm device object. 85 * @size: user-desired size. 86 * flags: user-desired memory type. 87 * user can set one or more types among several types to memory 88 * allocation and cache attribute types. and as default, 89 * EXYNOS_BO_NONCONTIG and EXYNOS-BO_NONCACHABLE types would 90 * be used. 91 * 92 * if true, return a exynos buffer object else NULL. 93 */ 94struct exynos_bo * exynos_bo_create(struct exynos_device *dev, 95 size_t size, uint32_t flags) 96{ 97 struct exynos_bo *bo; 98 struct drm_exynos_gem_create req = { 99 .size = size, 100 .flags = flags, 101 }; 102 103 if (size == 0) { 104 fprintf(stderr, "invalid size.\n"); 105 goto fail; 106 } 107 108 bo = calloc(sizeof(*bo), 1); 109 if (!bo) { 110 fprintf(stderr, "failed to create bo[%s].\n", 111 strerror(errno)); 112 goto err_free_bo; 113 } 114 115 bo->dev = dev; 116 117 if (drmIoctl(dev->fd, DRM_IOCTL_EXYNOS_GEM_CREATE, &req)){ 118 fprintf(stderr, "failed to create gem object[%s].\n", 119 strerror(errno)); 120 goto err_free_bo; 121 } 122 123 bo->handle = req.handle; 124 bo->size = size; 125 bo->flags = flags; 126 127 return bo; 128 129err_free_bo: 130 free(bo); 131fail: 132 return NULL; 133} 134 135/* 136 * Get information to gem region allocated. 137 * 138 * @dev: exynos drm device object. 139 * @handle: gem handle to request gem info. 140 * @size: size to gem object and returned by kernel side. 141 * @flags: gem flags to gem object and returned by kernel side. 142 * 143 * with this function call, you can get flags and size to gem handle 144 * through bo object. 145 * 146 * if true, return 0 else negative. 147 */ 148int exynos_bo_get_info(struct exynos_device *dev, uint32_t handle, 149 size_t *size, uint32_t *flags) 150{ 151 int ret; 152 struct drm_exynos_gem_info req = { 153 .handle = handle, 154 }; 155 156 ret = drmIoctl(dev->fd, DRM_IOCTL_EXYNOS_GEM_GET, &req); 157 if (ret < 0) { 158 fprintf(stderr, "failed to get gem object information[%s].\n", 159 strerror(errno)); 160 return ret; 161 } 162 163 *size = req.size; 164 *flags = req.flags; 165 166 return 0; 167} 168 169/* 170 * Destroy a exynos buffer object. 171 * 172 * @bo: a exynos buffer object to be destroyed. 173 */ 174void exynos_bo_destroy(struct exynos_bo *bo) 175{ 176 if (!bo) 177 return; 178 179 if (bo->vaddr) 180 munmap(bo->vaddr, bo->size); 181 182 if (bo->handle) { 183 struct drm_gem_close req = { 184 .handle = bo->handle, 185 }; 186 187 drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_CLOSE, &req); 188 } 189 190 free(bo); 191} 192 193 194/* 195 * Get a exynos buffer object from a gem global object name. 196 * 197 * @dev: a exynos device object. 198 * @name: a gem global object name exported by another process. 199 * 200 * this interface is used to get a exynos buffer object from a gem 201 * global object name sent by another process for buffer sharing. 202 * 203 * if true, return a exynos buffer object else NULL. 204 * 205 */ 206struct exynos_bo * 207exynos_bo_from_name(struct exynos_device *dev, uint32_t name) 208{ 209 struct exynos_bo *bo; 210 struct drm_gem_open req = { 211 .name = name, 212 }; 213 214 bo = calloc(sizeof(*bo), 1); 215 if (!bo) { 216 fprintf(stderr, "failed to allocate bo[%s].\n", 217 strerror(errno)); 218 return NULL; 219 } 220 221 if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) { 222 fprintf(stderr, "failed to open gem object[%s].\n", 223 strerror(errno)); 224 goto err_free_bo; 225 } 226 227 bo->dev = dev; 228 bo->name = name; 229 bo->handle = req.handle; 230 231 return bo; 232 233err_free_bo: 234 free(bo); 235 return NULL; 236} 237 238/* 239 * Get a gem global object name from a gem object handle. 240 * 241 * @bo: a exynos buffer object including gem handle. 242 * @name: a gem global object name to be got by kernel driver. 243 * 244 * this interface is used to get a gem global object name from a gem object 245 * handle to a buffer that wants to share it with another process. 246 * 247 * if true, return 0 else negative. 248 */ 249int exynos_bo_get_name(struct exynos_bo *bo, uint32_t *name) 250{ 251 if (!bo->name) { 252 struct drm_gem_flink req = { 253 .handle = bo->handle, 254 }; 255 int ret; 256 257 ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req); 258 if (ret) { 259 fprintf(stderr, "failed to get gem global name[%s].\n", 260 strerror(errno)); 261 return ret; 262 } 263 264 bo->name = req.name; 265 } 266 267 *name = bo->name; 268 269 return 0; 270} 271 272uint32_t exynos_bo_handle(struct exynos_bo *bo) 273{ 274 return bo->handle; 275} 276 277/* 278 * Mmap a buffer to user space. 279 * 280 * @bo: a exynos buffer object including a gem object handle to be mmapped 281 * to user space. 282 * 283 * if true, user pointer mmaped else NULL. 284 */ 285void *exynos_bo_map(struct exynos_bo *bo) 286{ 287 if (!bo->vaddr) { 288 struct exynos_device *dev = bo->dev; 289 struct drm_mode_map_dumb arg; 290 void *map = NULL; 291 int ret; 292 293 memset(&arg, 0, sizeof(arg)); 294 arg.handle = bo->handle; 295 296 ret = drmIoctl(dev->fd, DRM_IOCTL_MODE_MAP_DUMB, &arg); 297 if (ret) { 298 fprintf(stderr, "failed to map dumb buffer[%s].\n", 299 strerror(errno)); 300 return NULL; 301 } 302 303 map = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, 304 dev->fd, arg.offset); 305 306 if (map != MAP_FAILED) 307 bo->vaddr = map; 308 } 309 310 return bo->vaddr; 311} 312 313/* 314 * Export gem object to dmabuf as file descriptor. 315 * 316 * @dev: exynos device object 317 * @handle: gem handle to export as file descriptor of dmabuf 318 * @fd: file descriptor returned from kernel 319 * 320 * @return: 0 on success, -1 on error, and errno will be set 321 */ 322int 323exynos_prime_handle_to_fd(struct exynos_device *dev, uint32_t handle, int *fd) 324{ 325 return drmPrimeHandleToFD(dev->fd, handle, 0, fd); 326} 327 328/* 329 * Import file descriptor into gem handle. 330 * 331 * @dev: exynos device object 332 * @fd: file descriptor of dmabuf to import 333 * @handle: gem handle returned from kernel 334 * 335 * @return: 0 on success, -1 on error, and errno will be set 336 */ 337int 338exynos_prime_fd_to_handle(struct exynos_device *dev, int fd, uint32_t *handle) 339{ 340 return drmPrimeFDToHandle(dev->fd, fd, handle); 341} 342 343 344 345/* 346 * Request Wireless Display connection or disconnection. 347 * 348 * @dev: a exynos device object. 349 * @connect: indicate whether connectoin or disconnection request. 350 * @ext: indicate whether edid data includes extentions data or not. 351 * @edid: a pointer to edid data from Wireless Display device. 352 * 353 * this interface is used to request Virtual Display driver connection or 354 * disconnection. for this, user should get a edid data from the Wireless 355 * Display device and then send that data to kernel driver with connection 356 * request 357 * 358 * if true, return 0 else negative. 359 */ 360int 361exynos_vidi_connection(struct exynos_device *dev, uint32_t connect, 362 uint32_t ext, void *edid) 363{ 364 struct drm_exynos_vidi_connection req = { 365 .connection = connect, 366 .extensions = ext, 367 .edid = (uint64_t)(uintptr_t)edid, 368 }; 369 int ret; 370 371 ret = drmIoctl(dev->fd, DRM_IOCTL_EXYNOS_VIDI_CONNECTION, &req); 372 if (ret) { 373 fprintf(stderr, "failed to request vidi connection[%s].\n", 374 strerror(errno)); 375 return ret; 376 } 377 378 return 0; 379} 380 381static void 382exynos_handle_vendor(int fd, struct drm_event *e, void *ctx) 383{ 384 struct drm_exynos_g2d_event *g2d; 385 struct exynos_event_context *ectx = ctx; 386 387 switch (e->type) { 388 case DRM_EXYNOS_G2D_EVENT: 389 if (ectx->version < 1 || ectx->g2d_event_handler == NULL) 390 break; 391 g2d = (struct drm_exynos_g2d_event *)e; 392 ectx->g2d_event_handler(fd, g2d->cmdlist_no, g2d->tv_sec, 393 g2d->tv_usec, U642VOID(g2d->user_data)); 394 break; 395 396 default: 397 break; 398 } 399} 400 401int 402exynos_handle_event(struct exynos_device *dev, struct exynos_event_context *ctx) 403{ 404 char buffer[1024]; 405 int len, i; 406 struct drm_event *e; 407 struct drm_event_vblank *vblank; 408 drmEventContextPtr evctx = &ctx->base; 409 410 /* The DRM read semantics guarantees that we always get only 411 * complete events. */ 412 len = read(dev->fd, buffer, sizeof buffer); 413 if (len == 0) 414 return 0; 415 if (len < (int)sizeof *e) 416 return -1; 417 418 i = 0; 419 while (i < len) { 420 e = (struct drm_event *) &buffer[i]; 421 switch (e->type) { 422 case DRM_EVENT_VBLANK: 423 if (evctx->version < 1 || 424 evctx->vblank_handler == NULL) 425 break; 426 vblank = (struct drm_event_vblank *) e; 427 evctx->vblank_handler(dev->fd, 428 vblank->sequence, 429 vblank->tv_sec, 430 vblank->tv_usec, 431 U642VOID (vblank->user_data)); 432 break; 433 case DRM_EVENT_FLIP_COMPLETE: 434 if (evctx->version < 2 || 435 evctx->page_flip_handler == NULL) 436 break; 437 vblank = (struct drm_event_vblank *) e; 438 evctx->page_flip_handler(dev->fd, 439 vblank->sequence, 440 vblank->tv_sec, 441 vblank->tv_usec, 442 U642VOID (vblank->user_data)); 443 break; 444 default: 445 exynos_handle_vendor(dev->fd, e, evctx); 446 break; 447 } 448 i += e->length; 449 } 450 451 return 0; 452} 453