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