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