summaryrefslogtreecommitdiff
path: root/isp/stats.c
diff options
context:
space:
mode:
Diffstat (limited to 'isp/stats.c')
-rw-r--r--isp/stats.c274
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);
}