Browse Source

video: driver: state handling code movement

state handling changes were spread across multiple files.
So re-arrange all state related handling changes into
msm_vidc_state.h/.c file.

Change-Id: I3826daa678d1e2b5ce7e74380d465e70b1b824c6
Signed-off-by: Govindaraj Rajagopal <[email protected]>
Govindaraj Rajagopal 2 years ago
parent
commit
c175e36454

+ 0 - 19
driver/vidc/inc/msm_vidc_driver.h

@@ -359,17 +359,6 @@ static inline bool is_enc_slice_delivery_mode(struct msm_vidc_inst *inst)
 			inst->capabilities->cap[DELIVERY_MODE].value);
 }
 
-static inline bool is_state(struct msm_vidc_inst *inst, enum msm_vidc_state state)
-{
-	return inst->state == state;
-}
-
-static inline bool is_sub_state(struct msm_vidc_inst *inst,
-	enum msm_vidc_sub_state sub_state)
-{
-	return (inst->sub_state & sub_state);
-}
-
 const char *cap_name(enum msm_vidc_inst_capability_type cap_id);
 const char *v4l2_pixelfmt_name(struct msm_vidc_inst *inst, u32 pixelfmt);
 const char *v4l2_type_name(u32 port);
@@ -400,12 +389,6 @@ u32 v4l2_matrix_coeff_from_driver(struct msm_vidc_inst *inst,
 int v4l2_type_to_driver_port(struct msm_vidc_inst *inst, u32 type,
 	const char *func);
 const char *allow_name(enum msm_vidc_allow allow);
-const char *state_name(enum msm_vidc_state state);
-int msm_vidc_change_state(struct msm_vidc_inst *inst,
-	enum msm_vidc_state request_state, const char *func);
-int msm_vidc_change_sub_state(struct msm_vidc_inst *inst,
-	enum msm_vidc_sub_state clear_sub_state,
-	enum msm_vidc_sub_state set_sub_state, const char *func);
 int msm_vidc_create_internal_buffer(struct msm_vidc_inst *inst,
 	enum msm_vidc_buffer_type buffer_type, u32 index);
 int msm_vidc_get_internal_buffers(struct msm_vidc_inst *inst,
@@ -436,8 +419,6 @@ int msm_vidc_change_core_state(struct msm_vidc_core *core,
 int msm_vidc_change_core_sub_state(struct msm_vidc_core *core,
 	enum msm_vidc_core_sub_state clear_sub_states,
 	enum msm_vidc_core_sub_state set_sub_states, const char *func);
-int prepare_sub_state_name(enum msm_vidc_sub_state sub_state,
-	char *buf, u32 size);
 int msm_vidc_core_init(struct msm_vidc_core *core);
 int msm_vidc_core_init_wait(struct msm_vidc_core *core);
 int msm_vidc_core_deinit(struct msm_vidc_core *core, bool force);

+ 0 - 28
driver/vidc/inc/msm_vidc_inst.h

@@ -14,15 +14,6 @@
 
 struct msm_vidc_inst;
 
-#define FOREACH_STATE(STATE) {                    \
-	STATE(OPEN)                               \
-	STATE(INPUT_STREAMING)                    \
-	STATE(OUTPUT_STREAMING)                   \
-	STATE(STREAMING)                          \
-	STATE(CLOSE)                              \
-	STATE(ERROR)                              \
-}
-
 #define call_session_op(c, op, ...)			\
 	(((c) && (c)->session_ops && (c)->session_ops->op) ? \
 	((c)->session_ops->op(__VA_ARGS__)) : 0)
@@ -68,25 +59,6 @@ struct msm_vidc_buffers_info {
 	struct msm_vidc_buffers        partial_data;
 };
 
-enum msm_vidc_state FOREACH_STATE(GENERATE_MSM_VIDC_ENUM);
-
-#define MSM_VIDC_SUB_STATE_NONE          0
-#define MSM_VIDC_MAX_SUB_STATES          6
-/*
- * max value of inst->sub_state if all
- * the 6 valid bits are set i.e 111111==>63
- */
-#define MSM_VIDC_MAX_SUB_STATE_VALUE     ((1 << MSM_VIDC_MAX_SUB_STATES) - 1)
-
-enum msm_vidc_sub_state {
-	MSM_VIDC_DRAIN                     = BIT(0),
-	MSM_VIDC_DRC                       = BIT(1),
-	MSM_VIDC_DRAIN_LAST_BUFFER         = BIT(2),
-	MSM_VIDC_DRC_LAST_BUFFER           = BIT(3),
-	MSM_VIDC_INPUT_PAUSE               = BIT(4),
-	MSM_VIDC_OUTPUT_PAUSE              = BIT(5),
-};
-
 struct buf_queue {
 	struct vb2_queue *vb2q;
 };

+ 38 - 5
driver/vidc/inc/msm_vidc_state.h

@@ -10,8 +10,6 @@
 #include "msm_vidc_internal.h"
 
 struct msm_vidc_core;
-enum msm_vidc_state;
-enum msm_vidc_sub_state;
 
 #define FOREACH_CORE_STATE(CORE_STATE) {               \
 	CORE_STATE(CORE_DEINIT)                        \
@@ -50,6 +48,34 @@ enum msm_vidc_core_event_type {
 	CORE_EVENT_UPDATE_SUB_STATE          = BIT(1),
 };
 
+#define FOREACH_STATE(STATE) {                    \
+	STATE(OPEN)                               \
+	STATE(INPUT_STREAMING)                    \
+	STATE(OUTPUT_STREAMING)                   \
+	STATE(STREAMING)                          \
+	STATE(CLOSE)                              \
+	STATE(ERROR)                              \
+}
+
+enum msm_vidc_state FOREACH_STATE(GENERATE_MSM_VIDC_ENUM);
+
+#define MSM_VIDC_SUB_STATE_NONE          0
+#define MSM_VIDC_MAX_SUB_STATES          6
+/*
+ * max value of inst->sub_state if all
+ * the 6 valid bits are set i.e 111111==>63
+ */
+#define MSM_VIDC_MAX_SUB_STATE_VALUE     ((1 << MSM_VIDC_MAX_SUB_STATES) - 1)
+
+enum msm_vidc_sub_state {
+	MSM_VIDC_DRAIN                     = BIT(0),
+	MSM_VIDC_DRC                       = BIT(1),
+	MSM_VIDC_DRAIN_LAST_BUFFER         = BIT(2),
+	MSM_VIDC_DRC_LAST_BUFFER           = BIT(3),
+	MSM_VIDC_INPUT_PAUSE               = BIT(4),
+	MSM_VIDC_OUTPUT_PAUSE              = BIT(5),
+};
+
 enum msm_vidc_event FOREACH_EVENT(GENERATE_MSM_VIDC_ENUM);
 
 /* core statemachine functions */
@@ -67,8 +93,15 @@ const char *core_sub_state_name(enum msm_vidc_core_sub_state sub_state);
 /* inst statemachine functions */
 int msm_vidc_update_state(struct msm_vidc_inst *inst,
 	enum msm_vidc_state request_state, const char *func);
-enum msm_vidc_allow msm_vidc_allow_state_change(
-	struct msm_vidc_inst *inst,
-	enum msm_vidc_state req_state);
+int msm_vidc_change_state(struct msm_vidc_inst *inst,
+	enum msm_vidc_state request_state, const char *func);
+int msm_vidc_change_sub_state(struct msm_vidc_inst *inst,
+	enum msm_vidc_sub_state clear_sub_state,
+	enum msm_vidc_sub_state set_sub_state, const char *func);
+const char *state_name(enum msm_vidc_state state);
+const char *sub_state_name(enum msm_vidc_sub_state sub_state);
+bool is_state(struct msm_vidc_inst *inst, enum msm_vidc_state state);
+bool is_sub_state(struct msm_vidc_inst *inst,
+	enum msm_vidc_sub_state sub_state);
 
 #endif // _MSM_VIDC_STATE_H_

+ 0 - 137
driver/vidc/src/msm_vidc_driver.c

@@ -99,59 +99,6 @@ exit:
 	return name;
 }
 
-/* do not modify the state names as it is used in test scripts */
-static const char * const state_name_arr[] =
-	FOREACH_STATE(GENERATE_STRING);
-
-const char *state_name(enum msm_vidc_state state)
-{
-	const char *name = "UNKNOWN STATE";
-
-	if (state >= ARRAY_SIZE(state_name_arr))
-		goto exit;
-
-	name = state_name_arr[state];
-
-exit:
-	return name;
-}
-
-const char *sub_state_name(enum msm_vidc_sub_state sub_state)
-{
-	switch (sub_state) {
-	case MSM_VIDC_DRAIN:               return "DRAIN ";
-	case MSM_VIDC_DRC:                 return "DRC ";
-	case MSM_VIDC_DRAIN_LAST_BUFFER:   return "DRAIN_LAST_BUFFER ";
-	case MSM_VIDC_DRC_LAST_BUFFER:     return "DRC_LAST_BUFFER ";
-	case MSM_VIDC_INPUT_PAUSE:         return "INPUT_PAUSE ";
-	case MSM_VIDC_OUTPUT_PAUSE:        return "OUTPUT_PAUSE ";
-	}
-
-	return "SUB_STATE_NONE";
-}
-
-int prepare_sub_state_name(enum msm_vidc_sub_state sub_state,
-	char *buf, u32 size)
-{
-	int i = 0;
-
-	if (!buf || !size)
-		return -EINVAL;
-
-	strscpy(buf, "\0", size);
-	if (sub_state == MSM_VIDC_SUB_STATE_NONE) {
-		strscpy(buf, "SUB_STATE_NONE", size);
-		return 0;
-	}
-
-	for (i = 0; i < MSM_VIDC_MAX_SUB_STATES; i++) {
-		if (sub_state & BIT(i))
-			strlcat(buf, sub_state_name(BIT(i)), size);
-	}
-
-	return 0;
-}
-
 const char *v4l2_type_name(u32 port)
 {
 	switch (port) {
@@ -1013,90 +960,6 @@ int signal_session_msg_receipt(struct msm_vidc_inst *inst,
 	return 0;
 }
 
-int msm_vidc_change_state(struct msm_vidc_inst *inst,
-		enum msm_vidc_state request_state, const char *func)
-{
-	enum msm_vidc_allow allow;
-	int rc;
-
-	if (!inst) {
-		d_vpr_e("%s: invalid params\n", __func__);
-		return -EINVAL;
-	}
-
-	if (is_session_error(inst)) {
-		i_vpr_h(inst,
-			"%s: inst is in bad state, can not change state to %s\n",
-			func, state_name(request_state));
-		return 0;
-	}
-
-	/* current and requested state is same */
-	if (inst->state == request_state)
-		return 0;
-
-	/* check if requested state movement is allowed */
-	allow = msm_vidc_allow_state_change(inst, request_state);
-	if (allow != MSM_VIDC_ALLOW) {
-		i_vpr_e(inst, "%s: %s state change %s -> %s\n", func,
-			allow_name(allow), state_name(inst->state),
-			state_name(request_state));
-		return (allow == MSM_VIDC_DISALLOW ? -EINVAL : 0);
-	}
-
-	/* go ahead and update inst state */
-	rc = msm_vidc_update_state(inst, request_state, func);
-	if (rc)
-		return rc;
-
-	return 0;
-}
-
-int msm_vidc_change_sub_state(struct msm_vidc_inst *inst,
-		enum msm_vidc_sub_state clear_sub_state,
-		enum msm_vidc_sub_state set_sub_state, const char *func)
-{
-	enum msm_vidc_sub_state prev_sub_state;
-	int rc = 0;
-
-	if (!inst) {
-		d_vpr_e("%s: invalid params\n", __func__);
-		return -EINVAL;
-	}
-
-	if (is_session_error(inst)) {
-		i_vpr_h(inst,
-			"%s: inst is in bad state, can not change sub state\n", func);
-		return 0;
-	}
-
-	if (!clear_sub_state && !set_sub_state)
-		return 0;
-
-	if ((clear_sub_state & set_sub_state) ||
-		(set_sub_state > MSM_VIDC_MAX_SUB_STATE_VALUE) ||
-		(clear_sub_state > MSM_VIDC_MAX_SUB_STATE_VALUE)) {
-		i_vpr_e(inst, "%s: invalid sub states to clear %#x or set %#x\n",
-			func, clear_sub_state, set_sub_state);
-		return -EINVAL;
-	}
-
-	prev_sub_state = inst->sub_state;
-	inst->sub_state |= set_sub_state;
-	inst->sub_state &= ~clear_sub_state;
-
-	/* print substates only when there is a change */
-	if (inst->sub_state != prev_sub_state) {
-		rc = prepare_sub_state_name(inst->sub_state, inst->sub_state_name,
-			sizeof(inst->sub_state_name));
-		if (!rc)
-			i_vpr_h(inst, "%s: state %s and sub state changed to %s\n",
-				func, state_name(inst->state), inst->sub_state_name);
-	}
-
-	return 0;
-}
-
 bool msm_vidc_allow_s_fmt(struct msm_vidc_inst *inst, u32 type)
 {
 	bool allow = false;

+ 277 - 130
driver/vidc/src/msm_vidc_state.c

@@ -496,6 +496,136 @@ int msm_vidc_change_core_sub_state(struct msm_vidc_core *core,
 	return 0;
 }
 
+/* do not modify the state names as it is used in test scripts */
+static const char * const state_name_arr[] =
+	FOREACH_STATE(GENERATE_STRING);
+
+const char *state_name(enum msm_vidc_state state)
+{
+	const char *name = "UNKNOWN STATE";
+
+	if (state >= ARRAY_SIZE(state_name_arr))
+		goto exit;
+
+	name = state_name_arr[state];
+
+exit:
+	return name;
+}
+
+bool is_state(struct msm_vidc_inst *inst, enum msm_vidc_state state)
+{
+	return inst->state == state;
+}
+
+bool is_sub_state(struct msm_vidc_inst *inst, enum msm_vidc_sub_state sub_state)
+{
+	return (inst->sub_state & sub_state);
+}
+
+const char *sub_state_name(enum msm_vidc_sub_state sub_state)
+{
+	switch (sub_state) {
+	case MSM_VIDC_DRAIN:               return "DRAIN ";
+	case MSM_VIDC_DRC:                 return "DRC ";
+	case MSM_VIDC_DRAIN_LAST_BUFFER:   return "DRAIN_LAST_BUFFER ";
+	case MSM_VIDC_DRC_LAST_BUFFER:     return "DRC_LAST_BUFFER ";
+	case MSM_VIDC_INPUT_PAUSE:         return "INPUT_PAUSE ";
+	case MSM_VIDC_OUTPUT_PAUSE:        return "OUTPUT_PAUSE ";
+	}
+
+	return "SUB_STATE_NONE";
+}
+
+static int prepare_sub_state_name(enum msm_vidc_sub_state sub_state,
+	char *buf, u32 size)
+{
+	int i = 0;
+
+	if (!buf || !size)
+		return -EINVAL;
+
+	strscpy(buf, "\0", size);
+	if (sub_state == MSM_VIDC_SUB_STATE_NONE) {
+		strscpy(buf, "SUB_STATE_NONE", size);
+		return 0;
+	}
+
+	for (i = 0; i < MSM_VIDC_MAX_SUB_STATES; i++) {
+		if (sub_state & BIT(i))
+			strlcat(buf, sub_state_name(BIT(i)), size);
+	}
+
+	return 0;
+}
+
+struct msm_vidc_state_allow {
+	enum msm_vidc_state        from;
+	enum msm_vidc_state        to;
+	enum msm_vidc_allow        allow;
+};
+
+static enum msm_vidc_allow msm_vidc_allow_state_change(
+	struct msm_vidc_inst *inst,
+	enum msm_vidc_state req_state)
+{
+	int cnt;
+	enum msm_vidc_allow allow = MSM_VIDC_DISALLOW;
+	static struct msm_vidc_state_allow state[] = {
+		/* from, to, allow */
+		{MSM_VIDC_OPEN,             MSM_VIDC_OPEN,               MSM_VIDC_IGNORE    },
+		{MSM_VIDC_OPEN,             MSM_VIDC_INPUT_STREAMING,    MSM_VIDC_ALLOW     },
+		{MSM_VIDC_OPEN,             MSM_VIDC_OUTPUT_STREAMING,   MSM_VIDC_ALLOW     },
+		{MSM_VIDC_OPEN,             MSM_VIDC_STREAMING,          MSM_VIDC_DISALLOW  },
+		{MSM_VIDC_OPEN,             MSM_VIDC_CLOSE,              MSM_VIDC_ALLOW     },
+		{MSM_VIDC_OPEN,             MSM_VIDC_ERROR,              MSM_VIDC_ALLOW     },
+
+		{MSM_VIDC_INPUT_STREAMING,  MSM_VIDC_OPEN,               MSM_VIDC_ALLOW     },
+		{MSM_VIDC_INPUT_STREAMING,  MSM_VIDC_INPUT_STREAMING,    MSM_VIDC_IGNORE    },
+		{MSM_VIDC_INPUT_STREAMING,  MSM_VIDC_OUTPUT_STREAMING,   MSM_VIDC_DISALLOW  },
+		{MSM_VIDC_INPUT_STREAMING,  MSM_VIDC_STREAMING,          MSM_VIDC_ALLOW     },
+		{MSM_VIDC_INPUT_STREAMING,  MSM_VIDC_CLOSE,              MSM_VIDC_ALLOW     },
+		{MSM_VIDC_INPUT_STREAMING,  MSM_VIDC_ERROR,              MSM_VIDC_ALLOW     },
+
+		{MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_OPEN,               MSM_VIDC_ALLOW     },
+		{MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_INPUT_STREAMING,    MSM_VIDC_DISALLOW  },
+		{MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_OUTPUT_STREAMING,   MSM_VIDC_IGNORE    },
+		{MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_STREAMING,          MSM_VIDC_ALLOW     },
+		{MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_CLOSE,              MSM_VIDC_ALLOW     },
+		{MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_ERROR,              MSM_VIDC_ALLOW     },
+
+		{MSM_VIDC_STREAMING,        MSM_VIDC_OPEN,               MSM_VIDC_DISALLOW  },
+		{MSM_VIDC_STREAMING,        MSM_VIDC_INPUT_STREAMING,    MSM_VIDC_ALLOW     },
+		{MSM_VIDC_STREAMING,        MSM_VIDC_OUTPUT_STREAMING,   MSM_VIDC_ALLOW     },
+		{MSM_VIDC_STREAMING,        MSM_VIDC_STREAMING,          MSM_VIDC_IGNORE    },
+		{MSM_VIDC_STREAMING,        MSM_VIDC_CLOSE,              MSM_VIDC_ALLOW     },
+		{MSM_VIDC_STREAMING,        MSM_VIDC_ERROR,              MSM_VIDC_ALLOW     },
+
+		{MSM_VIDC_CLOSE,            MSM_VIDC_OPEN,               MSM_VIDC_DISALLOW  },
+		{MSM_VIDC_CLOSE,            MSM_VIDC_INPUT_STREAMING,    MSM_VIDC_DISALLOW  },
+		{MSM_VIDC_CLOSE,            MSM_VIDC_OUTPUT_STREAMING,   MSM_VIDC_DISALLOW  },
+		{MSM_VIDC_CLOSE,            MSM_VIDC_STREAMING,          MSM_VIDC_DISALLOW  },
+		{MSM_VIDC_CLOSE,            MSM_VIDC_CLOSE,              MSM_VIDC_IGNORE    },
+		{MSM_VIDC_CLOSE,            MSM_VIDC_ERROR,              MSM_VIDC_IGNORE    },
+
+		{MSM_VIDC_ERROR,            MSM_VIDC_OPEN,               MSM_VIDC_IGNORE    },
+		{MSM_VIDC_ERROR,            MSM_VIDC_INPUT_STREAMING,    MSM_VIDC_IGNORE    },
+		{MSM_VIDC_ERROR,            MSM_VIDC_OUTPUT_STREAMING,   MSM_VIDC_IGNORE    },
+		{MSM_VIDC_ERROR,            MSM_VIDC_STREAMING,          MSM_VIDC_IGNORE    },
+		{MSM_VIDC_ERROR,            MSM_VIDC_CLOSE,              MSM_VIDC_ALLOW     },
+		{MSM_VIDC_ERROR,            MSM_VIDC_ERROR,              MSM_VIDC_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;
+}
+
 static int msm_vidc_open_state(struct msm_vidc_inst *inst,
 	enum msm_vidc_event event, void *data)
 {
@@ -611,6 +741,33 @@ static int msm_vidc_input_streaming_state(struct msm_vidc_inst *inst,
 	}
 
 	switch (event) {
+	case MSM_VIDC_BUF_QUEUE:
+	{
+		struct msm_vidc_buffer *buf = (struct msm_vidc_buffer *)data;
+
+		/* defer meta port */
+		if (buf->type == MSM_VIDC_BUF_INPUT_META || buf->type == MSM_VIDC_BUF_OUTPUT_META) {
+			print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf);
+			return 0;
+		}
+
+		/* disallow */
+		if (buf->type != MSM_VIDC_BUF_INPUT && buf->type != MSM_VIDC_BUF_OUTPUT) {
+			i_vpr_e(inst, "%s: invalid buf type %u\n", __func__, buf->type);
+			return -EINVAL;
+		}
+
+		/* defer output port */
+		if (buf->type == MSM_VIDC_BUF_OUTPUT) {
+			print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf);
+			return 0;
+		}
+
+		rc = msm_vidc_buf_queue(inst, buf);
+		if (rc)
+			return rc;
+		break;
+	}
 	case MSM_VIDC_S_FMT:
 	{
 		struct v4l2_format *f = (struct v4l2_format *)data;
@@ -707,33 +864,6 @@ static int msm_vidc_input_streaming_state(struct msm_vidc_inst *inst,
 			return rc;
 		break;
 	}
-	case MSM_VIDC_BUF_QUEUE:
-	{
-		struct msm_vidc_buffer *buf = (struct msm_vidc_buffer *)data;
-
-		/* defer meta port */
-		if (buf->type == MSM_VIDC_BUF_INPUT_META || buf->type == MSM_VIDC_BUF_OUTPUT_META) {
-			print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf);
-			return 0;
-		}
-
-		/* disallow */
-		if (buf->type != MSM_VIDC_BUF_INPUT && buf->type != MSM_VIDC_BUF_OUTPUT) {
-			i_vpr_e(inst, "%s: invalid buf type %u\n", __func__, buf->type);
-			return -EINVAL;
-		}
-
-		/* defer output port */
-		if (buf->type == MSM_VIDC_BUF_OUTPUT) {
-			print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf);
-			return 0;
-		}
-
-		rc = msm_vidc_buf_queue(inst, buf);
-		if (rc)
-			return rc;
-		break;
-	}
 	default:
 	{
 		i_vpr_e(inst, "%s: unexpected event %s\n", __func__, event_name(event));
@@ -762,6 +892,33 @@ static int msm_vidc_output_streaming_state(struct msm_vidc_inst *inst,
 	}
 
 	switch (event) {
+	case MSM_VIDC_BUF_QUEUE:
+	{
+		struct msm_vidc_buffer *buf = (struct msm_vidc_buffer *)data;
+
+		/* defer meta port */
+		if (buf->type == MSM_VIDC_BUF_INPUT_META || buf->type == MSM_VIDC_BUF_OUTPUT_META) {
+			print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf);
+			return 0;
+		}
+
+		/* disallow */
+		if (buf->type != MSM_VIDC_BUF_INPUT && buf->type != MSM_VIDC_BUF_OUTPUT) {
+			i_vpr_e(inst, "%s: invalid buf type %u\n", __func__, buf->type);
+			return -EINVAL;
+		}
+
+		/* defer input port */
+		if (buf->type == MSM_VIDC_BUF_INPUT) {
+			print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf);
+			return 0;
+		}
+
+		rc = msm_vidc_buf_queue(inst, buf);
+		if (rc)
+			return rc;
+		break;
+	}
 	case MSM_VIDC_S_FMT:
 	{
 		struct v4l2_format *f = (struct v4l2_format *)data;
@@ -858,33 +1015,6 @@ static int msm_vidc_output_streaming_state(struct msm_vidc_inst *inst,
 			return rc;
 		break;
 	}
-	case MSM_VIDC_BUF_QUEUE:
-	{
-		struct msm_vidc_buffer *buf = (struct msm_vidc_buffer *)data;
-
-		/* defer meta port */
-		if (buf->type == MSM_VIDC_BUF_INPUT_META || buf->type == MSM_VIDC_BUF_OUTPUT_META) {
-			print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf);
-			return 0;
-		}
-
-		/* disallow */
-		if (buf->type != MSM_VIDC_BUF_INPUT && buf->type != MSM_VIDC_BUF_OUTPUT) {
-			i_vpr_e(inst, "%s: invalid buf type %u\n", __func__, buf->type);
-			return -EINVAL;
-		}
-
-		/* defer input port */
-		if (buf->type == MSM_VIDC_BUF_INPUT) {
-			print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf);
-			return 0;
-		}
-
-		rc = msm_vidc_buf_queue(inst, buf);
-		if (rc)
-			return rc;
-		break;
-	}
 	default: {
 		i_vpr_e(inst, "%s: unexpected event %s\n", __func__, event_name(event));
 		return -EINVAL;
@@ -912,6 +1042,27 @@ static int msm_vidc_streaming_state(struct msm_vidc_inst *inst,
 	}
 
 	switch (event) {
+	case MSM_VIDC_BUF_QUEUE:
+	{
+		struct msm_vidc_buffer *buf = (struct msm_vidc_buffer *)data;
+
+		/* defer meta port */
+		if (buf->type == MSM_VIDC_BUF_INPUT_META || buf->type == MSM_VIDC_BUF_OUTPUT_META) {
+			print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf);
+			return 0;
+		}
+
+		/* disallow */
+		if (buf->type != MSM_VIDC_BUF_INPUT && buf->type != MSM_VIDC_BUF_OUTPUT) {
+			i_vpr_e(inst, "%s: invalid buf type %u\n", __func__, buf->type);
+			return -EINVAL;
+		}
+
+		rc = msm_vidc_buf_queue(inst, buf);
+		if (rc)
+			return rc;
+		break;
+	}
 	case MSM_VIDC_S_CTRL:
 	{
 		struct v4l2_ctrl *ctrl = (struct v4l2_ctrl *)data;
@@ -971,27 +1122,6 @@ static int msm_vidc_streaming_state(struct msm_vidc_inst *inst,
 			return rc;
 		break;
 	}
-	case MSM_VIDC_BUF_QUEUE:
-	{
-		struct msm_vidc_buffer *buf = (struct msm_vidc_buffer *)data;
-
-		/* defer meta port */
-		if (buf->type == MSM_VIDC_BUF_INPUT_META || buf->type == MSM_VIDC_BUF_OUTPUT_META) {
-			print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf);
-			return 0;
-		}
-
-		/* disallow */
-		if (buf->type != MSM_VIDC_BUF_INPUT && buf->type != MSM_VIDC_BUF_OUTPUT) {
-			i_vpr_e(inst, "%s: invalid buf type %u\n", __func__, buf->type);
-			return -EINVAL;
-		}
-
-		rc = msm_vidc_buf_queue(inst, buf);
-		if (rc)
-			return rc;
-		break;
-	}
 	default: {
 		i_vpr_e(inst, "%s: unexpected event %s\n", __func__, event_name(event));
 		return -EINVAL;
@@ -1124,69 +1254,86 @@ int msm_vidc_update_state(struct msm_vidc_inst *inst,
 	return rc;
 }
 
-struct msm_vidc_state_allow {
-	enum msm_vidc_state        from;
-	enum msm_vidc_state        to;
-	enum msm_vidc_allow        allow;
-};
+int msm_vidc_change_state(struct msm_vidc_inst *inst,
+		enum msm_vidc_state request_state, const char *func)
+{
+	enum msm_vidc_allow allow;
+	int rc;
 
-enum msm_vidc_allow msm_vidc_allow_state_change(
-	struct msm_vidc_inst *inst,
-	enum msm_vidc_state req_state)
+	if (!inst) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	if (is_session_error(inst)) {
+		i_vpr_h(inst,
+			"%s: inst is in bad state, can not change state to %s\n",
+			func, state_name(request_state));
+		return 0;
+	}
+
+	/* current and requested state is same */
+	if (inst->state == request_state)
+		return 0;
+
+	/* check if requested state movement is allowed */
+	allow = msm_vidc_allow_state_change(inst, request_state);
+	if (allow != MSM_VIDC_ALLOW) {
+		i_vpr_e(inst, "%s: %s state change %s -> %s\n", func,
+			allow_name(allow), state_name(inst->state),
+			state_name(request_state));
+		return (allow == MSM_VIDC_DISALLOW ? -EINVAL : 0);
+	}
+
+	/* go ahead and update inst state */
+	rc = msm_vidc_update_state(inst, request_state, func);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+int msm_vidc_change_sub_state(struct msm_vidc_inst *inst,
+		enum msm_vidc_sub_state clear_sub_state,
+		enum msm_vidc_sub_state set_sub_state, const char *func)
 {
-	int cnt;
-	enum msm_vidc_allow allow = MSM_VIDC_DISALLOW;
-	static struct msm_vidc_state_allow state[] = {
-		/* from, to, allow */
-		{MSM_VIDC_OPEN,             MSM_VIDC_OPEN,               MSM_VIDC_IGNORE    },
-		{MSM_VIDC_OPEN,             MSM_VIDC_INPUT_STREAMING,    MSM_VIDC_ALLOW     },
-		{MSM_VIDC_OPEN,             MSM_VIDC_OUTPUT_STREAMING,   MSM_VIDC_ALLOW     },
-		{MSM_VIDC_OPEN,             MSM_VIDC_STREAMING,          MSM_VIDC_DISALLOW  },
-		{MSM_VIDC_OPEN,             MSM_VIDC_CLOSE,              MSM_VIDC_ALLOW     },
-		{MSM_VIDC_OPEN,             MSM_VIDC_ERROR,              MSM_VIDC_ALLOW     },
+	enum msm_vidc_sub_state prev_sub_state;
+	int rc = 0;
 
-		{MSM_VIDC_INPUT_STREAMING,  MSM_VIDC_OPEN,               MSM_VIDC_ALLOW     },
-		{MSM_VIDC_INPUT_STREAMING,  MSM_VIDC_INPUT_STREAMING,    MSM_VIDC_IGNORE    },
-		{MSM_VIDC_INPUT_STREAMING,  MSM_VIDC_OUTPUT_STREAMING,   MSM_VIDC_DISALLOW  },
-		{MSM_VIDC_INPUT_STREAMING,  MSM_VIDC_STREAMING,          MSM_VIDC_ALLOW     },
-		{MSM_VIDC_INPUT_STREAMING,  MSM_VIDC_CLOSE,              MSM_VIDC_ALLOW     },
-		{MSM_VIDC_INPUT_STREAMING,  MSM_VIDC_ERROR,              MSM_VIDC_ALLOW     },
+	if (!inst) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
 
-		{MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_OPEN,               MSM_VIDC_ALLOW     },
-		{MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_INPUT_STREAMING,    MSM_VIDC_DISALLOW  },
-		{MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_OUTPUT_STREAMING,   MSM_VIDC_IGNORE    },
-		{MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_STREAMING,          MSM_VIDC_ALLOW     },
-		{MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_CLOSE,              MSM_VIDC_ALLOW     },
-		{MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_ERROR,              MSM_VIDC_ALLOW     },
+	if (is_session_error(inst)) {
+		i_vpr_h(inst,
+			"%s: inst is in bad state, can not change sub state\n", func);
+		return 0;
+	}
 
-		{MSM_VIDC_STREAMING,        MSM_VIDC_OPEN,               MSM_VIDC_DISALLOW  },
-		{MSM_VIDC_STREAMING,        MSM_VIDC_INPUT_STREAMING,    MSM_VIDC_ALLOW     },
-		{MSM_VIDC_STREAMING,        MSM_VIDC_OUTPUT_STREAMING,   MSM_VIDC_ALLOW     },
-		{MSM_VIDC_STREAMING,        MSM_VIDC_STREAMING,          MSM_VIDC_IGNORE    },
-		{MSM_VIDC_STREAMING,        MSM_VIDC_CLOSE,              MSM_VIDC_ALLOW     },
-		{MSM_VIDC_STREAMING,        MSM_VIDC_ERROR,              MSM_VIDC_ALLOW     },
+	if (!clear_sub_state && !set_sub_state)
+		return 0;
 
-		{MSM_VIDC_CLOSE,            MSM_VIDC_OPEN,               MSM_VIDC_DISALLOW  },
-		{MSM_VIDC_CLOSE,            MSM_VIDC_INPUT_STREAMING,    MSM_VIDC_DISALLOW  },
-		{MSM_VIDC_CLOSE,            MSM_VIDC_OUTPUT_STREAMING,   MSM_VIDC_DISALLOW  },
-		{MSM_VIDC_CLOSE,            MSM_VIDC_STREAMING,          MSM_VIDC_DISALLOW  },
-		{MSM_VIDC_CLOSE,            MSM_VIDC_CLOSE,              MSM_VIDC_IGNORE    },
-		{MSM_VIDC_CLOSE,            MSM_VIDC_ERROR,              MSM_VIDC_IGNORE    },
+	if ((clear_sub_state & set_sub_state) ||
+		(set_sub_state > MSM_VIDC_MAX_SUB_STATE_VALUE) ||
+		(clear_sub_state > MSM_VIDC_MAX_SUB_STATE_VALUE)) {
+		i_vpr_e(inst, "%s: invalid sub states to clear %#x or set %#x\n",
+			func, clear_sub_state, set_sub_state);
+		return -EINVAL;
+	}
 
-		{MSM_VIDC_ERROR,            MSM_VIDC_OPEN,               MSM_VIDC_IGNORE    },
-		{MSM_VIDC_ERROR,            MSM_VIDC_INPUT_STREAMING,    MSM_VIDC_IGNORE    },
-		{MSM_VIDC_ERROR,            MSM_VIDC_OUTPUT_STREAMING,   MSM_VIDC_IGNORE    },
-		{MSM_VIDC_ERROR,            MSM_VIDC_STREAMING,          MSM_VIDC_IGNORE    },
-		{MSM_VIDC_ERROR,            MSM_VIDC_CLOSE,              MSM_VIDC_ALLOW     },
-		{MSM_VIDC_ERROR,            MSM_VIDC_ERROR,              MSM_VIDC_IGNORE    },
-	};
+	prev_sub_state = inst->sub_state;
+	inst->sub_state |= set_sub_state;
+	inst->sub_state &= ~clear_sub_state;
 
-	for (cnt = 0; cnt < ARRAY_SIZE(state); cnt++) {
-		if (state[cnt].from == inst->state && state[cnt].to == req_state) {
-			allow = state[cnt].allow;
-			break;
-		}
+	/* print substates only when there is a change */
+	if (inst->sub_state != prev_sub_state) {
+		rc = prepare_sub_state_name(inst->sub_state, inst->sub_state_name,
+			sizeof(inst->sub_state_name));
+		if (!rc)
+			i_vpr_h(inst, "%s: state %s and sub state changed to %s\n",
+				func, state_name(inst->state), inst->sub_state_name);
 	}
 
-	return allow;
+	return 0;
 }