media: vimc: sensor: Use subdev active state
Store the active formats and crop rectangle in the subdevice active state. This simplifies implementation of the format and selection accessors, and allows using the v4l2_subdev_get_fmt() helper to implement the .get_fmt() operation. The active configuration that is used in the .process_frame() handler is still stored in the vimc_sensor_device structure. The driver could instead access the active state in the .process_frame() handler, but the required locking could interfere with the real time constraints of the frame processing. This data would be stored in registers in the .s_stream() handler for real hardware, storing it in dedicated storage thus mimics a real driver. To differentiate them from the rest of the device private data, move the corresponding fields to a sub-structure of vimc_sensor_device named hw. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Shuah Khan <skhan@linuxfoundation.org> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
This commit is contained in:
parent
b3f73b2188
commit
cf2552d87a
@ -24,13 +24,20 @@ struct vimc_sensor_device {
|
||||
struct vimc_ent_device ved;
|
||||
struct v4l2_subdev sd;
|
||||
struct tpg_data tpg;
|
||||
u8 *frame;
|
||||
enum vimc_sensor_osd_mode osd_value;
|
||||
u64 start_stream_ts;
|
||||
/* The active format */
|
||||
struct v4l2_mbus_framefmt mbus_format;
|
||||
struct v4l2_ctrl_handler hdl;
|
||||
struct media_pad pad;
|
||||
|
||||
u8 *frame;
|
||||
|
||||
/*
|
||||
* Virtual "hardware" configuration, filled when the stream starts or
|
||||
* when controls are set.
|
||||
*/
|
||||
struct {
|
||||
struct v4l2_area size;
|
||||
enum vimc_sensor_osd_mode osd_value;
|
||||
u64 start_stream_ts;
|
||||
} hw;
|
||||
};
|
||||
|
||||
static const struct v4l2_mbus_framefmt fmt_default = {
|
||||
@ -88,36 +95,22 @@ static int vimc_sensor_enum_frame_size(struct v4l2_subdev *sd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vimc_sensor_get_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
static void vimc_sensor_tpg_s_format(struct vimc_sensor_device *vsensor,
|
||||
const struct v4l2_mbus_framefmt *format)
|
||||
{
|
||||
struct vimc_sensor_device *vsensor =
|
||||
container_of(sd, struct vimc_sensor_device, sd);
|
||||
const struct vimc_pix_map *vpix = vimc_pix_map_by_code(format->code);
|
||||
|
||||
fmt->format = fmt->which == V4L2_SUBDEV_FORMAT_TRY ?
|
||||
*v4l2_subdev_state_get_format(sd_state, fmt->pad) :
|
||||
vsensor->mbus_format;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vimc_sensor_tpg_s_format(struct vimc_sensor_device *vsensor)
|
||||
{
|
||||
const struct vimc_pix_map *vpix =
|
||||
vimc_pix_map_by_code(vsensor->mbus_format.code);
|
||||
|
||||
tpg_reset_source(&vsensor->tpg, vsensor->mbus_format.width,
|
||||
vsensor->mbus_format.height, vsensor->mbus_format.field);
|
||||
tpg_s_bytesperline(&vsensor->tpg, 0, vsensor->mbus_format.width * vpix->bpp);
|
||||
tpg_s_buf_height(&vsensor->tpg, vsensor->mbus_format.height);
|
||||
tpg_reset_source(&vsensor->tpg, format->width, format->height,
|
||||
format->field);
|
||||
tpg_s_bytesperline(&vsensor->tpg, 0, format->width * vpix->bpp);
|
||||
tpg_s_buf_height(&vsensor->tpg, format->height);
|
||||
tpg_s_fourcc(&vsensor->tpg, vpix->pixelformat);
|
||||
/* TODO: add support for V4L2_FIELD_ALTERNATE */
|
||||
tpg_s_field(&vsensor->tpg, vsensor->mbus_format.field, false);
|
||||
tpg_s_colorspace(&vsensor->tpg, vsensor->mbus_format.colorspace);
|
||||
tpg_s_ycbcr_enc(&vsensor->tpg, vsensor->mbus_format.ycbcr_enc);
|
||||
tpg_s_quantization(&vsensor->tpg, vsensor->mbus_format.quantization);
|
||||
tpg_s_xfer_func(&vsensor->tpg, vsensor->mbus_format.xfer_func);
|
||||
tpg_s_field(&vsensor->tpg, format->field, false);
|
||||
tpg_s_colorspace(&vsensor->tpg, format->colorspace);
|
||||
tpg_s_ycbcr_enc(&vsensor->tpg, format->ycbcr_enc);
|
||||
tpg_s_quantization(&vsensor->tpg, format->quantization);
|
||||
tpg_s_xfer_func(&vsensor->tpg, format->xfer_func);
|
||||
}
|
||||
|
||||
static void vimc_sensor_adjust_fmt(struct v4l2_mbus_framefmt *fmt)
|
||||
@ -148,15 +141,11 @@ static int vimc_sensor_set_fmt(struct v4l2_subdev *sd,
|
||||
struct vimc_sensor_device *vsensor = v4l2_get_subdevdata(sd);
|
||||
struct v4l2_mbus_framefmt *mf;
|
||||
|
||||
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
|
||||
/* Do not change the format while stream is on */
|
||||
if (vsensor->frame)
|
||||
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE && vsensor->frame)
|
||||
return -EBUSY;
|
||||
|
||||
mf = &vsensor->mbus_format;
|
||||
} else {
|
||||
mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
|
||||
}
|
||||
|
||||
/* Set the new format */
|
||||
vimc_sensor_adjust_fmt(&fmt->format);
|
||||
@ -181,7 +170,7 @@ static int vimc_sensor_set_fmt(struct v4l2_subdev *sd,
|
||||
static const struct v4l2_subdev_pad_ops vimc_sensor_pad_ops = {
|
||||
.enum_mbus_code = vimc_sensor_enum_mbus_code,
|
||||
.enum_frame_size = vimc_sensor_enum_frame_size,
|
||||
.get_fmt = vimc_sensor_get_fmt,
|
||||
.get_fmt = v4l2_subdev_get_fmt,
|
||||
.set_fmt = vimc_sensor_set_fmt,
|
||||
};
|
||||
|
||||
@ -198,7 +187,7 @@ static void *vimc_sensor_process_frame(struct vimc_ent_device *ved,
|
||||
|
||||
tpg_fill_plane_buffer(&vsensor->tpg, 0, 0, vsensor->frame);
|
||||
tpg_calc_text_basep(&vsensor->tpg, basep, 0, vsensor->frame);
|
||||
switch (vsensor->osd_value) {
|
||||
switch (vsensor->hw.osd_value) {
|
||||
case VIMC_SENSOR_OSD_SHOW_ALL: {
|
||||
const char *order = tpg_g_color_order(&vsensor->tpg);
|
||||
|
||||
@ -212,15 +201,14 @@ static void *vimc_sensor_process_frame(struct vimc_ent_device *ved,
|
||||
vsensor->tpg.hue);
|
||||
tpg_gen_text(&vsensor->tpg, basep, line++ * line_height, 16, str);
|
||||
snprintf(str, sizeof(str), "sensor size: %dx%d",
|
||||
vsensor->mbus_format.width,
|
||||
vsensor->mbus_format.height);
|
||||
vsensor->hw.size.width, vsensor->hw.size.height);
|
||||
tpg_gen_text(&vsensor->tpg, basep, line++ * line_height, 16, str);
|
||||
fallthrough;
|
||||
}
|
||||
case VIMC_SENSOR_OSD_SHOW_COUNTERS: {
|
||||
unsigned int ms;
|
||||
|
||||
ms = div_u64(ktime_get_ns() - vsensor->start_stream_ts, 1000000);
|
||||
ms = div_u64(ktime_get_ns() - vsensor->hw.start_stream_ts, 1000000);
|
||||
snprintf(str, sizeof(str), "%02d:%02d:%02d:%03d",
|
||||
(ms / (60 * 60 * 1000)) % 24,
|
||||
(ms / (60 * 1000)) % 60,
|
||||
@ -243,15 +231,25 @@ static int vimc_sensor_s_stream(struct v4l2_subdev *sd, int enable)
|
||||
container_of(sd, struct vimc_sensor_device, sd);
|
||||
|
||||
if (enable) {
|
||||
const struct v4l2_mbus_framefmt *format;
|
||||
struct v4l2_subdev_state *state;
|
||||
const struct vimc_pix_map *vpix;
|
||||
unsigned int frame_size;
|
||||
|
||||
vsensor->start_stream_ts = ktime_get_ns();
|
||||
state = v4l2_subdev_lock_and_get_active_state(sd);
|
||||
format = v4l2_subdev_state_get_format(state, 0);
|
||||
|
||||
/* Calculate the frame size */
|
||||
vpix = vimc_pix_map_by_code(vsensor->mbus_format.code);
|
||||
frame_size = vsensor->mbus_format.width * vpix->bpp *
|
||||
vsensor->mbus_format.height;
|
||||
/* Configure the test pattern generator. */
|
||||
vimc_sensor_tpg_s_format(vsensor, format);
|
||||
|
||||
/* Calculate the frame size. */
|
||||
vpix = vimc_pix_map_by_code(format->code);
|
||||
frame_size = format->width * vpix->bpp * format->height;
|
||||
|
||||
vsensor->hw.size.width = format->width;
|
||||
vsensor->hw.size.height = format->height;
|
||||
|
||||
v4l2_subdev_unlock_state(state);
|
||||
|
||||
/*
|
||||
* Allocate the frame buffer. Use vmalloc to be able to
|
||||
@ -261,9 +259,7 @@ static int vimc_sensor_s_stream(struct v4l2_subdev *sd, int enable)
|
||||
if (!vsensor->frame)
|
||||
return -ENOMEM;
|
||||
|
||||
/* configure the test pattern generator */
|
||||
vimc_sensor_tpg_s_format(vsensor);
|
||||
|
||||
vsensor->hw.start_stream_ts = ktime_get_ns();
|
||||
} else {
|
||||
|
||||
vfree(vsensor->frame);
|
||||
@ -321,7 +317,7 @@ static int vimc_sensor_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||
tpg_s_saturation(&vsensor->tpg, ctrl->val);
|
||||
break;
|
||||
case VIMC_CID_OSD_TEXT_MODE:
|
||||
vsensor->osd_value = ctrl->val;
|
||||
vsensor->hw.osd_value = ctrl->val;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@ -414,8 +410,7 @@ static struct vimc_ent_device *vimc_sensor_add(struct vimc_device *vimc,
|
||||
}
|
||||
|
||||
/* Initialize the test pattern generator */
|
||||
tpg_init(&vsensor->tpg, vsensor->mbus_format.width,
|
||||
vsensor->mbus_format.height);
|
||||
tpg_init(&vsensor->tpg, fmt_default.width, fmt_default.height);
|
||||
ret = tpg_alloc(&vsensor->tpg, VIMC_FRAME_MAX_WIDTH);
|
||||
if (ret)
|
||||
goto err_free_hdl;
|
||||
@ -432,9 +427,6 @@ static struct vimc_ent_device *vimc_sensor_add(struct vimc_device *vimc,
|
||||
vsensor->ved.process_frame = vimc_sensor_process_frame;
|
||||
vsensor->ved.dev = vimc->mdev.dev;
|
||||
|
||||
/* Initialize the frame format */
|
||||
vsensor->mbus_format = fmt_default;
|
||||
|
||||
return &vsensor->ved;
|
||||
|
||||
err_free_tpg:
|
||||
|
Loading…
Reference in New Issue
Block a user