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