diff --git a/drivers/cam_core/cam_context.c b/drivers/cam_core/cam_context.c index 68e6b28eac..536fc5ad3e 100644 --- a/drivers/cam_core/cam_context.c +++ b/drivers/cam_core/cam_context.c @@ -556,6 +556,31 @@ int cam_context_handle_stop_dev(struct cam_context *ctx, return rc; } +int cam_context_handle_shutdown_dev(struct cam_context *ctx, + struct cam_control *cmd, struct v4l2_subdev_fh *fh) +{ + int rc = 0; + + if (!ctx || !ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (!cmd) { + CAM_ERR(CAM_CORE, "Invalid stop device command payload"); + return -EINVAL; + } + + if (ctx->state_machine[ctx->state].ioctl_ops.shutdown_dev) + rc = ctx->state_machine[ctx->state].ioctl_ops.shutdown_dev( + (struct v4l2_subdev *)cmd->handle, fh); + else + CAM_WARN(CAM_CORE, "No shutdown device in dev %d, state %d", + ctx->dev_hdl, ctx->state); + + return rc; +} + int cam_context_handle_info_dump(void *context, enum cam_context_dump_id id) { diff --git a/drivers/cam_core/cam_context.h b/drivers/cam_core/cam_context.h index 91323c78d9..39f51aa160 100644 --- a/drivers/cam_core/cam_context.h +++ b/drivers/cam_core/cam_context.h @@ -9,6 +9,7 @@ #include #include #include +#include #include "cam_req_mgr_interface.h" #include "cam_hw_mgr_intf.h" #include "cam_smmu_api.h" @@ -97,6 +98,7 @@ struct cam_ctx_request { * @acquire_hw: Function pointer for acquire hw * @release_hw: Function pointer for release hw * @dump_dev: Function pointer for dump dev + * @shutdown_dev: Function pointer for shutdown dev * */ struct cam_ctx_ioctl_ops { @@ -116,6 +118,8 @@ struct cam_ctx_ioctl_ops { int (*release_hw)(struct cam_context *ctx, void *args); int (*dump_dev)(struct cam_context *ctx, struct cam_dump_req_cmd *cmd); + int (*shutdown_dev)(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh); }; /** @@ -483,6 +487,19 @@ int cam_context_handle_start_dev(struct cam_context *ctx, int cam_context_handle_stop_dev(struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd); +/** + * cam_context_handle_shutdown_dev() + * + * @brief: Handle shutdown device command + * + * @ctx: Object pointer for cam_context + * @cmd: Shutdown device command payload + * @fh: Pointer to struct v4l2_subdev_fh + * + */ +int cam_context_handle_shutdown_dev(struct cam_context *ctx, + struct cam_control *cmd, struct v4l2_subdev_fh *fh); + /** * cam_context_handle_dump_dev() * diff --git a/drivers/cam_core/cam_node.c b/drivers/cam_core/cam_node.c index c3770f2df7..7a535f1cff 100644 --- a/drivers/cam_core/cam_node.c +++ b/drivers/cam_core/cam_node.c @@ -297,6 +297,27 @@ static int __cam_node_handle_stop_dev(struct cam_node *node, return rc; } +int cam_node_handle_shutdown_dev(struct cam_node *node, + struct cam_control *cmd, struct v4l2_subdev_fh *fh) +{ + struct cam_context *ctx = NULL; + int32_t dev_index = -1; + int rc = 0, ret = 0; + + while ((dev_index = cam_get_dev_handle_info(cmd->handle, + &ctx, dev_index)) < CAM_REQ_MGR_MAX_HANDLES_V2) { + ret = cam_context_handle_shutdown_dev(ctx, cmd, fh); + if (ret) { + rc = ret; + CAM_ERR(CAM_CORE, "Shutdown failure for node %s", + node->name); + continue; + } + } + + return rc; +} + static int __cam_node_handle_config_dev(struct cam_node *node, struct cam_config_dev_cmd *config) { diff --git a/drivers/cam_core/cam_node.h b/drivers/cam_core/cam_node.h index 062d021311..8b707a1524 100644 --- a/drivers/cam_core/cam_node.h +++ b/drivers/cam_core/cam_node.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, 2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_NODE_H_ @@ -100,4 +100,30 @@ int cam_node_init(struct cam_node *node, struct cam_hw_mgr_intf *hw_mgr_intf, */ void cam_node_put_ctxt_to_free_list(struct kref *ref); +/** + * cam_get_dev_handle_info() + * + * @brief: provides the active dev index. + * + * @handle: pointer to struct v4l2_dev + * @ctx: pointer to struct cam_context + * @dev_index: dev index + * + */ +int32_t cam_get_dev_handle_info(uint64_t handle, + struct cam_context **ctx, int32_t dev_index); + +/** + * cam_node_handle_shutdown_dev() + * + * @brief: Shutdowns all the active devices. + * + * @node: pointer to struct node + * @cmd: pointer to struct cmd + * @fh: pointer to struct v4l2_subdev_fh + * + */ +int cam_node_handle_shutdown_dev(struct cam_node *node, + struct cam_control *cmd, struct v4l2_subdev_fh *fh); + #endif /* _CAM_NODE_H_ */ diff --git a/drivers/cam_core/cam_subdev.c b/drivers/cam_core/cam_subdev.c index 1a81a4d59e..a0e3458400 100644 --- a/drivers/cam_core/cam_subdev.c +++ b/drivers/cam_core/cam_subdev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018, 2021 The Linux Foundation. All rights reserved. */ #include "cam_subdev.h" @@ -45,6 +45,8 @@ static long cam_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, long rc; struct cam_node *node = (struct cam_node *) v4l2_get_subdevdata(sd); + struct v4l2_subdev_fh *fh = (struct v4l2_subdev_fh *)arg; + struct cam_control cntrl_cmd; if (!node || node->state == CAM_NODE_STATE_UNINIT) { rc = -EINVAL; @@ -56,6 +58,19 @@ static long cam_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, rc = cam_node_handle_ioctl(node, (struct cam_control *) arg); break; + case CAM_SD_SHUTDOWN: + if (!cam_req_mgr_is_shutdown()) { + CAM_WARN(CAM_CORE, "SD shouldn't come from user space"); + return 0; + } + + cntrl_cmd.op_code = CAM_SD_SHUTDOWN; + cntrl_cmd.handle = (uint64_t)sd; + rc = cam_node_handle_shutdown_dev(node, &cntrl_cmd, fh); + if (rc) + CAM_ERR(CAM_CORE, "shutdown device failed(rc = %d)", + rc); + break; default: CAM_ERR(CAM_CORE, "Invalid command %d for %s", cmd, node->name); diff --git a/drivers/cam_cpas/cam_cpas_intf.c b/drivers/cam_cpas/cam_cpas_intf.c index a392f26d8c..776d84baf2 100644 --- a/drivers/cam_cpas/cam_cpas_intf.c +++ b/drivers/cam_cpas/cam_cpas_intf.c @@ -678,7 +678,7 @@ static int cam_cpas_subdev_open(struct v4l2_subdev *sd, return 0; } -static int cam_cpas_subdev_close(struct v4l2_subdev *sd, +static int __cam_cpas_subdev_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd); @@ -689,6 +689,11 @@ static int cam_cpas_subdev_close(struct v4l2_subdev *sd, } mutex_lock(&cpas_intf->intf_lock); + if (cpas_intf->open_cnt <= 0) { + CAM_WARN(CAM_CPAS, "device already closed, open_cnt: %d", cpas_intf->open_cnt); + mutex_unlock(&cpas_intf->intf_lock); + return 0; + } cpas_intf->open_cnt--; CAM_DBG(CAM_CPAS, "CPAS Subdev close count %d", cpas_intf->open_cnt); mutex_unlock(&cpas_intf->intf_lock); @@ -696,6 +701,19 @@ static int cam_cpas_subdev_close(struct v4l2_subdev *sd, return 0; } +static int cam_cpas_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_CPAS); + + if (crm_active) { + CAM_DBG(CAM_CPAS, "CRM is ACTIVE, close should be from CRM"); + return 0; + } + + return __cam_cpas_subdev_close(sd, fh); +} + static long cam_cpas_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { @@ -711,6 +729,9 @@ static long cam_cpas_subdev_ioctl(struct v4l2_subdev *sd, case VIDIOC_CAM_CONTROL: rc = cam_cpas_subdev_cmd(cpas_intf, (struct cam_control *) arg); break; + case CAM_SD_SHUTDOWN: + rc = __cam_cpas_subdev_close(sd, NULL); + break; default: CAM_ERR(CAM_CPAS, "Invalid command %d for CPAS!", cmd); rc = -EINVAL; @@ -798,6 +819,7 @@ static int cam_cpas_subdev_register(struct platform_device *pdev) subdev->sd_flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; subdev->ent_function = CAM_CPAS_DEVICE_TYPE; + subdev->close_seq_prior = CAM_SD_CLOSE_LOW_PRIORITY; rc = cam_register_subdev(subdev); if (rc) { diff --git a/drivers/cam_cust/cam_custom_context.c b/drivers/cam_cust/cam_custom_context.c index f9098e791e..30958b2fe3 100644 --- a/drivers/cam_cust/cam_custom_context.c +++ b/drivers/cam_cust/cam_custom_context.c @@ -1604,6 +1604,19 @@ static int __cam_custom_ctx_apply_default_req( return rc; } +static int __cam_custom_ctx_shutdown_dev( + struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + int rc = -EINVAL; + + if (!sd || !fh) { + CAM_ERR(CAM_CUSTOM, "Invalid input pointer"); + return rc; + } + + return cam_custom_subdev_close_internal(sd, fh); +} + /* top state machine */ static struct cam_ctx_ops cam_custom_dev_ctx_top_state_machine[CAM_CTX_STATE_MAX] = { @@ -1618,6 +1631,7 @@ static struct cam_ctx_ops .ioctl_ops = { .acquire_dev = __cam_custom_ctx_acquire_dev_in_available, + .shutdown_dev = __cam_custom_ctx_shutdown_dev, }, .crm_ops = {}, .irq_ops = NULL, @@ -1629,6 +1643,7 @@ static struct cam_ctx_ops .release_dev = __cam_custom_release_dev_in_acquired, .config_dev = __cam_custom_ctx_config_dev_in_acquired, .release_hw = __cam_custom_ctx_release_hw_in_top_state, + .shutdown_dev = __cam_custom_ctx_shutdown_dev, }, .crm_ops = { .link = __cam_custom_ctx_link_in_acquired, @@ -1647,6 +1662,7 @@ static struct cam_ctx_ops .release_dev = __cam_custom_release_dev_in_acquired, .config_dev = __cam_custom_ctx_config_dev, .release_hw = __cam_custom_ctx_release_hw_in_top_state, + .shutdown_dev = __cam_custom_ctx_shutdown_dev, }, .crm_ops = { .unlink = __cam_custom_ctx_unlink_in_ready, @@ -1664,6 +1680,7 @@ static struct cam_ctx_ops .config_dev = __cam_custom_ctx_config_dev_in_flushed, .release_hw = __cam_custom_ctx_release_hw_in_activated_state, + .shutdown_dev = __cam_custom_ctx_shutdown_dev, }, .crm_ops = { .unlink = __cam_custom_ctx_unlink_in_ready, @@ -1680,6 +1697,7 @@ static struct cam_ctx_ops .config_dev = __cam_custom_ctx_config_dev, .release_hw = __cam_custom_ctx_release_hw_in_activated_state, + .shutdown_dev = __cam_custom_ctx_shutdown_dev, }, .crm_ops = { .unlink = __cam_custom_ctx_unlink_in_activated, diff --git a/drivers/cam_cust/cam_custom_context.h b/drivers/cam_cust/cam_custom_context.h index ef7fe1f874..74c45d5416 100644 --- a/drivers/cam_cust/cam_custom_context.h +++ b/drivers/cam_cust/cam_custom_context.h @@ -150,4 +150,16 @@ int cam_custom_dev_context_init(struct cam_custom_context *ctx, */ int cam_custom_dev_context_deinit(struct cam_custom_context *ctx); +/** + * cam_custom_subdev_close_internal() + * + * @brief: Close function for the Custom context + * + * @sd: Pointer to struct v4l2_subdev + * @fh: Pointer to struct v4l2_subdev_fh + * + */ +int cam_custom_subdev_close_internal(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh); + #endif /* _CAM_CUSTOM_CONTEXT_H_ */ diff --git a/drivers/cam_cust/cam_custom_dev.c b/drivers/cam_cust/cam_custom_dev.c index d1a3444084..36dde62fc5 100644 --- a/drivers/cam_cust/cam_custom_dev.c +++ b/drivers/cam_cust/cam_custom_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ #include @@ -58,7 +58,7 @@ static int cam_custom_subdev_open(struct v4l2_subdev *sd, return 0; } -static int cam_custom_subdev_close(struct v4l2_subdev *sd, +int cam_custom_subdev_close_internal(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { int rc = 0; @@ -86,6 +86,19 @@ end: return rc; } +static int cam_custom_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_CUSTOM); + + if (crm_active) { + CAM_DBG(CAM_CUSTOM, "CRM is ACTIVE, close should be from CRM"); + return 0; + } + + return cam_custom_subdev_close_internal(sd, fh); +} + static const struct v4l2_subdev_internal_ops cam_custom_subdev_internal_ops = { .close = cam_custom_subdev_close, .open = cam_custom_subdev_open, @@ -102,6 +115,7 @@ static int cam_custom_component_bind(struct device *dev, struct platform_device *pdev = to_platform_device(dev); g_custom_dev.sd.internal_ops = &cam_custom_subdev_internal_ops; + g_custom_dev.sd.close_seq_prior = CAM_SD_CLOSE_HIGH_PRIORITY; rc = cam_subdev_probe(&g_custom_dev.sd, pdev, CAM_CUSTOM_DEV_NAME, CAM_CUSTOM_DEVICE_TYPE); diff --git a/drivers/cam_fd/cam_fd_context.c b/drivers/cam_fd/cam_fd_context.c index 4976bb2c89..2037215630 100644 --- a/drivers/cam_fd/cam_fd_context.c +++ b/drivers/cam_fd/cam_fd_context.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -169,6 +169,19 @@ static int __cam_fd_ctx_handle_irq_in_activated(void *context, return rc; } +static int __cam_fd_shutdown_dev(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + int rc = -EINVAL; + + if (!sd || !fh) { + CAM_ERR(CAM_FD, "Invalid input pointer"); + return rc; + } + + return cam_fd_dev_close_internal(sd, fh); +} + /* top state machine */ static struct cam_ctx_ops cam_fd_ctx_state_machine[CAM_CTX_STATE_MAX] = { @@ -182,6 +195,7 @@ static struct cam_ctx_ops { .ioctl_ops = { .acquire_dev = __cam_fd_ctx_acquire_dev_in_available, + .shutdown_dev = __cam_fd_shutdown_dev, }, .crm_ops = {}, .irq_ops = NULL, @@ -192,18 +206,25 @@ static struct cam_ctx_ops .release_dev = __cam_fd_ctx_release_dev_in_acquired, .config_dev = __cam_fd_ctx_config_dev_in_acquired, .start_dev = __cam_fd_ctx_start_dev_in_acquired, + .shutdown_dev = __cam_fd_shutdown_dev, }, .crm_ops = {}, .irq_ops = NULL, }, /* Ready */ { - .ioctl_ops = { }, + .ioctl_ops = { + .shutdown_dev = __cam_fd_shutdown_dev, + }, .crm_ops = {}, .irq_ops = NULL, }, /* Flushed */ - {}, + { + .ioctl_ops = { + .shutdown_dev = __cam_fd_shutdown_dev, + }, + }, /* Activated */ { .ioctl_ops = { @@ -212,6 +233,7 @@ static struct cam_ctx_ops .config_dev = __cam_fd_ctx_config_dev_in_activated, .flush_dev = __cam_fd_ctx_flush_dev_in_activated, .dump_dev = __cam_fd_ctx_dump_dev_in_activated, + .shutdown_dev = __cam_fd_shutdown_dev, }, .crm_ops = {}, .irq_ops = __cam_fd_ctx_handle_irq_in_activated, diff --git a/drivers/cam_fd/cam_fd_context.h b/drivers/cam_fd/cam_fd_context.h index ab0fa92b43..a57ed91d45 100644 --- a/drivers/cam_fd/cam_fd_context.h +++ b/drivers/cam_fd/cam_fd_context.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018, 2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_FD_CONTEXT_H_ @@ -27,4 +27,15 @@ int cam_fd_context_init(struct cam_fd_context *fd_ctx, uint32_t ctx_id); int cam_fd_context_deinit(struct cam_fd_context *ctx); +/** + * cam_fd_dev_close_internal() + * + * @brief: Close function for the fd dev + * + * @sd: Pointer to struct v4l2_subdev + * @fh: Pointer to struct v4l2_subdev_fh + */ +int cam_fd_dev_close_internal(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh); + #endif /* _CAM_FD_CONTEXT_H_ */ diff --git a/drivers/cam_fd/cam_fd_dev.c b/drivers/cam_fd/cam_fd_dev.c index e4285e2bf0..a58db056f6 100644 --- a/drivers/cam_fd/cam_fd_dev.c +++ b/drivers/cam_fd/cam_fd_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -57,7 +57,7 @@ static int cam_fd_dev_open(struct v4l2_subdev *sd, return 0; } -static int cam_fd_dev_close(struct v4l2_subdev *sd, +static int cam_fd_dev_close_internal(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct cam_fd_dev *fd_dev = &g_fd_dev; @@ -69,6 +69,11 @@ static int cam_fd_dev_close(struct v4l2_subdev *sd, } mutex_lock(&fd_dev->lock); + if (fd_dev->open_cnt == 0) { + CAM_WARN(CAM_FD, "device already closed"); + mutex_unlock(&fd_dev->lock); + return 0; + } fd_dev->open_cnt--; CAM_DBG(CAM_FD, "FD Subdev open count %d", fd_dev->open_cnt); mutex_unlock(&fd_dev->lock); @@ -83,6 +88,19 @@ static int cam_fd_dev_close(struct v4l2_subdev *sd, return 0; } +static int cam_fd_dev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_FD); + + if (crm_active) { + CAM_DBG(CAM_FD, "CRM is ACTIVE, close should be from CRM"); + return 0; + } + + return cam_fd_dev_close_internal(sd, fh); +} + static const struct v4l2_subdev_internal_ops cam_fd_subdev_internal_ops = { .open = cam_fd_dev_open, .close = cam_fd_dev_close, @@ -98,6 +116,7 @@ static int cam_fd_dev_component_bind(struct device *dev, struct platform_device *pdev = to_platform_device(dev); g_fd_dev.sd.internal_ops = &cam_fd_subdev_internal_ops; + g_fd_dev.sd.close_seq_prior = CAM_SD_CLOSE_MEDIUM_PRIORITY; /* Initialize the v4l2 subdevice first. (create cam_node) */ rc = cam_subdev_probe(&g_fd_dev.sd, pdev, CAM_FD_DEV_NAME, diff --git a/drivers/cam_icp/cam_icp_context.c b/drivers/cam_icp/cam_icp_context.c index 794bde09ee..88a84105b8 100644 --- a/drivers/cam_icp/cam_icp_context.c +++ b/drivers/cam_icp/cam_icp_context.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -221,6 +221,12 @@ static int __cam_icp_handle_buf_done_in_ready(void *ctx, return cam_context_buf_done_from_hw(ctx, done, evt_id); } +static int __cam_icp_shutdown_dev( + struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + return cam_icp_subdev_close_internal(sd, fh); +} + static struct cam_ctx_ops cam_icp_ctx_state_machine[CAM_CTX_STATE_MAX] = { /* Uninit */ @@ -233,6 +239,7 @@ static struct cam_ctx_ops { .ioctl_ops = { .acquire_dev = __cam_icp_acquire_dev_in_available, + .shutdown_dev = __cam_icp_shutdown_dev, }, .crm_ops = {}, .irq_ops = NULL, @@ -245,6 +252,7 @@ static struct cam_ctx_ops .config_dev = __cam_icp_config_dev_in_ready, .flush_dev = __cam_icp_flush_dev_in_ready, .dump_dev = __cam_icp_dump_dev_in_ready, + .shutdown_dev = __cam_icp_shutdown_dev, }, .crm_ops = {}, .irq_ops = __cam_icp_handle_buf_done_in_ready, @@ -258,16 +266,23 @@ static struct cam_ctx_ops .config_dev = __cam_icp_config_dev_in_ready, .flush_dev = __cam_icp_flush_dev_in_ready, .dump_dev = __cam_icp_dump_dev_in_ready, + .shutdown_dev = __cam_icp_shutdown_dev, }, .crm_ops = {}, .irq_ops = __cam_icp_handle_buf_done_in_ready, .pagefault_ops = cam_icp_context_dump_active_request, }, /* Flushed */ - {}, + { + .ioctl_ops = { + .shutdown_dev = __cam_icp_shutdown_dev, + }, + }, /* Activated */ { - .ioctl_ops = {}, + .ioctl_ops = { + .shutdown_dev = __cam_icp_shutdown_dev, + }, .crm_ops = {}, .irq_ops = NULL, .pagefault_ops = cam_icp_context_dump_active_request, diff --git a/drivers/cam_icp/cam_icp_context.h b/drivers/cam_icp/cam_icp_context.h index 1062e8f005..9150bcf43f 100644 --- a/drivers/cam_icp/cam_icp_context.h +++ b/drivers/cam_icp/cam_icp_context.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_ICP_CONTEXT_H_ @@ -39,4 +39,12 @@ int cam_icp_context_init(struct cam_icp_context *ctx, */ int cam_icp_context_deinit(struct cam_icp_context *ctx); +/** + * cam_icp_subdev_close_internal() - Close function for the icp dev + * @sd: Pointer to struct v4l2_subdev + * @fh: Pointer to struct v4l2_subdev_fh + */ +int cam_icp_subdev_close_internal(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh); + #endif /* _CAM_ICP_CONTEXT_H_ */ diff --git a/drivers/cam_icp/cam_icp_subdev.c b/drivers/cam_icp/cam_icp_subdev.c index 8c79bbbde5..3288964444 100644 --- a/drivers/cam_icp/cam_icp_subdev.c +++ b/drivers/cam_icp/cam_icp_subdev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -98,7 +98,7 @@ end: return rc; } -static int cam_icp_subdev_close(struct v4l2_subdev *sd, +int cam_icp_subdev_close_internal(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { int rc = 0; @@ -107,9 +107,8 @@ static int cam_icp_subdev_close(struct v4l2_subdev *sd, mutex_lock(&g_icp_dev.icp_lock); if (g_icp_dev.open_cnt <= 0) { - CAM_DBG(CAM_ICP, "ICP subdev is already closed"); - rc = -EINVAL; - goto end; + CAM_WARN(CAM_ICP, "ICP subdev is already closed"); + return 0; } g_icp_dev.open_cnt--; if (!node) { @@ -133,7 +132,20 @@ static int cam_icp_subdev_close(struct v4l2_subdev *sd, end: mutex_unlock(&g_icp_dev.icp_lock); - return 0; + return rc; +} + +static int cam_icp_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_ICP); + + if (crm_active) { + CAM_DBG(CAM_ICP, "CRM is ACTIVE, close should be from CRM"); + return 0; + } + + return cam_icp_subdev_close_internal(sd, fh); } const struct v4l2_subdev_internal_ops cam_icp_subdev_internal_ops = { @@ -157,6 +169,7 @@ static int cam_icp_component_bind(struct device *dev, g_icp_dev.sd.pdev = pdev; g_icp_dev.sd.internal_ops = &cam_icp_subdev_internal_ops; + g_icp_dev.sd.close_seq_prior = CAM_SD_CLOSE_MEDIUM_PRIORITY; rc = cam_subdev_probe(&g_icp_dev.sd, pdev, CAM_ICP_DEV_NAME, CAM_ICP_DEVICE_TYPE); if (rc) { diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 44059756cf..068c00a445 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -5943,6 +5943,12 @@ static int __cam_isp_ctx_handle_irq_in_activated(void *context, return rc; } +static int __cam_isp_shutdown_dev( + struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + return cam_isp_subdev_close_internal(sd, fh); +} + /* top state machine */ static struct cam_ctx_ops cam_isp_ctx_top_state_machine[CAM_CTX_STATE_MAX] = { @@ -5956,6 +5962,7 @@ static struct cam_ctx_ops { .ioctl_ops = { .acquire_dev = __cam_isp_ctx_acquire_dev_in_available, + .shutdown_dev = __cam_isp_shutdown_dev, }, .crm_ops = {}, .irq_ops = NULL, @@ -5967,6 +5974,7 @@ static struct cam_ctx_ops .release_dev = __cam_isp_ctx_release_dev_in_top_state, .config_dev = __cam_isp_ctx_config_dev_in_acquired, .release_hw = __cam_isp_ctx_release_hw_in_top_state, + .shutdown_dev = __cam_isp_shutdown_dev, }, .crm_ops = { .link = __cam_isp_ctx_link_in_acquired, @@ -5986,6 +5994,7 @@ static struct cam_ctx_ops .release_dev = __cam_isp_ctx_release_dev_in_top_state, .config_dev = __cam_isp_ctx_config_dev_in_top_state, .release_hw = __cam_isp_ctx_release_hw_in_top_state, + .shutdown_dev = __cam_isp_shutdown_dev, }, .crm_ops = { .unlink = __cam_isp_ctx_unlink_in_ready, @@ -6003,6 +6012,7 @@ static struct cam_ctx_ops .release_dev = __cam_isp_ctx_release_dev_in_activated, .config_dev = __cam_isp_ctx_config_dev_in_flushed, .release_hw = __cam_isp_ctx_release_hw_in_activated, + .shutdown_dev = __cam_isp_shutdown_dev, }, .crm_ops = { .unlink = __cam_isp_ctx_unlink_in_ready, @@ -6019,6 +6029,7 @@ static struct cam_ctx_ops .release_dev = __cam_isp_ctx_release_dev_in_activated, .config_dev = __cam_isp_ctx_config_dev_in_top_state, .release_hw = __cam_isp_ctx_release_hw_in_activated, + .shutdown_dev = __cam_isp_shutdown_dev, }, .crm_ops = { .unlink = __cam_isp_ctx_unlink_in_activated, diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index fbabb598e0..a3907c28c7 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -365,5 +365,16 @@ int cam_isp_context_init(struct cam_isp_context *ctx, */ int cam_isp_context_deinit(struct cam_isp_context *ctx); +/** + * cam_isp_subdev_close_internal() + * + * @brief: Close function for the isp dev + * + * @sd: Pointer to struct v4l2_subdev + * @fh: Pointer to struct v4l2_subdev_fh + * + */ +int cam_isp_subdev_close_internal(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh); #endif /* __CAM_ISP_CONTEXT_H__ */ diff --git a/drivers/cam_isp/cam_isp_dev.c b/drivers/cam_isp/cam_isp_dev.c index 68eb02e9b4..afd6c2d977 100644 --- a/drivers/cam_isp/cam_isp_dev.c +++ b/drivers/cam_isp/cam_isp_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -55,7 +55,7 @@ static int cam_isp_subdev_open(struct v4l2_subdev *sd, return 0; } -static int cam_isp_subdev_close(struct v4l2_subdev *sd, +int cam_isp_subdev_close_internal(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { int rc = 0; @@ -83,6 +83,18 @@ end: return rc; } +static int cam_isp_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_ISP); + + if (crm_active) { + CAM_DBG(CAM_ISP, "CRM is ACTIVE, close should be from CRM"); + return 0; + } + return cam_isp_subdev_close_internal(sd, fh); +} + static const struct v4l2_subdev_internal_ops cam_isp_subdev_internal_ops = { .close = cam_isp_subdev_close, .open = cam_isp_subdev_open, @@ -104,6 +116,7 @@ static int cam_isp_dev_component_bind(struct device *dev, (const char **)&compat_str); g_isp_dev.sd.internal_ops = &cam_isp_subdev_internal_ops; + g_isp_dev.sd.close_seq_prior = CAM_SD_CLOSE_HIGH_PRIORITY; /* Initialize the v4l2 subdevice first. (create cam_node) */ if (strnstr(compat_str, "ife", strlen(compat_str))) { rc = cam_subdev_probe(&g_isp_dev.sd, pdev, CAM_ISP_DEV_NAME, diff --git a/drivers/cam_jpeg/cam_jpeg_context.c b/drivers/cam_jpeg/cam_jpeg_context.c index 4175db84db..1bc4e54e28 100644 --- a/drivers/cam_jpeg/cam_jpeg_context.c +++ b/drivers/cam_jpeg/cam_jpeg_context.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -135,6 +135,12 @@ static int __cam_jpeg_ctx_stop_dev_in_acquired(struct cam_context *ctx, return rc; } +static int __cam_jpeg_shutdown_dev( + struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + return cam_jpeg_subdev_close_internal(sd, fh); +} + /* top state machine */ static struct cam_ctx_ops cam_jpeg_ctx_state_machine[CAM_CTX_STATE_MAX] = { @@ -148,6 +154,7 @@ static struct cam_ctx_ops { .ioctl_ops = { .acquire_dev = __cam_jpeg_ctx_acquire_dev_in_available, + .shutdown_dev = __cam_jpeg_shutdown_dev, }, .crm_ops = { }, .irq_ops = NULL, @@ -160,11 +167,30 @@ static struct cam_ctx_ops .stop_dev = __cam_jpeg_ctx_stop_dev_in_acquired, .flush_dev = __cam_jpeg_ctx_flush_dev_in_acquired, .dump_dev = __cam_jpeg_ctx_dump_dev_in_acquired, + .shutdown_dev = __cam_jpeg_shutdown_dev, }, .crm_ops = { }, .irq_ops = __cam_jpeg_ctx_handle_buf_done_in_acquired, .pagefault_ops = cam_jpeg_context_dump_active_request, }, + /* Ready */ + { + .ioctl_ops = { + .shutdown_dev = __cam_jpeg_shutdown_dev, + }, + }, + /* Flushed */ + { + .ioctl_ops = { + .shutdown_dev = __cam_jpeg_shutdown_dev, + }, + }, + /* Activated */ + { + .ioctl_ops = { + .shutdown_dev = __cam_jpeg_shutdown_dev, + }, + }, }; int cam_jpeg_context_init(struct cam_jpeg_context *ctx, diff --git a/drivers/cam_jpeg/cam_jpeg_context.h b/drivers/cam_jpeg/cam_jpeg_context.h index 3a11865a60..d36bfb8bb1 100644 --- a/drivers/cam_jpeg/cam_jpeg_context.h +++ b/drivers/cam_jpeg/cam_jpeg_context.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018, 2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_JPEG_CONTEXT_H_ @@ -64,4 +64,16 @@ int cam_jpeg_context_init(struct cam_jpeg_context *ctx, */ int cam_jpeg_context_deinit(struct cam_jpeg_context *ctx); +/** + * cam_jpeg_subdev_close_internal() + * + * @brief: Close function for the jpeg dev + * + * @sd: Pointer to struct v4l2_subdev + * @fh: Pointer to struct v4l2_subdev_fh + * + */ +int cam_jpeg_subdev_close_internal(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh); + #endif /* __CAM_JPEG_CONTEXT_H__ */ diff --git a/drivers/cam_jpeg/cam_jpeg_dev.c b/drivers/cam_jpeg/cam_jpeg_dev.c index f627e8850d..a47476a061 100644 --- a/drivers/cam_jpeg/cam_jpeg_dev.c +++ b/drivers/cam_jpeg/cam_jpeg_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -56,13 +56,12 @@ static int cam_jpeg_subdev_open(struct v4l2_subdev *sd, return 0; } -static int cam_jpeg_subdev_close(struct v4l2_subdev *sd, +int cam_jpeg_subdev_close_internal(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { int rc = 0; struct cam_node *node = v4l2_get_subdevdata(sd); - mutex_lock(&g_jpeg_dev.jpeg_mutex); if (g_jpeg_dev.open_cnt <= 0) { CAM_DBG(CAM_JPEG, "JPEG subdev is already closed"); @@ -86,6 +85,18 @@ end: return rc; } +static int cam_jpeg_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_JPEG); + + if (crm_active) { + CAM_DBG(CAM_JPEG, "CRM is ACTIVE, close should be from CRM"); + return 0; + } + return cam_jpeg_subdev_close_internal(sd, fh); +} + static const struct v4l2_subdev_internal_ops cam_jpeg_subdev_internal_ops = { .close = cam_jpeg_subdev_close, .open = cam_jpeg_subdev_open, @@ -102,6 +113,7 @@ static int cam_jpeg_dev_component_bind(struct device *dev, struct platform_device *pdev = to_platform_device(dev); g_jpeg_dev.sd.internal_ops = &cam_jpeg_subdev_internal_ops; + g_jpeg_dev.sd.close_seq_prior = CAM_SD_CLOSE_MEDIUM_PRIORITY; rc = cam_subdev_probe(&g_jpeg_dev.sd, pdev, CAM_JPEG_DEV_NAME, CAM_JPEG_DEVICE_TYPE); if (rc) { diff --git a/drivers/cam_lrme/cam_lrme_context.c b/drivers/cam_lrme/cam_lrme_context.c index f74aa56f9d..a61ab4f914 100644 --- a/drivers/cam_lrme/cam_lrme_context.c +++ b/drivers/cam_lrme/cam_lrme_context.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -172,6 +172,12 @@ static int __cam_lrme_ctx_handle_irq_in_activated(void *context, return rc; } +static int __cam_lrme_shutdown_dev( + struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + return cam_lrme_dev_close_internal(sd, fh); +} + /* top state machine */ static struct cam_ctx_ops cam_lrme_ctx_state_machine[CAM_CTX_STATE_MAX] = { @@ -185,6 +191,7 @@ static struct cam_ctx_ops { .ioctl_ops = { .acquire_dev = __cam_lrme_ctx_acquire_dev_in_available, + .shutdown_dev = __cam_lrme_shutdown_dev, }, .crm_ops = {}, .irq_ops = NULL, @@ -195,18 +202,25 @@ static struct cam_ctx_ops .config_dev = __cam_lrme_ctx_config_dev_in_activated, .release_dev = __cam_lrme_ctx_release_dev_in_acquired, .start_dev = __cam_lrme_ctx_start_dev_in_acquired, + .shutdown_dev = __cam_lrme_shutdown_dev, }, .crm_ops = {}, .irq_ops = NULL, }, /* Ready */ { - .ioctl_ops = {}, + .ioctl_ops = { + .shutdown_dev = __cam_lrme_shutdown_dev, + }, .crm_ops = {}, .irq_ops = NULL, }, /* Flushed */ - {}, + { + .ioctl_ops = { + .shutdown_dev = __cam_lrme_shutdown_dev, + }, + }, /* Activate */ { .ioctl_ops = { @@ -215,6 +229,7 @@ static struct cam_ctx_ops .stop_dev = __cam_lrme_ctx_stop_dev_in_activated, .flush_dev = __cam_lrme_ctx_flush_dev_in_activated, .dump_dev = __cam_lrme_ctx_dump_dev_in_activated, + .shutdown_dev = __cam_lrme_shutdown_dev, }, .crm_ops = {}, .irq_ops = __cam_lrme_ctx_handle_irq_in_activated, diff --git a/drivers/cam_lrme/cam_lrme_context.h b/drivers/cam_lrme/cam_lrme_context.h index 9fb88ed85f..f1b5ff267f 100644 --- a/drivers/cam_lrme/cam_lrme_context.h +++ b/drivers/cam_lrme/cam_lrme_context.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, 2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_LRME_CONTEXT_H_ @@ -30,4 +30,16 @@ int cam_lrme_context_init(struct cam_lrme_context *lrme_ctx, uint32_t index); int cam_lrme_context_deinit(struct cam_lrme_context *lrme_ctx); +/** + * cam_lrme_dev_close_internal() + * + * @brief: Close function for the jpeg dev + * + * @sd: Pointer to struct v4l2_subdev + * @fh: Pointer to struct v4l2_subdev_fh + * + */ +int cam_lrme_dev_close_internal(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh); + #endif /* _CAM_LRME_CONTEXT_H_ */ diff --git a/drivers/cam_lrme/cam_lrme_dev.c b/drivers/cam_lrme/cam_lrme_dev.c index 28d1130522..5055444c3d 100644 --- a/drivers/cam_lrme/cam_lrme_dev.c +++ b/drivers/cam_lrme/cam_lrme_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -72,7 +72,7 @@ static int cam_lrme_dev_open(struct v4l2_subdev *sd, return 0; } -static int cam_lrme_dev_close(struct v4l2_subdev *sd, +int cam_lrme_dev_close_internal(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { int rc = 0; @@ -106,6 +106,18 @@ end: return rc; } +static int cam_lrme_dev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_LRME); + + if (crm_active) { + CAM_DBG(CAM_LRME, "CRM is ACTIVE, close should be from CRM"); + return 0; + } + return cam_lrme_dev_close_internal(sd, fh); +} + static const struct v4l2_subdev_internal_ops cam_lrme_subdev_internal_ops = { .open = cam_lrme_dev_open, .close = cam_lrme_dev_close, @@ -126,6 +138,7 @@ static int cam_lrme_component_bind(struct device *dev, return -ENOMEM; } g_lrme_dev->sd.internal_ops = &cam_lrme_subdev_internal_ops; + g_lrme_dev->sd.close_seq_prior = CAM_SD_CLOSE_MEDIUM_PRIORITY; mutex_init(&g_lrme_dev->lock); diff --git a/drivers/cam_ope/cam_ope_context.c b/drivers/cam_ope/cam_ope_context.c index 6229a9ca11..23f89dd2b0 100644 --- a/drivers/cam_ope/cam_ope_context.c +++ b/drivers/cam_ope/cam_ope_context.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ #include @@ -195,6 +195,12 @@ static int __cam_ope_handle_buf_done_in_ready(void *ctx, return cam_context_buf_done_from_hw(ctx, done, evt_id); } +static int __cam_ope_shutdown_dev( + struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + return cam_ope_subdev_close_internal(sd, fh); +} + static struct cam_ctx_ops cam_ope_ctx_state_machine[CAM_CTX_STATE_MAX] = { /* Uninit */ @@ -207,6 +213,7 @@ static struct cam_ctx_ops { .ioctl_ops = { .acquire_dev = __cam_ope_acquire_dev_in_available, + .shutdown_dev = __cam_ope_shutdown_dev, }, .crm_ops = {}, .irq_ops = NULL, @@ -219,6 +226,7 @@ static struct cam_ctx_ops .config_dev = __cam_ope_config_dev_in_ready, .flush_dev = __cam_ope_flush_dev_in_ready, .dump_dev = __cam_ope_dump_dev_in_ready, + .shutdown_dev = __cam_ope_shutdown_dev, }, .crm_ops = {}, .irq_ops = __cam_ope_handle_buf_done_in_ready, @@ -232,14 +240,23 @@ static struct cam_ctx_ops .config_dev = __cam_ope_config_dev_in_ready, .flush_dev = __cam_ope_flush_dev_in_ready, .dump_dev = __cam_ope_dump_dev_in_ready, + .shutdown_dev = __cam_ope_shutdown_dev, }, .crm_ops = {}, .irq_ops = __cam_ope_handle_buf_done_in_ready, .pagefault_ops = cam_ope_context_dump_active_request, }, + /* Flushed */ + { + .ioctl_ops = { + .shutdown_dev = __cam_ope_shutdown_dev, + }, + }, /* Activated */ { - .ioctl_ops = {}, + .ioctl_ops = { + .shutdown_dev = __cam_ope_shutdown_dev, + }, .crm_ops = {}, .irq_ops = NULL, .pagefault_ops = cam_ope_context_dump_active_request, diff --git a/drivers/cam_ope/cam_ope_context.h b/drivers/cam_ope/cam_ope_context.h index 9d0779ce2b..5e6d28c3ff 100644 --- a/drivers/cam_ope/cam_ope_context.h +++ b/drivers/cam_ope/cam_ope_context.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_OPE_CONTEXT_H_ @@ -41,4 +41,12 @@ int cam_ope_context_init(struct cam_ope_context *ctx, */ int cam_ope_context_deinit(struct cam_ope_context *ctx); +/** + * cam_ope_subdev_close_internal() - Close function for the icp dev + * @sd: Pointer to struct v4l2_subdev + * @fh: Pointer to struct v4l2_subdev_fh + */ +int cam_ope_subdev_close_internal(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh); + #endif /* _CAM_OPE_CONTEXT_H_ */ diff --git a/drivers/cam_ope/cam_ope_subdev.c b/drivers/cam_ope/cam_ope_subdev.c index df9de9993a..a04abe3bcf 100644 --- a/drivers/cam_ope/cam_ope_subdev.c +++ b/drivers/cam_ope/cam_ope_subdev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ #include @@ -95,7 +95,7 @@ end: return rc; } -static int cam_ope_subdev_close(struct v4l2_subdev *sd, +int cam_ope_subdev_close_internal(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { int rc = 0; @@ -134,6 +134,19 @@ end: return rc; } +static int cam_ope_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_OPE); + + if (crm_active) { + CAM_DBG(CAM_OPE, "CRM is ACTIVE, close should be from CRM"); + return 0; + } + + return cam_ope_subdev_close_internal(sd, fh); +} + const struct v4l2_subdev_internal_ops cam_ope_subdev_internal_ops = { .open = cam_ope_subdev_open, .close = cam_ope_subdev_close, @@ -156,6 +169,7 @@ static int cam_ope_subdev_component_bind(struct device *dev, g_ope_dev.sd.pdev = pdev; g_ope_dev.sd.internal_ops = &cam_ope_subdev_internal_ops; + g_ope_dev.sd.close_seq_prior = CAM_SD_CLOSE_MEDIUM_PRIORITY; rc = cam_subdev_probe(&g_ope_dev.sd, pdev, OPE_DEV_NAME, CAM_OPE_DEVICE_TYPE); if (rc) { diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.c b/drivers/cam_req_mgr/cam_req_mgr_dev.c index 44b4bc3eb2..3e11fcee51 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "cam_req_mgr_dev.h" #include "cam_req_mgr_util.h" @@ -32,6 +33,7 @@ static struct cam_req_mgr_device g_dev; struct kmem_cache *g_cam_req_mgr_timer_cachep; +static struct list_head cam_req_mgr_ordered_sd_list; static struct device_attribute camera_debug_sysfs_attr = __ATTR(debug_node, 0600, NULL, cam_debug_sysfs_node_store); @@ -122,6 +124,7 @@ static int cam_req_mgr_open(struct file *filep) spin_unlock_bh(&g_dev.cam_eventq_lock); g_dev.open_cnt++; + g_dev.read_active_dev_id_hdls = 0; rc = cam_mem_mgr_init(); if (rc) { g_dev.open_cnt--; @@ -158,6 +161,7 @@ static unsigned int cam_req_mgr_poll(struct file *f, static int cam_req_mgr_close(struct file *filep) { struct v4l2_subdev *sd; + struct cam_subdev *csd; struct v4l2_fh *vfh = filep->private_data; struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); @@ -172,18 +176,23 @@ static int cam_req_mgr_close(struct file *filep) } cam_req_mgr_handle_core_shutdown(); + g_dev.shutdown_state = true; - list_for_each_entry(sd, &g_dev.v4l2_dev->subdevs, list) { + list_for_each_entry(csd, &cam_req_mgr_ordered_sd_list, list) { + sd = &csd->sd; if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) continue; - if (sd->internal_ops && sd->internal_ops->close) { + if (sd->internal_ops) { CAM_DBG(CAM_CRM, "Invoke subdev close for device %s", sd->name); - sd->internal_ops->close(sd, subdev_fh); + v4l2_subdev_call(sd, core, ioctl, + CAM_SD_SHUTDOWN, subdev_fh); } } g_dev.open_cnt--; + g_dev.shutdown_state = false; + g_dev.read_active_dev_id_hdls = 0; v4l2_fh_release(filep); spin_lock_bh(&g_dev.cam_eventq_lock); @@ -659,6 +668,51 @@ void cam_subdev_notify_message(u32 subdev_type, } EXPORT_SYMBOL(cam_subdev_notify_message); + +static int cam_req_mgr_ordered_list_cmp(void *priv, + struct list_head *head_1, struct list_head *head_2) +{ + struct cam_subdev *entry_1 = + list_entry(head_1, struct cam_subdev, list); + struct cam_subdev *entry_2 = + list_entry(head_2, struct cam_subdev, list); + int ret = -1; + + if (entry_1->close_seq_prior > entry_2->close_seq_prior) + return 1; + else if (entry_1->close_seq_prior < entry_2->close_seq_prior) + return ret; + else + return 0; +} + +bool cam_req_mgr_is_open(uint64_t dev_id) +{ + bool crm_status; + bool dev_id_status; + + mutex_lock(&g_dev.cam_lock); + crm_status = g_dev.open_cnt ? true : false; + + if (!g_dev.read_active_dev_id_hdls) { + g_dev.active_dev_id_hdls = cam_get_dev_handle_status(); + g_dev.read_active_dev_id_hdls++; + } + + dev_id_status = (g_dev.active_dev_id_hdls & dev_id) ? true : false; + crm_status &= dev_id_status; + mutex_unlock(&g_dev.cam_lock); + + return crm_status; +} +EXPORT_SYMBOL(cam_req_mgr_is_open); + +bool cam_req_mgr_is_shutdown(void) +{ + return g_dev.shutdown_state; +} +EXPORT_SYMBOL(cam_req_mgr_is_shutdown); + int cam_register_subdev(struct cam_subdev *csd) { struct v4l2_subdev *sd; @@ -687,6 +741,10 @@ int cam_register_subdev(struct cam_subdev *csd) sd->entity.pads = NULL; sd->entity.function = csd->ent_function; + list_add(&csd->list, &cam_req_mgr_ordered_sd_list); + list_sort(NULL, &cam_req_mgr_ordered_sd_list, + cam_req_mgr_ordered_list_cmp); + rc = v4l2_device_register_subdev(g_dev.v4l2_dev, sd); if (rc) { CAM_ERR(CAM_CRM, "register subdev failed"); @@ -747,6 +805,7 @@ static int cam_req_mgr_component_master_bind(struct device *dev) goto video_setup_fail; g_dev.open_cnt = 0; + g_dev.shutdown_state = false; mutex_init(&g_dev.cam_lock); spin_lock_init(&g_dev.cam_eventq_lock); mutex_init(&g_dev.dev_lock); @@ -764,6 +823,7 @@ static int cam_req_mgr_component_master_bind(struct device *dev) } g_dev.state = true; + INIT_LIST_HEAD(&cam_req_mgr_ordered_sd_list); if (g_cam_req_mgr_timer_cachep == NULL) { g_cam_req_mgr_timer_cachep = kmem_cache_create("crm_timer", diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.h b/drivers/cam_req_mgr/cam_req_mgr_dev.h index 464720efb0..0a55789b7c 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_dev.h +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_REQ_MGR_DEV_H_ @@ -19,6 +19,9 @@ * @cam_lock: per file handle lock * @cam_eventq: event queue * @cam_eventq_lock: lock for event queue + * @shutdown_state: shutdown state + * @active_dev_id_hdls: active dev id handles + * @read_active_dev_id_hdls: read active_dev_id_hdls status */ struct cam_req_mgr_device { struct video_device *video; @@ -30,6 +33,9 @@ struct cam_req_mgr_device { struct mutex cam_lock; struct v4l2_fh *cam_eventq; spinlock_t cam_eventq_lock; + bool shutdown_state; + uint64_t active_dev_id_hdls; + int read_active_dev_id_hdls; }; #define CAM_REQ_MGR_GET_PAYLOAD_PTR(ev, type) \ diff --git a/drivers/cam_req_mgr/cam_req_mgr_util.c b/drivers/cam_req_mgr/cam_req_mgr_util.c index 4b1f4d8e86..00b919fcec 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_util.c +++ b/drivers/cam_req_mgr/cam_req_mgr_util.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "CAM-REQ-MGR_UTIL %s:%d " fmt, __func__, __LINE__ @@ -14,6 +14,7 @@ #include #include "cam_req_mgr_util.h" #include "cam_debug_util.h" +#include "cam_context.h" static struct cam_req_mgr_util_hdl_tbl *hdl_tbl; static DEFINE_SPINLOCK(hdl_tbl_lock); @@ -209,6 +210,36 @@ int32_t cam_create_device_hdl(struct cam_create_dev_hdl *hdl_data) return handle; } +int32_t cam_get_dev_handle_info(uint64_t handle, + struct cam_context **ctx, int32_t dev_index) +{ + int32_t idx; + struct v4l2_subdev *sd = (struct v4l2_subdev *)handle; + + for (idx = dev_index + 1; idx < CAM_REQ_MGR_MAX_HANDLES_V2; idx++) { + if (hdl_tbl->hdl[idx].state == HDL_ACTIVE) { + *ctx = (struct cam_context *)cam_get_device_priv( + hdl_tbl->hdl[idx].hdl_value); + if ((*ctx) && !strcmp(sd->name, (*ctx)->dev_name)) + return idx; + } + } + *ctx = NULL; + return CAM_REQ_MGR_MAX_HANDLES_V2; +} + +uint64_t cam_get_dev_handle_status(void) +{ + int32_t idx; + uint64_t active_dev_hdls = 0; + + for (idx = 0; idx < CAM_REQ_MGR_MAX_HANDLES_V2; idx++) + if (hdl_tbl->hdl[idx].state == HDL_ACTIVE) + active_dev_hdls |= hdl_tbl->hdl[idx].dev_id; + + return active_dev_hdls; +} + void *cam_get_device_priv(int32_t dev_hdl) { int idx; diff --git a/drivers/cam_req_mgr/cam_req_mgr_util.h b/drivers/cam_req_mgr/cam_req_mgr_util.h index 9cf7338715..6656f1d1da 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_util.h +++ b/drivers/cam_req_mgr/cam_req_mgr_util.h @@ -166,4 +166,11 @@ int32_t cam_req_mgr_util_deinit(void); */ int32_t cam_req_mgr_util_free_hdls(void); +/** + * cam_get_dev_handle_status() - get dev handles status + * + * Returns dev handle status + */ +uint64_t cam_get_dev_handle_status(void); + #endif /* _CAM_REQ_MGR_UTIL_API_H_ */ diff --git a/drivers/cam_req_mgr/cam_subdev.h b/drivers/cam_req_mgr/cam_subdev.h index c2ded0c910..c09203fa13 100644 --- a/drivers/cam_req_mgr/cam_subdev.h +++ b/drivers/cam_req_mgr/cam_subdev.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_SUBDEV_H_ @@ -20,6 +20,13 @@ enum cam_subdev_message_type_t { CAM_SUBDEV_MESSAGE_IRQ_ERR = 0x1 }; +/* Enum for close sequence priority */ +enum cam_subdev_close_seq_priority { + CAM_SD_CLOSE_HIGH_PRIORITY, + CAM_SD_CLOSE_MEDIUM_PRIORITY, + CAM_SD_CLOSE_LOW_PRIORITY +}; + /** * struct cam_subdev - describes a camera sub-device * @@ -38,6 +45,8 @@ enum cam_subdev_message_type_t { * @ent_function: Media entity function type. Can be: * %CAM_IFE_DEVICE_TYPE - identifies as IFE device. * %CAM_ICP_DEVICE_TYPE - identifies as ICP device. + * @list: list pointer + * @close_seq_prior: cam_subdev_close_seq_priority type * * Each instance of a subdev driver should create this struct, either * stand-alone or embedded in a larger struct. This structure should be @@ -57,6 +66,8 @@ struct cam_subdev { struct v4l2_subdev *sd, enum cam_subdev_message_type_t msg_type, uint32_t data); + struct list_head list; + enum cam_subdev_close_seq_priority close_seq_prior; }; /** @@ -118,4 +129,20 @@ int cam_register_subdev(struct cam_subdev *sd); */ int cam_unregister_subdev(struct cam_subdev *sd); +/** + * cam_req_mgr_is_open() + * + * @brief: This common utility function returns the crm active status + * + * @dev_id: device id type + */ +bool cam_req_mgr_is_open(uint64_t dev_id); + +/** + * cam_req_mgr_is_shutdown() + * + * @brief: This common utility function returns the shutdown state + */ +bool cam_req_mgr_is_shutdown(void); + #endif /* _CAM_SUBDEV_H_ */ diff --git a/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.c b/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.c index 8b180a767d..d51dae6d37 100644 --- a/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.c +++ b/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include "cam_actuator_dev.h" @@ -10,6 +10,38 @@ #include "cam_trace.h" #include "camera_main.h" +static int cam_actuator_subdev_close_internal(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_actuator_ctrl_t *a_ctrl = + v4l2_get_subdevdata(sd); + + if (!a_ctrl) { + CAM_ERR(CAM_ACTUATOR, "a_ctrl ptr is NULL"); + return -EINVAL; + } + + mutex_lock(&(a_ctrl->actuator_mutex)); + cam_actuator_shutdown(a_ctrl); + mutex_unlock(&(a_ctrl->actuator_mutex)); + + return 0; +} + +static int cam_actuator_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_ACTUATOR); + + if (crm_active) { + CAM_INFO(CAM_ACTUATOR, + "CRM is ACTIVE, close should be from CRM"); + return 0; + } + + return cam_actuator_subdev_close_internal(sd, fh); +} + static long cam_actuator_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { @@ -24,6 +56,14 @@ static long cam_actuator_subdev_ioctl(struct v4l2_subdev *sd, CAM_ERR(CAM_ACTUATOR, "Failed for driver_cmd: %d", rc); break; + case CAM_SD_SHUTDOWN: + if (!cam_req_mgr_is_shutdown()) { + CAM_ERR(CAM_CORE, "SD shouldn't come from user space"); + return 0; + } + + rc = cam_actuator_subdev_close_internal(sd, NULL); + break; default: CAM_ERR(CAM_ACTUATOR, "Invalid ioctl cmd: %u", cmd); rc = -ENOIOCTLCMD; @@ -77,24 +117,6 @@ static long cam_actuator_init_subdev_do_ioctl(struct v4l2_subdev *sd, } #endif -static int cam_actuator_subdev_close(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh) -{ - struct cam_actuator_ctrl_t *a_ctrl = - v4l2_get_subdevdata(sd); - - if (!a_ctrl) { - CAM_ERR(CAM_ACTUATOR, "a_ctrl ptr is NULL"); - return -EINVAL; - } - - mutex_lock(&(a_ctrl->actuator_mutex)); - cam_actuator_shutdown(a_ctrl); - mutex_unlock(&(a_ctrl->actuator_mutex)); - - return 0; -} - static struct v4l2_subdev_core_ops cam_actuator_subdev_core_ops = { .ioctl = cam_actuator_subdev_ioctl, #ifdef CONFIG_COMPAT @@ -127,10 +149,13 @@ static int cam_actuator_init_subdev(struct cam_actuator_ctrl_t *a_ctrl) a_ctrl->v4l2_dev_str.ent_function = CAM_ACTUATOR_DEVICE_TYPE; a_ctrl->v4l2_dev_str.token = a_ctrl; + a_ctrl->v4l2_dev_str.close_seq_prior = + CAM_SD_CLOSE_MEDIUM_PRIORITY; rc = cam_register_subdev(&(a_ctrl->v4l2_dev_str)); if (rc) - CAM_ERR(CAM_SENSOR, "Fail with cam_register_subdev rc: %d", rc); + CAM_ERR(CAM_ACTUATOR, + "Fail with cam_register_subdev rc: %d", rc); return rc; } diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c index 099210a2ae..1de755beba 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c @@ -76,29 +76,7 @@ static void cam_csiphy_debug_unregister(void) root_dentry = NULL; } -static long cam_csiphy_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - struct csiphy_device *csiphy_dev = v4l2_get_subdevdata(sd); - int rc = 0; - - switch (cmd) { - case VIDIOC_CAM_CONTROL: - rc = cam_csiphy_core_cfg(csiphy_dev, arg); - if (rc) - CAM_ERR(CAM_CSIPHY, - "Failed in configuring the device: %d", rc); - break; - default: - CAM_ERR(CAM_CSIPHY, "Wrong ioctl : %d", cmd); - rc = -ENOIOCTLCMD; - break; - } - - return rc; -} - -static int cam_csiphy_subdev_close(struct v4l2_subdev *sd, +static int cam_csiphy_subdev_close_internal(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct csiphy_device *csiphy_dev = @@ -116,6 +94,49 @@ static int cam_csiphy_subdev_close(struct v4l2_subdev *sd, return 0; } +static int cam_csiphy_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_CSIPHY); + + if (crm_active) { + CAM_INFO(CAM_CSIPHY, "CRM is ACTIVE, close should be from CRM"); + return 0; + } + + return cam_csiphy_subdev_close_internal(sd, fh); +} + +static long cam_csiphy_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + struct csiphy_device *csiphy_dev = v4l2_get_subdevdata(sd); + int rc = 0; + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_csiphy_core_cfg(csiphy_dev, arg); + if (rc) + CAM_ERR(CAM_CSIPHY, + "Failed in configuring the device: %d", rc); + break; + case CAM_SD_SHUTDOWN: + if (!cam_req_mgr_is_shutdown()) { + CAM_ERR(CAM_CORE, "SD shouldn't come from user space"); + return 0; + } + + rc = cam_csiphy_subdev_close_internal(sd, NULL); + break; + default: + CAM_ERR(CAM_CSIPHY, "Wrong ioctl : %d", cmd); + rc = -ENOIOCTLCMD; + break; + } + + return rc; +} + #ifdef CONFIG_COMPAT static long cam_csiphy_subdev_compat_ioctl(struct v4l2_subdev *sd, unsigned int cmd, unsigned long arg) @@ -226,6 +247,8 @@ static int cam_csiphy_component_bind(struct device *dev, cam_csiphy_subdev_handle_message; new_csiphy_dev->v4l2_dev_str.token = new_csiphy_dev; + new_csiphy_dev->v4l2_dev_str.close_seq_prior = + CAM_SD_CLOSE_MEDIUM_PRIORITY; rc = cam_register_subdev(&(new_csiphy_dev->v4l2_dev_str)); if (rc < 0) { diff --git a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c index 435ca815e4..cfcc166892 100644 --- a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c +++ b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include "cam_eeprom_dev.h" @@ -10,28 +10,7 @@ #include "cam_debug_util.h" #include "camera_main.h" -static long cam_eeprom_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - int rc = 0; - struct cam_eeprom_ctrl_t *e_ctrl = v4l2_get_subdevdata(sd); - - switch (cmd) { - case VIDIOC_CAM_CONTROL: - rc = cam_eeprom_driver_cmd(e_ctrl, arg); - if (rc) - CAM_ERR(CAM_EEPROM, - "Failed in Driver cmd: %d", rc); - break; - default: - rc = -ENOIOCTLCMD; - break; - } - - return rc; -} - -static int cam_eeprom_subdev_close(struct v4l2_subdev *sd, +static int cam_eeprom_subdev_close_internal(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct cam_eeprom_ctrl_t *e_ctrl = @@ -49,6 +28,48 @@ static int cam_eeprom_subdev_close(struct v4l2_subdev *sd, return 0; } +static int cam_eeprom_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_EEPROM); + + if (crm_active) { + CAM_INFO(CAM_EEPROM, "CRM is ACTIVE, close should be from CRM"); + return 0; + } + + return cam_eeprom_subdev_close_internal(sd, fh); +} + +static long cam_eeprom_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int rc = 0; + struct cam_eeprom_ctrl_t *e_ctrl = v4l2_get_subdevdata(sd); + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_eeprom_driver_cmd(e_ctrl, arg); + if (rc) + CAM_ERR(CAM_EEPROM, + "Failed in Driver cmd: %d", rc); + break; + case CAM_SD_SHUTDOWN: + if (!cam_req_mgr_is_shutdown()) { + CAM_ERR(CAM_CORE, "SD shouldn't come from user space"); + return 0; + } + + rc = cam_eeprom_subdev_close_internal(sd, NULL); + break; + default: + rc = -ENOIOCTLCMD; + break; + } + + return rc; +} + int32_t cam_eeprom_update_i2c_info(struct cam_eeprom_ctrl_t *e_ctrl, struct cam_eeprom_i2c_info_t *i2c_info) { @@ -147,6 +168,7 @@ static int cam_eeprom_init_subdev(struct cam_eeprom_ctrl_t *e_ctrl) (V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS); e_ctrl->v4l2_dev_str.ent_function = CAM_EEPROM_DEVICE_TYPE; e_ctrl->v4l2_dev_str.token = e_ctrl; + e_ctrl->v4l2_dev_str.close_seq_prior = CAM_SD_CLOSE_MEDIUM_PRIORITY; rc = cam_register_subdev(&(e_ctrl->v4l2_dev_str)); if (rc) diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c index 8929a4b889..8386d8d6b8 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -236,6 +236,37 @@ static const struct of_device_id cam_flash_dt_match[] = { {} }; +static int cam_flash_subdev_close_internal(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_flash_ctrl *fctrl = + v4l2_get_subdevdata(sd); + + if (!fctrl) { + CAM_ERR(CAM_FLASH, "Flash ctrl ptr is NULL"); + return -EINVAL; + } + + mutex_lock(&fctrl->flash_mutex); + cam_flash_shutdown(fctrl); + mutex_unlock(&fctrl->flash_mutex); + + return 0; +} + +static int cam_flash_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_FLASH); + + if (crm_active) { + CAM_INFO(CAM_FLASH, "CRM is ACTIVE, close should be from CRM"); + return 0; + } + + return cam_flash_subdev_close_internal(sd, fh); +} + static long cam_flash_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { @@ -257,6 +288,14 @@ static long cam_flash_subdev_ioctl(struct v4l2_subdev *sd, "Failed in driver cmd: %d", rc); break; } + case CAM_SD_SHUTDOWN: + if (!cam_req_mgr_is_shutdown()) { + CAM_ERR(CAM_CORE, "SD shouldn't come from user space"); + return 0; + } + + rc = cam_flash_subdev_close_internal(sd, NULL); + break; default: CAM_ERR(CAM_FLASH, "Invalid ioctl cmd type"); rc = -ENOIOCTLCMD; @@ -328,24 +367,6 @@ static int32_t cam_flash_i2c_driver_remove(struct i2c_client *client) return rc; } -static int cam_flash_subdev_close(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh) -{ - struct cam_flash_ctrl *fctrl = - v4l2_get_subdevdata(sd); - - if (!fctrl) { - CAM_ERR(CAM_FLASH, "Flash ctrl ptr is NULL"); - return -EINVAL; - } - - mutex_lock(&fctrl->flash_mutex); - cam_flash_shutdown(fctrl); - mutex_unlock(&fctrl->flash_mutex); - - return 0; -} - static struct v4l2_subdev_core_ops cam_flash_subdev_core_ops = { .ioctl = cam_flash_subdev_ioctl, #ifdef CONFIG_COMPAT @@ -375,6 +396,7 @@ static int cam_flash_init_subdev(struct cam_flash_ctrl *fctrl) V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; fctrl->v4l2_dev_str.ent_function = CAM_FLASH_DEVICE_TYPE; fctrl->v4l2_dev_str.token = fctrl; + fctrl->v4l2_dev_str.close_seq_prior = CAM_SD_CLOSE_MEDIUM_PRIORITY; rc = cam_register_subdev(&(fctrl->v4l2_dev_str)); if (rc) diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c index 819ffb030f..2b08681cad 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include "cam_ois_dev.h" @@ -10,29 +10,7 @@ #include "cam_debug_util.h" #include "camera_main.h" -static long cam_ois_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - int rc = 0; - struct cam_ois_ctrl_t *o_ctrl = v4l2_get_subdevdata(sd); - - switch (cmd) { - case VIDIOC_CAM_CONTROL: - rc = cam_ois_driver_cmd(o_ctrl, arg); - if (rc) - CAM_ERR(CAM_OIS, - "Failed with driver cmd: %d", rc); - break; - default: - CAM_ERR(CAM_OIS, "Wrong IOCTL cmd: %u", cmd); - rc = -ENOIOCTLCMD; - break; - } - - return rc; -} - -static int cam_ois_subdev_close(struct v4l2_subdev *sd, +static int cam_ois_subdev_close_internal(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct cam_ois_ctrl_t *o_ctrl = @@ -50,6 +28,48 @@ static int cam_ois_subdev_close(struct v4l2_subdev *sd, return 0; } +static int cam_ois_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_OIS); + + if (crm_active) { + CAM_INFO(CAM_OIS, "CRM is ACTIVE, close should be from CRM"); + return 0; + } + + return cam_ois_subdev_close_internal(sd, fh); +} + +static long cam_ois_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int rc = 0; + struct cam_ois_ctrl_t *o_ctrl = v4l2_get_subdevdata(sd); + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_ois_driver_cmd(o_ctrl, arg); + if (rc) + CAM_ERR(CAM_OIS, + "Failed with driver cmd: %d", rc); + break; + case CAM_SD_SHUTDOWN: + if (!cam_req_mgr_is_shutdown()) { + CAM_ERR(CAM_CORE, "SD shouldn't come from user space"); + return 0; + } + rc = cam_ois_subdev_close_internal(sd, NULL); + break; + default: + CAM_ERR(CAM_OIS, "Wrong IOCTL cmd: %u", cmd); + rc = -ENOIOCTLCMD; + break; + } + + return rc; +} + static int32_t cam_ois_update_i2c_info(struct cam_ois_ctrl_t *o_ctrl, struct cam_ois_i2c_info_t *i2c_info) { @@ -144,6 +164,7 @@ static int cam_ois_init_subdev_param(struct cam_ois_ctrl_t *o_ctrl) (V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS); o_ctrl->v4l2_dev_str.ent_function = CAM_OIS_DEVICE_TYPE; o_ctrl->v4l2_dev_str.token = o_ctrl; + o_ctrl->v4l2_dev_str.close_seq_prior = CAM_SD_CLOSE_MEDIUM_PRIORITY; rc = cam_register_subdev(&(o_ctrl->v4l2_dev_str)); if (rc) diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c index 1b7f026126..9c6e2f2a20 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include "cam_sensor_dev.h" @@ -9,29 +9,7 @@ #include "cam_sensor_core.h" #include "camera_main.h" -static long cam_sensor_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - int rc = 0; - struct cam_sensor_ctrl_t *s_ctrl = - v4l2_get_subdevdata(sd); - - switch (cmd) { - case VIDIOC_CAM_CONTROL: - rc = cam_sensor_driver_cmd(s_ctrl, arg); - if (rc) - CAM_ERR(CAM_SENSOR, - "Failed in Driver cmd: %d", rc); - break; - default: - CAM_ERR(CAM_SENSOR, "Invalid ioctl cmd: %d", cmd); - rc = -ENOIOCTLCMD; - break; - } - return rc; -} - -static int cam_sensor_subdev_close(struct v4l2_subdev *sd, +static int cam_sensor_subdev_close_internal(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct cam_sensor_ctrl_t *s_ctrl = @@ -49,6 +27,49 @@ static int cam_sensor_subdev_close(struct v4l2_subdev *sd, return 0; } +static int cam_sensor_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_SENSOR); + + if (crm_active) { + CAM_INFO(CAM_SENSOR, "CRM is ACTIVE, close should be from CRM"); + return 0; + } + + return cam_sensor_subdev_close_internal(sd, fh); +} + +static long cam_sensor_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int rc = 0; + struct cam_sensor_ctrl_t *s_ctrl = + v4l2_get_subdevdata(sd); + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_sensor_driver_cmd(s_ctrl, arg); + if (rc) + CAM_ERR(CAM_SENSOR, + "Failed in Driver cmd: %d", rc); + break; + case CAM_SD_SHUTDOWN: + if (!cam_req_mgr_is_shutdown()) { + CAM_ERR(CAM_CORE, "SD shouldn't come from user space"); + return 0; + } + + rc = cam_sensor_subdev_close_internal(sd, NULL); + break; + default: + CAM_ERR(CAM_SENSOR, "Invalid ioctl cmd: %d", cmd); + rc = -ENOIOCTLCMD; + break; + } + return rc; +} + #ifdef CONFIG_COMPAT static long cam_sensor_init_subdev_do_ioctl(struct v4l2_subdev *sd, unsigned int cmd, unsigned long arg) @@ -122,6 +143,8 @@ static int cam_sensor_init_subdev_params(struct cam_sensor_ctrl_t *s_ctrl) s_ctrl->v4l2_dev_str.ent_function = CAM_SENSOR_DEVICE_TYPE; s_ctrl->v4l2_dev_str.token = s_ctrl; + s_ctrl->v4l2_dev_str.close_seq_prior = + CAM_SD_CLOSE_MEDIUM_PRIORITY; rc = cam_register_subdev(&(s_ctrl->v4l2_dev_str)); if (rc)