From 9a5f1e0365265310545abdd43da7d28a44fd43a6 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 7 Oct 2011 18:38:02 +0300 Subject: Rename files to match the names of the libraries Rename media.* to mediactl.* and subdev.* v4l2subdev.*. Signed-off-by: Sakari Ailus Acked-by: Laurent Pinchart --- src/Makefile.am | 6 +- src/main.c | 4 +- src/media.c | 475 ------------------------------------------------------- src/media.h | 161 ------------------- src/mediactl.c | 474 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/mediactl.h | 160 +++++++++++++++++++ src/subdev.c | 188 ---------------------- src/subdev.h | 162 ------------------- src/v4l2subdev.c | 188 ++++++++++++++++++++++ src/v4l2subdev.h | 161 +++++++++++++++++++ 10 files changed, 988 insertions(+), 991 deletions(-) delete mode 100644 src/media.c delete mode 100644 src/media.h create mode 100644 src/mediactl.c create mode 100644 src/mediactl.h delete mode 100644 src/subdev.c delete mode 100644 src/subdev.h create mode 100644 src/v4l2subdev.c create mode 100644 src/v4l2subdev.h diff --git a/src/Makefile.am b/src/Makefile.am index 52628d2..2583464 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,8 +1,8 @@ lib_LTLIBRARIES = libmediactl.la libv4l2subdev.la -libmediactl_la_SOURCES = media.c -libv4l2subdev_la_SOURCES = subdev.c +libmediactl_la_SOURCES = mediactl.c +libv4l2subdev_la_SOURCES = v4l2subdev.c mediactl_includedir=$(includedir)/mediactl -mediactl_include_HEADERS = media.h subdev.h +mediactl_include_HEADERS = mediactl.h v4l2subdev.h bin_PROGRAMS = media-ctl media_ctl_CFLAGS = $(LIBUDEV_CFLAGS) diff --git a/src/main.c b/src/main.c index b9b9150..55a6e2d 100644 --- a/src/main.c +++ b/src/main.c @@ -36,9 +36,9 @@ #include #include -#include "media.h" +#include "mediactl.h" #include "options.h" -#include "subdev.h" +#include "v4l2subdev.h" #include "tools.h" /* ----------------------------------------------------------------------------- diff --git a/src/media.c b/src/media.c deleted file mode 100644 index f443d0c..0000000 --- a/src/media.c +++ /dev/null @@ -1,475 +0,0 @@ -/* - * Media controller test application - * - * Copyright (C) 2010 Ideas on board SPRL - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - */ - -#include "config.h" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "media.h" -#include "tools.h" - -struct media_pad *media_entity_remote_source(struct media_pad *pad) -{ - unsigned int i; - - if (!(pad->flags & MEDIA_PAD_FL_SINK)) - return NULL; - - for (i = 0; i < pad->entity->num_links; ++i) { - struct media_link *link = &pad->entity->links[i]; - - if (!(link->flags & MEDIA_LNK_FL_ENABLED)) - continue; - - if (link->sink == pad) - return link->source; - } - - return NULL; -} - -struct media_entity *media_get_entity_by_name(struct media_device *media, - const char *name, size_t length) -{ - unsigned int i; - - for (i = 0; i < media->entities_count; ++i) { - struct media_entity *entity = &media->entities[i]; - - if (strncmp(entity->info.name, name, length) == 0) - return entity; - } - - return NULL; -} - -struct media_entity *media_get_entity_by_id(struct media_device *media, - __u32 id) -{ - unsigned int i; - - for (i = 0; i < media->entities_count; ++i) { - struct media_entity *entity = &media->entities[i]; - - if (entity->info.id == id) - return entity; - } - - return NULL; -} - -int media_setup_link(struct media_device *media, - struct media_pad *source, - struct media_pad *sink, - __u32 flags) -{ - struct media_link *link; - struct media_link_desc ulink; - unsigned int i; - int ret; - - for (i = 0; i < source->entity->num_links; i++) { - link = &source->entity->links[i]; - - if (link->source->entity == source->entity && - link->source->index == source->index && - link->sink->entity == sink->entity && - link->sink->index == sink->index) - break; - } - - if (i == source->entity->num_links) { - printf("%s: Link not found\n", __func__); - return -EINVAL; - } - - /* source pad */ - ulink.source.entity = source->entity->info.id; - ulink.source.index = source->index; - ulink.source.flags = MEDIA_PAD_FL_SOURCE; - - /* sink pad */ - ulink.sink.entity = sink->entity->info.id; - ulink.sink.index = sink->index; - ulink.sink.flags = MEDIA_PAD_FL_SINK; - - ulink.flags = flags | (link->flags & MEDIA_LNK_FL_IMMUTABLE); - - ret = ioctl(media->fd, MEDIA_IOC_SETUP_LINK, &ulink); - if (ret < 0) { - printf("%s: Unable to setup link (%s)\n", __func__, - strerror(errno)); - return ret; - } - - link->flags = ulink.flags; - link->twin->flags = ulink.flags; - return 0; -} - -int media_reset_links(struct media_device *media) -{ - unsigned int i, j; - int ret; - - for (i = 0; i < media->entities_count; ++i) { - struct media_entity *entity = &media->entities[i]; - - for (j = 0; j < entity->num_links; j++) { - struct media_link *link = &entity->links[j]; - - if (link->flags & MEDIA_LNK_FL_IMMUTABLE || - link->source->entity != entity) - continue; - - ret = media_setup_link(media, link->source, link->sink, - link->flags & ~MEDIA_LNK_FL_ENABLED); - if (ret < 0) - return ret; - } - } - - return 0; -} - -static struct media_link *media_entity_add_link(struct media_entity *entity) -{ - if (entity->num_links >= entity->max_links) { - struct media_link *links = entity->links; - unsigned int max_links = entity->max_links * 2; - unsigned int i; - - links = realloc(links, max_links * sizeof *links); - if (links == NULL) - return NULL; - - for (i = 0; i < entity->num_links; ++i) - links[i].twin->twin = &links[i]; - - entity->max_links = max_links; - entity->links = links; - } - - return &entity->links[entity->num_links++]; -} - -static int media_enum_links(struct media_device *media) -{ - __u32 id; - int ret = 0; - - for (id = 1; id <= media->entities_count; id++) { - struct media_entity *entity = &media->entities[id - 1]; - struct media_links_enum links; - unsigned int i; - - links.entity = entity->info.id; - links.pads = malloc(entity->info.pads * sizeof(struct media_pad_desc)); - links.links = malloc(entity->info.links * sizeof(struct media_link_desc)); - - if (ioctl(media->fd, MEDIA_IOC_ENUM_LINKS, &links) < 0) { - printf("%s: Unable to enumerate pads and links (%s).\n", - __func__, strerror(errno)); - free(links.pads); - free(links.links); - return -errno; - } - - for (i = 0; i < entity->info.pads; ++i) { - entity->pads[i].entity = entity; - entity->pads[i].index = links.pads[i].index; - entity->pads[i].flags = links.pads[i].flags; - } - - for (i = 0; i < entity->info.links; ++i) { - struct media_link_desc *link = &links.links[i]; - struct media_link *fwdlink; - struct media_link *backlink; - struct media_entity *source; - struct media_entity *sink; - - source = media_get_entity_by_id(media, link->source.entity); - sink = media_get_entity_by_id(media, link->sink.entity); - - if (source == NULL || sink == NULL) { - printf("WARNING entity %u link %u from %u/%u to %u/%u is invalid!\n", - id, i, link->source.entity, link->source.index, - link->sink.entity, link->sink.index); - ret = -EINVAL; - } else { - fwdlink = media_entity_add_link(source); - fwdlink->source = &source->pads[link->source.index]; - fwdlink->sink = &sink->pads[link->sink.index]; - fwdlink->flags = link->flags; - - backlink = media_entity_add_link(sink); - backlink->source = &source->pads[link->source.index]; - backlink->sink = &sink->pads[link->sink.index]; - backlink->flags = link->flags; - - fwdlink->twin = backlink; - backlink->twin = fwdlink; - } - } - - free(links.pads); - free(links.links); - } - - return ret; -} - -#ifdef HAVE_LIBUDEV - -#include - -static inline int media_udev_open(struct udev **udev) -{ - *udev = udev_new(); - if (*udev == NULL) - return -ENOMEM; - return 0; -} - -static inline void media_udev_close(struct udev *udev) -{ - if (udev != NULL) - udev_unref(udev); -} - -static int media_get_devname_udev(struct udev *udev, - struct media_entity *entity, int verbose) -{ - struct udev_device *device; - dev_t devnum; - const char *p; - int ret = -ENODEV; - - if (udev == NULL) - return -EINVAL; - - devnum = makedev(entity->info.v4l.major, entity->info.v4l.minor); - if (verbose) - printf("looking up device: %u:%u\n", major(devnum), minor(devnum)); - device = udev_device_new_from_devnum(udev, 'c', devnum); - if (device) { - p = udev_device_get_devnode(device); - if (p) { - strncpy(entity->devname, p, sizeof(entity->devname)); - entity->devname[sizeof(entity->devname) - 1] = '\0'; - } - ret = 0; - } - - udev_device_unref(device); - - return ret; -} - -#else /* HAVE_LIBUDEV */ - -struct udev; - -static inline int media_udev_open(struct udev **udev) { return 0; } - -static inline void media_udev_close(struct udev *udev) { } - -static inline int media_get_devname_udev(struct udev *udev, - struct media_entity *entity, int verbose) -{ - return -ENOTSUP; -} - -#endif /* HAVE_LIBUDEV */ - -static int media_get_devname_sysfs(struct media_entity *entity) -{ - struct stat devstat; - char devname[32]; - char sysname[32]; - char target[1024]; - char *p; - int ret; - - sprintf(sysname, "/sys/dev/char/%u:%u", entity->info.v4l.major, - entity->info.v4l.minor); - ret = readlink(sysname, target, sizeof(target)); - if (ret < 0) - return -errno; - - target[ret] = '\0'; - p = strrchr(target, '/'); - if (p == NULL) - return -EINVAL; - - sprintf(devname, "/dev/%s", p + 1); - ret = stat(devname, &devstat); - if (ret < 0) - return -errno; - - /* Sanity check: udev might have reordered the device nodes. - * Make sure the major/minor match. We should really use - * libudev. - */ - if (major(devstat.st_rdev) == entity->info.v4l.major && - minor(devstat.st_rdev) == entity->info.v4l.minor) - strcpy(entity->devname, devname); - - return 0; -} - -static int media_enum_entities(struct media_device *media, int verbose) -{ - struct media_entity *entity; - struct udev *udev; - unsigned int size; - __u32 id; - int ret; - - ret = media_udev_open(&udev); - if (ret < 0) - printf("%s: Can't get udev context\n", __func__); - - for (id = 0, ret = 0; ; id = entity->info.id) { - size = (media->entities_count + 1) * sizeof(*media->entities); - media->entities = realloc(media->entities, size); - - entity = &media->entities[media->entities_count]; - memset(entity, 0, sizeof(*entity)); - entity->fd = -1; - entity->info.id = id | MEDIA_ENT_ID_FLAG_NEXT; - - ret = ioctl(media->fd, MEDIA_IOC_ENUM_ENTITIES, &entity->info); - if (ret < 0) { - ret = errno != EINVAL ? -errno : 0; - break; - } - - /* Number of links (for outbound links) plus number of pads (for - * inbound links) is a good safe initial estimate of the total - * number of links. - */ - entity->max_links = entity->info.pads + entity->info.links; - - entity->pads = malloc(entity->info.pads * sizeof(*entity->pads)); - entity->links = malloc(entity->max_links * sizeof(*entity->links)); - if (entity->pads == NULL || entity->links == NULL) { - ret = -ENOMEM; - break; - } - - media->entities_count++; - - /* Find the corresponding device name. */ - if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE && - media_entity_type(entity) != MEDIA_ENT_T_V4L2_SUBDEV) - continue; - - /* Try to get the device name via udev */ - if (!media_get_devname_udev(udev, entity, verbose)) - continue; - - /* Fall back to get the device name via sysfs */ - media_get_devname_sysfs(entity); - } - - media_udev_close(udev); - return ret; -} - -struct media_device *media_open(const char *name, int verbose) -{ - struct media_device *media; - int ret; - - media = calloc(1, sizeof(*media)); - if (media == NULL) { - printf("%s: unable to allocate memory\n", __func__); - return NULL; - } - - if (verbose) - printf("Opening media device %s\n", name); - media->fd = open(name, O_RDWR); - if (media->fd < 0) { - media_close(media); - printf("%s: Can't open media device %s\n", __func__, name); - return NULL; - } - - if (verbose) - printf("Enumerating entities\n"); - - ret = media_enum_entities(media, verbose); - - if (ret < 0) { - printf("%s: Unable to enumerate entities for device %s (%s)\n", - __func__, name, strerror(-ret)); - media_close(media); - return NULL; - } - - if (verbose) { - printf("Found %u entities\n", media->entities_count); - printf("Enumerating pads and links\n"); - } - - ret = media_enum_links(media); - if (ret < 0) { - printf("%s: Unable to enumerate pads and linksfor device %s\n", - __func__, name); - media_close(media); - return NULL; - } - - return media; -} - -void media_close(struct media_device *media) -{ - unsigned int i; - - if (media->fd != -1) - close(media->fd); - - for (i = 0; i < media->entities_count; ++i) { - struct media_entity *entity = &media->entities[i]; - - free(entity->pads); - free(entity->links); - if (entity->fd != -1) - close(entity->fd); - } - - free(media->entities); - free(media); -} - diff --git a/src/media.h b/src/media.h deleted file mode 100644 index b91a2ac..0000000 --- a/src/media.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Media controller test application - * - * Copyright (C) 2010 Ideas on board SPRL - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - */ - -#ifndef __MEDIA_H__ -#define __MEDIA_H__ - -#include - -struct media_link { - struct media_pad *source; - struct media_pad *sink; - struct media_link *twin; - __u32 flags; - __u32 padding[3]; -}; - -struct media_pad { - struct media_entity *entity; - __u32 index; - __u32 flags; - __u32 padding[3]; -}; - -struct media_entity { - struct media_entity_desc info; - struct media_pad *pads; - struct media_link *links; - unsigned int max_links; - unsigned int num_links; - - char devname[32]; - int fd; - __u32 padding[6]; -}; - -struct media_device { - int fd; - struct media_entity *entities; - unsigned int entities_count; - __u32 padding[6]; -}; - -/** - * @brief Open a media device. - * @param name - name (including path) of the device node. - * @param verbose - whether to print verbose information on the standard output. - * - * Open the media device referenced by @a name and enumerate entities, pads and - * links. - * - * @return A pointer to a newly allocated media_device structure instance on - * success and NULL on failure. The returned pointer must be freed with - * media_close when the device isn't needed anymore. - */ -struct media_device *media_open(const char *name, int verbose); - -/** - * @brief Close a media device. - * @param media - device instance. - * - * Close the @a media device instance and free allocated resources. Access to the - * device instance is forbidden after this function returns. - */ -void media_close(struct media_device *media); - -/** - * @brief Locate the pad at the other end of a link. - * @param pad - sink pad at one end of the link. - * - * Locate the source pad connected to @a pad through an enabled link. As only one - * link connected to a sink pad can be enabled at a time, the connected source - * pad is guaranteed to be unique. - * - * @return A pointer to the connected source pad, or NULL if all links connected - * to @a pad are disabled. Return NULL also if @a pad is not a sink pad. - */ -struct media_pad *media_entity_remote_source(struct media_pad *pad); - -/** - * @brief Get the type of an entity. - * @param entity - the entity. - * - * @return The type of @a entity. - */ -static inline unsigned int media_entity_type(struct media_entity *entity) -{ - return entity->info.type & MEDIA_ENT_TYPE_MASK; -} - -/** - * @brief Find an entity by its name. - * @param media - media device. - * @param name - entity name. - * @param length - size of @a name. - * - * Search for an entity with a name equal to @a name. - * - * @return A pointer to the entity if found, or NULL otherwise. - */ -struct media_entity *media_get_entity_by_name(struct media_device *media, - const char *name, size_t length); - -/** - * @brief Find an entity by its ID. - * @param media - media device. - * @param id - entity ID. - * - * Search for an entity with an ID equal to @a id. - * - * @return A pointer to the entity if found, or NULL otherwise. - */ -struct media_entity *media_get_entity_by_id(struct media_device *media, - __u32 id); - -/** - * @brief Configure a link. - * @param media - media device. - * @param source - source pad at the link origin. - * @param sink - sink pad at the link target. - * @param flags - configuration flags. - * - * Locate the link between @a source and @a sink, and configure it by applying - * the new @a flags. - * - * Only the MEDIA_LINK_FLAG_ENABLED flag is writable. - * - * @return 0 on success, or a negative error code on failure. - */ -int media_setup_link(struct media_device *media, - struct media_pad *source, struct media_pad *sink, - __u32 flags); - -/** - * @brief Reset all links to the disabled state. - * @param media - media device. - * - * Disable all links in the media device. This function is usually used after - * opening a media device to reset all links to a known state. - * - * @return 0 on success, or a negative error code on failure. - */ -int media_reset_links(struct media_device *media); - -#endif - diff --git a/src/mediactl.c b/src/mediactl.c new file mode 100644 index 0000000..8f7d0a9 --- /dev/null +++ b/src/mediactl.c @@ -0,0 +1,474 @@ +/* + * Media controller test application + * + * Copyright (C) 2010 Ideas on board SPRL + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "mediactl.h" +#include "tools.h" + +struct media_pad *media_entity_remote_source(struct media_pad *pad) +{ + unsigned int i; + + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + return NULL; + + for (i = 0; i < pad->entity->num_links; ++i) { + struct media_link *link = &pad->entity->links[i]; + + if (!(link->flags & MEDIA_LNK_FL_ENABLED)) + continue; + + if (link->sink == pad) + return link->source; + } + + return NULL; +} + +struct media_entity *media_get_entity_by_name(struct media_device *media, + const char *name, size_t length) +{ + unsigned int i; + + for (i = 0; i < media->entities_count; ++i) { + struct media_entity *entity = &media->entities[i]; + + if (strncmp(entity->info.name, name, length) == 0) + return entity; + } + + return NULL; +} + +struct media_entity *media_get_entity_by_id(struct media_device *media, + __u32 id) +{ + unsigned int i; + + for (i = 0; i < media->entities_count; ++i) { + struct media_entity *entity = &media->entities[i]; + + if (entity->info.id == id) + return entity; + } + + return NULL; +} + +int media_setup_link(struct media_device *media, + struct media_pad *source, + struct media_pad *sink, + __u32 flags) +{ + struct media_link *link; + struct media_link_desc ulink; + unsigned int i; + int ret; + + for (i = 0; i < source->entity->num_links; i++) { + link = &source->entity->links[i]; + + if (link->source->entity == source->entity && + link->source->index == source->index && + link->sink->entity == sink->entity && + link->sink->index == sink->index) + break; + } + + if (i == source->entity->num_links) { + printf("%s: Link not found\n", __func__); + return -EINVAL; + } + + /* source pad */ + ulink.source.entity = source->entity->info.id; + ulink.source.index = source->index; + ulink.source.flags = MEDIA_PAD_FL_SOURCE; + + /* sink pad */ + ulink.sink.entity = sink->entity->info.id; + ulink.sink.index = sink->index; + ulink.sink.flags = MEDIA_PAD_FL_SINK; + + ulink.flags = flags | (link->flags & MEDIA_LNK_FL_IMMUTABLE); + + ret = ioctl(media->fd, MEDIA_IOC_SETUP_LINK, &ulink); + if (ret < 0) { + printf("%s: Unable to setup link (%s)\n", __func__, + strerror(errno)); + return ret; + } + + link->flags = ulink.flags; + link->twin->flags = ulink.flags; + return 0; +} + +int media_reset_links(struct media_device *media) +{ + unsigned int i, j; + int ret; + + for (i = 0; i < media->entities_count; ++i) { + struct media_entity *entity = &media->entities[i]; + + for (j = 0; j < entity->num_links; j++) { + struct media_link *link = &entity->links[j]; + + if (link->flags & MEDIA_LNK_FL_IMMUTABLE || + link->source->entity != entity) + continue; + + ret = media_setup_link(media, link->source, link->sink, + link->flags & ~MEDIA_LNK_FL_ENABLED); + if (ret < 0) + return ret; + } + } + + return 0; +} + +static struct media_link *media_entity_add_link(struct media_entity *entity) +{ + if (entity->num_links >= entity->max_links) { + struct media_link *links = entity->links; + unsigned int max_links = entity->max_links * 2; + unsigned int i; + + links = realloc(links, max_links * sizeof *links); + if (links == NULL) + return NULL; + + for (i = 0; i < entity->num_links; ++i) + links[i].twin->twin = &links[i]; + + entity->max_links = max_links; + entity->links = links; + } + + return &entity->links[entity->num_links++]; +} + +static int media_enum_links(struct media_device *media) +{ + __u32 id; + int ret = 0; + + for (id = 1; id <= media->entities_count; id++) { + struct media_entity *entity = &media->entities[id - 1]; + struct media_links_enum links; + unsigned int i; + + links.entity = entity->info.id; + links.pads = malloc(entity->info.pads * sizeof(struct media_pad_desc)); + links.links = malloc(entity->info.links * sizeof(struct media_link_desc)); + + if (ioctl(media->fd, MEDIA_IOC_ENUM_LINKS, &links) < 0) { + printf("%s: Unable to enumerate pads and links (%s).\n", + __func__, strerror(errno)); + free(links.pads); + free(links.links); + return -errno; + } + + for (i = 0; i < entity->info.pads; ++i) { + entity->pads[i].entity = entity; + entity->pads[i].index = links.pads[i].index; + entity->pads[i].flags = links.pads[i].flags; + } + + for (i = 0; i < entity->info.links; ++i) { + struct media_link_desc *link = &links.links[i]; + struct media_link *fwdlink; + struct media_link *backlink; + struct media_entity *source; + struct media_entity *sink; + + source = media_get_entity_by_id(media, link->source.entity); + sink = media_get_entity_by_id(media, link->sink.entity); + + if (source == NULL || sink == NULL) { + printf("WARNING entity %u link %u from %u/%u to %u/%u is invalid!\n", + id, i, link->source.entity, link->source.index, + link->sink.entity, link->sink.index); + ret = -EINVAL; + } else { + fwdlink = media_entity_add_link(source); + fwdlink->source = &source->pads[link->source.index]; + fwdlink->sink = &sink->pads[link->sink.index]; + fwdlink->flags = link->flags; + + backlink = media_entity_add_link(sink); + backlink->source = &source->pads[link->source.index]; + backlink->sink = &sink->pads[link->sink.index]; + backlink->flags = link->flags; + + fwdlink->twin = backlink; + backlink->twin = fwdlink; + } + } + + free(links.pads); + free(links.links); + } + + return ret; +} + +#ifdef HAVE_LIBUDEV + +#include + +static inline int media_udev_open(struct udev **udev) +{ + *udev = udev_new(); + if (*udev == NULL) + return -ENOMEM; + return 0; +} + +static inline void media_udev_close(struct udev *udev) +{ + if (udev != NULL) + udev_unref(udev); +} + +static int media_get_devname_udev(struct udev *udev, + struct media_entity *entity, int verbose) +{ + struct udev_device *device; + dev_t devnum; + const char *p; + int ret = -ENODEV; + + if (udev == NULL) + return -EINVAL; + + devnum = makedev(entity->info.v4l.major, entity->info.v4l.minor); + if (verbose) + printf("looking up device: %u:%u\n", major(devnum), minor(devnum)); + device = udev_device_new_from_devnum(udev, 'c', devnum); + if (device) { + p = udev_device_get_devnode(device); + if (p) { + strncpy(entity->devname, p, sizeof(entity->devname)); + entity->devname[sizeof(entity->devname) - 1] = '\0'; + } + ret = 0; + } + + udev_device_unref(device); + + return ret; +} + +#else /* HAVE_LIBUDEV */ + +struct udev; + +static inline int media_udev_open(struct udev **udev) { return 0; } + +static inline void media_udev_close(struct udev *udev) { } + +static inline int media_get_devname_udev(struct udev *udev, + struct media_entity *entity, int verbose) +{ + return -ENOTSUP; +} + +#endif /* HAVE_LIBUDEV */ + +static int media_get_devname_sysfs(struct media_entity *entity) +{ + struct stat devstat; + char devname[32]; + char sysname[32]; + char target[1024]; + char *p; + int ret; + + sprintf(sysname, "/sys/dev/char/%u:%u", entity->info.v4l.major, + entity->info.v4l.minor); + ret = readlink(sysname, target, sizeof(target)); + if (ret < 0) + return -errno; + + target[ret] = '\0'; + p = strrchr(target, '/'); + if (p == NULL) + return -EINVAL; + + sprintf(devname, "/dev/%s", p + 1); + ret = stat(devname, &devstat); + if (ret < 0) + return -errno; + + /* Sanity check: udev might have reordered the device nodes. + * Make sure the major/minor match. We should really use + * libudev. + */ + if (major(devstat.st_rdev) == entity->info.v4l.major && + minor(devstat.st_rdev) == entity->info.v4l.minor) + strcpy(entity->devname, devname); + + return 0; +} + +static int media_enum_entities(struct media_device *media, int verbose) +{ + struct media_entity *entity; + struct udev *udev; + unsigned int size; + __u32 id; + int ret; + + ret = media_udev_open(&udev); + if (ret < 0) + printf("%s: Can't get udev context\n", __func__); + + for (id = 0, ret = 0; ; id = entity->info.id) { + size = (media->entities_count + 1) * sizeof(*media->entities); + media->entities = realloc(media->entities, size); + + entity = &media->entities[media->entities_count]; + memset(entity, 0, sizeof(*entity)); + entity->fd = -1; + entity->info.id = id | MEDIA_ENT_ID_FLAG_NEXT; + + ret = ioctl(media->fd, MEDIA_IOC_ENUM_ENTITIES, &entity->info); + if (ret < 0) { + ret = errno != EINVAL ? -errno : 0; + break; + } + + /* Number of links (for outbound links) plus number of pads (for + * inbound links) is a good safe initial estimate of the total + * number of links. + */ + entity->max_links = entity->info.pads + entity->info.links; + + entity->pads = malloc(entity->info.pads * sizeof(*entity->pads)); + entity->links = malloc(entity->max_links * sizeof(*entity->links)); + if (entity->pads == NULL || entity->links == NULL) { + ret = -ENOMEM; + break; + } + + media->entities_count++; + + /* Find the corresponding device name. */ + if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE && + media_entity_type(entity) != MEDIA_ENT_T_V4L2_SUBDEV) + continue; + + /* Try to get the device name via udev */ + if (!media_get_devname_udev(udev, entity, verbose)) + continue; + + /* Fall back to get the device name via sysfs */ + media_get_devname_sysfs(entity); + } + + media_udev_close(udev); + return ret; +} + +struct media_device *media_open(const char *name, int verbose) +{ + struct media_device *media; + int ret; + + media = calloc(1, sizeof(*media)); + if (media == NULL) { + printf("%s: unable to allocate memory\n", __func__); + return NULL; + } + + if (verbose) + printf("Opening media device %s\n", name); + media->fd = open(name, O_RDWR); + if (media->fd < 0) { + media_close(media); + printf("%s: Can't open media device %s\n", __func__, name); + return NULL; + } + + if (verbose) + printf("Enumerating entities\n"); + + ret = media_enum_entities(media, verbose); + + if (ret < 0) { + printf("%s: Unable to enumerate entities for device %s (%s)\n", + __func__, name, strerror(-ret)); + media_close(media); + return NULL; + } + + if (verbose) { + printf("Found %u entities\n", media->entities_count); + printf("Enumerating pads and links\n"); + } + + ret = media_enum_links(media); + if (ret < 0) { + printf("%s: Unable to enumerate pads and linksfor device %s\n", + __func__, name); + media_close(media); + return NULL; + } + + return media; +} + +void media_close(struct media_device *media) +{ + unsigned int i; + + if (media->fd != -1) + close(media->fd); + + for (i = 0; i < media->entities_count; ++i) { + struct media_entity *entity = &media->entities[i]; + + free(entity->pads); + free(entity->links); + if (entity->fd != -1) + close(entity->fd); + } + + free(media->entities); + free(media); +} diff --git a/src/mediactl.h b/src/mediactl.h new file mode 100644 index 0000000..b53b9cc --- /dev/null +++ b/src/mediactl.h @@ -0,0 +1,160 @@ +/* + * Media controller test application + * + * Copyright (C) 2010 Ideas on board SPRL + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + */ + +#ifndef __MEDIA_H__ +#define __MEDIA_H__ + +#include + +struct media_link { + struct media_pad *source; + struct media_pad *sink; + struct media_link *twin; + __u32 flags; + __u32 padding[3]; +}; + +struct media_pad { + struct media_entity *entity; + __u32 index; + __u32 flags; + __u32 padding[3]; +}; + +struct media_entity { + struct media_entity_desc info; + struct media_pad *pads; + struct media_link *links; + unsigned int max_links; + unsigned int num_links; + + char devname[32]; + int fd; + __u32 padding[6]; +}; + +struct media_device { + int fd; + struct media_entity *entities; + unsigned int entities_count; + __u32 padding[6]; +}; + +/** + * @brief Open a media device. + * @param name - name (including path) of the device node. + * @param verbose - whether to print verbose information on the standard output. + * + * Open the media device referenced by @a name and enumerate entities, pads and + * links. + * + * @return A pointer to a newly allocated media_device structure instance on + * success and NULL on failure. The returned pointer must be freed with + * media_close when the device isn't needed anymore. + */ +struct media_device *media_open(const char *name, int verbose); + +/** + * @brief Close a media device. + * @param media - device instance. + * + * Close the @a media device instance and free allocated resources. Access to the + * device instance is forbidden after this function returns. + */ +void media_close(struct media_device *media); + +/** + * @brief Locate the pad at the other end of a link. + * @param pad - sink pad at one end of the link. + * + * Locate the source pad connected to @a pad through an enabled link. As only one + * link connected to a sink pad can be enabled at a time, the connected source + * pad is guaranteed to be unique. + * + * @return A pointer to the connected source pad, or NULL if all links connected + * to @a pad are disabled. Return NULL also if @a pad is not a sink pad. + */ +struct media_pad *media_entity_remote_source(struct media_pad *pad); + +/** + * @brief Get the type of an entity. + * @param entity - the entity. + * + * @return The type of @a entity. + */ +static inline unsigned int media_entity_type(struct media_entity *entity) +{ + return entity->info.type & MEDIA_ENT_TYPE_MASK; +} + +/** + * @brief Find an entity by its name. + * @param media - media device. + * @param name - entity name. + * @param length - size of @a name. + * + * Search for an entity with a name equal to @a name. + * + * @return A pointer to the entity if found, or NULL otherwise. + */ +struct media_entity *media_get_entity_by_name(struct media_device *media, + const char *name, size_t length); + +/** + * @brief Find an entity by its ID. + * @param media - media device. + * @param id - entity ID. + * + * Search for an entity with an ID equal to @a id. + * + * @return A pointer to the entity if found, or NULL otherwise. + */ +struct media_entity *media_get_entity_by_id(struct media_device *media, + __u32 id); + +/** + * @brief Configure a link. + * @param media - media device. + * @param source - source pad at the link origin. + * @param sink - sink pad at the link target. + * @param flags - configuration flags. + * + * Locate the link between @a source and @a sink, and configure it by applying + * the new @a flags. + * + * Only the MEDIA_LINK_FLAG_ENABLED flag is writable. + * + * @return 0 on success, or a negative error code on failure. + */ +int media_setup_link(struct media_device *media, + struct media_pad *source, struct media_pad *sink, + __u32 flags); + +/** + * @brief Reset all links to the disabled state. + * @param media - media device. + * + * Disable all links in the media device. This function is usually used after + * opening a media device to reset all links to a known state. + * + * @return 0 on success, or a negative error code on failure. + */ +int media_reset_links(struct media_device *media); + +#endif diff --git a/src/subdev.c b/src/subdev.c deleted file mode 100644 index f8ccfe3..0000000 --- a/src/subdev.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Media controller test application - * - * Copyright (C) 2010 Ideas on board SPRL - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - */ - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include "media.h" -#include "subdev.h" -#include "tools.h" - -int v4l2_subdev_open(struct media_entity *entity) -{ - if (entity->fd != -1) - return 0; - - entity->fd = open(entity->devname, O_RDWR); - if (entity->fd == -1) { - printf("%s: Failed to open subdev device node %s\n", __func__, - entity->devname); - return -errno; - } - - return 0; -} - -void v4l2_subdev_close(struct media_entity *entity) -{ - close(entity->fd); - entity->fd = -1; -} - -int v4l2_subdev_get_format(struct media_entity *entity, - struct v4l2_mbus_framefmt *format, unsigned int pad, - enum v4l2_subdev_format_whence which) -{ - struct v4l2_subdev_format fmt; - int ret; - - ret = v4l2_subdev_open(entity); - if (ret < 0) - return ret; - - memset(&fmt, 0, sizeof(fmt)); - fmt.pad = pad; - fmt.which = which; - - ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_FMT, &fmt); - if (ret < 0) - return -errno; - - *format = fmt.format; - return 0; -} - -int v4l2_subdev_set_format(struct media_entity *entity, - struct v4l2_mbus_framefmt *format, unsigned int pad, - enum v4l2_subdev_format_whence which) -{ - struct v4l2_subdev_format fmt; - int ret; - - ret = v4l2_subdev_open(entity); - if (ret < 0) - return ret; - - memset(&fmt, 0, sizeof(fmt)); - fmt.pad = pad; - fmt.which = which; - fmt.format = *format; - - ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_FMT, &fmt); - if (ret < 0) - return -errno; - - *format = fmt.format; - return 0; -} - -int v4l2_subdev_get_crop(struct media_entity *entity, struct v4l2_rect *rect, - unsigned int pad, enum v4l2_subdev_format_whence which) -{ - struct v4l2_subdev_crop crop; - int ret; - - ret = v4l2_subdev_open(entity); - if (ret < 0) - return ret; - - memset(&crop, 0, sizeof(crop)); - crop.pad = pad; - crop.which = which; - - ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_CROP, &crop); - if (ret < 0) - return -errno; - - *rect = crop.rect; - return 0; -} - -int v4l2_subdev_set_crop(struct media_entity *entity, struct v4l2_rect *rect, - unsigned int pad, enum v4l2_subdev_format_whence which) -{ - struct v4l2_subdev_crop crop; - int ret; - - ret = v4l2_subdev_open(entity); - if (ret < 0) - return ret; - - memset(&crop, 0, sizeof(crop)); - crop.pad = pad; - crop.which = which; - crop.rect = *rect; - - ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_CROP, &crop); - if (ret < 0) - return -errno; - - *rect = crop.rect; - return 0; -} - -int v4l2_subdev_get_frame_interval(struct media_entity *entity, - struct v4l2_fract *interval) -{ - struct v4l2_subdev_frame_interval ival; - int ret; - - ret = v4l2_subdev_open(entity); - if (ret < 0) - return ret; - - memset(&ival, 0, sizeof(ival)); - - ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_FRAME_INTERVAL, &ival); - if (ret < 0) - return -errno; - - *interval = ival.interval; - return 0; -} - -int v4l2_subdev_set_frame_interval(struct media_entity *entity, - struct v4l2_fract *interval) -{ - struct v4l2_subdev_frame_interval ival; - int ret; - - ret = v4l2_subdev_open(entity); - if (ret < 0) - return ret; - - memset(&ival, 0, sizeof(ival)); - ival.interval = *interval; - - ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &ival); - if (ret < 0) - return -errno; - - *interval = ival.interval; - return 0; -} diff --git a/src/subdev.h b/src/subdev.h deleted file mode 100644 index b5772e0..0000000 --- a/src/subdev.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Media controller test application - * - * Copyright (C) 2010 Ideas on board SPRL - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - */ - -#ifndef __SUBDEV_H__ -#define __SUBDEV_H__ - -#include - -struct media_entity; - -/** - * @brief Open a sub-device. - * @param entity - sub-device media entity. - * - * Open the V4L2 subdev device node associated with @a entity. The file - * descriptor is stored in the media_entity structure. - * - * @return 0 on success, or a negative error code on failure. - */ -int v4l2_subdev_open(struct media_entity *entity); - -/** - * @brief Close a sub-device. - * @param entity - sub-device media entity. - * - * Close the V4L2 subdev device node associated with the @a entity and opened by - * a previous call to v4l2_subdev_open() (either explicit or implicit). - */ -void v4l2_subdev_close(struct media_entity *entity); - -/** - * @brief Retrieve the format on a pad. - * @param entity - subdev-device media entity. - * @param format - format to be filled. - * @param pad - pad number. - * @param which - identifier of the format to get. - * - * Retrieve the current format on the @a entity @a pad and store it in the - * @a format structure. - * - * @a which is set to V4L2_SUBDEV_FORMAT_TRY to retrieve the try format stored - * in the file handle, of V4L2_SUBDEV_FORMAT_ACTIVE to retrieve the current - * active format. - * - * @return 0 on success, or a negative error code on failure. - */ -int v4l2_subdev_get_format(struct media_entity *entity, - struct v4l2_mbus_framefmt *format, unsigned int pad, - enum v4l2_subdev_format_whence which); - -/** - * @brief Set the format on a pad. - * @param entity - subdev-device media entity. - * @param format - format. - * @param pad - pad number. - * @param which - identifier of the format to set. - * - * Set the format on the @a entity @a pad to @a format. The driver is allowed to - * modify the requested format, in which case @a format is updated with the - * modifications. - * - * @a which is set to V4L2_SUBDEV_FORMAT_TRY to set the try format stored in the - * file handle, of V4L2_SUBDEV_FORMAT_ACTIVE to configure the device with an - * active format. - * - * @return 0 on success, or a negative error code on failure. - */ -int v4l2_subdev_set_format(struct media_entity *entity, - struct v4l2_mbus_framefmt *format, unsigned int pad, - enum v4l2_subdev_format_whence which); - -/** - * @brief Retrieve the crop rectangle on a pad. - * @param entity - subdev-device media entity. - * @param rect - crop rectangle to be filled. - * @param pad - pad number. - * @param which - identifier of the format to get. - * - * Retrieve the current crop rectangleon the @a entity @a pad and store it in - * the @a rect structure. - * - * @a which is set to V4L2_SUBDEV_FORMAT_TRY to retrieve the try crop rectangle - * stored in the file handle, of V4L2_SUBDEV_FORMAT_ACTIVE to retrieve the - * current active crop rectangle. - * - * @return 0 on success, or a negative error code on failure. - */ -int v4l2_subdev_get_crop(struct media_entity *entity, struct v4l2_rect *rect, - unsigned int pad, enum v4l2_subdev_format_whence which); - -/** - * @brief Set the crop rectangle on a pad. - * @param entity - subdev-device media entity. - * @param rect - crop rectangle. - * @param pad - pad number. - * @param which - identifier of the format to set. - * - * Set the crop rectangle on the @a entity @a pad to @a rect. The driver is - * allowed to modify the requested rectangle, in which case @a rect is updated - * with the modifications. - * - * @a which is set to V4L2_SUBDEV_FORMAT_TRY to set the try crop rectangle - * stored in the file handle, of V4L2_SUBDEV_FORMAT_ACTIVE to configure the - * device with an active crop rectangle. - * - * @return 0 on success, or a negative error code on failure. - */ -int v4l2_subdev_set_crop(struct media_entity *entity, struct v4l2_rect *rect, - unsigned int pad, enum v4l2_subdev_format_whence which); - -/** - * @brief Retrieve the frame interval on a sub-device. - * @param entity - subdev-device media entity. - * @param interval - frame interval to be filled. - * - * Retrieve the current frame interval on subdev @a entity and store it in the - * @a interval structure. - * - * Frame interval retrieving is usually supported only on devices at the - * beginning of video pipelines, such as sensors. - * - * @return 0 on success, or a negative error code on failure. - */ - -int v4l2_subdev_get_frame_interval(struct media_entity *entity, - struct v4l2_fract *interval); - -/** - * @brief Set the frame interval on a sub-device. - * @param entity - subdev-device media entity. - * @param interval - frame interval. - * - * Set the frame interval on subdev @a entity to @a interval. The driver is - * allowed to modify the requested frame interval, in which case @a interval is - * updated with the modifications. - * - * Frame interval setting is usually supported only on devices at the beginning - * of video pipelines, such as sensors. - * - * @return 0 on success, or a negative error code on failure. - */ -int v4l2_subdev_set_frame_interval(struct media_entity *entity, - struct v4l2_fract *interval); - -#endif - diff --git a/src/v4l2subdev.c b/src/v4l2subdev.c new file mode 100644 index 0000000..785209b --- /dev/null +++ b/src/v4l2subdev.c @@ -0,0 +1,188 @@ +/* + * Media controller test application + * + * Copyright (C) 2010 Ideas on board SPRL + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "mediactl.h" +#include "v4l2subdev.h" +#include "tools.h" + +int v4l2_subdev_open(struct media_entity *entity) +{ + if (entity->fd != -1) + return 0; + + entity->fd = open(entity->devname, O_RDWR); + if (entity->fd == -1) { + printf("%s: Failed to open subdev device node %s\n", __func__, + entity->devname); + return -errno; + } + + return 0; +} + +void v4l2_subdev_close(struct media_entity *entity) +{ + close(entity->fd); + entity->fd = -1; +} + +int v4l2_subdev_get_format(struct media_entity *entity, + struct v4l2_mbus_framefmt *format, unsigned int pad, + enum v4l2_subdev_format_whence which) +{ + struct v4l2_subdev_format fmt; + int ret; + + ret = v4l2_subdev_open(entity); + if (ret < 0) + return ret; + + memset(&fmt, 0, sizeof(fmt)); + fmt.pad = pad; + fmt.which = which; + + ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_FMT, &fmt); + if (ret < 0) + return -errno; + + *format = fmt.format; + return 0; +} + +int v4l2_subdev_set_format(struct media_entity *entity, + struct v4l2_mbus_framefmt *format, unsigned int pad, + enum v4l2_subdev_format_whence which) +{ + struct v4l2_subdev_format fmt; + int ret; + + ret = v4l2_subdev_open(entity); + if (ret < 0) + return ret; + + memset(&fmt, 0, sizeof(fmt)); + fmt.pad = pad; + fmt.which = which; + fmt.format = *format; + + ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_FMT, &fmt); + if (ret < 0) + return -errno; + + *format = fmt.format; + return 0; +} + +int v4l2_subdev_get_crop(struct media_entity *entity, struct v4l2_rect *rect, + unsigned int pad, enum v4l2_subdev_format_whence which) +{ + struct v4l2_subdev_crop crop; + int ret; + + ret = v4l2_subdev_open(entity); + if (ret < 0) + return ret; + + memset(&crop, 0, sizeof(crop)); + crop.pad = pad; + crop.which = which; + + ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_CROP, &crop); + if (ret < 0) + return -errno; + + *rect = crop.rect; + return 0; +} + +int v4l2_subdev_set_crop(struct media_entity *entity, struct v4l2_rect *rect, + unsigned int pad, enum v4l2_subdev_format_whence which) +{ + struct v4l2_subdev_crop crop; + int ret; + + ret = v4l2_subdev_open(entity); + if (ret < 0) + return ret; + + memset(&crop, 0, sizeof(crop)); + crop.pad = pad; + crop.which = which; + crop.rect = *rect; + + ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_CROP, &crop); + if (ret < 0) + return -errno; + + *rect = crop.rect; + return 0; +} + +int v4l2_subdev_get_frame_interval(struct media_entity *entity, + struct v4l2_fract *interval) +{ + struct v4l2_subdev_frame_interval ival; + int ret; + + ret = v4l2_subdev_open(entity); + if (ret < 0) + return ret; + + memset(&ival, 0, sizeof(ival)); + + ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_FRAME_INTERVAL, &ival); + if (ret < 0) + return -errno; + + *interval = ival.interval; + return 0; +} + +int v4l2_subdev_set_frame_interval(struct media_entity *entity, + struct v4l2_fract *interval) +{ + struct v4l2_subdev_frame_interval ival; + int ret; + + ret = v4l2_subdev_open(entity); + if (ret < 0) + return ret; + + memset(&ival, 0, sizeof(ival)); + ival.interval = *interval; + + ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &ival); + if (ret < 0) + return -errno; + + *interval = ival.interval; + return 0; +} diff --git a/src/v4l2subdev.h b/src/v4l2subdev.h new file mode 100644 index 0000000..37cae08 --- /dev/null +++ b/src/v4l2subdev.h @@ -0,0 +1,161 @@ +/* + * Media controller test application + * + * Copyright (C) 2010 Ideas on board SPRL + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + */ + +#ifndef __SUBDEV_H__ +#define __SUBDEV_H__ + +#include + +struct media_entity; + +/** + * @brief Open a sub-device. + * @param entity - sub-device media entity. + * + * Open the V4L2 subdev device node associated with @a entity. The file + * descriptor is stored in the media_entity structure. + * + * @return 0 on success, or a negative error code on failure. + */ +int v4l2_subdev_open(struct media_entity *entity); + +/** + * @brief Close a sub-device. + * @param entity - sub-device media entity. + * + * Close the V4L2 subdev device node associated with the @a entity and opened by + * a previous call to v4l2_subdev_open() (either explicit or implicit). + */ +void v4l2_subdev_close(struct media_entity *entity); + +/** + * @brief Retrieve the format on a pad. + * @param entity - subdev-device media entity. + * @param format - format to be filled. + * @param pad - pad number. + * @param which - identifier of the format to get. + * + * Retrieve the current format on the @a entity @a pad and store it in the + * @a format structure. + * + * @a which is set to V4L2_SUBDEV_FORMAT_TRY to retrieve the try format stored + * in the file handle, of V4L2_SUBDEV_FORMAT_ACTIVE to retrieve the current + * active format. + * + * @return 0 on success, or a negative error code on failure. + */ +int v4l2_subdev_get_format(struct media_entity *entity, + struct v4l2_mbus_framefmt *format, unsigned int pad, + enum v4l2_subdev_format_whence which); + +/** + * @brief Set the format on a pad. + * @param entity - subdev-device media entity. + * @param format - format. + * @param pad - pad number. + * @param which - identifier of the format to set. + * + * Set the format on the @a entity @a pad to @a format. The driver is allowed to + * modify the requested format, in which case @a format is updated with the + * modifications. + * + * @a which is set to V4L2_SUBDEV_FORMAT_TRY to set the try format stored in the + * file handle, of V4L2_SUBDEV_FORMAT_ACTIVE to configure the device with an + * active format. + * + * @return 0 on success, or a negative error code on failure. + */ +int v4l2_subdev_set_format(struct media_entity *entity, + struct v4l2_mbus_framefmt *format, unsigned int pad, + enum v4l2_subdev_format_whence which); + +/** + * @brief Retrieve the crop rectangle on a pad. + * @param entity - subdev-device media entity. + * @param rect - crop rectangle to be filled. + * @param pad - pad number. + * @param which - identifier of the format to get. + * + * Retrieve the current crop rectangleon the @a entity @a pad and store it in + * the @a rect structure. + * + * @a which is set to V4L2_SUBDEV_FORMAT_TRY to retrieve the try crop rectangle + * stored in the file handle, of V4L2_SUBDEV_FORMAT_ACTIVE to retrieve the + * current active crop rectangle. + * + * @return 0 on success, or a negative error code on failure. + */ +int v4l2_subdev_get_crop(struct media_entity *entity, struct v4l2_rect *rect, + unsigned int pad, enum v4l2_subdev_format_whence which); + +/** + * @brief Set the crop rectangle on a pad. + * @param entity - subdev-device media entity. + * @param rect - crop rectangle. + * @param pad - pad number. + * @param which - identifier of the format to set. + * + * Set the crop rectangle on the @a entity @a pad to @a rect. The driver is + * allowed to modify the requested rectangle, in which case @a rect is updated + * with the modifications. + * + * @a which is set to V4L2_SUBDEV_FORMAT_TRY to set the try crop rectangle + * stored in the file handle, of V4L2_SUBDEV_FORMAT_ACTIVE to configure the + * device with an active crop rectangle. + * + * @return 0 on success, or a negative error code on failure. + */ +int v4l2_subdev_set_crop(struct media_entity *entity, struct v4l2_rect *rect, + unsigned int pad, enum v4l2_subdev_format_whence which); + +/** + * @brief Retrieve the frame interval on a sub-device. + * @param entity - subdev-device media entity. + * @param interval - frame interval to be filled. + * + * Retrieve the current frame interval on subdev @a entity and store it in the + * @a interval structure. + * + * Frame interval retrieving is usually supported only on devices at the + * beginning of video pipelines, such as sensors. + * + * @return 0 on success, or a negative error code on failure. + */ + +int v4l2_subdev_get_frame_interval(struct media_entity *entity, + struct v4l2_fract *interval); + +/** + * @brief Set the frame interval on a sub-device. + * @param entity - subdev-device media entity. + * @param interval - frame interval. + * + * Set the frame interval on subdev @a entity to @a interval. The driver is + * allowed to modify the requested frame interval, in which case @a interval is + * updated with the modifications. + * + * Frame interval setting is usually supported only on devices at the beginning + * of video pipelines, such as sensors. + * + * @return 0 on success, or a negative error code on failure. + */ +int v4l2_subdev_set_frame_interval(struct media_entity *entity, + struct v4l2_fract *interval); + +#endif -- cgit v1.2.3