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