From 7250ca2bc92d75af37d1bb3ff796d6fd7394bba7 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 25 Jul 2011 14:18:11 +0200 Subject: omap3isp: Add transparent buffer pools support Buffers pools can be inserted in a pipeline between a video capture device and a video output device. They will automatically relay buffers from the capture device to the output device in a transparent way. One use case of buffer pools is to work around hardware issues. When the CCDC is directly connected to the preview engine, any ESD-induce noise on the HS or VS signals will make the preview engine loose sync, is it only relies on line counts. Introducing a buffer pool between the CCDC and preview engine work around the issue. This patch only implements buffer pool creation during pipeline build. Signed-off-by: Laurent Pinchart --- isp/omap3isp.c | 207 ++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 161 insertions(+), 46 deletions(-) (limited to 'isp/omap3isp.c') diff --git a/isp/omap3isp.c b/isp/omap3isp.c index be5ea3d..eb90dcd 100644 --- a/isp/omap3isp.c +++ b/isp/omap3isp.c @@ -88,6 +88,17 @@ static __u32 mbus_to_pix(enum v4l2_mbus_pixelcode code) } } +static const char *entity_name(struct omap3_isp_entity *entity) +{ + if (entity == NULL) + return "NULL"; + + if (entity->type == OMAP3_ISP_ENTITY_POOL) + return "POOL"; + + return entity->entity->info.name; +} + /* ----------------------------------------------------------------------------- * Pipeline management */ @@ -95,6 +106,7 @@ static __u32 mbus_to_pix(enum v4l2_mbus_pixelcode code) static void omap3_isp_pipeline_init(struct omap3_isp_pipeline *pipe) { list_init(&pipe->entities); + list_init(&pipe->pools); } static void omap3_isp_pipeline_destroy(struct omap3_isp_pipeline *pipe) @@ -102,10 +114,18 @@ static void omap3_isp_pipeline_destroy(struct omap3_isp_pipeline *pipe) struct omap3_isp_entity *entity; struct omap3_isp_entity *next; struct omap3_isp_video *video; + struct omap3_isp_pool *pool; list_for_each_entry_safe(entity, next, &pipe->entities, list) { list_remove(&entity->list); switch (entity->type) { + case OMAP3_ISP_ENTITY_POOL: + pool = to_omap3_isp_pool(entity); + v4l2_buffers_pool_delete(pool->pool); + list_remove(&pool->list); + free(pool); + break; + case OMAP3_ISP_ENTITY_VIDEO: video = to_omap3_isp_video(entity); v4l2_close(video->video); @@ -119,14 +139,135 @@ static void omap3_isp_pipeline_destroy(struct omap3_isp_pipeline *pipe) } } +static struct omap3_isp_pool * +omap3_isp_pipeline_create_pool(struct omap3_isp_device *isp __attribute__((__unused__)), + const char *name) +{ + struct omap3_isp_pool *pool; + unsigned int nbufs; + char *endp; + + name += 5; + if (*name != '\0') { + if (*name != ':') + return NULL; + + nbufs = strtoul(name + 1, &endp, 10); + if (*endp != '\0') + return NULL; + } + + pool = malloc(sizeof *pool); + if (pool == NULL) + return NULL; + + memset(pool, 0, sizeof *pool); + pool->entity.type = OMAP3_ISP_ENTITY_POOL; + + pool->pool = v4l2_buffers_pool_new(nbufs); + if (pool->pool == NULL) { + free(pool); + return NULL; + } + + return pool; +} + +static struct omap3_isp_entity * +omap3_isp_pipeline_create_entity(struct omap3_isp_device *isp, + const char *name) +{ + struct omap3_isp_entity *entity; + struct omap3_isp_video *video; + struct media_entity *ment; + + ment = media_get_entity_by_name(isp->mdev, name); + if (ment == NULL) + return NULL; + + if (media_entity_type(ment) == MEDIA_ENT_T_DEVNODE) { + video = malloc(sizeof *video); + if (video == NULL) + return NULL; + + memset(video, 0, sizeof *video); + + video->video = v4l2_open(ment->devname); + if (video->video == NULL) { + printf("error: unable to open video device %s\n", + ment->devname); + return NULL; + } + + entity = &video->entity; + entity->type = OMAP3_ISP_ENTITY_VIDEO; + } else { + entity = malloc(sizeof *entity); + if (entity == NULL) + return NULL; + + memset(entity, 0, sizeof *entity); + entity->type = OMAP3_ISP_ENTITY_ENTITY; + } + + entity->entity = ment; + return entity; +} + +static int omap3_isp_pipeline_validate_link(struct omap3_isp_entity *source, + struct omap3_isp_entity *sink) +{ + struct omap3_isp_video *video; + struct omap3_isp_pool *pool; + unsigned int i; + + if (source == NULL) + return 0; + + if (source->type != OMAP3_ISP_ENTITY_POOL && + sink->type != OMAP3_ISP_ENTITY_POOL) { + /* Make sure there's a link between the source and sink + * entities. + */ + for (i = 0; i < source->entity->num_links; ++i) { + if (source->entity->links[i].sink->entity == sink->entity) + break; + } + + if (i == source->entity->num_links) + return -EPIPE; + + /* Store link information in source and sink */ + source->source.link = &source->entity->links[i]; + sink->sink.link = &source->entity->links[i]; + return 0; + } + + if (source->type == OMAP3_ISP_ENTITY_VIDEO && + sink->type == OMAP3_ISP_ENTITY_POOL) { + pool = to_omap3_isp_pool(sink); + video = to_omap3_isp_video(source); + pool->input = video; + return 0; + } + + if (source->type == OMAP3_ISP_ENTITY_POOL && + sink->type == OMAP3_ISP_ENTITY_VIDEO) { + pool = to_omap3_isp_pool(source); + video = to_omap3_isp_video(sink); + pool->output = video; + return 0; + } + + return -EPIPE; +} + static int omap3_isp_pipeline_build(struct omap3_isp_device *isp, struct omap3_isp_pipeline *pipe, ...) { struct omap3_isp_entity *source = NULL; struct omap3_isp_entity *sink; - struct omap3_isp_video *video; - struct media_entity *entity; - unsigned int i; + struct omap3_isp_pool *pool; va_list ap; char *name; int ret; @@ -135,67 +276,41 @@ static int omap3_isp_pipeline_build(struct omap3_isp_device *isp, while ((name = va_arg(ap, char *)) != NULL) { - entity = media_get_entity_by_name(isp->mdev, name); - if (entity == NULL) { - ret = -ENOENT; - goto done; - } + if (strncmp(name, ":POOL", 5) == 0) { + /* The previous entity must be a device node. */ + if (source == NULL || media_entity_type(source->entity) + != MEDIA_ENT_T_DEVNODE) + return -EPIPE; - if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE) { - video = malloc(sizeof *video); - if (video == NULL) { + pool = omap3_isp_pipeline_create_pool(isp, name); + if (pool == NULL) { ret = -ENOMEM; goto done; } - memset(video, 0, sizeof *video); - - video->video = v4l2_open(entity->devname); - if (video->video == NULL) { - printf("error: unable to open video device %s\n", - entity->devname); - ret = -ENXIO; - goto done; - } - - sink = &video->entity; + list_append(&pool->list, &pipe->pools); + sink = &pool->entity; } else { - sink = malloc(sizeof *entity); + sink = omap3_isp_pipeline_create_entity(isp, name); if (sink == NULL) { ret = -ENOMEM; goto done; } - - memset(sink, 0, sizeof *sink); } - sink->entity = entity; - - if (source != NULL) { - /* Make sure there's a link between the source and sink - * entities. - */ - for (i = 0; i < source->entity->num_links; ++i) { - if (source->entity->links[i].sink->entity == sink->entity) - break; - } - - if (i == source->entity->num_links) { - free(sink); - ret = -EPIPE; - goto done; - } + list_append(&sink->list, &pipe->entities); - /* Store link information in source and sink */ - source->source.link = &source->entity->links[i]; - sink->sink.link = &source->entity->links[i]; + ret = omap3_isp_pipeline_validate_link(source, sink); + if (ret < 0) { + printf("No valid link found between %s and %s\n", + entity_name(source), entity_name(sink)); + goto done; } - list_append(&sink->list, &pipe->entities); source = sink; } - if (source == NULL) { + if (source == NULL || source->type != OMAP3_ISP_ENTITY_VIDEO) { ret = -EINVAL; goto done; } -- cgit v1.2.3