1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
- * 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_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)
- {
- return (core->state == MSM_VIDC_CORE_INIT ||
- core->state == MSM_VIDC_CORE_INIT_WAIT);
- }
- bool is_core_state(struct msm_vidc_core *core, enum msm_vidc_core_state state)
- {
- return core->state == state;
- }
- bool is_drc_pending(struct msm_vidc_inst *inst)
- {
- return is_sub_state(inst, MSM_VIDC_DRC) &&
- is_sub_state(inst, MSM_VIDC_DRC_LAST_BUFFER);
- }
- bool is_drain_pending(struct msm_vidc_inst *inst)
- {
- return is_sub_state(inst, MSM_VIDC_DRAIN) &&
- is_sub_state(inst, MSM_VIDC_DRAIN_LAST_BUFFER);
- }
- static const char * const core_state_name_arr[] =
- FOREACH_CORE_STATE(GENERATE_STRING);
- const char *core_state_name(enum msm_vidc_core_state state)
- {
- const char *name = "UNKNOWN STATE";
- if (state >= ARRAY_SIZE(core_state_name_arr))
- goto exit;
- name = core_state_name_arr[state];
- 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);
- WARN_ON(fatal);
- if (fatal)
- d_vpr_e("%s: strict check failed\n", 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)
- {
- if (!core || !data) {
- d_vpr_e("%s: invalid params\n", __func__);
- return -EINVAL;
- }
- d_vpr_e("%s: unexpected core event type %u\n", __func__, type);
- return -EINVAL;
- }
- static int msm_vidc_core_init_wait_state(struct msm_vidc_core *core,
- enum msm_vidc_core_event_type type,
- struct msm_vidc_event_data *data)
- {
- int rc = 0;
- if (!core || !data) {
- d_vpr_e("%s: invalid params\n", __func__);
- return -EINVAL;
- }
- switch (type) {
- case CORE_EVENT_UPDATE_SUB_STATE:
- {
- u32 req_sub_state;
- u32 allow_mask = -1;
- req_sub_state = data->edata.uval;
- /* none of the requested substate supported */
- if (!(req_sub_state & allow_mask)) {
- d_vpr_e("%s: invalid substate update request %#x\n",
- __func__, req_sub_state);
- return -EINVAL;
- }
- /* update core substate */
- core->sub_state |= req_sub_state & allow_mask;
- return rc;
- }
- default: {
- d_vpr_e("%s: unexpected core event type %u\n",
- __func__, type);
- return -EINVAL;
- }
- }
- return rc;
- }
- static int msm_vidc_core_init_state(struct msm_vidc_core *core,
- enum msm_vidc_core_event_type type,
- struct msm_vidc_event_data *data)
- {
- int rc = 0;
- if (!core || !data) {
- d_vpr_e("%s: invalid params\n", __func__);
- return -EINVAL;
- }
- switch (type) {
- case CORE_EVENT_UPDATE_SUB_STATE:
- {
- u32 req_sub_state;
- u32 allow_mask = -1;
- req_sub_state = data->edata.uval;
- /* none of the requested substate supported */
- if (!(req_sub_state & allow_mask)) {
- d_vpr_e("%s: invalid substate update request %#x\n",
- __func__, req_sub_state);
- return -EINVAL;
- }
- /* update core substate */
- core->sub_state |= req_sub_state & allow_mask;
- return rc;
- }
- default: {
- d_vpr_e("%s: unexpected core event type %u\n",
- __func__, type);
- return -EINVAL;
- }
- }
- return rc;
- }
- static int msm_vidc_core_error_state(struct msm_vidc_core *core,
- enum msm_vidc_core_event_type type,
- struct msm_vidc_event_data *data)
- {
- int rc = 0;
- if (!core || !data) {
- d_vpr_e("%s: invalid params\n", __func__);
- return -EINVAL;
- }
- switch (type) {
- case CORE_EVENT_UPDATE_SUB_STATE:
- {
- u32 req_sub_state;
- u32 allow_mask = -1;
- req_sub_state = data->edata.uval;
- /* none of the requested substate supported */
- if (!(req_sub_state & allow_mask)) {
- d_vpr_e("%s: invalid substate update request %#x\n",
- __func__, req_sub_state);
- return -EINVAL;
- }
- /* update core substate */
- core->sub_state |= req_sub_state & allow_mask;
- return rc;
- }
- default: {
- d_vpr_e("%s: unexpected core event type %u\n",
- __func__, type);
- return -EINVAL;
- }
- }
- return rc;
- }
- 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;
- struct msm_vidc_core_state_handle *core_state_handle = NULL;
- static struct msm_vidc_core_state_handle state_handle[] = {
- {MSM_VIDC_CORE_DEINIT, msm_vidc_core_deinit_state },
- {MSM_VIDC_CORE_INIT_WAIT, msm_vidc_core_init_wait_state },
- {MSM_VIDC_CORE_INIT, msm_vidc_core_init_state },
- {MSM_VIDC_CORE_ERROR, msm_vidc_core_error_state },
- };
- for (cnt = 0; cnt < ARRAY_SIZE(state_handle); cnt++) {
- if (state_handle[cnt].state == req_state) {
- core_state_handle = &state_handle[cnt];
- break;
- }
- }
- /* if req_state does not exist in the table */
- if (cnt == ARRAY_SIZE(state_handle)) {
- d_vpr_e("%s: invalid core state \"%s\" requested\n",
- __func__, core_state_name(req_state));
- return core_state_handle;
- }
- return core_state_handle;
- }
- int msm_vidc_update_core_state(struct msm_vidc_core *core,
- enum msm_vidc_core_state request_state, const char *func)
- {
- struct msm_vidc_core_state_handle *state_handle = NULL;
- int rc = 0;
- /* get core state handler for requested state */
- state_handle = msm_vidc_get_core_state_handle(request_state);
- if (!state_handle)
- return -EINVAL;
- d_vpr_h("%s: core state changed to %s from %s\n", func,
- core_state_name(state_handle->state), core_state_name(core->state));
- /* finally update core state and handler */
- core->state = state_handle->state;
- core->state_handle = state_handle->handle;
- return rc;
- }
- struct msm_vidc_core_state_allow {
- enum msm_vidc_core_state from;
- enum msm_vidc_core_state to;
- enum msm_vidc_allow allow;
- };
- enum msm_vidc_allow msm_vidc_allow_core_state_change(
- struct msm_vidc_core *core,
- enum msm_vidc_core_state req_state)
- {
- int cnt;
- enum msm_vidc_allow allow = MSM_VIDC_DISALLOW;
- static struct msm_vidc_core_state_allow state[] = {
- /* from, to, allow */
- {MSM_VIDC_CORE_DEINIT, MSM_VIDC_CORE_DEINIT, MSM_VIDC_IGNORE },
- {MSM_VIDC_CORE_DEINIT, MSM_VIDC_CORE_INIT_WAIT, MSM_VIDC_ALLOW },
- {MSM_VIDC_CORE_DEINIT, MSM_VIDC_CORE_INIT, MSM_VIDC_DISALLOW },
- {MSM_VIDC_CORE_DEINIT, MSM_VIDC_CORE_ERROR, MSM_VIDC_IGNORE },
- {MSM_VIDC_CORE_INIT_WAIT, MSM_VIDC_CORE_DEINIT, MSM_VIDC_DISALLOW },
- {MSM_VIDC_CORE_INIT_WAIT, MSM_VIDC_CORE_INIT_WAIT, MSM_VIDC_IGNORE },
- {MSM_VIDC_CORE_INIT_WAIT, MSM_VIDC_CORE_INIT, MSM_VIDC_ALLOW },
- {MSM_VIDC_CORE_INIT_WAIT, MSM_VIDC_CORE_ERROR, MSM_VIDC_ALLOW },
- {MSM_VIDC_CORE_INIT, MSM_VIDC_CORE_DEINIT, MSM_VIDC_ALLOW },
- {MSM_VIDC_CORE_INIT, MSM_VIDC_CORE_INIT_WAIT, MSM_VIDC_DISALLOW },
- {MSM_VIDC_CORE_INIT, MSM_VIDC_CORE_INIT, MSM_VIDC_IGNORE },
- {MSM_VIDC_CORE_INIT, MSM_VIDC_CORE_ERROR, MSM_VIDC_ALLOW },
- {MSM_VIDC_CORE_ERROR, MSM_VIDC_CORE_DEINIT, MSM_VIDC_ALLOW },
- {MSM_VIDC_CORE_ERROR, MSM_VIDC_CORE_INIT_WAIT, MSM_VIDC_IGNORE },
- {MSM_VIDC_CORE_ERROR, MSM_VIDC_CORE_INIT, MSM_VIDC_IGNORE },
- {MSM_VIDC_CORE_ERROR, MSM_VIDC_CORE_ERROR, MSM_VIDC_IGNORE },
- };
- for (cnt = 0; cnt < ARRAY_SIZE(state); cnt++) {
- if (state[cnt].from == core->state && state[cnt].to == req_state) {
- allow = state[cnt].allow;
- break;
- }
- }
- return allow;
- }
- int msm_vidc_change_core_state(struct msm_vidc_core *core,
- enum msm_vidc_core_state request_state, const char *func)
- {
- enum msm_vidc_allow allow;
- int rc = 0;
- if (!core) {
- d_vpr_e("%s: invalid params\n", __func__);
- return -EINVAL;
- }
- /* core must be locked */
- rc = __strict_check(core, func);
- if (rc) {
- d_vpr_e("%s(): core was not locked\n", func);
- return rc;
- }
- /* current and requested state is same */
- if (core->state == request_state)
- return 0;
- /* check if requested state movement is allowed */
- allow = msm_vidc_allow_core_state_change(core, request_state);
- if (allow == MSM_VIDC_IGNORE) {
- d_vpr_h("%s: %s core state change %s -> %s\n", func,
- allow_name(allow), core_state_name(core->state),
- core_state_name(request_state));
- return 0;
- } else if (allow == MSM_VIDC_DISALLOW) {
- d_vpr_e("%s: %s core state change %s -> %s\n", func,
- allow_name(allow), core_state_name(core->state),
- core_state_name(request_state));
- return -EINVAL;
- }
- /* go ahead and update core state */
- rc = msm_vidc_update_core_state(core, request_state, func);
- if (rc)
- return rc;
- return rc;
- }
- bool is_core_sub_state(struct msm_vidc_core *core,
- enum msm_vidc_core_sub_state sub_state)
- {
- return !!(core->sub_state & sub_state);
- }
- const char *core_sub_state_name(enum msm_vidc_core_sub_state sub_state)
- {
- switch (sub_state) {
- case CORE_SUBSTATE_NONE: return "NONE ";
- case CORE_SUBSTATE_GDSC_HANDOFF: return "GDSC_HANDOFF ";
- case CORE_SUBSTATE_PM_SUSPEND: return "PM_SUSPEND ";
- case CORE_SUBSTATE_FW_PWR_CTRL: return "FW_PWR_CTRL ";
- case CORE_SUBSTATE_POWER_ENABLE: return "POWER_ENABLE ";
- case CORE_SUBSTATE_PAGE_FAULT: return "PAGE_FAULT ";
- case CORE_SUBSTATE_CPU_WATCHDOG: return "CPU_WATCHDOG ";
- case CORE_SUBSTATE_VIDEO_UNRESPONSIVE: return "VIDEO_UNRESPONSIVE ";
- case CORE_SUBSTATE_MAX: return "MAX ";
- }
- return "UNKNOWN ";
- }
- static int prepare_core_sub_state_name(enum msm_vidc_core_sub_state sub_state,
- char *buf, u32 size)
- {
- int i = 0;
- if (!buf || !size)
- return -EINVAL;
- strscpy(buf, "\0", size);
- if (sub_state == CORE_SUBSTATE_NONE) {
- strscpy(buf, "CORE_SUBSTATE_NONE", size);
- return 0;
- }
- for (i = 0; BIT(i) < CORE_SUBSTATE_MAX; i++) {
- if (sub_state & BIT(i))
- strlcat(buf, core_sub_state_name(BIT(i)), size);
- }
- return 0;
- }
- static int msm_vidc_update_core_sub_state(struct msm_vidc_core *core,
- enum msm_vidc_core_sub_state sub_state, const char *func)
- {
- struct msm_vidc_event_data data;
- char sub_state_name[MAX_NAME_LENGTH];
- int ret = 0, rc = 0;
- if (!core) {
- d_vpr_e("%s: invalid params\n", __func__);
- return -EINVAL;
- }
- /* no substate update */
- if (!sub_state)
- return 0;
- /* invoke update core substate event */
- memset(&data, 0, sizeof(struct msm_vidc_event_data));
- data.edata.uval = sub_state;
- rc = core->state_handle(core, CORE_EVENT_UPDATE_SUB_STATE, &data);
- if (rc) {
- ret = prepare_core_sub_state_name(sub_state,
- sub_state_name, sizeof(sub_state_name) - 1);
- if (!ret)
- d_vpr_e("%s: state %s, requested invalid core substate %s\n",
- func, core_state_name(core->state), sub_state_name);
- return rc;
- }
- return rc;
- }
- int msm_vidc_change_core_sub_state(struct msm_vidc_core *core,
- enum msm_vidc_core_sub_state clear_sub_state,
- enum msm_vidc_core_sub_state set_sub_state, const char *func)
- {
- int rc = 0;
- enum msm_vidc_core_sub_state prev_sub_state;
- if (!core) {
- d_vpr_e("%s: invalid params\n", __func__);
- return -EINVAL;
- }
- /* core must be locked */
- rc = __strict_check(core, func);
- if (rc) {
- d_vpr_e("%s(): core was not locked\n", func);
- return rc;
- }
- /* sanitize core state handler */
- if (!core->state_handle) {
- d_vpr_e("%s: invalid core state handle\n", __func__);
- return -EINVAL;
- }
- /* final value will not change */
- if (clear_sub_state == set_sub_state)
- return 0;
- /* sanitize clear & set value */
- if (set_sub_state > CORE_SUBSTATE_MAX ||
- clear_sub_state > CORE_SUBSTATE_MAX) {
- d_vpr_e("%s: invalid sub states. clear %#x or set %#x\n",
- func, clear_sub_state, set_sub_state);
- return -EINVAL;
- }
- prev_sub_state = core->sub_state;
- /* set sub state */
- rc = msm_vidc_update_core_sub_state(core, set_sub_state, func);
- if (rc)
- return rc;
- /* check if all core substates updated */
- if ((core->sub_state & set_sub_state) != set_sub_state)
- d_vpr_e("%s: all substates not updated %#x, expected %#x\n",
- func, core->sub_state & set_sub_state, set_sub_state);
- /* clear sub state */
- core->sub_state &= ~clear_sub_state;
- /* print substates only when there is a change */
- if (core->sub_state != prev_sub_state) {
- rc = prepare_core_sub_state_name(core->sub_state, core->sub_state_name,
- sizeof(core->sub_state_name) - 1);
- if (!rc)
- d_vpr_h("%s: core sub state changed to %s\n", func, core->sub_state_name);
- }
- 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_IGNORE },
- {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)
- {
- 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;
- /* allow s_fmt request in open state */
- 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;
- /* allow reqbufs request in open state */
- rc = msm_vidc_reqbufs(inst, b);
- if (rc)
- return rc;
- break;
- }
- case MSM_VIDC_STREAMON:
- {
- struct vb2_queue *q = (struct vb2_queue *)data;
- /* allow streamon request in open state */
- 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_h(inst, "%s: streamoff of (%s) ignored in state (%s)\n",
- __func__, v4l2_type_name(q->type), state_name(inst->state));
- break;
- }
- case MSM_VIDC_CMD_START:
- {
- /* disallow start cmd request in open state */
- i_vpr_e(inst, "%s: (%s) not allowed, sub_state (%s)\n",
- __func__, event_name(event), inst->sub_state_name);
- return -EBUSY;
- }
- case MSM_VIDC_CMD_STOP:
- {
- /* ignore stop cmd request in open state */
- i_vpr_h(inst, "%s: (%s) ignored, sub_state (%s)\n",
- __func__, event_name(event), inst->sub_state_name);
- 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_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;
- /* disallow */
- if (f->type == INPUT_MPLANE || f->type == INPUT_META_PLANE) {
- i_vpr_e(inst, "%s: (%s) not allowed for (%s) port\n",
- __func__, event_name(event), v4l2_type_name(f->type));
- return -EBUSY;
- }
- 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;
- /* disallow */
- if (b->type == INPUT_MPLANE || b->type == INPUT_META_PLANE) {
- i_vpr_e(inst, "%s: (%s) not allowed for (%s) port\n",
- __func__, event_name(event), v4l2_type_name(b->type));
- return -EBUSY;
- }
- rc = msm_vidc_reqbufs(inst, b);
- if (rc)
- return rc;
- break;
- }
- case MSM_VIDC_STREAMON:
- {
- struct vb2_queue *q = (struct vb2_queue *)data;
- /* disallow */
- if (q->type == INPUT_MPLANE || q->type == INPUT_META_PLANE) {
- i_vpr_e(inst, "%s: (%s) not allowed for (%s) type\n",
- __func__, event_name(event), v4l2_type_name(q->type));
- return -EBUSY;
- }
- 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 */
- if (q->type == OUTPUT_MPLANE || q->type == OUTPUT_META_PLANE) {
- i_vpr_h(inst, "%s: streamoff of (%s) ignored in state (%s)\n",
- __func__, v4l2_type_name(q->type), state_name(inst->state));
- return 0;
- }
- /* disallow */
- if (q->type == INPUT_META_PLANE) {
- i_vpr_e(inst, "%s: streamoff of (%s) not allowed in state (%s)\n",
- __func__, v4l2_type_name(q->type), state_name(inst->state));
- return -EINVAL;
- }
- /* 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:
- {
- /* disallow if START called for non DRC/drain cases */
- if (!is_drc_pending(inst) && !is_drain_pending(inst)) {
- i_vpr_e(inst, "%s: (%s) not allowed, sub_state (%s)\n",
- __func__, event_name(event), inst->sub_state_name);
- return -EBUSY;
- }
- /* client would call start(resume) to complete DRC/drain sequence */
- rc = msm_vidc_start_cmd(inst);
- if (rc)
- return rc;
- break;
- }
- case MSM_VIDC_CMD_STOP:
- {
- /* back to back drain not allowed */
- if (is_sub_state(inst, MSM_VIDC_DRAIN)) {
- i_vpr_e(inst, "%s: drain (%s) not allowed, sub_state (%s)\n\n",
- __func__, event_name(event), inst->sub_state_name);
- return -EBUSY;
- }
- rc = msm_vidc_stop_cmd(inst);
- 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_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;
- /* disallow */
- if (f->type == OUTPUT_MPLANE || f->type == OUTPUT_META_PLANE) {
- i_vpr_e(inst, "%s: (%s) not allowed for (%s) port\n",
- __func__, event_name(event), v4l2_type_name(f->type));
- return -EBUSY;
- }
- 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;
- /* disallow */
- if (b->type == OUTPUT_MPLANE || b->type == OUTPUT_META_PLANE) {
- i_vpr_e(inst, "%s: (%s) not allowed for (%s) port\n",
- __func__, event_name(event), v4l2_type_name(b->type));
- return -EBUSY;
- }
- rc = msm_vidc_reqbufs(inst, b);
- if (rc)
- return rc;
- break;
- }
- case MSM_VIDC_STREAMON:
- {
- struct vb2_queue *q = (struct vb2_queue *)data;
- /* disallow */
- if (q->type == OUTPUT_MPLANE || q->type == OUTPUT_META_PLANE) {
- i_vpr_e(inst, "%s: (%s) not allowed for (%s) type\n",
- __func__, event_name(event), v4l2_type_name(q->type));
- return -EBUSY;
- }
- 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 */
- if (q->type == INPUT_MPLANE || q->type == INPUT_META_PLANE) {
- i_vpr_h(inst, "%s: streamoff of (%s) ignored in state (%s)\n",
- __func__, v4l2_type_name(q->type), state_name(inst->state));
- return 0;
- }
- /* disallow */
- if (q->type == OUTPUT_META_PLANE) {
- i_vpr_e(inst, "%s: streamoff of (%s) not allowed in state (%s)\n",
- __func__, v4l2_type_name(q->type), state_name(inst->state));
- return -EINVAL;
- }
- /* 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:
- {
- /* disallow if START called for non DRC/drain cases */
- if (!is_drc_pending(inst) && !is_drain_pending(inst)) {
- i_vpr_e(inst, "%s: (%s) not allowed, sub_state (%s)\n",
- __func__, event_name(event), inst->sub_state_name);
- return -EBUSY;
- }
- /* client would call start(resume) to complete DRC/drain sequence */
- rc = msm_vidc_start_cmd(inst);
- if (rc)
- return rc;
- break;
- }
- case MSM_VIDC_CMD_STOP:
- {
- /* drain not allowed as input is not streaming */
- i_vpr_e(inst, "%s: drain (%s) not allowed, sub state %s\n",
- __func__, event_name(event), inst->sub_state_name);
- return -EBUSY;
- }
- 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_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;
- 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: streamoff of (%s) not allowed in state (%s)\n",
- __func__, v4l2_type_name(q->type), 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:
- {
- /* disallow if START called for non DRC/drain cases */
- if (!is_drc_pending(inst) && !is_drain_pending(inst)) {
- i_vpr_e(inst, "%s: (%s) not allowed, sub_state (%s)\n",
- __func__, event_name(event), inst->sub_state_name);
- return -EBUSY;
- }
- /* client would call start(resume) to complete DRC/drain sequence */
- rc = msm_vidc_start_cmd(inst);
- if (rc)
- return rc;
- break;
- }
- case MSM_VIDC_CMD_STOP:
- {
- /* back to back drain not allowed */
- if (is_sub_state(inst, MSM_VIDC_DRAIN)) {
- i_vpr_e(inst, "%s: drain (%s) not allowed, sub_state (%s)\n\n",
- __func__, event_name(event), inst->sub_state_name);
- return -EBUSY;
- }
- rc = msm_vidc_stop_cmd(inst);
- 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;
- }
- 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;
- }
- struct msm_vidc_sub_state_allow {
- enum msm_vidc_state state;
- enum msm_vidc_allow allow;
- u32 sub_state_mask;
- };
- static int msm_vidc_set_sub_state(struct msm_vidc_inst *inst,
- enum msm_vidc_sub_state sub_state, const char *func)
- {
- char sub_state_name[MAX_NAME_LENGTH];
- int cnt, rc = 0;
- static struct msm_vidc_sub_state_allow sub_state_allow[] = {
- /* state, allow, sub_state */
- {MSM_VIDC_OPEN, MSM_VIDC_DISALLOW, MSM_VIDC_DRC |
- MSM_VIDC_DRAIN |
- MSM_VIDC_DRC_LAST_BUFFER |
- MSM_VIDC_DRAIN_LAST_BUFFER |
- MSM_VIDC_INPUT_PAUSE |
- MSM_VIDC_OUTPUT_PAUSE },
- {MSM_VIDC_INPUT_STREAMING, MSM_VIDC_DISALLOW, MSM_VIDC_DRC_LAST_BUFFER |
- MSM_VIDC_DRAIN_LAST_BUFFER |
- MSM_VIDC_OUTPUT_PAUSE },
- {MSM_VIDC_INPUT_STREAMING, MSM_VIDC_ALLOW, MSM_VIDC_DRC |
- MSM_VIDC_DRAIN |
- MSM_VIDC_INPUT_PAUSE },
- {MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_DISALLOW, MSM_VIDC_DRC |
- MSM_VIDC_DRAIN |
- MSM_VIDC_INPUT_PAUSE },
- {MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_ALLOW, MSM_VIDC_DRC_LAST_BUFFER |
- MSM_VIDC_DRAIN_LAST_BUFFER |
- MSM_VIDC_OUTPUT_PAUSE },
- {MSM_VIDC_STREAMING, MSM_VIDC_ALLOW, MSM_VIDC_DRC |
- MSM_VIDC_DRAIN |
- MSM_VIDC_DRC_LAST_BUFFER |
- MSM_VIDC_DRAIN_LAST_BUFFER |
- MSM_VIDC_INPUT_PAUSE |
- MSM_VIDC_OUTPUT_PAUSE },
- {MSM_VIDC_CLOSE, MSM_VIDC_ALLOW, MSM_VIDC_DRC |
- MSM_VIDC_DRAIN |
- MSM_VIDC_DRC_LAST_BUFFER |
- MSM_VIDC_DRAIN_LAST_BUFFER |
- MSM_VIDC_INPUT_PAUSE |
- MSM_VIDC_OUTPUT_PAUSE },
- {MSM_VIDC_ERROR, MSM_VIDC_ALLOW, MSM_VIDC_DRC |
- MSM_VIDC_DRAIN |
- MSM_VIDC_DRC_LAST_BUFFER |
- MSM_VIDC_DRAIN_LAST_BUFFER |
- MSM_VIDC_INPUT_PAUSE |
- MSM_VIDC_OUTPUT_PAUSE },
- };
- if (!inst) {
- d_vpr_e("%s: invalid params\n", __func__);
- return -EINVAL;
- }
- /* no substate to update */
- if (!sub_state)
- return 0;
- /* check if any substate is disallowed */
- for (cnt = 0; cnt < ARRAY_SIZE(sub_state_allow); cnt++) {
- /* skip other states */
- if (sub_state_allow[cnt].state != inst->state)
- continue;
- /* continue if not disallowed */
- if (sub_state_allow[cnt].allow != MSM_VIDC_DISALLOW)
- continue;
- if (sub_state_allow[cnt].sub_state_mask & sub_state) {
- prepare_sub_state_name(sub_state, sub_state_name, sizeof(sub_state_name));
- i_vpr_e(inst, "%s: state (%s), disallow substate (%s)\n",
- func, state_name(inst->state), sub_state_name);
- return -EINVAL;
- }
- }
- /* remove ignorable substates from a given substate */
- for (cnt = 0; cnt < ARRAY_SIZE(sub_state_allow); cnt++) {
- /* skip other states */
- if (sub_state_allow[cnt].state != inst->state)
- continue;
- /* continue if not ignored */
- if (sub_state_allow[cnt].allow != MSM_VIDC_IGNORE)
- continue;
- if (sub_state_allow[cnt].sub_state_mask & sub_state) {
- prepare_sub_state_name(sub_state, sub_state_name, sizeof(sub_state_name));
- i_vpr_h(inst, "%s: state (%s), ignore substate (%s)\n",
- func, state_name(inst->state), sub_state_name);
- /* remove ignorable substate bits from actual */
- sub_state &= ~(sub_state_allow[cnt].sub_state_mask & sub_state);
- break;
- }
- }
- /* check if all substate bits are allowed */
- for (cnt = 0; cnt < ARRAY_SIZE(sub_state_allow); cnt++) {
- /* skip other states */
- if (sub_state_allow[cnt].state != inst->state)
- continue;
- /* continue if not allowed */
- if (sub_state_allow[cnt].allow != MSM_VIDC_ALLOW)
- continue;
- if ((sub_state_allow[cnt].sub_state_mask & sub_state) != sub_state) {
- prepare_sub_state_name(sub_state, sub_state_name, sizeof(sub_state_name));
- i_vpr_e(inst, "%s: state (%s), not all substates allowed (%s)\n",
- func, state_name(inst->state), sub_state_name);
- return -EINVAL;
- }
- }
- /* update substate */
- inst->sub_state |= sub_state;
- return rc;
- }
- 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;
- }
- /* final value will not change */
- if (!clear_sub_state && !set_sub_state)
- return 0;
- /* sanitize clear & set value */
- 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;
- /* set sub state */
- rc = msm_vidc_set_sub_state(inst, set_sub_state, __func__);
- if (rc)
- return rc;
- /* clear 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;
- }
|