adf.c revision b85d12a3074c13e37f59b47edb81e1d4ff34eeb0
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, __u32 match), 498 __u32 match) 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, match)) 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 542static bool adf_overlay_engine_format_filter(struct adf_overlay_engine_data *data, 543 __u32 format) 544{ 545 size_t i; 546 for (i = 0; i < data->n_supported_formats; i++) 547 if (data->supported_formats[i] == format) 548 return true; 549 return false; 550} 551 552ssize_t adf_overlay_engines_filter_by_format(struct adf_device *dev, 553 __u32 format, adf_id_t *in, size_t n_in, adf_id_t **out) 554{ 555 return adf_overlay_engines_filter(dev, in, n_in, out, 556 adf_overlay_engine_format_filter, format); 557} 558 559int adf_overlay_engine_open(struct adf_device *dev, adf_id_t id, int flags) 560{ 561 char filename[64]; 562 563 snprintf(filename, sizeof(filename), 564 ADF_BASE_PATH "adf-overlay-engine%u.%u", dev->id, id); 565 566 int fd = open(filename, flags); 567 if (fd < 0) 568 return -errno; 569 return fd; 570} 571 572int adf_get_overlay_engine_data(int fd, struct adf_overlay_engine_data *data) 573{ 574 int err; 575 int ret = 0; 576 577 memset(data, 0, sizeof(*data)); 578 579 err = ioctl(fd, ADF_GET_OVERLAY_ENGINE_DATA, data); 580 if (err < 0) 581 return -errno; 582 583 if (data->n_supported_formats) { 584 data->supported_formats = malloc(sizeof(data->supported_formats[0]) * 585 data->n_supported_formats); 586 if (!data->supported_formats) 587 return -ENOMEM; 588 } 589 590 if (data->custom_data_size) { 591 data->custom_data = malloc(data->custom_data_size); 592 if (!data->custom_data) { 593 ret = -ENOMEM; 594 goto done; 595 } 596 } 597 598 err = ioctl(fd, ADF_GET_OVERLAY_ENGINE_DATA, data); 599 if (err < 0) 600 ret = -errno; 601 602done: 603 if (ret < 0) 604 adf_free_overlay_engine_data(data); 605 return ret; 606} 607 608void adf_free_overlay_engine_data(struct adf_overlay_engine_data *data) 609{ 610 free(data->supported_formats); 611 free(data->custom_data); 612} 613 614bool adf_overlay_engine_supports_format(int fd, __u32 format) 615{ 616 struct adf_overlay_engine_data data; 617 bool ret = false; 618 size_t i; 619 620 int err = adf_get_overlay_engine_data(fd, &data); 621 if (err < 0) 622 return false; 623 624 for (i = 0; i < data.n_supported_formats; i++) { 625 if (data.supported_formats[i] == format) { 626 ret = true; 627 break; 628 } 629 } 630 631 adf_free_overlay_engine_data(&data); 632 return ret; 633} 634 635int adf_set_event(int fd, enum adf_event_type type, bool enabled) 636{ 637 struct adf_set_event data; 638 639 data.type = type; 640 data.enabled = enabled; 641 642 int err = ioctl(fd, ADF_SET_EVENT, &data); 643 if (err < 0) 644 return -errno; 645 return 0; 646} 647 648int adf_read_event(int fd, struct adf_event **event) 649{ 650 struct adf_event header; 651 struct { 652 struct adf_event base; 653 uint8_t data[0]; 654 } *event_ret; 655 size_t data_size; 656 int ret = 0; 657 658 int err = read(fd, &header, sizeof(header)); 659 if (err < 0) 660 return -errno; 661 if ((size_t)err < sizeof(header)) 662 return -EIO; 663 if (header.length < sizeof(header)) 664 return -EIO; 665 666 event_ret = malloc(header.length); 667 if (!event_ret) 668 return -ENOMEM; 669 data_size = header.length - sizeof(header); 670 671 memcpy(event_ret, &header, sizeof(header)); 672 ssize_t read_size = read(fd, &event_ret->data, data_size); 673 if (read_size < 0) { 674 ret = -errno; 675 goto done; 676 } 677 if ((size_t)read_size < data_size) { 678 ret = -EIO; 679 goto done; 680 } 681 682 *event = &event_ret->base; 683 684done: 685 if (ret < 0) 686 free(event_ret); 687 return ret; 688} 689 690void adf_format_str(__u32 format, char buf[ADF_FORMAT_STR_SIZE]) 691{ 692 buf[0] = format & 0xFF; 693 buf[1] = (format >> 8) & 0xFF; 694 buf[2] = (format >> 16) & 0xFF; 695 buf[3] = (format >> 24) & 0xFF; 696 buf[4] = '\0'; 697} 698