/* Get buffer to userspace. */ static struct ispstat_buffer *isp_stat_buf_get(struct ispstat *stat, struct omap3isp_stat_data *data) { int rval = 0; unsigned long flags; struct ispstat_buffer *buf; spin_lock_irqsave(&stat->isp->stat_lock, flags); while (1) { buf = isp_stat_buf_find_oldest(stat); if (!buf) { spin_unlock_irqrestore(&stat->isp->stat_lock, flags); dev_dbg(stat->isp->dev, "%s: cannot find a buffer.\n", stat->subdev.name); return ERR_PTR(-EBUSY); } if (isp_stat_buf_check_magic(stat, buf)) { dev_dbg(stat->isp->dev, "%s: current buffer has corrupted data\n.", stat->subdev.name); /* Mark empty because it doesn't have valid data. */ buf->empty = 1; } else { /* Buffer isn't corrupted. */ break; } } stat->locked_buf = buf; spin_unlock_irqrestore(&stat->isp->stat_lock, flags); if (buf->buf_size > data->buf_size) { dev_warn(stat->isp->dev, "%s: userspace's buffer size is not enough.\n", stat->subdev.name); isp_stat_buf_release(stat); return ERR_PTR(-EINVAL); } isp_stat_buf_sync_for_cpu(stat, buf); rval = copy_to_user(data->buf, buf->virt_addr, buf->buf_size); if (rval) { dev_info(stat->isp->dev, "%s: failed copying %d bytes of stat data\n", stat->subdev.name, rval); buf = ERR_PTR(-EFAULT); isp_stat_buf_release(stat); } return buf; }
/* * omap3isp_stat_request_statistics - Request statistics. * @data: Pointer to return statistics data. * * Returns 0 if successful. */ int omap3isp_stat_request_statistics(struct ispstat *stat, struct omap3isp_stat_data *data) { struct ispstat_buffer *buf; if (stat->state != ISPSTAT_ENABLED) { dev_dbg(stat->isp->dev, "%s: engine not enabled.\n", stat->subdev.name); return -EINVAL; } mutex_lock(&stat->ioctl_lock); buf = isp_stat_buf_get(stat, data); if (IS_ERR(buf)) { mutex_unlock(&stat->ioctl_lock); return PTR_ERR(buf); } data->ts.tv_sec = buf->ts.tv_sec; data->ts.tv_usec = buf->ts.tv_nsec / NSEC_PER_USEC; data->config_counter = buf->config_counter; data->frame_number = buf->frame_number; data->buf_size = buf->buf_size; buf->empty = 1; isp_stat_buf_release(stat); mutex_unlock(&stat->ioctl_lock); return 0; }