1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <dirent.h> 18 #include <errno.h> 19 #include <fcntl.h> 20 #include <malloc.h> 21 #include <stdint.h> 22 #include <stdio.h> 23 #include <string.h> 24 #include <unistd.h> 25 26 #include <linux/limits.h> 27 28 #include <sys/ioctl.h> 29 30 #include <adf/adf.h> 31 32 #define ADF_BASE_PATH "/dev/" 33 34 static ssize_t adf_find_nodes(const char *pattern, adf_id_t **ids) 35 { 36 DIR *dir; 37 struct dirent *dirent; 38 size_t n = 0; 39 ssize_t ret; 40 adf_id_t *ids_ret = NULL; 41 42 dir = opendir(ADF_BASE_PATH); 43 if (!dir) 44 return -errno; 45 46 errno = 0; 47 while ((dirent = readdir(dir))) { 48 adf_id_t id; 49 int matched = sscanf(dirent->d_name, pattern, &id); 50 51 if (matched < 0) { 52 ret = -errno; 53 goto done; 54 } else if (matched != 1) { 55 continue; 56 } 57 58 adf_id_t *new_ids = realloc(ids_ret, (n + 1) * sizeof(ids_ret[0])); 59 if (!new_ids) { 60 ret = -ENOMEM; 61 goto done; 62 } 63 64 ids_ret = new_ids; 65 ids_ret[n] = id; 66 n++; 67 } 68 if (errno) 69 ret = -errno; 70 else 71 ret = n; 72 73 done: 74 closedir(dir); 75 if (ret < 0) 76 free(ids_ret); 77 else 78 *ids = ids_ret; 79 return ret; 80 } 81 82 ssize_t adf_devices(adf_id_t **ids) 83 { 84 return adf_find_nodes("adf%u", ids); 85 } 86 87 int adf_device_open(adf_id_t id, int flags, struct adf_device *dev) 88 { 89 char filename[64]; 90 91 dev->id = id; 92 93 snprintf(filename, sizeof(filename), ADF_BASE_PATH "adf%u", id); 94 dev->fd = open(filename, flags); 95 if (dev->fd < 0) 96 return -errno; 97 98 return 0; 99 } 100 101 void adf_device_close(struct adf_device *dev) 102 { 103 if (dev->fd >= 0) 104 close(dev->fd); 105 } 106 107 int adf_get_device_data(struct adf_device *dev, struct adf_device_data *data) 108 { 109 int err; 110 int ret = 0; 111 112 memset(data, 0, sizeof(*data)); 113 114 err = ioctl(dev->fd, ADF_GET_DEVICE_DATA, data); 115 if (err < 0) 116 return -ENOMEM; 117 118 if (data->n_attachments) { 119 data->attachments = malloc(sizeof(data->attachments[0]) * 120 data->n_attachments); 121 if (!data->attachments) 122 return -ENOMEM; 123 } 124 125 if (data->n_allowed_attachments) { 126 data->allowed_attachments = 127 malloc(sizeof(data->allowed_attachments[0]) * 128 data->n_allowed_attachments); 129 if (!data->allowed_attachments) { 130 ret = -ENOMEM; 131 goto done; 132 } 133 } 134 135 if (data->custom_data_size) { 136 data->custom_data = malloc(data->custom_data_size); 137 if (!data->custom_data) { 138 ret = -ENOMEM; 139 goto done; 140 } 141 } 142 143 err = ioctl(dev->fd, ADF_GET_DEVICE_DATA, data); 144 if (err < 0) 145 ret = -errno; 146 147 done: 148 if (ret < 0) 149 adf_free_device_data(data); 150 return ret; 151 } 152 153 void adf_free_device_data(struct adf_device_data *data) 154 { 155 free(data->attachments); 156 free(data->allowed_attachments); 157 free(data->custom_data); 158 } 159 160 int adf_device_post(struct adf_device *dev, 161 adf_id_t *interfaces, size_t n_interfaces, 162 struct adf_buffer_config *bufs, size_t n_bufs, 163 void *custom_data, size_t custom_data_size) 164 { 165 int err; 166 struct adf_post_config data; 167 168 memset(&data, 0, sizeof(data)); 169 data.interfaces = interfaces; 170 data.n_interfaces = n_interfaces; 171 data.bufs = bufs; 172 data.n_bufs = n_bufs; 173 data.custom_data = custom_data; 174 data.custom_data_size = custom_data_size; 175 176 err = ioctl(dev->fd, ADF_POST_CONFIG, &data); 177 if (err < 0) 178 return -errno; 179 180 return (int)data.complete_fence; 181 } 182 183 static int adf_device_attachment(struct adf_device *dev, 184 adf_id_t overlay_engine, adf_id_t interface, bool attach) 185 { 186 int err; 187 struct adf_attachment_config data; 188 189 memset(&data, 0, sizeof(data)); 190 data.overlay_engine = overlay_engine; 191 data.interface = interface; 192 193 err = ioctl(dev->fd, attach ? ADF_ATTACH : ADF_DETACH, &data); 194 if (err < 0) 195 return -errno; 196 197 return 0; 198 } 199 200 int adf_device_attach(struct adf_device *dev, adf_id_t overlay_engine, 201 adf_id_t interface) 202 { 203 return adf_device_attachment(dev, overlay_engine, interface, true); 204 } 205 206 int adf_device_detach(struct adf_device *dev, adf_id_t overlay_engine, 207 adf_id_t interface) 208 { 209 return adf_device_attachment(dev, overlay_engine, interface, false); 210 } 211 212 ssize_t adf_interfaces(struct adf_device *dev, adf_id_t **interfaces) 213 { 214 char pattern[64]; 215 216 snprintf(pattern, sizeof(pattern), "adf-interface%u.%%u", dev->id); 217 return adf_find_nodes(pattern, interfaces); 218 } 219 220 ssize_t adf_interfaces_for_overlay_engine(struct adf_device *dev, 221 adf_id_t overlay_engine, adf_id_t **interfaces) 222 { 223 struct adf_device_data data; 224 ssize_t n = 0; 225 ssize_t ret; 226 adf_id_t *ids_ret = NULL; 227 228 ret = adf_get_device_data(dev, &data); 229 if (ret < 0) 230 return ret; 231 232 size_t i; 233 for (i = 0; i < data.n_allowed_attachments; i++) { 234 if (data.allowed_attachments[i].overlay_engine != overlay_engine) 235 continue; 236 237 adf_id_t *new_ids = realloc(ids_ret, (n + 1) * sizeof(ids_ret[0])); 238 if (!new_ids) { 239 ret = -ENOMEM; 240 goto done; 241 } 242 243 ids_ret = new_ids; 244 ids_ret[n] = data.allowed_attachments[i].interface; 245 n++; 246 } 247 248 ret = n; 249 250 done: 251 adf_free_device_data(&data); 252 if (ret < 0) 253 free(ids_ret); 254 else 255 *interfaces = ids_ret; 256 return ret; 257 } 258 259 static ssize_t adf_interfaces_filter(struct adf_device *dev, 260 adf_id_t *in, size_t n_in, adf_id_t **out, 261 bool (*filter)(struct adf_interface_data *data, __u32 match), 262 __u32 match) 263 { 264 size_t n = 0; 265 ssize_t ret; 266 adf_id_t *ids_ret = NULL; 267 268 size_t i; 269 for (i = 0; i < n_in; i++) { 270 int fd = adf_interface_open(dev, in[i], O_RDONLY); 271 if (fd < 0) { 272 ret = fd; 273 goto done; 274 } 275 276 struct adf_interface_data data; 277 ret = adf_get_interface_data(fd, &data); 278 close(fd); 279 if (ret < 0) 280 goto done; 281 282 if (!filter(&data, match)) 283 continue; 284 285 adf_id_t *new_ids = realloc(ids_ret, (n + 1) * sizeof(ids_ret[0])); 286 if (!new_ids) { 287 ret = -ENOMEM; 288 goto done; 289 } 290 291 ids_ret = new_ids; 292 ids_ret[n] = in[i]; 293 n++; 294 } 295 296 ret = n; 297 298 done: 299 if (ret < 0) 300 free(ids_ret); 301 else 302 *out = ids_ret; 303 return ret; 304 } 305 306 static bool adf_interface_type_filter(struct adf_interface_data *data, 307 __u32 type) 308 { 309 return data->type == (enum adf_interface_type)type; 310 } 311 312 ssize_t adf_interfaces_filter_by_type(struct adf_device *dev, 313 enum adf_interface_type type, 314 adf_id_t *in, size_t n_in, adf_id_t **out) 315 { 316 return adf_interfaces_filter(dev, in, n_in, out, adf_interface_type_filter, 317 type); 318 } 319 320 static bool adf_interface_flags_filter(struct adf_interface_data *data, 321 __u32 flag) 322 { 323 return !!(data->flags & flag); 324 } 325 326 ssize_t adf_interfaces_filter_by_flag(struct adf_device *dev, __u32 flag, 327 adf_id_t *in, size_t n_in, adf_id_t **out) 328 { 329 return adf_interfaces_filter(dev, in, n_in, out, adf_interface_flags_filter, 330 flag); 331 } 332 333 int adf_interface_open(struct adf_device *dev, adf_id_t id, int flags) 334 { 335 char filename[64]; 336 337 snprintf(filename, sizeof(filename), ADF_BASE_PATH "adf-interface%u.%u", 338 dev->id, id); 339 340 int fd = open(filename, flags); 341 if (fd < 0) 342 return -errno; 343 return fd; 344 } 345 346 int adf_get_interface_data(int fd, struct adf_interface_data *data) 347 { 348 int err; 349 int ret = 0; 350 351 memset(data, 0, sizeof(*data)); 352 353 err = ioctl(fd, ADF_GET_INTERFACE_DATA, data); 354 if (err < 0) 355 return -errno; 356 357 if (data->n_available_modes) { 358 data->available_modes = malloc(sizeof(data->available_modes[0]) * 359 data->n_available_modes); 360 if (!data->available_modes) 361 return -ENOMEM; 362 } 363 364 if (data->custom_data_size) { 365 data->custom_data = malloc(data->custom_data_size); 366 if (!data->custom_data) { 367 ret = -ENOMEM; 368 goto done; 369 } 370 } 371 372 err = ioctl(fd, ADF_GET_INTERFACE_DATA, data); 373 if (err < 0) 374 ret = -errno; 375 376 done: 377 if (ret < 0) 378 adf_free_interface_data(data); 379 return ret; 380 } 381 382 void adf_free_interface_data(struct adf_interface_data *data) 383 { 384 free(data->available_modes); 385 free(data->custom_data); 386 } 387 388 int adf_interface_blank(int fd, __u8 mode) 389 { 390 int err = ioctl(fd, ADF_BLANK, mode); 391 if (err < 0) 392 return -errno; 393 return 0; 394 } 395 396 int adf_interface_set_mode(int fd, struct drm_mode_modeinfo *mode) 397 { 398 int err = ioctl(fd, ADF_SET_MODE, mode); 399 if (err < 0) 400 return -errno; 401 return 0; 402 } 403 404 int adf_interface_simple_buffer_alloc(int fd, __u32 w, __u32 h, 405 __u32 format, __u32 *offset, __u32 *pitch) 406 { 407 int err; 408 struct adf_simple_buffer_alloc data; 409 410 memset(&data, 0, sizeof(data)); 411 data.w = w; 412 data.h = h; 413 data.format = format; 414 415 err = ioctl(fd, ADF_SIMPLE_BUFFER_ALLOC, &data); 416 if (err < 0) 417 return -errno; 418 419 *offset = data.offset; 420 *pitch = data.pitch; 421 return (int)data.fd; 422 } 423 424 int adf_interface_simple_post(int fd, __u32 overlay_engine, 425 __u32 w, __u32 h, __u32 format, int buf_fd, __u32 offset, 426 __u32 pitch, int acquire_fence) 427 { 428 int ret; 429 struct adf_simple_post_config data; 430 431 memset(&data, 0, sizeof(data)); 432 data.buf.overlay_engine = overlay_engine; 433 data.buf.w = w; 434 data.buf.h = h; 435 data.buf.format = format; 436 data.buf.fd[0] = buf_fd; 437 data.buf.offset[0] = offset; 438 data.buf.pitch[0] = pitch; 439 data.buf.n_planes = 1; 440 data.buf.acquire_fence = acquire_fence; 441 442 ret = ioctl(fd, ADF_SIMPLE_POST_CONFIG, &data); 443 if (ret < 0) 444 return -errno; 445 446 return (int)data.complete_fence; 447 } 448 449 ssize_t adf_overlay_engines(struct adf_device *dev, adf_id_t **overlay_engines) 450 { 451 char pattern[64]; 452 453 snprintf(pattern, sizeof(pattern), "adf-overlay-engine%u.%%u", dev->id); 454 return adf_find_nodes(pattern, overlay_engines); 455 } 456 457 ssize_t adf_overlay_engines_for_interface(struct adf_device *dev, 458 adf_id_t interface, adf_id_t **overlay_engines) 459 { 460 struct adf_device_data data; 461 ssize_t n = 0; 462 ssize_t ret; 463 adf_id_t *ids_ret = NULL; 464 465 ret = adf_get_device_data(dev, &data); 466 if (ret < 0) 467 return ret; 468 469 size_t i; 470 for (i = 0; i < data.n_allowed_attachments; i++) { 471 if (data.allowed_attachments[i].interface != interface) 472 continue; 473 474 adf_id_t *new_ids = realloc(ids_ret, (n + 1) * sizeof(ids_ret[0])); 475 if (!new_ids) { 476 ret = -ENOMEM; 477 goto done; 478 } 479 480 ids_ret = new_ids; 481 ids_ret[n] = data.allowed_attachments[i].overlay_engine; 482 n++; 483 } 484 485 ret = n; 486 487 done: 488 adf_free_device_data(&data); 489 if (ret < 0) 490 free(ids_ret); 491 else 492 *overlay_engines = ids_ret; 493 return ret; 494 } 495 496 static ssize_t adf_overlay_engines_filter(struct adf_device *dev, 497 adf_id_t *in, size_t n_in, adf_id_t **out, 498 bool (*filter)(struct adf_overlay_engine_data *data, void *cookie), 499 void *cookie) 500 { 501 size_t n = 0; 502 ssize_t ret; 503 adf_id_t *ids_ret = NULL; 504 505 size_t i; 506 for (i = 0; i < n_in; i++) { 507 int fd = adf_overlay_engine_open(dev, in[i], O_RDONLY); 508 if (fd < 0) { 509 ret = fd; 510 goto done; 511 } 512 513 struct adf_overlay_engine_data data; 514 ret = adf_get_overlay_engine_data(fd, &data); 515 close(fd); 516 if (ret < 0) 517 goto done; 518 519 if (!filter(&data, cookie)) 520 continue; 521 522 adf_id_t *new_ids = realloc(ids_ret, (n + 1) * sizeof(ids_ret[0])); 523 if (!new_ids) { 524 ret = -ENOMEM; 525 goto done; 526 } 527 528 ids_ret = new_ids; 529 ids_ret[n] = in[i]; 530 n++; 531 } 532 533 ret = n; 534 535 done: 536 if (ret < 0) 537 free(ids_ret); 538 else 539 *out = ids_ret; 540 return ret; 541 } 542 543 struct format_filter_cookie { 544 const __u32 *formats; 545 size_t n_formats; 546 }; 547 548 static bool adf_overlay_engine_format_filter( 549 struct adf_overlay_engine_data *data, void *cookie) 550 { 551 struct format_filter_cookie *c = cookie; 552 size_t i; 553 for (i = 0; i < data->n_supported_formats; i++) { 554 size_t j; 555 for (j = 0; j < c->n_formats; j++) 556 if (data->supported_formats[i] == c->formats[j]) 557 return true; 558 } 559 return false; 560 } 561 562 ssize_t adf_overlay_engines_filter_by_format(struct adf_device *dev, 563 const __u32 *formats, size_t n_formats, adf_id_t *in, size_t n_in, 564 adf_id_t **out) 565 { 566 struct format_filter_cookie cookie = { formats, n_formats }; 567 return adf_overlay_engines_filter(dev, in, n_in, out, 568 adf_overlay_engine_format_filter, &cookie); 569 } 570 571 int adf_overlay_engine_open(struct adf_device *dev, adf_id_t id, int flags) 572 { 573 char filename[64]; 574 575 snprintf(filename, sizeof(filename), 576 ADF_BASE_PATH "adf-overlay-engine%u.%u", dev->id, id); 577 578 int fd = open(filename, flags); 579 if (fd < 0) 580 return -errno; 581 return fd; 582 } 583 584 int adf_get_overlay_engine_data(int fd, struct adf_overlay_engine_data *data) 585 { 586 int err; 587 int ret = 0; 588 589 memset(data, 0, sizeof(*data)); 590 591 err = ioctl(fd, ADF_GET_OVERLAY_ENGINE_DATA, data); 592 if (err < 0) 593 return -errno; 594 595 if (data->n_supported_formats) { 596 data->supported_formats = malloc(sizeof(data->supported_formats[0]) * 597 data->n_supported_formats); 598 if (!data->supported_formats) 599 return -ENOMEM; 600 } 601 602 if (data->custom_data_size) { 603 data->custom_data = malloc(data->custom_data_size); 604 if (!data->custom_data) { 605 ret = -ENOMEM; 606 goto done; 607 } 608 } 609 610 err = ioctl(fd, ADF_GET_OVERLAY_ENGINE_DATA, data); 611 if (err < 0) 612 ret = -errno; 613 614 done: 615 if (ret < 0) 616 adf_free_overlay_engine_data(data); 617 return ret; 618 } 619 620 void adf_free_overlay_engine_data(struct adf_overlay_engine_data *data) 621 { 622 free(data->supported_formats); 623 free(data->custom_data); 624 } 625 626 bool adf_overlay_engine_supports_format(int fd, __u32 format) 627 { 628 struct adf_overlay_engine_data data; 629 bool ret = false; 630 size_t i; 631 632 int err = adf_get_overlay_engine_data(fd, &data); 633 if (err < 0) 634 return false; 635 636 for (i = 0; i < data.n_supported_formats; i++) { 637 if (data.supported_formats[i] == format) { 638 ret = true; 639 break; 640 } 641 } 642 643 adf_free_overlay_engine_data(&data); 644 return ret; 645 } 646 647 int adf_set_event(int fd, enum adf_event_type type, bool enabled) 648 { 649 struct adf_set_event data; 650 651 data.type = type; 652 data.enabled = enabled; 653 654 int err = ioctl(fd, ADF_SET_EVENT, &data); 655 if (err < 0) 656 return -errno; 657 return 0; 658 } 659 660 int adf_read_event(int fd, struct adf_event **event) 661 { 662 struct adf_event header; 663 struct { 664 struct adf_event base; 665 uint8_t data[0]; 666 } *event_ret; 667 size_t data_size; 668 int ret = 0; 669 670 int err = read(fd, &header, sizeof(header)); 671 if (err < 0) 672 return -errno; 673 if ((size_t)err < sizeof(header)) 674 return -EIO; 675 if (header.length < sizeof(header)) 676 return -EIO; 677 678 event_ret = malloc(header.length); 679 if (!event_ret) 680 return -ENOMEM; 681 data_size = header.length - sizeof(header); 682 683 memcpy(event_ret, &header, sizeof(header)); 684 ssize_t read_size = read(fd, &event_ret->data, data_size); 685 if (read_size < 0) { 686 ret = -errno; 687 goto done; 688 } 689 if ((size_t)read_size < data_size) { 690 ret = -EIO; 691 goto done; 692 } 693 694 *event = &event_ret->base; 695 696 done: 697 if (ret < 0) 698 free(event_ret); 699 return ret; 700 } 701 702 void adf_format_str(__u32 format, char buf[ADF_FORMAT_STR_SIZE]) 703 { 704 buf[0] = format & 0xFF; 705 buf[1] = (format >> 8) & 0xFF; 706 buf[2] = (format >> 16) & 0xFF; 707 buf[3] = (format >> 24) & 0xFF; 708 buf[4] = '\0'; 709 } 710 711 static bool adf_find_simple_post_overlay_engine(struct adf_device *dev, 712 const __u32 *formats, size_t n_formats, 713 adf_id_t interface, adf_id_t *overlay_engine) 714 { 715 adf_id_t *engs; 716 ssize_t n_engs = adf_overlay_engines_for_interface(dev, interface, &engs); 717 718 if (n_engs <= 0) 719 return false; 720 721 adf_id_t *filtered_engs; 722 ssize_t n_filtered_engs = adf_overlay_engines_filter_by_format(dev, 723 formats, n_formats, engs, n_engs, &filtered_engs); 724 free(engs); 725 726 if (n_filtered_engs <= 0) 727 return false; 728 729 *overlay_engine = filtered_engs[0]; 730 free(filtered_engs); 731 return true; 732 } 733 734 static const __u32 any_rgb_format[] = { 735 DRM_FORMAT_C8, 736 DRM_FORMAT_RGB332, 737 DRM_FORMAT_BGR233, 738 DRM_FORMAT_XRGB1555, 739 DRM_FORMAT_XBGR1555, 740 DRM_FORMAT_RGBX5551, 741 DRM_FORMAT_BGRX5551, 742 DRM_FORMAT_ARGB1555, 743 DRM_FORMAT_ABGR1555, 744 DRM_FORMAT_RGBA5551, 745 DRM_FORMAT_BGRA5551, 746 DRM_FORMAT_RGB565, 747 DRM_FORMAT_BGR565, 748 DRM_FORMAT_RGB888, 749 DRM_FORMAT_BGR888, 750 DRM_FORMAT_XRGB8888, 751 DRM_FORMAT_XBGR8888, 752 DRM_FORMAT_RGBX8888, 753 DRM_FORMAT_BGRX8888, 754 DRM_FORMAT_XRGB2101010, 755 DRM_FORMAT_XBGR2101010, 756 DRM_FORMAT_RGBX1010102, 757 DRM_FORMAT_BGRX1010102, 758 DRM_FORMAT_ARGB2101010, 759 DRM_FORMAT_ABGR2101010, 760 DRM_FORMAT_RGBA1010102, 761 DRM_FORMAT_BGRA1010102, 762 DRM_FORMAT_ARGB8888, 763 DRM_FORMAT_ABGR8888, 764 DRM_FORMAT_RGBA8888, 765 DRM_FORMAT_BGRA8888, 766 }; 767 768 int adf_find_simple_post_configuration(struct adf_device *dev, 769 const __u32 *formats, size_t n_formats, 770 adf_id_t *interface, adf_id_t *overlay_engine) 771 { 772 adf_id_t *intfs = NULL; 773 ssize_t n_intfs = adf_interfaces(dev, &intfs); 774 775 if (n_intfs < 0) 776 return n_intfs; 777 else if (!n_intfs) 778 return -ENODEV; 779 780 adf_id_t *primary_intfs; 781 ssize_t n_primary_intfs = adf_interfaces_filter_by_flag(dev, 782 ADF_INTF_FLAG_PRIMARY, intfs, n_intfs, &primary_intfs); 783 free(intfs); 784 785 if (n_primary_intfs < 0) 786 return n_primary_intfs; 787 else if (!n_primary_intfs) 788 return -ENODEV; 789 790 if (!formats) { 791 formats = any_rgb_format; 792 n_formats = sizeof(any_rgb_format) / sizeof(any_rgb_format[0]); 793 } 794 795 bool found = false; 796 ssize_t i = 0; 797 for (i = 0; i < n_primary_intfs; i++) { 798 found = adf_find_simple_post_overlay_engine(dev, formats, n_formats, 799 primary_intfs[i], overlay_engine); 800 if (found) { 801 *interface = primary_intfs[i]; 802 break; 803 } 804 } 805 free(primary_intfs); 806 807 if (!found) 808 return -ENODEV; 809 810 return 0; 811 } 812