From 7c365bdb94784e70e0d9545570f455035bb7c5e0 Mon Sep 17 00:00:00 2001 From: Govindaraj Rajagopal Date: Fri, 25 Nov 2022 21:28:41 +0530 Subject: [PATCH] video: driver: restructure video state machine Re-structure video driver statemachine to use event handler. Added event handler support for event states. Added change to handle event depending on the underlying state implementation. Change-Id: Ib55c12c6cadc4d780797a5aee75d5ea61e95c94f Signed-off-by: Govindaraj Rajagopal --- .../platform/common/src/msm_vidc_platform.c | 14 +- driver/vidc/inc/msm_vdec.h | 3 +- driver/vidc/inc/msm_venc.h | 3 +- driver/vidc/inc/msm_vidc.h | 3 +- driver/vidc/inc/msm_vidc_control.h | 1 + driver/vidc/inc/msm_vidc_driver.h | 11 +- driver/vidc/inc/msm_vidc_inst.h | 4 +- driver/vidc/inc/msm_vidc_internal.h | 2 +- driver/vidc/inc/msm_vidc_state.h | 28 +- driver/vidc/inc/msm_vidc_vb2.h | 17 +- driver/vidc/src/msm_vdec.c | 162 ++-- driver/vidc/src/msm_venc.c | 72 +- driver/vidc/src/msm_vidc.c | 56 +- driver/vidc/src/msm_vidc_control.c | 63 +- driver/vidc/src/msm_vidc_driver.c | 246 ++---- driver/vidc/src/msm_vidc_state.c | 738 +++++++++++++++++- driver/vidc/src/msm_vidc_v4l2.c | 40 +- driver/vidc/src/msm_vidc_vb2.c | 163 ++-- driver/vidc/src/venus_hfi_queue.c | 6 +- 19 files changed, 1174 insertions(+), 458 deletions(-) diff --git a/driver/platform/common/src/msm_vidc_platform.c b/driver/platform/common/src/msm_vidc_platform.c index 63e2b7d151..dae8cd0553 100644 --- a/driver/platform/common/src/msm_vidc_platform.c +++ b/driver/platform/common/src/msm_vidc_platform.c @@ -168,13 +168,13 @@ static struct v4l2_ctrl_ops msm_v4l2_ctrl_ops = { }; static struct vb2_ops msm_vb2_ops = { - .queue_setup = msm_vidc_queue_setup, - .start_streaming = msm_vidc_start_streaming, - .buf_queue = msm_vidc_buf_queue, - .buf_cleanup = msm_vidc_buf_cleanup, - .stop_streaming = msm_vidc_stop_streaming, - .buf_out_validate = msm_vidc_buf_out_validate, - .buf_request_complete = msm_vidc_buf_request_complete, + .queue_setup = msm_vb2_queue_setup, + .start_streaming = msm_vb2_start_streaming, + .buf_queue = msm_vb2_buf_queue, + .buf_cleanup = msm_vb2_buf_cleanup, + .stop_streaming = msm_vb2_stop_streaming, + .buf_out_validate = msm_vb2_buf_out_validate, + .buf_request_complete = msm_vb2_request_complete, }; static struct vb2_mem_ops msm_vb2_mem_ops = { diff --git a/driver/vidc/inc/msm_vdec.h b/driver/vidc/inc/msm_vdec.h index 124fce3f8d..dbe2ff10eb 100644 --- a/driver/vidc/inc/msm_vdec.h +++ b/driver/vidc/inc/msm_vdec.h @@ -28,7 +28,8 @@ int msm_vdec_inst_deinit(struct msm_vidc_inst *inst); int msm_vdec_init_input_subcr_params(struct msm_vidc_inst *inst); int msm_vdec_input_port_settings_change(struct msm_vidc_inst *inst); int msm_vdec_output_port_settings_change(struct msm_vidc_inst *inst); -int msm_vdec_process_cmd(struct msm_vidc_inst *inst, u32 cmd); +int msm_vdec_stop_cmd(struct msm_vidc_inst *inst); +int msm_vdec_start_cmd(struct msm_vidc_inst *inst); int msm_vdec_handle_release_buffer(struct msm_vidc_inst *inst, struct msm_vidc_buffer *buf); int msm_vdec_set_num_comv(struct msm_vidc_inst *inst); diff --git a/driver/vidc/inc/msm_venc.h b/driver/vidc/inc/msm_venc.h index fced6b5347..594236fe0f 100644 --- a/driver/vidc/inc/msm_venc.h +++ b/driver/vidc/inc/msm_venc.h @@ -15,7 +15,8 @@ int msm_venc_streamon_input(struct msm_vidc_inst *inst); int msm_venc_streamoff_output(struct msm_vidc_inst *inst); int msm_venc_streamon_output(struct msm_vidc_inst *inst); int msm_venc_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb2); -int msm_venc_process_cmd(struct msm_vidc_inst *inst, u32 cmd); +int msm_venc_stop_cmd(struct msm_vidc_inst *inst); +int msm_venc_start_cmd(struct msm_vidc_inst *inst); int msm_venc_try_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f); int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f); int msm_venc_s_fmt_output(struct msm_vidc_inst *inst, struct v4l2_format *f); diff --git a/driver/vidc/inc/msm_vidc.h b/driver/vidc/inc/msm_vidc.h index 6fd83f4822..891c3db405 100644 --- a/driver/vidc/inc/msm_vidc.h +++ b/driver/vidc/inc/msm_vidc.h @@ -41,7 +41,8 @@ int msm_vidc_query_ctrl(void *instance, struct v4l2_queryctrl *ctrl); int msm_vidc_query_menu(void *instance, struct v4l2_querymenu *qmenu); int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i); int msm_vidc_try_cmd(void *instance, union msm_v4l2_cmd *cmd); -int msm_vidc_cmd(void *instance, union msm_v4l2_cmd *cmd); +int msm_vidc_start_cmd(void *instance); +int msm_vidc_stop_cmd(void *instance); int msm_vidc_poll(void *instance, struct file *filp, struct poll_table_struct *pt); int msm_vidc_subscribe_event(void *instance, diff --git a/driver/vidc/inc/msm_vidc_control.h b/driver/vidc/inc/msm_vidc_control.h index 84081ba3b3..fe5e0d1714 100644 --- a/driver/vidc/inc/msm_vidc_control.h +++ b/driver/vidc/inc/msm_vidc_control.h @@ -14,6 +14,7 @@ int msm_vidc_ctrl_init(struct msm_vidc_inst *inst); int msm_vidc_ctrl_deinit(struct msm_vidc_inst *inst); int msm_v4l2_op_s_ctrl(struct v4l2_ctrl *ctrl); int msm_v4l2_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl); +int msm_vidc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl); int msm_vidc_prepare_dependency_list(struct msm_vidc_inst *inst); int msm_vidc_adjust_set_v4l2_properties(struct msm_vidc_inst *inst); bool is_valid_cap_id(enum msm_vidc_inst_capability_type cap_id); diff --git a/driver/vidc/inc/msm_vidc_driver.h b/driver/vidc/inc/msm_vidc_driver.h index 4d65601633..76304676b8 100644 --- a/driver/vidc/inc/msm_vidc_driver.h +++ b/driver/vidc/inc/msm_vidc_driver.h @@ -404,8 +404,8 @@ 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_states, - enum msm_vidc_sub_state set_sub_states, const char *func); + 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,6 +436,8 @@ 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); @@ -482,6 +484,7 @@ int cancel_stats_work_sync(struct msm_vidc_inst *inst); void msm_vidc_print_stats(struct msm_vidc_inst *inst); enum msm_vidc_buffer_type v4l2_type_to_driver(u32 type, const char *func); +int msm_vidc_buf_queue(struct msm_vidc_inst *inst, struct msm_vidc_buffer *buf); int msm_vidc_queue_buffer_single(struct msm_vidc_inst *inst, struct vb2_buffer *vb2); int msm_vidc_queue_deferred_buffers(struct msm_vidc_inst *inst, @@ -501,8 +504,6 @@ struct msm_vidc_inst *get_inst(struct msm_vidc_core *core, u32 session_id); void put_inst(struct msm_vidc_inst *inst); bool msm_vidc_allow_s_fmt(struct msm_vidc_inst *inst, u32 type); -bool msm_vidc_allow_s_ctrl(struct msm_vidc_inst *inst, - enum msm_vidc_inst_capability_type cap_id); bool msm_vidc_allow_metadata_delivery(struct msm_vidc_inst *inst, u32 cap_id, u32 port); bool msm_vidc_allow_metadata_subscription(struct msm_vidc_inst *inst, @@ -514,8 +515,6 @@ bool msm_vidc_allow_reqbufs(struct msm_vidc_inst *inst, u32 type); enum msm_vidc_allow msm_vidc_allow_stop(struct msm_vidc_inst *inst); bool msm_vidc_allow_start(struct msm_vidc_inst *inst); bool msm_vidc_allow_streamon(struct msm_vidc_inst *inst, u32 type); -enum msm_vidc_allow msm_vidc_allow_streamoff(struct msm_vidc_inst *inst, u32 type); -enum msm_vidc_allow msm_vidc_allow_qbuf(struct msm_vidc_inst *inst, u32 type); enum msm_vidc_allow msm_vidc_allow_input_psc(struct msm_vidc_inst *inst); bool msm_vidc_allow_drain_last_flag(struct msm_vidc_inst *inst); bool msm_vidc_allow_psc_last_flag(struct msm_vidc_inst *inst); diff --git a/driver/vidc/inc/msm_vidc_inst.h b/driver/vidc/inc/msm_vidc_inst.h index 0339489ef0..7ea7bd963b 100644 --- a/driver/vidc/inc/msm_vidc_inst.h +++ b/driver/vidc/inc/msm_vidc_inst.h @@ -9,12 +9,12 @@ #include "msm_vidc_internal.h" #include "msm_vidc_memory.h" +#include "msm_vidc_state.h" #include "hfi_property.h" struct msm_vidc_inst; #define FOREACH_STATE(STATE) { \ - STATE(NONE) \ STATE(OPEN) \ STATE(INPUT_STREAMING) \ STATE(OUTPUT_STREAMING) \ @@ -97,6 +97,8 @@ struct msm_vidc_inst { struct mutex request_lock; struct mutex client_lock; enum msm_vidc_state state; + int (*event_handle)(struct msm_vidc_inst *inst, + enum msm_vidc_event event, void *data); enum msm_vidc_sub_state sub_state; char sub_state_name[MAX_NAME_LENGTH]; enum msm_vidc_domain_type domain; diff --git a/driver/vidc/inc/msm_vidc_internal.h b/driver/vidc/inc/msm_vidc_internal.h index 7db0cf7cdd..a12847fde7 100644 --- a/driver/vidc/inc/msm_vidc_internal.h +++ b/driver/vidc/inc/msm_vidc_internal.h @@ -377,7 +377,7 @@ enum msm_vidc_metadata_bits { BUF_TYPE(INPUT_META) \ BUF_TYPE(OUTPUT_META) \ BUF_TYPE(READ_ONLY) \ - BUF_TYPE(QUEUE) \ + BUF_TYPE(INTERFACE_QUEUE) \ BUF_TYPE(BIN) \ BUF_TYPE(ARP) \ BUF_TYPE(COMV) \ diff --git a/driver/vidc/inc/msm_vidc_state.h b/driver/vidc/inc/msm_vidc_state.h index c5a35089d8..12aa5045f3 100644 --- a/driver/vidc/inc/msm_vidc_state.h +++ b/driver/vidc/inc/msm_vidc_state.h @@ -10,6 +10,8 @@ #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) \ @@ -18,6 +20,17 @@ struct msm_vidc_core; CORE_STATE(CORE_ERROR) \ } +#define FOREACH_EVENT(EVENT) { \ + EVENT(S_FMT) \ + EVENT(REQBUFS) \ + EVENT(S_CTRL) \ + EVENT(STREAMON) \ + EVENT(STREAMOFF) \ + EVENT(CMD_START) \ + EVENT(CMD_STOP) \ + EVENT(BUF_QUEUE) \ +} + enum msm_vidc_core_state FOREACH_CORE_STATE(GENERATE_MSM_VIDC_ENUM); enum msm_vidc_core_sub_state { @@ -37,13 +50,9 @@ enum msm_vidc_core_event_type { CORE_EVENT_UPDATE_SUB_STATE = BIT(1), }; -struct msm_vidc_core_state_handle { - enum msm_vidc_core_state state; - int (*handle)(struct msm_vidc_core *core, - enum msm_vidc_core_event_type type, - struct msm_vidc_event_data *data); -}; +enum msm_vidc_event FOREACH_EVENT(GENERATE_MSM_VIDC_ENUM); +/* core statemachine functions */ enum msm_vidc_allow msm_vidc_allow_core_state_change( struct msm_vidc_core *core, enum msm_vidc_core_state req_state); int msm_vidc_update_core_state(struct msm_vidc_core *core, @@ -55,4 +64,11 @@ bool is_core_sub_state(struct msm_vidc_core *core, const char *core_state_name(enum msm_vidc_core_state state); 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); + #endif // _MSM_VIDC_STATE_H_ diff --git a/driver/vidc/inc/msm_vidc_vb2.h b/driver/vidc/inc/msm_vidc_vb2.h index 50492af4f6..3deb3a5598 100644 --- a/driver/vidc/inc/msm_vidc_vb2.h +++ b/driver/vidc/inc/msm_vidc_vb2.h @@ -35,14 +35,15 @@ int msm_vb2_map_dmabuf(void *buf_priv); void msm_vb2_unmap_dmabuf(void *buf_priv); /* vb2_ops */ -int msm_vidc_queue_setup(struct vb2_queue *q, +int msm_vb2_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], struct device *alloc_devs[]); -int msm_vidc_start_streaming(struct vb2_queue *q, unsigned int count); -void msm_vidc_stop_streaming(struct vb2_queue *q); -void msm_vidc_buf_queue(struct vb2_buffer *vb2); -void msm_vidc_buf_cleanup(struct vb2_buffer *vb); -int msm_vidc_buf_out_validate(struct vb2_buffer *vb); -void msm_vidc_buf_request_complete(struct vb2_buffer *vb); - +int msm_vidc_start_streaming(struct msm_vidc_inst *inst, struct vb2_queue *q); +int msm_vidc_stop_streaming(struct msm_vidc_inst *inst, struct vb2_queue *q); +int msm_vb2_start_streaming(struct vb2_queue *q, unsigned int count); +void msm_vb2_stop_streaming(struct vb2_queue *q); +void msm_vb2_buf_queue(struct vb2_buffer *vb2); +void msm_vb2_buf_cleanup(struct vb2_buffer *vb); +int msm_vb2_buf_out_validate(struct vb2_buffer *vb); +void msm_vb2_request_complete(struct vb2_buffer *vb); #endif // _MSM_VIDC_VB2_H_ diff --git a/driver/vidc/src/msm_vdec.c b/driver/vidc/src/msm_vdec.c index 5b2516d38c..90cc6cf647 100644 --- a/driver/vidc/src/msm_vdec.c +++ b/driver/vidc/src/msm_vdec.c @@ -1874,11 +1874,8 @@ static int msm_vdec_qbuf_batch(struct msm_vidc_inst *inst, if (!buf) return -EINVAL; - allow = msm_vidc_allow_qbuf(inst, vb2->type); - if (allow == MSM_VIDC_DISALLOW) { - i_vpr_e(inst, "%s: qbuf not allowed\n", __func__); - return -EINVAL; - } else if (allow == MSM_VIDC_DEFER) { + if (is_state(inst, MSM_VIDC_OPEN) || + is_state(inst, MSM_VIDC_INPUT_STREAMING)) { print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf); return 0; } @@ -2068,95 +2065,96 @@ static int msm_vdec_alloc_and_queue_additional_dpb_buffers(struct msm_vidc_inst return 0; } -int msm_vdec_process_cmd(struct msm_vidc_inst *inst, u32 cmd) +int msm_vdec_stop_cmd(struct msm_vidc_inst *inst) { - int rc = 0; enum msm_vidc_allow allow = MSM_VIDC_DISALLOW; - struct msm_vidc_inst_capability *capability; + int rc = 0; - if (!inst || !inst->core || !inst->capabilities) { + i_vpr_h(inst, "received cmd: drain\n"); + allow = msm_vidc_allow_stop(inst); + if (allow == MSM_VIDC_DISALLOW) + return -EBUSY; + else if (allow == MSM_VIDC_IGNORE) + return 0; + else if (allow != MSM_VIDC_ALLOW) + return -EINVAL; + rc = msm_vidc_process_drain(inst); + if (rc) + return rc; + + return rc; +} + +int msm_vdec_start_cmd(struct msm_vidc_inst *inst) +{ + struct msm_vidc_inst_capability *capability; + int rc = 0; + + if (!inst || !inst->capabilities) { d_vpr_e("%s: invalid params\n", __func__); return -EINVAL; } capability = inst->capabilities; - if (cmd == V4L2_DEC_CMD_STOP) { - i_vpr_h(inst, "received cmd: drain\n"); - allow = msm_vidc_allow_stop(inst); - if (allow == MSM_VIDC_DISALLOW) - return -EBUSY; - else if (allow == MSM_VIDC_IGNORE) - return 0; - else if (allow != MSM_VIDC_ALLOW) - return -EINVAL; - rc = msm_vidc_process_drain(inst); - if (rc) - return rc; - } else if (cmd == V4L2_DEC_CMD_START) { - i_vpr_h(inst, "received cmd: resume\n"); - vb2_clear_last_buffer_dequeued(inst->bufq[OUTPUT_META_PORT].vb2q); - vb2_clear_last_buffer_dequeued(inst->bufq[OUTPUT_PORT].vb2q); + i_vpr_h(inst, "received cmd: resume\n"); + vb2_clear_last_buffer_dequeued(inst->bufq[OUTPUT_META_PORT].vb2q); + vb2_clear_last_buffer_dequeued(inst->bufq[OUTPUT_PORT].vb2q); - if (capability->cap[CODED_FRAMES].value == CODED_FRAMES_INTERLACE && - !is_ubwc_colorformat(capability->cap[PIX_FMTS].value)) { - i_vpr_e(inst, - "%s: interlace with non-ubwc color format is unsupported\n", - __func__); - return -EINVAL; - } - - if (!msm_vidc_allow_start(inst)) - return -EBUSY; - - /* tune power features */ - inst->decode_batch.enable = msm_vidc_allow_decode_batch(inst); - msm_vidc_allow_dcvs(inst); - msm_vidc_power_data_reset(inst); - - /* - * client is completing partial port reconfiguration, - * hence reallocate input internal buffers before input port - * is resumed. - */ - if (is_sub_state(inst, MSM_VIDC_DRC) && - is_sub_state(inst, MSM_VIDC_DRC_LAST_BUFFER) && - is_sub_state(inst, MSM_VIDC_INPUT_PAUSE)) { - rc = msm_vidc_alloc_and_queue_input_internal_buffers(inst); - if (rc) - return rc; - - rc = msm_vidc_set_stage(inst, STAGE); - if (rc) - return rc; - - rc = msm_vidc_set_pipe(inst, PIPE); - if (rc) - return rc; - } - - /* allocate and queue extra dpb buffers */ - rc = msm_vdec_alloc_and_queue_additional_dpb_buffers(inst); - if (rc) - return rc; - - /* queue pending deferred buffers */ - rc = msm_vidc_queue_deferred_buffers(inst, MSM_VIDC_BUF_OUTPUT); - if (rc) - return rc; - - /* print final buffer counts & size details */ - msm_vidc_print_buffer_info(inst); - - rc = msm_vidc_process_resume(inst); - if (rc) - return rc; - - } else { - i_vpr_e(inst, "%s: unknown cmd %d\n", __func__, cmd); + if (capability->cap[CODED_FRAMES].value == CODED_FRAMES_INTERLACE && + !is_ubwc_colorformat(capability->cap[PIX_FMTS].value)) { + i_vpr_e(inst, + "%s: interlace with non-ubwc color format is unsupported\n", + __func__); return -EINVAL; } - return 0; + if (!msm_vidc_allow_start(inst)) + return -EBUSY; + + /* tune power features */ + inst->decode_batch.enable = msm_vidc_allow_decode_batch(inst); + msm_vidc_allow_dcvs(inst); + msm_vidc_power_data_reset(inst); + + /* + * client is completing partial port reconfiguration, + * hence reallocate input internal buffers before input port + * is resumed. + */ + if (is_sub_state(inst, MSM_VIDC_DRC) && + is_sub_state(inst, MSM_VIDC_DRC_LAST_BUFFER) && + is_sub_state(inst, MSM_VIDC_INPUT_PAUSE)) { + rc = msm_vidc_alloc_and_queue_input_internal_buffers(inst); + if (rc) + return rc; + + rc = msm_vidc_set_stage(inst, STAGE); + if (rc) + return rc; + + rc = msm_vidc_set_pipe(inst, PIPE); + if (rc) + return rc; + } + + /* allocate and queue extra dpb buffers */ + rc = msm_vdec_alloc_and_queue_additional_dpb_buffers(inst); + if (rc) + return rc; + + /* queue pending deferred buffers */ + rc = msm_vidc_queue_deferred_buffers(inst, MSM_VIDC_BUF_OUTPUT); + if (rc) + return rc; + + /* print final buffer counts & size details */ + msm_vidc_print_buffer_info(inst); + + rc = msm_vidc_process_resume(inst); + if (rc) + return rc; + + return rc; } int msm_vdec_try_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f) diff --git a/driver/vidc/src/msm_venc.c b/driver/vidc/src/msm_venc.c index 690d9bb109..0249915b88 100644 --- a/driver/vidc/src/msm_venc.c +++ b/driver/vidc/src/msm_venc.c @@ -881,50 +881,48 @@ int msm_venc_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb2) return rc; } -int msm_venc_process_cmd(struct msm_vidc_inst *inst, u32 cmd) +int msm_venc_stop_cmd(struct msm_vidc_inst *inst) +{ + enum msm_vidc_allow allow = MSM_VIDC_DISALLOW; + int rc = 0; + + i_vpr_h(inst, "received cmd: drain\n"); + allow = msm_vidc_allow_stop(inst); + if (allow == MSM_VIDC_DISALLOW) + return -EBUSY; + else if (allow == MSM_VIDC_IGNORE) + return 0; + else if (allow != MSM_VIDC_ALLOW) + return -EINVAL; + rc = msm_vidc_process_drain(inst); + if (rc) + return rc; + + return rc; +} + +int msm_venc_start_cmd(struct msm_vidc_inst *inst) { int rc = 0; - enum msm_vidc_allow allow = MSM_VIDC_DISALLOW; - if (!inst || !inst->core) { - d_vpr_e("%s: invalid params\n", __func__); - return -EINVAL; - } + i_vpr_h(inst, "received cmd: resume\n"); + if (!msm_vidc_allow_start(inst)) + return -EBUSY; + vb2_clear_last_buffer_dequeued(inst->bufq[OUTPUT_META_PORT].vb2q); + vb2_clear_last_buffer_dequeued(inst->bufq[OUTPUT_PORT].vb2q); - if (cmd == V4L2_ENC_CMD_STOP) { - i_vpr_h(inst, "received cmd: drain\n"); - allow = msm_vidc_allow_stop(inst); - if (allow == MSM_VIDC_DISALLOW) - return -EBUSY; - else if (allow == MSM_VIDC_IGNORE) - return 0; - else if (allow != MSM_VIDC_ALLOW) - return -EINVAL; - rc = msm_vidc_process_drain(inst); - if (rc) - return rc; - } else if (cmd == V4L2_ENC_CMD_START) { - i_vpr_h(inst, "received cmd: resume\n"); - if (!msm_vidc_allow_start(inst)) - return -EBUSY; - vb2_clear_last_buffer_dequeued(inst->bufq[OUTPUT_META_PORT].vb2q); - vb2_clear_last_buffer_dequeued(inst->bufq[OUTPUT_PORT].vb2q); + /* tune power features */ + msm_vidc_allow_dcvs(inst); + msm_vidc_power_data_reset(inst); - /* tune power features */ - msm_vidc_allow_dcvs(inst); - msm_vidc_power_data_reset(inst); + /* print final buffer counts & size details */ + msm_vidc_print_buffer_info(inst); - /* print final buffer counts & size details */ - msm_vidc_print_buffer_info(inst); + rc = msm_vidc_process_resume(inst); + if (rc) + return rc; - rc = msm_vidc_process_resume(inst); - if (rc) - return rc; - } else { - i_vpr_e(inst, "%s: unknown cmd %d\n", __func__, cmd); - return -EINVAL; - } - return 0; + return rc; } int msm_venc_streamoff_output(struct msm_vidc_inst *inst) diff --git a/driver/vidc/src/msm_vidc.c b/driver/vidc/src/msm_vidc.c index f81b1e54b7..449ffee961 100644 --- a/driver/vidc/src/msm_vidc.c +++ b/driver/vidc/src/msm_vidc.c @@ -658,26 +658,53 @@ int msm_vidc_try_cmd(void *instance, union msm_v4l2_cmd *cmd) } EXPORT_SYMBOL(msm_vidc_try_cmd); -int msm_vidc_cmd(void *instance, union msm_v4l2_cmd *cmd) +int msm_vidc_start_cmd(void *instance) { - int rc = 0; struct msm_vidc_inst *inst = instance; - struct v4l2_decoder_cmd *dec = NULL; - struct v4l2_encoder_cmd *enc = NULL; + int rc = 0; + + if (!is_decode_session(inst) && !is_encode_session(inst)) { + i_vpr_e(inst, "%s: invalid session %d\n", __func__, inst->domain); + return -EINVAL; + } if (is_decode_session(inst)) { - dec = (struct v4l2_decoder_cmd *)cmd; - rc = msm_vdec_process_cmd(inst, dec->cmd); + rc = msm_vdec_start_cmd(inst); + if (rc) + return rc; } else if (is_encode_session(inst)) { - enc = (struct v4l2_encoder_cmd *)cmd; - rc = msm_venc_process_cmd(inst, enc->cmd); + rc = msm_venc_start_cmd(inst); + if (rc) + return rc; } - if (rc) - return rc; - return 0; + return rc; } -EXPORT_SYMBOL(msm_vidc_cmd); +EXPORT_SYMBOL(msm_vidc_start_cmd); + +int msm_vidc_stop_cmd(void *instance) +{ + struct msm_vidc_inst *inst = instance; + int rc = 0; + + if (!is_decode_session(inst) && !is_encode_session(inst)) { + i_vpr_e(inst, "%s: invalid session %d\n", __func__, inst->domain); + return -EINVAL; + } + + if (is_decode_session(inst)) { + rc = msm_vdec_stop_cmd(inst); + if (rc) + return rc; + } else if (is_encode_session(inst)) { + rc = msm_venc_stop_cmd(inst); + if (rc) + return rc; + } + + return rc; +} +EXPORT_SYMBOL(msm_vidc_stop_cmd); int msm_vidc_enum_framesizes(void *instance, struct v4l2_frmsizeenum *fsize) { @@ -894,7 +921,7 @@ void *msm_vidc_open(void *vidc_core, u32 session_type) inst->core = core; inst->domain = session_type; inst->session_id = hash32_ptr(inst); - msm_vidc_change_state(inst, MSM_VIDC_OPEN, __func__); + msm_vidc_update_state(inst, MSM_VIDC_OPEN, __func__); inst->sub_state = MSM_VIDC_SUB_STATE_NONE; strlcpy(inst->sub_state_name, "SUB_STATE_NONE", sizeof(inst->sub_state_name)); inst->active = true; @@ -1041,6 +1068,9 @@ int msm_vidc_close(void *instance) msm_vidc_event_queue_deinit(inst); msm_vidc_vb2_queue_deinit(inst); msm_vidc_remove_session(inst); + msm_vidc_change_state(inst, MSM_VIDC_CLOSE, __func__); + inst->sub_state = MSM_VIDC_SUB_STATE_NONE; + strscpy(inst->sub_state_name, "SUB_STATE_NONE", sizeof(inst->sub_state_name)); inst_unlock(inst, __func__); client_unlock(inst, __func__); cancel_stability_work_sync(inst); diff --git a/driver/vidc/src/msm_vidc_control.c b/driver/vidc/src/msm_vidc_control.c index 1c7f7f8a41..38c7370e5b 100644 --- a/driver/vidc/src/msm_vidc_control.c +++ b/driver/vidc/src/msm_vidc_control.c @@ -841,29 +841,17 @@ static int msm_vidc_update_static_property(struct msm_vidc_inst *inst, return rc; } -int msm_v4l2_op_s_ctrl(struct v4l2_ctrl *ctrl) +int msm_vidc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) { - int rc = 0; - struct msm_vidc_inst *inst; enum msm_vidc_inst_capability_type cap_id; struct msm_vidc_inst_capability *capability; + int rc = 0; u32 port; - if (!ctrl) { - d_vpr_e("%s: invalid ctrl parameter\n", __func__); + if (!inst || !inst->capabilities || !ctrl) { + d_vpr_e("%s: invalid params\n", __func__); return -EINVAL; } - - inst = container_of(ctrl->handler, - struct msm_vidc_inst, ctrl_handler); - inst = get_inst_ref(g_core, inst); - if (!inst || !inst->capabilities) { - d_vpr_e("%s: invalid parameters for inst\n", __func__); - return -EINVAL; - } - - client_lock(inst, __func__); - inst_lock(inst, __func__); capability = inst->capabilities; i_vpr_h(inst, FMT_STRING_SET_CTRL, @@ -871,15 +859,8 @@ int msm_v4l2_op_s_ctrl(struct v4l2_ctrl *ctrl) cap_id = msm_vidc_get_cap_id(inst, ctrl->id); if (!is_valid_cap_id(cap_id)) { - i_vpr_e(inst, "%s: could not find cap_id for ctrl %s\n", - __func__, ctrl->name); - rc = -EINVAL; - goto unlock; - } - - if (!msm_vidc_allow_s_ctrl(inst, cap_id)) { - rc = -EINVAL; - goto unlock; + i_vpr_e(inst, "%s: invalid cap_id for ctrl %s\n", __func__, ctrl->name); + return -EINVAL; } /* mark client set flag */ @@ -890,18 +871,44 @@ int msm_v4l2_op_s_ctrl(struct v4l2_ctrl *ctrl) /* static case */ rc = msm_vidc_update_static_property(inst, cap_id, ctrl); if (rc) - goto unlock; + return rc; } else { /* dynamic case */ rc = msm_vidc_adjust_dynamic_property(inst, cap_id, ctrl); if (rc) - goto unlock; + return rc; rc = msm_vidc_set_dynamic_property(inst); if (rc) - goto unlock; + return rc; } + return rc; +} + +int msm_v4l2_op_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct msm_vidc_inst *inst; + int rc = 0; + + if (!ctrl) { + d_vpr_e("%s: invalid ctrl parameter\n", __func__); + return -EINVAL; + } + + inst = container_of(ctrl->handler, struct msm_vidc_inst, ctrl_handler); + inst = get_inst_ref(g_core, inst); + if (!inst) { + d_vpr_e("%s: invalid instance\n", __func__); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + rc = inst->event_handle(inst, MSM_VIDC_S_CTRL, ctrl); + if (rc) + goto unlock; + unlock: inst_unlock(inst, __func__); client_unlock(inst, __func__); diff --git a/driver/vidc/src/msm_vidc_driver.c b/driver/vidc/src/msm_vidc_driver.c index 349542e370..7b39fd855c 100644 --- a/driver/vidc/src/msm_vidc_driver.c +++ b/driver/vidc/src/msm_vidc_driver.c @@ -130,6 +130,28 @@ const char *sub_state_name(enum msm_vidc_sub_state sub_state) 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) { @@ -888,7 +910,7 @@ struct msm_vidc_buffers *msm_vidc_get_buffers( return &inst->buffers.vpss; case MSM_VIDC_BUF_PARTIAL_DATA: return &inst->buffers.partial_data; - case MSM_VIDC_BUF_QUEUE: + case MSM_VIDC_BUF_INTERFACE_QUEUE: return NULL; default: i_vpr_e(inst, "%s: invalid driver buffer type %d\n", @@ -994,16 +1016,14 @@ int signal_session_msg_receipt(struct msm_vidc_inst *inst, 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 (!request_state) { - i_vpr_e(inst, "%s: invalid request state\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", @@ -1011,17 +1031,23 @@ int msm_vidc_change_state(struct msm_vidc_inst *inst, return 0; } - if (request_state == MSM_VIDC_ERROR) - i_vpr_e(inst, FMT_STRING_STATE_CHANGE, - func, state_name(request_state), state_name(inst->state)); - else - i_vpr_h(inst, FMT_STRING_STATE_CHANGE, - func, state_name(request_state), state_name(inst->state)); + /* current and requested state is same */ + if (inst->state == request_state) + return 0; - trace_msm_vidc_common_state_change(inst, func, state_name(inst->state), + /* 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); + } - inst->state = request_state; + /* go ahead and update inst state */ + rc = msm_vidc_update_state(inst, request_state, func); + if (rc) + return rc; return 0; } @@ -1030,8 +1056,8 @@ 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 i = 0; enum msm_vidc_sub_state prev_sub_state; + int rc = 0; if (!inst) { d_vpr_e("%s: invalid params\n", __func__); @@ -1061,18 +1087,11 @@ int msm_vidc_change_sub_state(struct msm_vidc_inst *inst, /* print substates only when there is a change */ if (inst->sub_state != prev_sub_state) { - strlcpy(inst->sub_state_name, "\0", sizeof(inst->sub_state_name)); - for (i = 0; i < MSM_VIDC_MAX_SUB_STATES; i++) { - if (inst->sub_state == MSM_VIDC_SUB_STATE_NONE) { - strlcpy(inst->sub_state_name, "SUB_STATE_NONE", - sizeof(inst->sub_state_name)); - break; - } - if (inst->sub_state & BIT(i)) - strlcat(inst->sub_state_name, sub_state_name(BIT(i)), - sizeof(inst->sub_state_name)); - } - i_vpr_h(inst, "%s: sub state changed to %s\n", func, inst->sub_state_name); + 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; @@ -1110,55 +1129,6 @@ exit: return allow; } -bool msm_vidc_allow_s_ctrl(struct msm_vidc_inst *inst, - enum msm_vidc_inst_capability_type cap_id) -{ - bool allow = false; - - if (!inst || !inst->capabilities) { - d_vpr_e("%s: invalid params\n", __func__); - return false; - } - if (is_state(inst, MSM_VIDC_OPEN)) { - allow = true; - goto exit; - } - - if (!inst->capabilities->cap[cap_id].cap_id || - !inst->capabilities->cap[cap_id].v4l2_id) { - allow = false; - goto exit; - } - - if (is_decode_session(inst)) { - if (!inst->bufq[INPUT_PORT].vb2q->streaming) { - allow = true; - goto exit; - } - if (inst->bufq[INPUT_PORT].vb2q->streaming) { - if (inst->capabilities->cap[cap_id].flags & - CAP_FLAG_DYNAMIC_ALLOWED) - allow = true; - } - } else if (is_encode_session(inst)) { - if (!inst->bufq[OUTPUT_PORT].vb2q->streaming) { - allow = true; - goto exit; - } - if (inst->bufq[OUTPUT_PORT].vb2q->streaming) { - if (inst->capabilities->cap[cap_id].flags & - CAP_FLAG_DYNAMIC_ALLOWED) - allow = true; - } - } - -exit: - if (!allow) - i_vpr_e(inst, "%s: cap_id %#x not allowed in state %s\n", - __func__, cap_id, state_name(inst->state)); - return allow; -} - bool msm_vidc_allow_metadata_delivery(struct msm_vidc_inst *inst, u32 cap_id, u32 port) { @@ -1387,79 +1357,6 @@ bool msm_vidc_allow_streamon(struct msm_vidc_inst *inst, u32 type) return false; } -enum msm_vidc_allow msm_vidc_allow_streamoff(struct msm_vidc_inst *inst, u32 type) -{ - enum msm_vidc_allow allow = MSM_VIDC_ALLOW; - - if (!inst) { - d_vpr_e("%s: invalid params\n", __func__); - return MSM_VIDC_DISALLOW; - } - if (type == INPUT_MPLANE) { - if (!inst->bufq[INPUT_PORT].vb2q->streaming) - allow = MSM_VIDC_IGNORE; - } else if (type == INPUT_META_PLANE) { - if (inst->bufq[INPUT_PORT].vb2q->streaming) - allow = MSM_VIDC_DISALLOW; - else if (!inst->bufq[INPUT_META_PORT].vb2q->streaming) - allow = MSM_VIDC_IGNORE; - } else if (type == OUTPUT_MPLANE) { - if (!inst->bufq[OUTPUT_PORT].vb2q->streaming) - allow = MSM_VIDC_IGNORE; - } else if (type == OUTPUT_META_PLANE) { - if (inst->bufq[OUTPUT_PORT].vb2q->streaming) - allow = MSM_VIDC_DISALLOW; - else if (!inst->bufq[OUTPUT_META_PORT].vb2q->streaming) - allow = MSM_VIDC_IGNORE; - } - if (allow != MSM_VIDC_ALLOW) - i_vpr_e(inst, "%s: type %d is %s in state %s\n", - __func__, type, allow_name(allow), - state_name(inst->state)); - - return allow; -} - -enum msm_vidc_allow msm_vidc_allow_qbuf(struct msm_vidc_inst *inst, u32 type) -{ - int port = 0; - - if (!inst) { - d_vpr_e("%s: invalid params\n", __func__); - return MSM_VIDC_DISALLOW; - } - - port = v4l2_type_to_driver_port(inst, type, __func__); - if (port < 0) - return MSM_VIDC_DISALLOW; - - /* defer queuing if streamon not completed */ - if (!inst->bufq[port].vb2q->streaming) - return MSM_VIDC_DEFER; - - if (type == INPUT_META_PLANE || type == OUTPUT_META_PLANE) - return MSM_VIDC_DEFER; - - if (type == INPUT_MPLANE) { - if (is_state(inst, MSM_VIDC_OPEN) || - is_state(inst, MSM_VIDC_OUTPUT_STREAMING)) - return MSM_VIDC_DEFER; - else - return MSM_VIDC_ALLOW; - } else if (type == OUTPUT_MPLANE) { - if (is_state(inst, MSM_VIDC_OPEN) || - is_state(inst, MSM_VIDC_INPUT_STREAMING)) - return MSM_VIDC_DEFER; - else - return MSM_VIDC_ALLOW; - } else { - i_vpr_e(inst, "%s: unknown buffer type %d\n", __func__, type); - return MSM_VIDC_DISALLOW; - } - - return MSM_VIDC_DISALLOW; -} - enum msm_vidc_allow msm_vidc_allow_input_psc(struct msm_vidc_inst *inst) { enum msm_vidc_allow allow = MSM_VIDC_ALLOW; @@ -3339,12 +3236,29 @@ int msm_vidc_queue_deferred_buffers(struct msm_vidc_inst *inst, enum msm_vidc_bu return 0; } +int msm_vidc_buf_queue(struct msm_vidc_inst *inst, struct msm_vidc_buffer *buf) +{ + int rc = 0; + + if (!inst || !buf) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + msm_vidc_scale_power(inst, is_input_buffer(buf->type)); + + rc = msm_vidc_queue_buffer(inst, buf); + if (rc) + return rc; + + return rc; +} + int msm_vidc_queue_buffer_single(struct msm_vidc_inst *inst, struct vb2_buffer *vb2) { int rc = 0; struct msm_vidc_buffer *buf = NULL; struct msm_vidc_fence *fence = NULL; - enum msm_vidc_allow allow; if (!inst || !vb2 || !inst->capabilities) { d_vpr_e("%s: invalid params\n", __func__); @@ -3363,20 +3277,7 @@ int msm_vidc_queue_buffer_single(struct msm_vidc_inst *inst, struct vb2_buffer * buf->fence_id = fence->dma_fence.seqno; } - allow = msm_vidc_allow_qbuf(inst, vb2->type); - if (allow == MSM_VIDC_DISALLOW) { - i_vpr_e(inst, "%s: qbuf not allowed\n", __func__); - rc = -EINVAL; - goto exit; - } else if (allow == MSM_VIDC_DEFER) { - print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf); - rc = 0; - goto exit; - } - - msm_vidc_scale_power(inst, is_input_buffer(buf->type)); - - rc = msm_vidc_queue_buffer(inst, buf); + rc = inst->event_handle(inst, MSM_VIDC_BUF_QUEUE, buf); if (rc) goto exit; @@ -4198,10 +4099,6 @@ int msm_vidc_session_streamoff(struct msm_vidc_inst *inst, if (rc) goto error; - rc = msm_vidc_state_change_streamoff(inst, port); - if (rc) - goto error; - core = inst->core; i_vpr_h(inst, "%s: wait on port: %d for time: %d ms\n", __func__, port, core->capabilities[HW_RESPONSE_TIMEOUT].value); @@ -4241,6 +4138,10 @@ int msm_vidc_session_streamoff(struct msm_vidc_inst *inst, goto error; } + rc = msm_vidc_state_change_streamoff(inst, port); + if (rc) + goto error; + /* flush deferred buffers */ msm_vidc_flush_buffers(inst, buffer_type); msm_vidc_flush_read_only_buffers(inst, buffer_type); @@ -4290,10 +4191,6 @@ int msm_vidc_session_close(struct msm_vidc_inst *inst) } inst_lock(inst, __func__); - msm_vidc_change_state(inst, MSM_VIDC_CLOSE, __func__); - inst->sub_state = MSM_VIDC_SUB_STATE_NONE; - strlcpy(inst->sub_state_name, "SUB_STATE_NONE", sizeof(inst->sub_state_name)); - return rc; } @@ -5129,7 +5026,6 @@ void msm_vidc_fw_unload_handler(struct work_struct *work) void msm_vidc_batch_handler(struct work_struct *work) { struct msm_vidc_inst *inst; - enum msm_vidc_allow allow; struct msm_vidc_core *core; int rc = 0; @@ -5152,8 +5048,8 @@ void msm_vidc_batch_handler(struct work_struct *work) goto exit; } - allow = msm_vidc_allow_qbuf(inst, OUTPUT_MPLANE); - if (allow != MSM_VIDC_ALLOW) { + if (is_state(inst, MSM_VIDC_OPEN) || + is_state(inst, MSM_VIDC_INPUT_STREAMING)) { i_vpr_e(inst, "%s: not allowed in state: %s\n", __func__, state_name(inst->state)); goto exit; diff --git a/driver/vidc/src/msm_vidc_state.c b/driver/vidc/src/msm_vidc_state.c index 6f521deade..47f22241f4 100644 --- a/driver/vidc/src/msm_vidc_state.c +++ b/driver/vidc/src/msm_vidc_state.c @@ -4,10 +4,14 @@ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ +#include "msm_vidc_control.h" #include "msm_vidc_driver.h" #include "msm_vidc_state.h" -#include "msm_vidc_core.h" #include "msm_vidc_debug.h" +#include "msm_vidc_core.h" +#include "msm_vidc_vb2.h" +#include "msm_vidc.h" +#include "msm_vidc_events.h" bool core_in_valid_state(struct msm_vidc_core *core) { @@ -36,6 +40,22 @@ exit: return name; } +static const char * const event_name_arr[] = + FOREACH_EVENT(GENERATE_STRING); + +static const char *event_name(enum msm_vidc_event event) +{ + const char *name = "UNKNOWN EVENT"; + + if (event >= ARRAY_SIZE(event_name_arr)) + goto exit; + + name = event_name_arr[event]; + +exit: + return name; +} + static int __strict_check(struct msm_vidc_core *core, const char *function) { bool fatal = !mutex_is_locked(&core->lock); @@ -48,6 +68,18 @@ static int __strict_check(struct msm_vidc_core *core, const char *function) return fatal ? -EINVAL : 0; } +static int __strict_inst_check(struct msm_vidc_inst *inst, const char *function) +{ + bool fatal = !mutex_is_locked(&inst->lock); + + WARN_ON(fatal); + + if (fatal) + d_vpr_e("%s: strict check failed\n", function); + + return fatal ? -EINVAL : 0; +} + static int msm_vidc_core_deinit_state(struct msm_vidc_core *core, enum msm_vidc_core_event_type type, struct msm_vidc_event_data *data) @@ -181,7 +213,14 @@ static int msm_vidc_core_error_state(struct msm_vidc_core *core, return rc; } -struct msm_vidc_core_state_handle *msm_vidc_get_core_state_handle( +struct msm_vidc_core_state_handle { + enum msm_vidc_core_state state; + int (*handle)(struct msm_vidc_core *core, + enum msm_vidc_core_event_type type, + struct msm_vidc_event_data *data); +}; + +static struct msm_vidc_core_state_handle *msm_vidc_get_core_state_handle( enum msm_vidc_core_state req_state) { int cnt; @@ -456,3 +495,698 @@ int msm_vidc_change_core_sub_state(struct msm_vidc_core *core, return 0; } + +static int msm_vidc_open_state(struct msm_vidc_inst *inst, + enum msm_vidc_event event, void *data) +{ + int rc = 0; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + /* inst must be locked */ + rc = __strict_inst_check(inst, __func__); + if (rc) { + i_vpr_e(inst, "%s(): inst was not locked\n", __func__); + return -EINVAL; + } + + switch (event) { + case MSM_VIDC_S_FMT: + { + struct v4l2_format *f = (struct v4l2_format *)data; + + rc = msm_vidc_s_fmt(inst, f); + if (rc) + return rc; + break; + } + case MSM_VIDC_S_CTRL: + { + struct v4l2_ctrl *ctrl = (struct v4l2_ctrl *)data; + + /* allow set_control request in open state */ + rc = msm_vidc_s_ctrl(inst, ctrl); + if (rc) + return rc; + break; + } + case MSM_VIDC_REQBUFS: + { + struct v4l2_requestbuffers *b = (struct v4l2_requestbuffers *)data; + + rc = msm_vidc_reqbufs(inst, b); + if (rc) + return rc; + break; + } + case MSM_VIDC_STREAMON: + { + struct vb2_queue *q = (struct vb2_queue *)data; + + rc = msm_vidc_start_streaming(inst, q); + if (rc) + return rc; + break; + } + case MSM_VIDC_STREAMOFF: + { + struct vb2_queue *q = (struct vb2_queue *)data; + + /* ignore streamoff request in open state */ + i_vpr_e(inst, "%s: type %d is %s in state %s\n", + __func__, q->type, allow_name(MSM_VIDC_IGNORE), + state_name(inst->state)); + break; + } + case MSM_VIDC_CMD_START: + { + rc = msm_vidc_start_cmd(inst); + if (rc) + return rc; + break; + } + case MSM_VIDC_CMD_STOP: + { + rc = msm_vidc_stop_cmd(inst); + if (rc) + return rc; + break; + } + case MSM_VIDC_BUF_QUEUE: + { + struct msm_vidc_buffer *buf = (struct msm_vidc_buffer *)data; + + /* defer qbuf request in open state */ + print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf); + break; + } + default: + { + i_vpr_e(inst, "%s: unexpected event %s\n", __func__, event_name(event)); + return -EINVAL; + } + } + + return rc; +} + +static int msm_vidc_input_streaming_state(struct msm_vidc_inst *inst, + enum msm_vidc_event event, void *data) +{ + int rc = 0; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + /* inst must be locked */ + rc = __strict_inst_check(inst, __func__); + if (rc) { + i_vpr_e(inst, "%s(): inst was not locked\n", __func__); + return -EINVAL; + } + + switch (event) { + case MSM_VIDC_S_FMT: + { + struct v4l2_format *f = (struct v4l2_format *)data; + + rc = msm_vidc_s_fmt(inst, f); + if (rc) + return rc; + break; + } + case MSM_VIDC_S_CTRL: + { + struct v4l2_ctrl *ctrl = (struct v4l2_ctrl *)data; + u32 cap_id = msm_vidc_get_cap_id(inst, ctrl->id); + + if (cap_id == INST_CAP_NONE) { + i_vpr_e(inst, "%s: invalid cap_id %u\n", __func__, cap_id); + return -EINVAL; + } + + /* disallow */ + if (is_decode_session(inst)) { + /* check dynamic allowed if master port is streaming */ + if (!(inst->capabilities->cap[cap_id].flags & CAP_FLAG_DYNAMIC_ALLOWED)) { + i_vpr_e(inst, "%s: cap_id %#x not allowed in state %s\n", + __func__, cap_id, state_name(inst->state)); + return -EINVAL; + } + } + + rc = msm_vidc_s_ctrl(inst, ctrl); + if (rc) + return rc; + break; + } + case MSM_VIDC_REQBUFS: + { + struct v4l2_requestbuffers *b = (struct v4l2_requestbuffers *)data; + + rc = msm_vidc_reqbufs(inst, b); + if (rc) + return rc; + break; + } + case MSM_VIDC_STREAMON: + { + struct vb2_queue *q = (struct vb2_queue *)data; + + rc = msm_vidc_start_streaming(inst, q); + if (rc) + return rc; + break; + } + case MSM_VIDC_STREAMOFF: + { + struct vb2_queue *q = (struct vb2_queue *)data; + enum msm_vidc_allow allow = MSM_VIDC_ALLOW; + + /* ignore */ + if (q->type == OUTPUT_MPLANE || q->type == OUTPUT_META_PLANE) + allow = MSM_VIDC_IGNORE; + /* disallow */ + else if (q->type == INPUT_META_PLANE) + allow = MSM_VIDC_DISALLOW; + + if (allow != MSM_VIDC_ALLOW) { + i_vpr_e(inst, "%s: type %d is %s in state %s\n", + __func__, q->type, allow_name(allow), + state_name(inst->state)); + return (allow == MSM_VIDC_DISALLOW ? -EINVAL : 0); + } + + /* sanitize type field */ + if (q->type != INPUT_MPLANE) { + i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type); + return -EINVAL; + } + + rc = msm_vidc_stop_streaming(inst, q); + if (rc) + return rc; + break; + } + case MSM_VIDC_CMD_START: + { + rc = msm_vidc_start_cmd(inst); + if (rc) + return rc; + break; + } + case MSM_VIDC_CMD_STOP: + { + rc = msm_vidc_stop_cmd(inst); + if (rc) + 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)); + return -EINVAL; + } + } + + return rc; +} + +static int msm_vidc_output_streaming_state(struct msm_vidc_inst *inst, + enum msm_vidc_event event, void *data) +{ + int rc = 0; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + /* inst must be locked */ + rc = __strict_inst_check(inst, __func__); + if (rc) { + i_vpr_e(inst, "%s(): inst was not locked\n", __func__); + return -EINVAL; + } + + switch (event) { + case MSM_VIDC_S_FMT: + { + struct v4l2_format *f = (struct v4l2_format *)data; + + rc = msm_vidc_s_fmt(inst, f); + if (rc) + return rc; + break; + } + case MSM_VIDC_S_CTRL: + { + struct v4l2_ctrl *ctrl = (struct v4l2_ctrl *)data; + u32 cap_id = msm_vidc_get_cap_id(inst, ctrl->id); + + if (cap_id == INST_CAP_NONE) { + i_vpr_e(inst, "%s: invalid cap_id %u\n", __func__, cap_id); + return -EINVAL; + } + + /* disallow */ + if (is_encode_session(inst)) { + /* check dynamic allowed if master port is streaming */ + if (!(inst->capabilities->cap[cap_id].flags & CAP_FLAG_DYNAMIC_ALLOWED)) { + i_vpr_e(inst, "%s: cap_id %#x not allowed in state %s\n", + __func__, cap_id, state_name(inst->state)); + return -EINVAL; + } + } + + rc = msm_vidc_s_ctrl(inst, ctrl); + if (rc) + return rc; + break; + } + case MSM_VIDC_REQBUFS: + { + struct v4l2_requestbuffers *b = (struct v4l2_requestbuffers *)data; + + rc = msm_vidc_reqbufs(inst, b); + if (rc) + return rc; + break; + } + case MSM_VIDC_STREAMON: + { + struct vb2_queue *q = (struct vb2_queue *)data; + + rc = msm_vidc_start_streaming(inst, q); + if (rc) + return rc; + break; + } + case MSM_VIDC_STREAMOFF: + { + struct vb2_queue *q = (struct vb2_queue *)data; + enum msm_vidc_allow allow = MSM_VIDC_ALLOW; + + /* ignore */ + if (q->type == INPUT_MPLANE || q->type == INPUT_META_PLANE) + allow = MSM_VIDC_IGNORE; + /* disallow */ + else if (q->type == OUTPUT_META_PLANE) + allow = MSM_VIDC_DISALLOW; + + if (allow != MSM_VIDC_ALLOW) { + i_vpr_e(inst, "%s: type %d is %s in state %s\n", + __func__, q->type, allow_name(allow), + state_name(inst->state)); + return (allow == MSM_VIDC_DISALLOW ? -EINVAL : 0); + } + + /* sanitize type field */ + if (q->type != OUTPUT_MPLANE) { + i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type); + return -EINVAL; + } + + rc = msm_vidc_stop_streaming(inst, q); + if (rc) + return rc; + break; + } + case MSM_VIDC_CMD_START: + { + rc = msm_vidc_start_cmd(inst); + if (rc) + return rc; + break; + } + case MSM_VIDC_CMD_STOP: + { + rc = msm_vidc_stop_cmd(inst); + if (rc) + 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; + } + } + + return rc; +} + +static int msm_vidc_streaming_state(struct msm_vidc_inst *inst, + enum msm_vidc_event event, void *data) +{ + int rc = 0; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + /* inst must be locked */ + rc = __strict_inst_check(inst, __func__); + if (rc) { + i_vpr_e(inst, "%s(): inst was not locked\n", __func__); + return -EINVAL; + } + + switch (event) { + case MSM_VIDC_S_CTRL: + { + struct v4l2_ctrl *ctrl = (struct v4l2_ctrl *)data; + u32 cap_id = msm_vidc_get_cap_id(inst, ctrl->id); + + if (cap_id == INST_CAP_NONE) { + i_vpr_e(inst, "%s: invalid cap_id %u\n", __func__, cap_id); + return -EINVAL; + } + + /* disallow */ + if (!(inst->capabilities->cap[cap_id].flags & CAP_FLAG_DYNAMIC_ALLOWED)) { + i_vpr_e(inst, "%s: cap_id %#x not allowed in state %s\n", + __func__, cap_id, state_name(inst->state)); + return -EINVAL; + } + + rc = msm_vidc_s_ctrl(inst, ctrl); + if (rc) + return rc; + break; + } + case MSM_VIDC_STREAMOFF: + { + struct vb2_queue *q = (struct vb2_queue *)data; + + /* disallow */ + if (q->type == INPUT_META_PLANE || q->type == OUTPUT_META_PLANE) { + i_vpr_e(inst, "%s: type %d is %s in state %s\n", + __func__, q->type, allow_name(MSM_VIDC_DISALLOW), + state_name(inst->state)); + return -EINVAL; + } + + /* sanitize type field */ + if (q->type != INPUT_MPLANE && q->type != OUTPUT_MPLANE) { + i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type); + return -EINVAL; + } + + rc = msm_vidc_stop_streaming(inst, q); + if (rc) + return rc; + break; + } + case MSM_VIDC_CMD_START: + { + rc = msm_vidc_start_cmd(inst); + if (rc) + return rc; + break; + } + case MSM_VIDC_CMD_STOP: + { + rc = msm_vidc_stop_cmd(inst); + if (rc) + 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; + } + } + + return rc; +} + +static int msm_vidc_close_state(struct msm_vidc_inst *inst, + enum msm_vidc_event event, void *data) +{ + int rc = 0; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + /* inst must be locked */ + rc = __strict_inst_check(inst, __func__); + if (rc) { + i_vpr_e(inst, "%s(): inst was not locked\n", __func__); + return -EINVAL; + } + + i_vpr_e(inst, "%s: unexpected event %s\n", __func__, event_name(event)); + + return -EINVAL; +} + +static int msm_vidc_error_state(struct msm_vidc_inst *inst, + enum msm_vidc_event event, void *data) +{ + int rc = 0; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + /* inst must be locked */ + rc = __strict_inst_check(inst, __func__); + if (rc) { + i_vpr_e(inst, "%s(): inst was not locked\n", __func__); + return -EINVAL; + } + + switch (event) { + case MSM_VIDC_STREAMOFF: + { + struct vb2_queue *q = (struct vb2_queue *)data; + + rc = msm_vidc_stop_streaming(inst, q); + if (rc) + return rc; + break; + } + default: { + i_vpr_e(inst, "%s: unexpected event %s\n", __func__, event_name(event)); + return -EINVAL; + } + } + + return rc; +} + +struct msm_vidc_state_handle { + enum msm_vidc_state state; + int (*handle)(struct msm_vidc_inst *inst, + enum msm_vidc_event event, void *data); +}; + +static struct msm_vidc_state_handle *msm_vidc_get_state_handle( + struct msm_vidc_inst *inst, + enum msm_vidc_state req_state) +{ + int cnt; + struct msm_vidc_state_handle *inst_state_handle = NULL; + static struct msm_vidc_state_handle state_handle[] = { + {MSM_VIDC_OPEN, msm_vidc_open_state }, + {MSM_VIDC_INPUT_STREAMING, msm_vidc_input_streaming_state }, + {MSM_VIDC_OUTPUT_STREAMING, msm_vidc_output_streaming_state }, + {MSM_VIDC_STREAMING, msm_vidc_streaming_state }, + {MSM_VIDC_CLOSE, msm_vidc_close_state }, + {MSM_VIDC_ERROR, msm_vidc_error_state }, + }; + + for (cnt = 0; cnt < ARRAY_SIZE(state_handle); cnt++) { + if (state_handle[cnt].state == req_state) { + inst_state_handle = &state_handle[cnt]; + break; + } + } + + /* check if req_state does not exist in the table */ + if (cnt == ARRAY_SIZE(state_handle)) { + i_vpr_e(inst, "%s: invalid state %s\n", __func__, state_name(req_state)); + return inst_state_handle; + } + + return inst_state_handle; +} + +int msm_vidc_update_state(struct msm_vidc_inst *inst, + enum msm_vidc_state request_state, const char *func) +{ + struct msm_vidc_state_handle *state_handle = NULL; + int rc = 0; + + /* get inst state handler for requested state */ + state_handle = msm_vidc_get_state_handle(inst, request_state); + if (!state_handle) + return -EINVAL; + + if (request_state == MSM_VIDC_ERROR) + i_vpr_e(inst, FMT_STRING_STATE_CHANGE, + func, state_name(request_state), state_name(inst->state)); + else + i_vpr_h(inst, FMT_STRING_STATE_CHANGE, + func, state_name(request_state), state_name(inst->state)); + + trace_msm_vidc_common_state_change(inst, func, state_name(inst->state), + state_name(request_state)); + + /* finally update inst state and handler */ + inst->state = state_handle->state; + inst->event_handle = state_handle->handle; + + return rc; +} + +struct msm_vidc_state_allow { + enum msm_vidc_state from; + enum msm_vidc_state to; + enum msm_vidc_allow allow; +}; + +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; +} diff --git a/driver/vidc/src/msm_vidc_v4l2.c b/driver/vidc/src/msm_vidc_v4l2.c index f7b37ef78d..2fc8ea9662 100644 --- a/driver/vidc/src/msm_vidc_v4l2.c +++ b/driver/vidc/src/msm_vidc_v4l2.c @@ -166,7 +166,7 @@ int msm_v4l2_s_fmt(struct file *filp, void *fh, rc = -EBUSY; goto unlock; } - rc = msm_vidc_s_fmt((void *)inst, f); + rc = inst->event_handle(inst, MSM_VIDC_S_FMT, f); if (rc) goto unlock; @@ -332,7 +332,7 @@ int msm_v4l2_reqbufs(struct file *filp, void *fh, client_lock(inst, __func__); inst_lock(inst, __func__); - rc = msm_vidc_reqbufs((void *)inst, b); + rc = inst->event_handle(inst, MSM_VIDC_REQBUFS, b); if (rc) goto unlock; @@ -437,11 +437,11 @@ int msm_v4l2_qbuf(struct file *filp, void *fh, } /* - * do not acquire inst lock here. acquire it in msm_vidc_buf_queue. - * for requests, msm_vidc_buf_queue() is not called from here. + * do not acquire inst lock here. acquire it in msm_vb2_buf_queue. + * for requests, msm_vb2_buf_queue() is not called from here. * instead it's called as part of msm_v4l2_request_queue(). * hence acquire the inst lock in common function i.e - * msm_vidc_buf_queue, to handle both requests and non-request + * msm_vb2_buf_queue, to handle both requests and non-request * scenarios. */ rc = msm_vidc_qbuf(inst, vdev->v4l2_dev->mdev, b); @@ -618,6 +618,7 @@ int msm_v4l2_decoder_cmd(struct file *filp, void *fh, struct v4l2_decoder_cmd *dec) { struct msm_vidc_inst *inst = get_vidc_inst(filp, fh); + enum msm_vidc_event event; int rc = 0; inst = get_inst_ref(g_core, inst); @@ -633,7 +634,19 @@ int msm_v4l2_decoder_cmd(struct file *filp, void *fh, rc = -EBUSY; goto unlock; } - rc = msm_vidc_cmd((void *)inst, (union msm_v4l2_cmd *)dec); + if (!dec) { + i_vpr_e(inst, "%s: invalid params\n", __func__); + rc = -EINVAL; + goto unlock; + } + if (dec->cmd != V4L2_DEC_CMD_START && + dec->cmd != V4L2_DEC_CMD_STOP) { + i_vpr_e(inst, "%s: invalid cmd %#x\n", __func__, dec->cmd); + rc = -EINVAL; + goto unlock; + } + event = (dec->cmd == V4L2_DEC_CMD_START ? MSM_VIDC_CMD_START : MSM_VIDC_CMD_STOP); + rc = inst->event_handle(inst, event, NULL); if (rc) goto unlock; @@ -680,6 +693,7 @@ int msm_v4l2_encoder_cmd(struct file *filp, void *fh, struct v4l2_encoder_cmd *enc) { struct msm_vidc_inst *inst = get_vidc_inst(filp, fh); + enum msm_vidc_event event; int rc = 0; inst = get_inst_ref(g_core, inst); @@ -695,7 +709,19 @@ int msm_v4l2_encoder_cmd(struct file *filp, void *fh, rc = -EBUSY; goto unlock; } - rc = msm_vidc_cmd((void *)inst, (union msm_v4l2_cmd *)enc); + if (!enc) { + i_vpr_e(inst, "%s: invalid params\n", __func__); + rc = -EINVAL; + goto unlock; + } + if (enc->cmd != V4L2_ENC_CMD_START && + enc->cmd != V4L2_ENC_CMD_STOP) { + i_vpr_e(inst, "%s: invalid cmd %#x\n", __func__, enc->cmd); + rc = -EINVAL; + goto unlock; + } + event = (enc->cmd == V4L2_ENC_CMD_START ? MSM_VIDC_CMD_START : MSM_VIDC_CMD_STOP); + rc = inst->event_handle(inst, event, NULL); if (rc) goto unlock; diff --git a/driver/vidc/src/msm_vidc_vb2.c b/driver/vidc/src/msm_vidc_vb2.c index ec9c37da68..4d5ac278f8 100644 --- a/driver/vidc/src/msm_vidc_vb2.c +++ b/driver/vidc/src/msm_vidc_vb2.c @@ -239,7 +239,7 @@ exit: return; } -int msm_vidc_queue_setup(struct vb2_queue *q, +int msm_vb2_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], struct device *alloc_devs[]) { @@ -366,11 +366,10 @@ int msm_vidc_queue_setup(struct vb2_queue *q, return rc; } -int msm_vidc_start_streaming(struct vb2_queue *q, unsigned int count) +int msm_vb2_start_streaming(struct vb2_queue *q, unsigned int count) { int rc = 0; struct msm_vidc_inst *inst; - enum msm_vidc_buffer_type buf_type; if (!q || !q->drv_priv) { d_vpr_e("%s: invalid input, q = %pK\n", __func__, q); @@ -391,22 +390,46 @@ int msm_vidc_start_streaming(struct vb2_queue *q, unsigned int count) goto unlock; } - if (!msm_vidc_allow_streamon(inst, q->type)) { - rc = -EBUSY; + rc = inst->event_handle(inst, MSM_VIDC_STREAMON, q); + if (rc) { + i_vpr_e(inst, "Streamon: %s failed\n", v4l2_type_name(q->type)); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); goto unlock; } +unlock: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_vidc_start_streaming(struct msm_vidc_inst *inst, struct vb2_queue *q) +{ + enum msm_vidc_buffer_type buf_type; + int rc = 0; + + if (!inst || !q) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + if (!msm_vidc_allow_streamon(inst, q->type)) + return -EBUSY; + if (q->type == INPUT_META_PLANE || q->type == OUTPUT_META_PLANE) { i_vpr_h(inst, "%s: nothing to start on %s\n", __func__, v4l2_type_name(q->type)); - rc = 0; - goto unlock; + return 0; + } + if (q->type != INPUT_MPLANE && q->type != OUTPUT_MPLANE) { + i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type); + return -EINVAL; } if (!is_decode_session(inst) && !is_encode_session(inst)) { - i_vpr_e(inst, "%s: invalid session %d\n", - __func__, inst->domain); - rc = -EINVAL; - goto unlock; + i_vpr_e(inst, "%s: invalid session %d\n", __func__, inst->domain); + return -EINVAL; } i_vpr_h(inst, "Streamon: %s\n", v4l2_type_name(q->type)); @@ -414,30 +437,30 @@ int msm_vidc_start_streaming(struct vb2_queue *q, unsigned int count) inst->once_per_session_set = true; rc = msm_vidc_prepare_dependency_list(inst); if (rc) - goto unlock; + return rc; rc = msm_vidc_session_set_codec(inst); if (rc) - goto unlock; + return rc; rc = msm_vidc_session_set_secure_mode(inst); if (rc) - goto unlock; + return rc; if (is_encode_session(inst)) { rc = msm_vidc_alloc_and_queue_session_internal_buffers(inst, MSM_VIDC_BUF_ARP); if (rc) - goto unlock; + return rc; } else if(is_decode_session(inst)) { rc = msm_vidc_session_set_default_header(inst); if (rc) - goto unlock; + return rc; rc = msm_vidc_alloc_and_queue_session_internal_buffers(inst, MSM_VIDC_BUF_PERSIST); if (rc) - goto unlock; + return rc; } } @@ -452,33 +475,26 @@ int msm_vidc_start_streaming(struct vb2_queue *q, unsigned int count) rc = msm_vdec_streamon_input(inst); else if (is_encode_session(inst)) rc = msm_venc_streamon_input(inst); - else - goto unlock; } else if (q->type == OUTPUT_MPLANE) { if (is_decode_session(inst)) rc = msm_vdec_streamon_output(inst); else if (is_encode_session(inst)) rc = msm_venc_streamon_output(inst); - else - goto unlock; - } else { - i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type); - goto unlock; } if (rc) - goto unlock; + return rc; /* print final buffer counts & size details */ msm_vidc_print_buffer_info(inst); buf_type = v4l2_type_to_driver(q->type, __func__); if (!buf_type) - goto unlock; + return -EINVAL; /* queue pending buffers */ rc = msm_vidc_queue_deferred_buffers(inst, buf_type); if (rc) - goto unlock; + return rc; /* initialize statistics timer(one time) */ if (!inst->stats.time_ms) @@ -487,71 +503,40 @@ int msm_vidc_start_streaming(struct vb2_queue *q, unsigned int count) /* schedule to print buffer statistics */ rc = schedule_stats_work(inst); if (rc) - goto unlock; + return rc; if ((q->type == INPUT_MPLANE && inst->bufq[OUTPUT_PORT].vb2q->streaming) || (q->type == OUTPUT_MPLANE && inst->bufq[INPUT_PORT].vb2q->streaming)) { rc = msm_vidc_get_properties(inst); if (rc) - goto unlock; + return rc; } i_vpr_h(inst, "Streamon: %s successful\n", v4l2_type_name(q->type)); - -unlock: - if (rc) { - i_vpr_e(inst, "Streamon: %s failed\n", v4l2_type_name(q->type)); - msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); - } - inst_unlock(inst, __func__); - client_unlock(inst, __func__); - put_inst(inst); return rc; } -void msm_vidc_stop_streaming(struct vb2_queue *q) +int msm_vidc_stop_streaming(struct msm_vidc_inst *inst, struct vb2_queue *q) { int rc = 0; - struct msm_vidc_inst *inst; - enum msm_vidc_allow allow; - if (!q || !q->drv_priv) { - d_vpr_e("%s: invalid input, q = %pK\n", __func__, q); - return; - } - inst = q->drv_priv; - inst = get_inst_ref(g_core, inst); - if (!inst || !inst->core) { + if (!inst || !q) { d_vpr_e("%s: invalid params\n", __func__); - return; + return -EINVAL; } - client_lock(inst, __func__); - inst_lock(inst, __func__); if (q->type == INPUT_META_PLANE || q->type == OUTPUT_META_PLANE) { i_vpr_h(inst, "%s: nothing to stop on %s\n", __func__, v4l2_type_name(q->type)); - rc = 0; - goto unlock; + return 0; } - - allow = msm_vidc_allow_streamoff(inst, q->type); - if (allow == MSM_VIDC_DISALLOW) { - rc = -EBUSY; - goto unlock; - } else if (allow == MSM_VIDC_IGNORE) { - rc = 0; - goto unlock; - } else if (allow != MSM_VIDC_ALLOW) { - rc = -EINVAL; - goto unlock; + if (q->type != INPUT_MPLANE && q->type != OUTPUT_MPLANE) { + i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type); + return -EINVAL; } - if (!is_decode_session(inst) && !is_encode_session(inst)) { - i_vpr_e(inst, "%s: invalid session %d\n", - __func__, inst->domain); - rc = -EINVAL; - goto unlock; + i_vpr_e(inst, "%s: invalid session %d\n", __func__, inst->domain); + return -EINVAL; } i_vpr_h(inst, "Streamoff: %s\n", v4l2_type_name(q->type)); @@ -565,13 +550,9 @@ void msm_vidc_stop_streaming(struct vb2_queue *q) rc = msm_vdec_streamoff_output(inst); else if (is_encode_session(inst)) rc = msm_venc_streamoff_output(inst); - } else { - i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type); - rc = -EINVAL; - goto unlock; } if (rc) - goto unlock; + return rc; /* Input port streamoff */ if (q->type == INPUT_MPLANE) { @@ -583,19 +564,43 @@ void msm_vidc_stop_streaming(struct vb2_queue *q) } i_vpr_h(inst, "Streamoff: %s successful\n", v4l2_type_name(q->type)); + return rc; +} -unlock: +void msm_vb2_stop_streaming(struct vb2_queue *q) +{ + struct msm_vidc_inst *inst; + int rc = 0; + + if (!q || !q->drv_priv) { + d_vpr_e("%s: invalid input, q = %pK\n", __func__, q); + return; + } + inst = q->drv_priv; + inst = get_inst_ref(g_core, inst); + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + rc = inst->event_handle(inst, MSM_VIDC_STREAMOFF, q); if (rc) { i_vpr_e(inst, "Streamoff: %s failed\n", v4l2_type_name(q->type)); msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + goto unlock; } + +unlock: inst_unlock(inst, __func__); client_unlock(inst, __func__); put_inst(inst); + return; } -void msm_vidc_buf_queue(struct vb2_buffer *vb2) +void msm_vb2_buf_queue(struct vb2_buffer *vb2) { int rc = 0; struct msm_vidc_inst *inst; @@ -700,11 +705,11 @@ unlock: put_inst(inst); } -void msm_vidc_buf_cleanup(struct vb2_buffer *vb) +void msm_vb2_buf_cleanup(struct vb2_buffer *vb) { } -int msm_vidc_buf_out_validate(struct vb2_buffer *vb) +int msm_vb2_buf_out_validate(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); @@ -712,7 +717,7 @@ int msm_vidc_buf_out_validate(struct vb2_buffer *vb) return 0; } -void msm_vidc_buf_request_complete(struct vb2_buffer *vb) +void msm_vb2_request_complete(struct vb2_buffer *vb) { struct msm_vidc_inst *inst = vb2_get_drv_priv(vb->vb2_queue); diff --git a/driver/vidc/src/venus_hfi_queue.c b/driver/vidc/src/venus_hfi_queue.c index 4597f49e81..36f276d244 100644 --- a/driver/vidc/src/venus_hfi_queue.c +++ b/driver/vidc/src/venus_hfi_queue.c @@ -509,7 +509,7 @@ int venus_hfi_queue_init(struct msm_vidc_core *core) } memset(&mem, 0, sizeof(mem)); - mem.type = MSM_VIDC_BUF_QUEUE; + mem.type = MSM_VIDC_BUF_INTERFACE_QUEUE; mem.region = MSM_VIDC_NON_SECURE; mem.size = TOTAL_QSIZE; mem.secure = false; @@ -570,7 +570,7 @@ int venus_hfi_queue_init(struct msm_vidc_core *core) /* sfr buffer */ memset(&mem, 0, sizeof(mem)); - mem.type = MSM_VIDC_BUF_QUEUE; + mem.type = MSM_VIDC_BUF_INTERFACE_QUEUE; mem.region = MSM_VIDC_NON_SECURE; mem.size = ALIGNED_SFR_SIZE; mem.secure = false; @@ -610,7 +610,7 @@ int venus_hfi_queue_init(struct msm_vidc_core *core) /* allocate 4k buffer for HFI_MMAP_ADDR */ memset(&mem, 0, sizeof(mem)); - mem.type = MSM_VIDC_BUF_QUEUE; + mem.type = MSM_VIDC_BUF_INTERFACE_QUEUE; mem.region = MSM_VIDC_NON_SECURE; mem.size = ALIGNED_MMAP_BUF_SIZE; mem.secure = false;