diff options
Diffstat (limited to 'isp/stats.c')
-rw-r--r-- | isp/stats.c | 274 |
1 files changed, 246 insertions, 28 deletions
diff --git a/isp/stats.c b/isp/stats.c index a96da5e..4ff11a9 100644 --- a/isp/stats.c +++ b/isp/stats.c @@ -278,32 +278,7 @@ int omap3_isp_aewb_configure(struct omap3_isp_device *isp, struct v4l2_rect *rec return 0; } -/* ----------------------------------------------------------------------------- - * Start/stop, init/cleanup - */ - -int omap3_isp_stats_get_format(struct omap3_isp_device *isp, - struct v4l2_mbus_framefmt *format) -{ - struct omap3_isp_aewb *aewb = &isp->aewb; - struct media_entity_pad *source; - - source = media_entity_remote_source(&aewb->entity->pads[0]); - if (source == NULL) - return -ENOENT; - - return v4l2_subdev_get_format(source->entity, format, source->index, - V4L2_SUBDEV_FORMAT_TRY); -} - -void omap3_isp_stats_enable(struct omap3_isp_device *isp, bool enable) -{ - struct omap3_isp_aewb *aewb = &isp->aewb; - - aewb->enabled = enable; -} - -int omap3_isp_stats_start(struct omap3_isp_device *isp) +static int omap3_isp_aewb_start(struct omap3_isp_device *isp) { struct omap3_isp_aewb *aewb = &isp->aewb; struct v4l2_event_subscription esub; @@ -342,7 +317,7 @@ int omap3_isp_stats_start(struct omap3_isp_device *isp) return 0; } -void omap3_isp_stats_stop(struct omap3_isp_device *isp) +static void omap3_isp_aewb_stop(struct omap3_isp_device *isp) { struct omap3_isp_aewb *aewb = &isp->aewb; struct v4l2_event_subscription esub; @@ -359,7 +334,7 @@ void omap3_isp_stats_stop(struct omap3_isp_device *isp) ioctl(aewb->entity->fd, VIDIOC_UNSUBSCRIBE_EVENT, &esub); } -int omap3_isp_stats_init(struct omap3_isp_device *isp) +static int omap3_isp_aewb_init(struct omap3_isp_device *isp) { struct omap3_isp_aewb *aewb = &isp->aewb; @@ -370,7 +345,250 @@ int omap3_isp_stats_init(struct omap3_isp_device *isp) return v4l2_subdev_open(aewb->entity); } +/* ----------------------------------------------------------------------------- + * Histogram + */ + +static void omap3_isp_histogram_process(struct omap3_isp_device *isp, + void *buffer, + size_t size __attribute__((__unused__))) +{ + struct omap3_isp_histogram_stats stats; + + memset(&stats, 0, sizeof stats); + stats.nbins = 256; + stats.bins = (uint32_t *)buffer; + + isp->ops->histogram_ready(isp, &stats); +} + +static void omap3_isp_histogram_event(void *priv) +{ + struct omap3_isp_device *isp = priv; + struct omap3_isp_histogram *hist = &isp->hist; + struct omap3isp_stat_data data; + struct v4l2_event event; + struct omap3isp_stat_event_status *status = + (struct omap3isp_stat_event_status *)event.u.data; + int ret; + + memset(&event, 0, sizeof event); + ret = ioctl(hist->entity->fd, VIDIOC_DQEVENT, &event); + if (ret < 0) { + printf("unable to retrieve histogram event: %s (%d).\n", + strerror(errno), errno); + return; + } + + if (status->buf_err) { + printf("histogram: stats error, skipping buffer.\n"); + return; + } + + memset(&data, 0, sizeof data); + data.buf = hist->buffer; + data.buf_size = hist->size; + + ret = ioctl(hist->entity->fd, VIDIOC_OMAP3ISP_STAT_REQ, &data); + if (ret < 0) { + printf("unable to retrieve histogram data: %s (%d).\n", + strerror(errno), errno); + return; + } + + omap3_isp_histogram_process(isp, data.buf, data.buf_size); +} + +static int omap3_isp_histogram_setup(struct omap3_isp_device *isp) +{ + struct omap3_isp_histogram *hist = &isp->hist; + struct omap3isp_hist_config config; + unsigned int buf_size; + int ret; + + memset(&config, 0, sizeof config); + config.num_acc_frames = 1; + config.hist_bins = OMAP3ISP_HIST_BINS_256; + config.cfa = OMAP3ISP_HIST_CFA_BAYER; + config.wg[0] = 1 << 5; + config.wg[1] = 1 << 5; + config.wg[2] = 1 << 5; + config.wg[3] = 1 << 5; + config.num_regions = 1; + config.region[0].h_start = hist->rect.left; + config.region[0].h_end = hist->rect.left + hist->rect.width - 1; + config.region[0].v_start = hist->rect.top; + config.region[0].v_end = hist->rect.top + hist->rect.height - 1; + + buf_size = OMAP3ISP_HIST_MEM_SIZE_BINS(config.hist_bins) + * config.num_regions; + config.buf_size = buf_size; + + ret = ioctl(hist->entity->fd, VIDIOC_OMAP3ISP_HIST_CFG, &config); + if (ret < 0) + return -errno; + + if (config.buf_size != buf_size) + printf("histogram: buf size was %u, is %u\n", buf_size, + config.buf_size); + + hist->size = config.buf_size; + hist->buffer = malloc(config.buf_size); + if (hist->buffer == NULL) + return -ENOMEM; + + return 0; +} + +int omap3_isp_histogram_configure(struct omap3_isp_device *isp, + struct v4l2_rect *rect) +{ + struct omap3_isp_histogram *hist = &isp->hist; + struct v4l2_mbus_framefmt format; + struct media_entity_pad *source; + int ret; + + source = media_entity_remote_source(&hist->entity->pads[0]); + if (source == NULL) + return -ENOENT; + + ret = v4l2_subdev_get_format(source->entity, &format, source->index, + V4L2_SUBDEV_FORMAT_TRY); + if (ret < 0) + return ret; + + /* Validate the requested rectangle. */ + if (rect->left < 0 || rect->left + rect->width > (int)format.width || + rect->top < 0 || rect->top + rect->height > (int)format.height) + return -ERANGE; + + hist->rect = *rect; + + return 0; +} + +static int omap3_isp_histogram_start(struct omap3_isp_device *isp) +{ + struct omap3_isp_histogram *hist = &isp->hist; + struct v4l2_event_subscription esub; + unsigned long enable = 1; + int ret; + + if (!hist->enabled) + return 0; + + ret = omap3_isp_histogram_setup(isp); + if (ret < 0) { + printf("unable to configure histogram engine: %s (%d).\n", + strerror(errno), errno); + return ret; + } + + memset(&esub, 0, sizeof esub); + esub.type = V4L2_EVENT_OMAP3ISP_HIST; + ret = ioctl(hist->entity->fd, VIDIOC_SUBSCRIBE_EVENT, &esub); + if (ret < 0) { + printf("unable to subscribe to histogram event: %s (%d).\n", + strerror(errno), errno); + return ret; + } + + ret = ioctl(hist->entity->fd, VIDIOC_OMAP3ISP_STAT_EN, &enable); + if (ret < 0) { + printf("unable to start histogram engine: %s (%d).\n", + strerror(errno), errno); + return ret; + } + + isp->ops->watch_fd(hist->entity->fd, OMAP3_ISP_EVENT_EXCEPTION, + omap3_isp_histogram_event, isp); + + return 0; +} + +static void omap3_isp_histogram_stop(struct omap3_isp_device *isp) +{ + struct omap3_isp_histogram *hist = &isp->hist; + struct v4l2_event_subscription esub; + unsigned long enable = 0; + + if (!hist->enabled) + return; + + isp->ops->unwatch_fd(hist->entity->fd); + ioctl(hist->entity->fd, VIDIOC_OMAP3ISP_STAT_EN, &enable); + + memset(&esub, 0, sizeof esub); + esub.type = V4L2_EVENT_OMAP3ISP_HIST; + ioctl(hist->entity->fd, VIDIOC_UNSUBSCRIBE_EVENT, &esub); +} + +static int omap3_isp_histogram_init(struct omap3_isp_device *isp) +{ + struct omap3_isp_histogram *hist = &isp->hist; + + hist->entity = media_get_entity_by_name(isp->mdev, "OMAP3 ISP histogram"); + if (hist->entity == NULL) + return -ENOENT; + + return v4l2_subdev_open(hist->entity); +} + +/* ----------------------------------------------------------------------------- + * Start/stop, init/cleanup + */ + +int omap3_isp_stats_get_format(struct omap3_isp_device *isp, + struct v4l2_mbus_framefmt *format) +{ + struct omap3_isp_aewb *aewb = &isp->aewb; + struct media_entity_pad *source; + + source = media_entity_remote_source(&aewb->entity->pads[0]); + if (source == NULL) + return -ENOENT; + + return v4l2_subdev_get_format(source->entity, format, source->index, + V4L2_SUBDEV_FORMAT_TRY); +} + +void omap3_isp_stats_enable(struct omap3_isp_device *isp, + enum omap3_isp_stat_engine which) +{ + isp->aewb.enabled = !!(which & OMAP3_ISP_STAT_AEWB); + isp->hist.enabled = !!(which & OMAP3_ISP_STAT_HIST); +} + +int omap3_isp_stats_start(struct omap3_isp_device *isp) +{ + int ret; + + ret = omap3_isp_aewb_start(isp); + if (ret < 0) + return ret; + + return omap3_isp_histogram_start(isp); +} + +void omap3_isp_stats_stop(struct omap3_isp_device *isp) +{ + omap3_isp_aewb_stop(isp); + omap3_isp_histogram_stop(isp); +} + +int omap3_isp_stats_init(struct omap3_isp_device *isp) +{ + int ret; + + ret = omap3_isp_aewb_init(isp); + if (ret < 0) + return ret; + + return omap3_isp_histogram_init(isp); +} + void omap3_isp_stats_cleanup(struct omap3_isp_device *isp) { v4l2_subdev_close(isp->aewb.entity); + v4l2_subdev_close(isp->hist.entity); } |