/* Get buffer to userspace. */ static struct ispstat_buffer *ispstat_buf_get(struct ispstat *stat, struct ispstat_data *data) { int rval = 0; unsigned long flags; struct ispstat_buffer *buf; spin_lock_irqsave(&stat->isp->stat_lock, flags); while (1) { buf = ispstat_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 (ispstat_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); ispstat_buf_release(stat); return ERR_PTR(-EINVAL); } ispstat_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); ispstat_buf_release(stat); } return buf; }
/* * ispstat_request_statistics - Request statistics. * @data: Pointer to return statistics data. * * Returns 0 if successful. */ int ispstat_request_statistics(struct ispstat *stat, struct ispstat_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; } buf = ispstat_buf_get(stat, data); if (IS_ERR(buf)) return PTR_ERR(buf); data->ts = buf->ts; data->config_counter = buf->config_counter; data->frame_number = buf->frame_number; data->buf_size = buf->buf_size; /* * Deprecated. Number of new buffers is always equal to number of * queued events without error flag. By setting it to 0, userspace * won't try to request new buffer without receiving new event. * This field must go away in future. */ data->new_bufs = 0; buf->empty = 1; ispstat_buf_release(stat); return 0; }
/* * This API allows the user to update White Balance gains, as well as * exposure time and analog gain. It is also used to request frame * statistics. */ int isp_af_request_statistics(struct isp_af_device *isp_af, struct isp_af_data *afdata) { struct device *dev = to_device(isp_af); struct ispstat_buffer *buf; if (!isp_af->config.af_config) { dev_dbg(dev, "af: statistics requested while af engine" " is not configured\n"); return -EINVAL; } if (afdata->update & REQUEST_STATISTICS) { buf = ispstat_buf_get(&isp_af->stat, (void *)afdata->af_statistics_buf, afdata->frame_number); if (IS_ERR(buf)) return PTR_ERR(buf); afdata->xtrastats.ts = buf->ts; afdata->config_counter = buf->config_counter; afdata->frame_number = buf->frame_number; ispstat_buf_release(&isp_af->stat); } afdata->curr_frame = isp_af->stat.frame_number; return 0; }
/** * isph3a_aewb_stats_available - Check for stats available of specified frame. * @aewbdata: Pointer to return AE AWB statistics data * * Returns 0 if successful, or -1 if statistics are unavailable. **/ static int isph3a_aewb_get_stats(struct isp_h3a_device *isp_h3a, struct isph3a_aewb_data *aewbdata) { unsigned long irqflags; struct ispstat_buffer *buf; buf = ispstat_buf_get(&isp_h3a->stat, (void *)aewbdata->h3a_aewb_statistics_buf, aewbdata->frame_number); if (IS_ERR(buf)) return PTR_ERR(buf); spin_lock_irqsave(isp_h3a->lock, irqflags); aewbdata->ts = buf->ts; aewbdata->config_counter = buf->config_counter; aewbdata->frame_number = buf->frame_number; spin_unlock_irqrestore(isp_h3a->lock, irqflags); ispstat_buf_release(&isp_h3a->stat); return 0; }
/** * isph3a_aewb_stats_available - Check for stats available of specified frame. * @aewbdata: Pointer to return AE AWB statistics data * * Returns 0 if successful, or -1 if statistics are unavailable. **/ static int isph3a_aewb_get_stats(struct isp_h3a_device *isp_h3a, struct isph3a_aewb_data *aewbdata) { struct ispstat_buffer *buf; buf = ispstat_buf_get(&isp_h3a->stat, (void *)aewbdata->h3a_aewb_statistics_buf, aewbdata->frame_number); if (IS_ERR(buf)) return PTR_ERR(buf); aewbdata->ts = buf->ts; aewbdata->config_counter = buf->config_counter; aewbdata->frame_number = buf->frame_number; ispstat_buf_release(&isp_h3a->stat); return 0; }
/** * ispstat_stats_available - Check for stats available of specified frame. * @aewbdata: Pointer to return AE AWB statistics data * * Returns 0 if successful, or -1 if statistics are unavailable. **/ struct ispstat_buffer *ispstat_buf_get(struct ispstat *stat, void __user *ptr, unsigned int frame_number) { int rval = 0; unsigned long flags; struct ispstat_buffer *buf; spin_lock_irqsave(&stat->lock, flags); buf = ispstat_buf_find(stat, frame_number); if (!buf) { spin_unlock_irqrestore(&stat->lock, flags); dev_dbg(stat->dev, "%s: cannot find requested buffer. " "frame_number = %d\n", stat->tag, frame_number); return ERR_PTR(-EBUSY); } stat->locked_buf = buf; spin_unlock_irqrestore(&stat->lock, flags); rval = copy_to_user((void *)ptr, buf->virt_addr, buf->buf_size); if (rval) { dev_info(stat->dev, "%s: failed copying %d bytes of stat data\n", stat->tag, rval); buf = ERR_PTR(-EFAULT); ispstat_buf_release(stat); } return buf; }