@@ -37,6 +37,7 @@
* @codec: codec type
* @buffers: structure of buffer info
* @fw_min_count: minimnum count of buffers needed by fw
+ * @state: instance state
*/
struct iris_inst {
@@ -60,6 +61,7 @@ struct iris_inst {
enum codec_type codec;
struct iris_buffers_info buffers;
u32 fw_min_count;
+ enum iris_inst_state state;
};
#endif
@@ -69,3 +69,89 @@ int iris_change_core_state(struct iris_core *core,
return ret;
}
+
+struct iris_inst_state_change_allow {
+ enum iris_inst_state from;
+ enum iris_inst_state to;
+ enum state_change allow;
+};
+
+static enum state_change iris_allow_inst_state_change(struct iris_inst *inst,
+ enum iris_inst_state req_state)
+{
+ enum state_change allow = STATE_CHANGE_ALLOW;
+ int cnt;
+ static struct iris_inst_state_change_allow state[] = {
+ /* from, to, allow */
+ {IRIS_INST_OPEN, IRIS_INST_OPEN, STATE_CHANGE_IGNORE },
+ {IRIS_INST_OPEN, IRIS_INST_INPUT_STREAMING, STATE_CHANGE_ALLOW },
+ {IRIS_INST_OPEN, IRIS_INST_OUTPUT_STREAMING, STATE_CHANGE_ALLOW },
+ {IRIS_INST_OPEN, IRIS_INST_STREAMING, STATE_CHANGE_DISALLOW },
+ {IRIS_INST_OPEN, IRIS_INST_CLOSE, STATE_CHANGE_ALLOW },
+ {IRIS_INST_OPEN, IRIS_INST_ERROR, STATE_CHANGE_ALLOW },
+
+ {IRIS_INST_INPUT_STREAMING, IRIS_INST_OPEN, STATE_CHANGE_ALLOW },
+ {IRIS_INST_INPUT_STREAMING, IRIS_INST_INPUT_STREAMING, STATE_CHANGE_IGNORE },
+ {IRIS_INST_INPUT_STREAMING, IRIS_INST_OUTPUT_STREAMING, STATE_CHANGE_DISALLOW },
+ {IRIS_INST_INPUT_STREAMING, IRIS_INST_STREAMING, STATE_CHANGE_ALLOW },
+ {IRIS_INST_INPUT_STREAMING, IRIS_INST_CLOSE, STATE_CHANGE_ALLOW },
+ {IRIS_INST_INPUT_STREAMING, IRIS_INST_ERROR, STATE_CHANGE_ALLOW },
+
+ {IRIS_INST_OUTPUT_STREAMING, IRIS_INST_OPEN, STATE_CHANGE_ALLOW },
+ {IRIS_INST_OUTPUT_STREAMING, IRIS_INST_INPUT_STREAMING, STATE_CHANGE_DISALLOW },
+ {IRIS_INST_OUTPUT_STREAMING, IRIS_INST_OUTPUT_STREAMING, STATE_CHANGE_IGNORE },
+ {IRIS_INST_OUTPUT_STREAMING, IRIS_INST_STREAMING, STATE_CHANGE_ALLOW },
+ {IRIS_INST_OUTPUT_STREAMING, IRIS_INST_CLOSE, STATE_CHANGE_ALLOW },
+ {IRIS_INST_OUTPUT_STREAMING, IRIS_INST_ERROR, STATE_CHANGE_ALLOW },
+
+ {IRIS_INST_STREAMING, IRIS_INST_OPEN, STATE_CHANGE_DISALLOW },
+ {IRIS_INST_STREAMING, IRIS_INST_INPUT_STREAMING, STATE_CHANGE_ALLOW },
+ {IRIS_INST_STREAMING, IRIS_INST_OUTPUT_STREAMING, STATE_CHANGE_ALLOW },
+ {IRIS_INST_STREAMING, IRIS_INST_STREAMING, STATE_CHANGE_IGNORE },
+ {IRIS_INST_STREAMING, IRIS_INST_CLOSE, STATE_CHANGE_ALLOW },
+ {IRIS_INST_STREAMING, IRIS_INST_ERROR, STATE_CHANGE_ALLOW },
+
+ {IRIS_INST_CLOSE, IRIS_INST_OPEN, STATE_CHANGE_DISALLOW },
+ {IRIS_INST_CLOSE, IRIS_INST_INPUT_STREAMING, STATE_CHANGE_DISALLOW },
+ {IRIS_INST_CLOSE, IRIS_INST_OUTPUT_STREAMING, STATE_CHANGE_DISALLOW },
+ {IRIS_INST_CLOSE, IRIS_INST_STREAMING, STATE_CHANGE_DISALLOW },
+ {IRIS_INST_CLOSE, IRIS_INST_CLOSE, STATE_CHANGE_IGNORE },
+ {IRIS_INST_CLOSE, IRIS_INST_ERROR, STATE_CHANGE_IGNORE },
+
+ {IRIS_INST_ERROR, IRIS_INST_OPEN, STATE_CHANGE_IGNORE },
+ {IRIS_INST_ERROR, IRIS_INST_INPUT_STREAMING, STATE_CHANGE_IGNORE },
+ {IRIS_INST_ERROR, IRIS_INST_OUTPUT_STREAMING, STATE_CHANGE_IGNORE },
+ {IRIS_INST_ERROR, IRIS_INST_STREAMING, STATE_CHANGE_IGNORE },
+ {IRIS_INST_ERROR, IRIS_INST_CLOSE, STATE_CHANGE_IGNORE },
+ {IRIS_INST_ERROR, IRIS_INST_ERROR, STATE_CHANGE_IGNORE },
+ };
+
+ for (cnt = 0; cnt < ARRAY_SIZE(state); cnt++) {
+ if (state[cnt].from == inst->state && state[cnt].to == req_state) {
+ allow = state[cnt].allow;
+ break;
+ }
+ }
+
+ return allow;
+}
+
+int iris_inst_change_state(struct iris_inst *inst,
+ enum iris_inst_state request_state)
+{
+ enum state_change allow;
+
+ if (IS_SESSION_ERROR(inst))
+ return 0;
+
+ if (inst->state == request_state)
+ return 0;
+
+ allow = iris_allow_inst_state_change(inst, request_state);
+ if (allow != STATE_CHANGE_ALLOW)
+ return (allow == STATE_CHANGE_DISALLOW ? -EINVAL : 0);
+
+ inst->state = request_state;
+
+ return 0;
+}
@@ -7,6 +7,7 @@
#define _IRIS_STATE_H_
struct iris_core;
+struct iris_inst;
enum iris_core_state {
IRIS_CORE_DEINIT,
@@ -15,8 +16,29 @@ enum iris_core_state {
IRIS_CORE_ERROR,
};
+enum iris_inst_state {
+ IRIS_INST_OPEN,
+ IRIS_INST_INPUT_STREAMING,
+ IRIS_INST_OUTPUT_STREAMING,
+ IRIS_INST_STREAMING,
+ IRIS_INST_CLOSE,
+ IRIS_INST_ERROR,
+};
+
+enum state_change {
+ STATE_CHANGE_ALLOW,
+ STATE_CHANGE_DISALLOW,
+ STATE_CHANGE_IGNORE,
+};
+
+#define IS_SESSION_ERROR(inst) \
+((inst)->state == IRIS_INST_ERROR)
+
bool core_in_valid_state(struct iris_core *core);
int iris_change_core_state(struct iris_core *core,
enum iris_core_state request_state);
+int iris_inst_change_state(struct iris_inst *inst,
+ enum iris_inst_state request_state);
+
#endif
@@ -34,6 +34,9 @@ int iris_vb2_queue_setup(struct vb2_queue *q,
else
f = inst->fmt_dst;
+ if (inst->state == IRIS_INST_STREAMING)
+ return -EINVAL;
+
if (*num_planes) {
if (*num_planes != f->fmt.pix_mp.num_planes ||
sizes[0] < f->fmt.pix_mp.plane_fmt[0].sizeimage)
@@ -168,6 +168,7 @@ int vidc_open(struct file *filp)
inst->core = core;
inst->session_id = hash32_ptr(inst);
+ iris_inst_change_state(inst, IRIS_INST_OPEN);
mutex_init(&inst->ctx_q_lock);
ret = vidc_add_session(inst);
@@ -244,6 +245,7 @@ int vidc_close(struct file *filp)
v4l2_ctrl_handler_free(&inst->ctrl_handler);
vdec_inst_deinit(inst);
close_session(inst);
+ iris_inst_change_state(inst, IRIS_INST_CLOSE);
vidc_vb2_queue_deinit(inst);
vidc_v4l2_fh_deinit(inst);
vidc_remove_session(inst);
@@ -295,6 +297,9 @@ static __poll_t vidc_poll(struct file *filp, struct poll_table_struct *pt)
if (!inst)
return EPOLLERR;
+ if (IS_SESSION_ERROR(inst))
+ return EPOLLERR;
+
poll_wait(filp, &inst->fh.wait, pt);
poll_wait(filp, &inst->vb2q_src->done_wq, pt);
poll_wait(filp, &inst->vb2q_dst->done_wq, pt);