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