1 /* 2 * Copyright (C) 2011 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 /*! 18 * \file exynos_mc.c 19 * \brief source file for libexynosv4l2 20 * \author Jinsung Yang (jsgood.yang (at) samsung.com) 21 * \author Sangwoo Park (sw5771.park (at) samsung.com) 22 * \date 2012/01/17 23 * 24 * <b>Revision History: </b> 25 * - 2012/01/17: Jinsung Yang (jsgood.yang (at) samsung.com) \n 26 * Initial version 27 * 28 */ 29 30 #include <stdio.h> 31 #include <stdarg.h> 32 #include <stdlib.h> 33 #include <fcntl.h> 34 #include <errno.h> 35 #include <ctype.h> 36 #include <string.h> 37 #include <sys/types.h> 38 #include <sys/ioctl.h> 39 #include <sys/stat.h> 40 #include <media.h> 41 #include <linux/kdev_t.h> 42 #include <linux/types.h> 43 44 #include "exynos_v4l2.h" 45 46 //#define LOG_NDEBUG 0 47 #define LOG_TAG "libexynosv4l2-mc" 48 #include <utils/Log.h> 49 50 static inline unsigned int __media_entity_type(struct media_entity *entity) 51 { 52 return entity->info.type & MEDIA_ENT_TYPE_MASK; 53 } 54 55 static void __media_debug_default(void *ptr, ...) 56 { 57 va_list argptr; 58 va_start(argptr, ptr); 59 vprintf((const char*)ptr, argptr); 60 va_end(argptr); 61 } 62 63 static void __media_debug_set_handler( 64 struct media_device *media, 65 void (*debug_handler)(void *, ...), 66 void *debug_priv) 67 { 68 if (debug_handler) { 69 media->debug_handler = debug_handler; 70 media->debug_priv = debug_priv; 71 } else { 72 media->debug_handler = __media_debug_default; 73 media->debug_priv = NULL; 74 } 75 } 76 77 static struct media_link *__media_entity_add_link(struct media_entity *entity) 78 { 79 if (entity->num_links >= entity->max_links) { 80 struct media_link *links = entity->links; 81 unsigned int max_links = entity->max_links * 2; 82 unsigned int i; 83 84 links = (struct media_link*)realloc(links, max_links * sizeof *links); 85 if (links == NULL) 86 return NULL; 87 88 for (i = 0; i < entity->num_links; ++i) 89 links[i].twin->twin = &links[i]; 90 91 entity->max_links = max_links; 92 entity->links = links; 93 } 94 95 return &entity->links[entity->num_links++]; 96 } 97 98 99 static int __media_enum_links(struct media_device *media) 100 { 101 ALOGD("%s: start", __func__); 102 __u32 id; 103 int ret = 0; 104 105 for (id = 1; id <= media->entities_count; id++) { 106 struct media_entity *entity = &media->entities[id - 1]; 107 struct media_links_enum links; 108 unsigned int i; 109 110 links.entity = entity->info.id; 111 links.pads = (struct media_pad_desc*)malloc(entity->info.pads * sizeof(struct media_pad_desc)); 112 links.links = (struct media_link_desc*)malloc(entity->info.links * sizeof(struct media_link_desc)); 113 114 if (ioctl(media->fd, MEDIA_IOC_ENUM_LINKS, &links) < 0) { 115 ALOGE("Unable to enumerate pads and links (%s)", strerror(errno)); 116 free(links.pads); 117 free(links.links); 118 return -errno; 119 } 120 121 for (i = 0; i < entity->info.pads; ++i) { 122 entity->pads[i].entity = entity; 123 entity->pads[i].index = links.pads[i].index; 124 entity->pads[i].flags = links.pads[i].flags; 125 } 126 127 for (i = 0; i < entity->info.links; ++i) { 128 struct media_link_desc *link = &links.links[i]; 129 struct media_link *fwdlink; 130 struct media_link *backlink; 131 struct media_entity *source; 132 struct media_entity *sink; 133 134 source = exynos_media_get_entity_by_id(media, link->source.entity); 135 sink = exynos_media_get_entity_by_id(media, link->sink.entity); 136 if (source == NULL || sink == NULL) { 137 ALOGE("WARNING entity %u link %u from %u/%u to %u/%u is invalid!", 138 id, i, link->source.entity, 139 link->source.index, 140 link->sink.entity, 141 link->sink.index); 142 ret = -EINVAL; 143 } else { 144 fwdlink = __media_entity_add_link(source); 145 fwdlink->source = &source->pads[link->source.index]; 146 fwdlink->sink = &sink->pads[link->sink.index]; 147 fwdlink->flags = link->flags; 148 149 backlink = __media_entity_add_link(sink); 150 backlink->source = &source->pads[link->source.index]; 151 backlink->sink = &sink->pads[link->sink.index]; 152 backlink->flags = link->flags; 153 154 fwdlink->twin = backlink; 155 backlink->twin = fwdlink; 156 } 157 } 158 159 free(links.pads); 160 free(links.links); 161 } 162 return ret; 163 } 164 165 static int __media_get_devname_sysfs(struct media_entity *entity) 166 { 167 //struct stat devstat; 168 char devname[32]; 169 char sysname[32]; 170 char target[1024]; 171 char *p; 172 int ret; 173 174 sprintf(sysname, "/sys/dev/char/%u:%u", entity->info.v4l.major, 175 entity->info.v4l.minor); 176 177 ret = readlink(sysname, target, sizeof(target)); 178 if (ret < 0) 179 return -errno; 180 181 target[ret] = '\0'; 182 p = strrchr(target, '/'); 183 if (p == NULL) 184 return -EINVAL; 185 186 sprintf(devname, "/tmp/%s", p + 1); 187 188 ret = mknod(devname, 0666 | S_IFCHR, MKDEV(81, entity->info.v4l.minor)); 189 strcpy(entity->devname, devname); 190 191 return 0; 192 } 193 194 static int __media_get_media_fd(const char *filename, struct media_device *media) 195 { 196 ssize_t num; 197 int media_node; 198 char *ptr; 199 char media_buf[6]; 200 201 ALOGD("%s: %s", __func__, filename); 202 203 media->fd = open(filename, O_RDWR, 0); 204 if (media->fd < 0) { 205 ALOGE("Open sysfs media device failed, media->fd: %d", media->fd); 206 return -1; 207 } 208 209 ALOGD("%s: media->fd: %d", __func__, media->fd); 210 211 return media->fd; 212 213 } 214 215 static int __media_enum_entities(struct media_device *media) 216 { 217 struct media_entity *entity, *temp_entity; 218 unsigned int size; 219 __u32 id; 220 int ret; 221 222 temp_entity = entity = (struct media_entity*)calloc(1, sizeof(struct media_entity)); 223 for (id = 0, ret = 0; ; id = entity->info.id) { 224 size = (media->entities_count + 1) * sizeof(*media->entities); 225 media->entities = (struct media_entity*)realloc(media->entities, size); 226 227 entity = &media->entities[media->entities_count]; 228 memset(entity, 0, sizeof(*entity)); 229 entity->fd = -1; 230 entity->info.id = id | MEDIA_ENT_ID_FLAG_NEXT; 231 entity->media = media; 232 233 ret = ioctl(media->fd, MEDIA_IOC_ENUM_ENTITIES, &entity->info); 234 235 if (ret < 0) { 236 ret = errno != EINVAL ? -errno : 0; 237 break; 238 } 239 240 /* Number of links (for outbound links) plus number of pads (for 241 * inbound links) is a good safe initial estimate of the total 242 * number of links. 243 */ 244 entity->max_links = entity->info.pads + entity->info.links; 245 246 entity->pads = (struct media_pad*)malloc(entity->info.pads * sizeof(*entity->pads)); 247 entity->links = (struct media_link*)malloc(entity->max_links * sizeof(*entity->links)); 248 if (entity->pads == NULL || entity->links == NULL) { 249 ret = -ENOMEM; 250 break; 251 } 252 253 media->entities_count++; 254 255 /* Find the corresponding device name. */ 256 if (__media_entity_type(entity) != MEDIA_ENT_T_DEVNODE && 257 __media_entity_type(entity) != MEDIA_ENT_T_V4L2_SUBDEV) 258 continue; 259 260 /* Fall back to get the device name via sysfs */ 261 __media_get_devname_sysfs(entity); 262 if (ret < 0) 263 ALOGE("media_get_devname failed"); 264 } 265 free(temp_entity); 266 267 return ret; 268 } 269 270 static struct media_device *__media_open_debug( 271 const char *filename, 272 void (*debug_handler)(void *, ...), 273 void *debug_priv) 274 { 275 struct media_device *media; 276 int ret; 277 278 media = (struct media_device *)calloc(1, sizeof(struct media_device)); 279 if (media == NULL) { 280 ALOGE("media: %p", media); 281 return NULL; 282 } 283 284 __media_debug_set_handler(media, debug_handler, debug_priv); 285 286 ALOGD("%s: Opening media device %s", __func__, filename); 287 ALOGD("%s: media: %p", __func__, media); 288 289 media->fd = __media_get_media_fd(filename, media); 290 if (media->fd < 0) { 291 exynos_media_close(media); 292 ALOGE("failed __media_get_media_fd %s", filename); 293 return NULL; 294 } 295 296 ALOGD("%s: media->fd: %d", __func__, media->fd); 297 ret = __media_enum_entities(media); 298 299 if (ret < 0) { 300 ALOGE("Unable to enumerate entities for device %s (%s)", filename, strerror(-ret)); 301 exynos_media_close(media); 302 return NULL; 303 } 304 305 ALOGD("%s: Found %u entities", __func__, media->entities_count); 306 ALOGD("%s: Enumerating pads and links", __func__); 307 308 ret = __media_enum_links(media); 309 if (ret < 0) { 310 ALOGE("Unable to enumerate pads and links for device %s", filename); 311 exynos_media_close(media); 312 return NULL; 313 } 314 315 return media; 316 } 317 318 /** 319 * @brief Open a media device. 320 * @param filename - name (including path) of the device node. 321 * 322 * Open the media device referenced by @a filename and enumerate entities, pads and 323 * links. 324 * 325 * @return A pointer to a newly allocated media_device structure instance on 326 * success and NULL on failure. The returned pointer must be freed with 327 * exynos_media_close when the device isn't needed anymore. 328 */ 329 struct media_device *exynos_media_open(const char *filename) 330 { 331 return __media_open_debug(filename, (void (*)(void *, ...))fprintf, stdout); 332 } 333 334 /** 335 * @brief Close a media device. 336 * @param media - device instance. 337 * 338 * Close the @a media device instance and free allocated resources. Access to the 339 * device instance is forbidden after this function returns. 340 */ 341 void exynos_media_close(struct media_device *media) 342 { 343 unsigned int i; 344 345 if (media->fd != -1) 346 close(media->fd); 347 348 for (i = 0; i < media->entities_count; ++i) { 349 struct media_entity *entity = &media->entities[i]; 350 351 free(entity->pads); 352 free(entity->links); 353 if (entity->fd != -1) 354 close(entity->fd); 355 } 356 357 free(media->entities); 358 free(media); 359 } 360 361 /** 362 * @brief Locate the pad at the other end of a link. 363 * @param pad - sink pad at one end of the link. 364 * 365 * Locate the source pad connected to @a pad through an enabled link. As only one 366 * link connected to a sink pad can be enabled at a time, the connected source 367 * pad is guaranteed to be unique. 368 * 369 * @return A pointer to the connected source pad, or NULL if all links connected 370 * to @a pad are disabled. Return NULL also if @a pad is not a sink pad. 371 */ 372 struct media_pad *exynos_media_entity_remote_source(struct media_pad *pad) 373 { 374 unsigned int i; 375 376 if (!(pad->flags & MEDIA_PAD_FL_SINK)) 377 return NULL; 378 379 for (i = 0; i < pad->entity->num_links; ++i) { 380 struct media_link *link = &pad->entity->links[i]; 381 382 if (!(link->flags & MEDIA_LNK_FL_ENABLED)) 383 continue; 384 385 if (link->sink == pad) 386 return link->source; 387 } 388 389 return NULL; 390 } 391 392 /** 393 * @brief Find an entity by its name. 394 * @param media - media device. 395 * @param name - entity name. 396 * @param length - size of @a name. 397 * 398 * Search for an entity with a name equal to @a name. 399 * 400 * @return A pointer to the entity if found, or NULL otherwise. 401 */ 402 struct media_entity *exynos_media_get_entity_by_name(struct media_device *media, 403 const char *name, size_t length) 404 { 405 unsigned int i; 406 struct media_entity *entity; 407 408 for (i = 0; i < media->entities_count; ++i) { 409 entity = &media->entities[i]; 410 411 if (strncmp(entity->info.name, name, length) == 0) 412 return entity; 413 } 414 415 return NULL; 416 } 417 418 /** 419 * @brief Find an entity by its ID. 420 * @param media - media device. 421 * @param id - entity ID. 422 * 423 * Search for an entity with an ID equal to @a id. 424 * 425 * @return A pointer to the entity if found, or NULL otherwise. 426 */ 427 struct media_entity *exynos_media_get_entity_by_id(struct media_device *media, 428 __u32 id) 429 { 430 unsigned int i; 431 432 for (i = 0; i < media->entities_count; ++i) { 433 struct media_entity *entity = &media->entities[i]; 434 435 if (entity->info.id == id) 436 return entity; 437 } 438 439 return NULL; 440 } 441 442 /** 443 * @brief Configure a link. 444 * @param media - media device. 445 * @param source - source pad at the link origin. 446 * @param sink - sink pad at the link target. 447 * @param flags - configuration flags. 448 * 449 * Locate the link between @a source and @a sink, and configure it by applying 450 * the new @a flags. 451 * 452 * Only the MEDIA_LINK_FLAG_ENABLED flag is writable. 453 * 454 * @return 0 on success, -1 on failure: 455 * -ENOENT: link not found 456 * - other error codes returned by MEDIA_IOC_SETUP_LINK 457 */ 458 int exynos_media_setup_link(struct media_device *media, 459 struct media_pad *source, 460 struct media_pad *sink, 461 __u32 flags) 462 { 463 struct media_link *link; 464 struct media_link_desc ulink; 465 unsigned int i; 466 int ret; 467 468 for (i = 0; i < source->entity->num_links; i++) { 469 link = &source->entity->links[i]; 470 471 if (link->source->entity == source->entity && 472 link->source->index == source->index && 473 link->sink->entity == sink->entity && 474 link->sink->index == sink->index) 475 break; 476 } 477 478 if (i == source->entity->num_links) { 479 ALOGE("Link not found"); 480 return -ENOENT; 481 } 482 483 /* source pad */ 484 ulink.source.entity = source->entity->info.id; 485 ulink.source.index = source->index; 486 ulink.source.flags = MEDIA_PAD_FL_SOURCE; 487 488 /* sink pad */ 489 ulink.sink.entity = sink->entity->info.id; 490 ulink.sink.index = sink->index; 491 ulink.sink.flags = MEDIA_PAD_FL_SINK; 492 493 ulink.flags = flags | (link->flags & MEDIA_LNK_FL_IMMUTABLE); 494 495 ret = ioctl(media->fd, MEDIA_IOC_SETUP_LINK, &ulink); 496 if (ret == -1) { 497 ALOGE("Unable to setup link (%s)", strerror(errno)); 498 return -errno; 499 } 500 501 link->flags = ulink.flags; 502 link->twin->flags = ulink.flags; 503 return 0; 504 } 505 506 /** 507 * @brief Reset all links to the disabled state. 508 * @param media - media device. 509 * 510 * Disable all links in the media device. This function is usually used after 511 * opening a media device to reset all links to a known state. 512 * 513 * @return 0 on success, or a negative error code on failure. 514 */ 515 int exynos_media_reset_links(struct media_device *media) 516 { 517 unsigned int i, j; 518 int ret; 519 520 for (i = 0; i < media->entities_count; ++i) { 521 struct media_entity *entity = &media->entities[i]; 522 523 for (j = 0; j < entity->num_links; j++) { 524 struct media_link *link = &entity->links[j]; 525 526 if (link->flags & MEDIA_LNK_FL_IMMUTABLE || 527 link->source->entity != entity) 528 continue; 529 530 ret = exynos_media_setup_link(media, link->source, link->sink, 531 link->flags & ~MEDIA_LNK_FL_ENABLED); 532 if (ret < 0) 533 return ret; 534 } 535 } 536 537 return 0; 538 } 539 540 #ifdef HAVE_LIBUDEV 541 542 #include <libudev.h> 543 544 static inline int __media_udev_open(struct udev **udev) 545 { 546 *udev = udev_new(); 547 if (*udev == NULL) 548 return -ENOMEM; 549 return 0; 550 } 551 552 static inline void __media_udev_close(struct udev *udev) 553 { 554 if (udev != NULL) 555 udev_unref(udev); 556 } 557 558 static int __media_get_devname_udev(struct udev *udev, 559 struct media_entity *entity) 560 { 561 struct udev_device *device; 562 dev_t devnum; 563 const char *p; 564 int ret = -ENODEV; 565 566 if (udev == NULL) 567 return -EINVAL; 568 569 devnum = makedev(entity->info.v4l.major, entity->info.v4l.minor); 570 ALOGE("looking up device: %u:%u", 571 major(devnum), minor(devnum)); 572 device = udev_device_new_from_devnum(udev, 'c', devnum); 573 if (device) { 574 p = udev_device_get_devnode(device); 575 if (p) { 576 strncpy(entity->devname, p, sizeof(entity->devname)); 577 entity->devname[sizeof(entity->devname) - 1] = '\0'; 578 } 579 ret = 0; 580 } 581 582 udev_device_unref(device); 583 584 return ret; 585 } 586 587 #else /* HAVE_LIBUDEV */ 588 589 struct udev; 590 591 static inline int __media_udev_open(struct udev **udev) { return 0; } 592 593 static inline void __media_udev_close(struct udev *udev) { } 594 595 static inline int __media_get_devname_udev(struct udev *udev, 596 struct media_entity *entity) 597 { 598 return -ENOTSUP; 599 } 600 601 #endif /* HAVE_LIBUDEV */ 602 603 /** 604 * @brief Parse string to a pad on the media device. 605 * @param media - media device. 606 * @param p - input string 607 * @param endp - pointer to string where parsing ended 608 * 609 * Parse NULL terminated string describing a pad and return its struct 610 * media_pad instance. 611 * 612 * @return Pointer to struct media_pad on success, NULL on failure. 613 */ 614 struct media_pad *exynos_media_parse_pad(struct media_device *media, 615 const char *p, char **endp) 616 { 617 unsigned int entity_id, pad; 618 struct media_entity *entity; 619 char *end; 620 621 for (; isspace(*p); ++p); 622 623 if (*p == '"') { 624 for (end = (char *)p + 1; *end && *end != '"'; ++end); 625 if (*end != '"') 626 return NULL; 627 628 entity = exynos_media_get_entity_by_name(media, p + 1, end - p - 1); 629 if (entity == NULL) 630 return NULL; 631 632 ++end; 633 } else { 634 entity_id = strtoul(p, &end, 10); 635 entity = exynos_media_get_entity_by_id(media, entity_id); 636 if (entity == NULL) 637 return NULL; 638 } 639 for (; isspace(*end); ++end); 640 641 if (*end != ':') 642 return NULL; 643 for (p = end + 1; isspace(*p); ++p); 644 645 pad = strtoul(p, &end, 10); 646 for (p = end; isspace(*p); ++p); 647 648 if (pad >= entity->info.pads) 649 return NULL; 650 651 for (p = end; isspace(*p); ++p); 652 if (endp) 653 *endp = (char *)p; 654 655 return &entity->pads[pad]; 656 } 657 658 /** 659 * @brief Parse string to a link on the media device. 660 * @param media - media device. 661 * @param p - input string 662 * @param endp - pointer to p where parsing ended 663 * 664 * Parse NULL terminated string p describing a link and return its struct 665 * media_link instance. 666 * 667 * @return Pointer to struct media_link on success, NULL on failure. 668 */ 669 struct media_link *exynos_media_parse_link( 670 struct media_device *media, 671 const char *p, 672 char **endp) 673 { 674 struct media_link *link; 675 struct media_pad *source; 676 struct media_pad *sink; 677 unsigned int i; 678 char *end; 679 680 source = exynos_media_parse_pad(media, p, &end); 681 if (source == NULL) 682 return NULL; 683 684 if (end[0] != '-' || end[1] != '>') 685 return NULL; 686 p = end + 2; 687 688 sink = exynos_media_parse_pad(media, p, &end); 689 if (sink == NULL) 690 return NULL; 691 692 *endp = end; 693 694 for (i = 0; i < source->entity->num_links; i++) { 695 link = &source->entity->links[i]; 696 697 if (link->source == source && link->sink == sink) 698 return link; 699 } 700 701 return NULL; 702 } 703 704 /** 705 * @brief Parse string to a link on the media device and set it up. 706 * @param media - media device. 707 * @param p - input string 708 * 709 * Parse NULL terminated string p describing a link and its configuration 710 * and configure the link. 711 * 712 * @return 0 on success, or a negative error code on failure. 713 */ 714 int exynos_media_parse_setup_link( 715 struct media_device *media, 716 const char *p, 717 char **endp) 718 { 719 struct media_link *link; 720 __u32 flags; 721 char *end; 722 723 link = exynos_media_parse_link(media, p, &end); 724 if (link == NULL) { 725 ALOGE("Unable to parse link"); 726 return -EINVAL; 727 } 728 729 p = end; 730 if (*p++ != '[') { 731 ALOGE("Unable to parse link flags"); 732 return -EINVAL; 733 } 734 735 flags = strtoul(p, &end, 10); 736 for (p = end; isspace(*p); p++); 737 if (*p++ != ']') { 738 ALOGE("Unable to parse link flags"); 739 return -EINVAL; 740 } 741 742 for (; isspace(*p); p++); 743 *endp = (char *)p; 744 745 ALOGD("%s: Setting up link %u:%u -> %u:%u [%u]", __func__, 746 link->source->entity->info.id, link->source->index, 747 link->sink->entity->info.id, link->sink->index, 748 flags); 749 750 return exynos_media_setup_link(media, link->source, link->sink, flags); 751 } 752 753 /** 754 * @brief Parse string to link(s) on the media device and set it up. 755 * @param media - media device. 756 * @param p - input string 757 * 758 * Parse NULL terminated string p describing link(s) separated by 759 * commas (,) and configure the link(s). 760 * 761 * @return 0 on success, or a negative error code on failure. 762 */ 763 int exynos_media_parse_setup_links(struct media_device *media, const char *p) 764 { 765 char *end; 766 int ret; 767 768 do { 769 ret = exynos_media_parse_setup_link(media, p, &end); 770 if (ret < 0) 771 return ret; 772 773 p = end + 1; 774 } while (*end == ','); 775 776 return *end ? -EINVAL : 0; 777 } 778