Merge "msm: camera: req_mgr: Enhance camera v4l2 subdev shutdown sequence" into camera-kernel.lnx.5.0

This commit is contained in:
Savita Patted
2021-06-21 18:38:47 -07:00
committed by Gerrit - the friendly Code Review server
38 changed files with 865 additions and 176 deletions

View File

@@ -610,6 +610,31 @@ int cam_context_handle_stop_dev(struct cam_context *ctx,
return rc; 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, int cam_context_handle_info_dump(void *context,
enum cam_context_dump_id id) enum cam_context_dump_id id)
{ {

View File

@@ -9,6 +9,7 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/spinlock_types.h> #include <linux/spinlock_types.h>
#include <linux/kref.h> #include <linux/kref.h>
#include <media/v4l2-subdev.h>
#include "cam_req_mgr_interface.h" #include "cam_req_mgr_interface.h"
#include "cam_hw_mgr_intf.h" #include "cam_hw_mgr_intf.h"
#include "cam_smmu_api.h" #include "cam_smmu_api.h"
@@ -97,6 +98,7 @@ struct cam_ctx_request {
* @acquire_hw: Function pointer for acquire hw * @acquire_hw: Function pointer for acquire hw
* @release_hw: Function pointer for release hw * @release_hw: Function pointer for release hw
* @dump_dev: Function pointer for dump dev * @dump_dev: Function pointer for dump dev
* @shutdown_dev: Function pointer for shutdown dev
* *
*/ */
struct cam_ctx_ioctl_ops { struct cam_ctx_ioctl_ops {
@@ -116,6 +118,8 @@ struct cam_ctx_ioctl_ops {
int (*release_hw)(struct cam_context *ctx, void *args); int (*release_hw)(struct cam_context *ctx, void *args);
int (*dump_dev)(struct cam_context *ctx, int (*dump_dev)(struct cam_context *ctx,
struct cam_dump_req_cmd *cmd); struct cam_dump_req_cmd *cmd);
int (*shutdown_dev)(struct v4l2_subdev *sd,
struct v4l2_subdev_fh *fh);
}; };
/** /**
@@ -513,6 +517,19 @@ int cam_context_handle_start_dev(struct cam_context *ctx,
int cam_context_handle_stop_dev(struct cam_context *ctx, int cam_context_handle_stop_dev(struct cam_context *ctx,
struct cam_start_stop_dev_cmd *cmd); 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() * cam_context_handle_dump_dev()
* *

View File

@@ -297,6 +297,27 @@ static int __cam_node_handle_stop_dev(struct cam_node *node,
return rc; 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, static int __cam_node_handle_config_dev(struct cam_node *node,
struct cam_config_dev_cmd *config) struct cam_config_dev_cmd *config)
{ {

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* 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_ #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); 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_ */ #endif /* _CAM_NODE_H_ */

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // 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" #include "cam_subdev.h"
@@ -45,6 +45,8 @@ static long cam_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd,
long rc; long rc;
struct cam_node *node = struct cam_node *node =
(struct cam_node *) v4l2_get_subdevdata(sd); (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) { if (!node || node->state == CAM_NODE_STATE_UNINIT) {
rc = -EINVAL; rc = -EINVAL;
@@ -56,6 +58,19 @@ static long cam_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd,
rc = cam_node_handle_ioctl(node, rc = cam_node_handle_ioctl(node,
(struct cam_control *) arg); (struct cam_control *) arg);
break; 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: default:
CAM_ERR(CAM_CORE, "Invalid command %d for %s", cmd, CAM_ERR(CAM_CORE, "Invalid command %d for %s", cmd,
node->name); node->name);

View File

@@ -779,7 +779,7 @@ static int cam_cpas_subdev_open(struct v4l2_subdev *sd,
return 0; 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 v4l2_subdev_fh *fh)
{ {
struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd); struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd);
@@ -790,6 +790,11 @@ static int cam_cpas_subdev_close(struct v4l2_subdev *sd,
} }
mutex_lock(&cpas_intf->intf_lock); 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--; cpas_intf->open_cnt--;
CAM_DBG(CAM_CPAS, "CPAS Subdev close count %d", cpas_intf->open_cnt); CAM_DBG(CAM_CPAS, "CPAS Subdev close count %d", cpas_intf->open_cnt);
mutex_unlock(&cpas_intf->intf_lock); mutex_unlock(&cpas_intf->intf_lock);
@@ -797,6 +802,19 @@ static int cam_cpas_subdev_close(struct v4l2_subdev *sd,
return 0; 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, static long cam_cpas_subdev_ioctl(struct v4l2_subdev *sd,
unsigned int cmd, void *arg) unsigned int cmd, void *arg)
{ {
@@ -812,6 +830,9 @@ static long cam_cpas_subdev_ioctl(struct v4l2_subdev *sd,
case VIDIOC_CAM_CONTROL: case VIDIOC_CAM_CONTROL:
rc = cam_cpas_subdev_cmd(cpas_intf, (struct cam_control *) arg); rc = cam_cpas_subdev_cmd(cpas_intf, (struct cam_control *) arg);
break; break;
case CAM_SD_SHUTDOWN:
rc = __cam_cpas_subdev_close(sd, NULL);
break;
default: default:
CAM_ERR(CAM_CPAS, "Invalid command %d for CPAS!", cmd); CAM_ERR(CAM_CPAS, "Invalid command %d for CPAS!", cmd);
rc = -EINVAL; rc = -EINVAL;
@@ -899,6 +920,7 @@ static int cam_cpas_subdev_register(struct platform_device *pdev)
subdev->sd_flags = subdev->sd_flags =
V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
subdev->ent_function = CAM_CPAS_DEVICE_TYPE; subdev->ent_function = CAM_CPAS_DEVICE_TYPE;
subdev->close_seq_prior = CAM_SD_CLOSE_LOW_PRIORITY;
rc = cam_register_subdev(subdev); rc = cam_register_subdev(subdev);
if (rc) { if (rc) {

View File

@@ -1605,6 +1605,19 @@ static int __cam_custom_ctx_apply_default_req(
return rc; 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 */ /* top state machine */
static struct cam_ctx_ops static struct cam_ctx_ops
cam_custom_dev_ctx_top_state_machine[CAM_CTX_STATE_MAX] = { cam_custom_dev_ctx_top_state_machine[CAM_CTX_STATE_MAX] = {
@@ -1619,6 +1632,7 @@ static struct cam_ctx_ops
.ioctl_ops = { .ioctl_ops = {
.acquire_dev = .acquire_dev =
__cam_custom_ctx_acquire_dev_in_available, __cam_custom_ctx_acquire_dev_in_available,
.shutdown_dev = __cam_custom_ctx_shutdown_dev,
}, },
.crm_ops = {}, .crm_ops = {},
.irq_ops = NULL, .irq_ops = NULL,
@@ -1630,6 +1644,7 @@ static struct cam_ctx_ops
.release_dev = __cam_custom_release_dev_in_acquired, .release_dev = __cam_custom_release_dev_in_acquired,
.config_dev = __cam_custom_ctx_config_dev_in_acquired, .config_dev = __cam_custom_ctx_config_dev_in_acquired,
.release_hw = __cam_custom_ctx_release_hw_in_top_state, .release_hw = __cam_custom_ctx_release_hw_in_top_state,
.shutdown_dev = __cam_custom_ctx_shutdown_dev,
}, },
.crm_ops = { .crm_ops = {
.link = __cam_custom_ctx_link_in_acquired, .link = __cam_custom_ctx_link_in_acquired,
@@ -1648,6 +1663,7 @@ static struct cam_ctx_ops
.release_dev = __cam_custom_release_dev_in_acquired, .release_dev = __cam_custom_release_dev_in_acquired,
.config_dev = __cam_custom_ctx_config_dev, .config_dev = __cam_custom_ctx_config_dev,
.release_hw = __cam_custom_ctx_release_hw_in_top_state, .release_hw = __cam_custom_ctx_release_hw_in_top_state,
.shutdown_dev = __cam_custom_ctx_shutdown_dev,
}, },
.crm_ops = { .crm_ops = {
.unlink = __cam_custom_ctx_unlink_in_ready, .unlink = __cam_custom_ctx_unlink_in_ready,
@@ -1665,6 +1681,7 @@ static struct cam_ctx_ops
.config_dev = __cam_custom_ctx_config_dev_in_flushed, .config_dev = __cam_custom_ctx_config_dev_in_flushed,
.release_hw = .release_hw =
__cam_custom_ctx_release_hw_in_activated_state, __cam_custom_ctx_release_hw_in_activated_state,
.shutdown_dev = __cam_custom_ctx_shutdown_dev,
}, },
.crm_ops = { .crm_ops = {
.unlink = __cam_custom_ctx_unlink_in_ready, .unlink = __cam_custom_ctx_unlink_in_ready,
@@ -1681,6 +1698,7 @@ static struct cam_ctx_ops
.config_dev = __cam_custom_ctx_config_dev, .config_dev = __cam_custom_ctx_config_dev,
.release_hw = .release_hw =
__cam_custom_ctx_release_hw_in_activated_state, __cam_custom_ctx_release_hw_in_activated_state,
.shutdown_dev = __cam_custom_ctx_shutdown_dev,
}, },
.crm_ops = { .crm_ops = {
.unlink = __cam_custom_ctx_unlink_in_activated, .unlink = __cam_custom_ctx_unlink_in_activated,

View File

@@ -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); 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_ */ #endif /* _CAM_CUSTOM_CONTEXT_H_ */

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // 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 <linux/delay.h> #include <linux/delay.h>
@@ -58,7 +58,7 @@ static int cam_custom_subdev_open(struct v4l2_subdev *sd,
return 0; 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) struct v4l2_subdev_fh *fh)
{ {
int rc = 0; int rc = 0;
@@ -86,6 +86,19 @@ end:
return rc; 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 = { static const struct v4l2_subdev_internal_ops cam_custom_subdev_internal_ops = {
.close = cam_custom_subdev_close, .close = cam_custom_subdev_close,
.open = cam_custom_subdev_open, .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); struct platform_device *pdev = to_platform_device(dev);
g_custom_dev.sd.internal_ops = &cam_custom_subdev_internal_ops; 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, rc = cam_subdev_probe(&g_custom_dev.sd, pdev, CAM_CUSTOM_DEV_NAME,
CAM_CUSTOM_DEVICE_TYPE); CAM_CUSTOM_DEVICE_TYPE);

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // 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 <linux/module.h> #include <linux/module.h>
@@ -169,6 +169,19 @@ static int __cam_fd_ctx_handle_irq_in_activated(void *context,
return rc; 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 */ /* top state machine */
static struct cam_ctx_ops static struct cam_ctx_ops
cam_fd_ctx_state_machine[CAM_CTX_STATE_MAX] = { cam_fd_ctx_state_machine[CAM_CTX_STATE_MAX] = {
@@ -182,6 +195,7 @@ static struct cam_ctx_ops
{ {
.ioctl_ops = { .ioctl_ops = {
.acquire_dev = __cam_fd_ctx_acquire_dev_in_available, .acquire_dev = __cam_fd_ctx_acquire_dev_in_available,
.shutdown_dev = __cam_fd_shutdown_dev,
}, },
.crm_ops = {}, .crm_ops = {},
.irq_ops = NULL, .irq_ops = NULL,
@@ -192,18 +206,25 @@ static struct cam_ctx_ops
.release_dev = __cam_fd_ctx_release_dev_in_acquired, .release_dev = __cam_fd_ctx_release_dev_in_acquired,
.config_dev = __cam_fd_ctx_config_dev_in_acquired, .config_dev = __cam_fd_ctx_config_dev_in_acquired,
.start_dev = __cam_fd_ctx_start_dev_in_acquired, .start_dev = __cam_fd_ctx_start_dev_in_acquired,
.shutdown_dev = __cam_fd_shutdown_dev,
}, },
.crm_ops = {}, .crm_ops = {},
.irq_ops = NULL, .irq_ops = NULL,
}, },
/* Ready */ /* Ready */
{ {
.ioctl_ops = { }, .ioctl_ops = {
.shutdown_dev = __cam_fd_shutdown_dev,
},
.crm_ops = {}, .crm_ops = {},
.irq_ops = NULL, .irq_ops = NULL,
}, },
/* Flushed */ /* Flushed */
{}, {
.ioctl_ops = {
.shutdown_dev = __cam_fd_shutdown_dev,
},
},
/* Activated */ /* Activated */
{ {
.ioctl_ops = { .ioctl_ops = {
@@ -212,6 +233,7 @@ static struct cam_ctx_ops
.config_dev = __cam_fd_ctx_config_dev_in_activated, .config_dev = __cam_fd_ctx_config_dev_in_activated,
.flush_dev = __cam_fd_ctx_flush_dev_in_activated, .flush_dev = __cam_fd_ctx_flush_dev_in_activated,
.dump_dev = __cam_fd_ctx_dump_dev_in_activated, .dump_dev = __cam_fd_ctx_dump_dev_in_activated,
.shutdown_dev = __cam_fd_shutdown_dev,
}, },
.crm_ops = {}, .crm_ops = {},
.irq_ops = __cam_fd_ctx_handle_irq_in_activated, .irq_ops = __cam_fd_ctx_handle_irq_in_activated,

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* 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_ #ifndef _CAM_FD_CONTEXT_H_
@@ -27,4 +27,15 @@ int cam_fd_context_init(struct cam_fd_context *fd_ctx,
uint32_t ctx_id); uint32_t ctx_id);
int cam_fd_context_deinit(struct cam_fd_context *ctx); 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_ */ #endif /* _CAM_FD_CONTEXT_H_ */

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // 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 <linux/device.h> #include <linux/device.h>
@@ -57,7 +57,7 @@ static int cam_fd_dev_open(struct v4l2_subdev *sd,
return 0; 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 v4l2_subdev_fh *fh)
{ {
struct cam_fd_dev *fd_dev = &g_fd_dev; 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); 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--; fd_dev->open_cnt--;
CAM_DBG(CAM_FD, "FD Subdev open count %d", fd_dev->open_cnt); CAM_DBG(CAM_FD, "FD Subdev open count %d", fd_dev->open_cnt);
mutex_unlock(&fd_dev->lock); mutex_unlock(&fd_dev->lock);
@@ -83,6 +88,19 @@ static int cam_fd_dev_close(struct v4l2_subdev *sd,
return 0; 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 = { static const struct v4l2_subdev_internal_ops cam_fd_subdev_internal_ops = {
.open = cam_fd_dev_open, .open = cam_fd_dev_open,
.close = cam_fd_dev_close, .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); struct platform_device *pdev = to_platform_device(dev);
g_fd_dev.sd.internal_ops = &cam_fd_subdev_internal_ops; 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) */ /* Initialize the v4l2 subdevice first. (create cam_node) */
rc = cam_subdev_probe(&g_fd_dev.sd, pdev, CAM_FD_DEV_NAME, rc = cam_subdev_probe(&g_fd_dev.sd, pdev, CAM_FD_DEV_NAME,

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // 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 <linux/debugfs.h> #include <linux/debugfs.h>
@@ -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); 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 static struct cam_ctx_ops
cam_icp_ctx_state_machine[CAM_CTX_STATE_MAX] = { cam_icp_ctx_state_machine[CAM_CTX_STATE_MAX] = {
/* Uninit */ /* Uninit */
@@ -233,6 +239,7 @@ static struct cam_ctx_ops
{ {
.ioctl_ops = { .ioctl_ops = {
.acquire_dev = __cam_icp_acquire_dev_in_available, .acquire_dev = __cam_icp_acquire_dev_in_available,
.shutdown_dev = __cam_icp_shutdown_dev,
}, },
.crm_ops = {}, .crm_ops = {},
.irq_ops = NULL, .irq_ops = NULL,
@@ -245,6 +252,7 @@ static struct cam_ctx_ops
.config_dev = __cam_icp_config_dev_in_ready, .config_dev = __cam_icp_config_dev_in_ready,
.flush_dev = __cam_icp_flush_dev_in_ready, .flush_dev = __cam_icp_flush_dev_in_ready,
.dump_dev = __cam_icp_dump_dev_in_ready, .dump_dev = __cam_icp_dump_dev_in_ready,
.shutdown_dev = __cam_icp_shutdown_dev,
}, },
.crm_ops = {}, .crm_ops = {},
.irq_ops = __cam_icp_handle_buf_done_in_ready, .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, .config_dev = __cam_icp_config_dev_in_ready,
.flush_dev = __cam_icp_flush_dev_in_ready, .flush_dev = __cam_icp_flush_dev_in_ready,
.dump_dev = __cam_icp_dump_dev_in_ready, .dump_dev = __cam_icp_dump_dev_in_ready,
.shutdown_dev = __cam_icp_shutdown_dev,
}, },
.crm_ops = {}, .crm_ops = {},
.irq_ops = __cam_icp_handle_buf_done_in_ready, .irq_ops = __cam_icp_handle_buf_done_in_ready,
.pagefault_ops = cam_icp_context_dump_active_request, .pagefault_ops = cam_icp_context_dump_active_request,
}, },
/* Flushed */ /* Flushed */
{}, {
.ioctl_ops = {
.shutdown_dev = __cam_icp_shutdown_dev,
},
},
/* Activated */ /* Activated */
{ {
.ioctl_ops = {}, .ioctl_ops = {
.shutdown_dev = __cam_icp_shutdown_dev,
},
.crm_ops = {}, .crm_ops = {},
.irq_ops = NULL, .irq_ops = NULL,
.pagefault_ops = cam_icp_context_dump_active_request, .pagefault_ops = cam_icp_context_dump_active_request,

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* 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_ #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); 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_ */ #endif /* _CAM_ICP_CONTEXT_H_ */

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // 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 <linux/delay.h> #include <linux/delay.h>
@@ -98,7 +98,7 @@ end:
return rc; 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) struct v4l2_subdev_fh *fh)
{ {
int rc = 0; int rc = 0;
@@ -107,9 +107,8 @@ static int cam_icp_subdev_close(struct v4l2_subdev *sd,
mutex_lock(&g_icp_dev.icp_lock); mutex_lock(&g_icp_dev.icp_lock);
if (g_icp_dev.open_cnt <= 0) { if (g_icp_dev.open_cnt <= 0) {
CAM_DBG(CAM_ICP, "ICP subdev is already closed"); CAM_WARN(CAM_ICP, "ICP subdev is already closed");
rc = -EINVAL; return 0;
goto end;
} }
g_icp_dev.open_cnt--; g_icp_dev.open_cnt--;
if (!node) { if (!node) {
@@ -133,9 +132,22 @@ static int cam_icp_subdev_close(struct v4l2_subdev *sd,
end: end:
mutex_unlock(&g_icp_dev.icp_lock); mutex_unlock(&g_icp_dev.icp_lock);
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 0;
} }
return cam_icp_subdev_close_internal(sd, fh);
}
const struct v4l2_subdev_internal_ops cam_icp_subdev_internal_ops = { const struct v4l2_subdev_internal_ops cam_icp_subdev_internal_ops = {
.open = cam_icp_subdev_open, .open = cam_icp_subdev_open,
.close = cam_icp_subdev_close, .close = cam_icp_subdev_close,
@@ -157,6 +169,7 @@ static int cam_icp_component_bind(struct device *dev,
g_icp_dev.sd.pdev = pdev; g_icp_dev.sd.pdev = pdev;
g_icp_dev.sd.internal_ops = &cam_icp_subdev_internal_ops; 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, rc = cam_subdev_probe(&g_icp_dev.sd, pdev, CAM_ICP_DEV_NAME,
CAM_ICP_DEVICE_TYPE); CAM_ICP_DEVICE_TYPE);
if (rc) { if (rc) {

View File

@@ -6405,6 +6405,12 @@ static int __cam_isp_ctx_handle_irq_in_activated(void *context,
return rc; 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 */ /* top state machine */
static struct cam_ctx_ops static struct cam_ctx_ops
cam_isp_ctx_top_state_machine[CAM_CTX_STATE_MAX] = { cam_isp_ctx_top_state_machine[CAM_CTX_STATE_MAX] = {
@@ -6418,6 +6424,7 @@ static struct cam_ctx_ops
{ {
.ioctl_ops = { .ioctl_ops = {
.acquire_dev = __cam_isp_ctx_acquire_dev_in_available, .acquire_dev = __cam_isp_ctx_acquire_dev_in_available,
.shutdown_dev = __cam_isp_shutdown_dev,
}, },
.crm_ops = {}, .crm_ops = {},
.irq_ops = NULL, .irq_ops = NULL,
@@ -6429,6 +6436,7 @@ static struct cam_ctx_ops
.release_dev = __cam_isp_ctx_release_dev_in_top_state, .release_dev = __cam_isp_ctx_release_dev_in_top_state,
.config_dev = __cam_isp_ctx_config_dev_in_acquired, .config_dev = __cam_isp_ctx_config_dev_in_acquired,
.release_hw = __cam_isp_ctx_release_hw_in_top_state, .release_hw = __cam_isp_ctx_release_hw_in_top_state,
.shutdown_dev = __cam_isp_shutdown_dev,
}, },
.crm_ops = { .crm_ops = {
.link = __cam_isp_ctx_link_in_acquired, .link = __cam_isp_ctx_link_in_acquired,
@@ -6448,6 +6456,7 @@ static struct cam_ctx_ops
.release_dev = __cam_isp_ctx_release_dev_in_top_state, .release_dev = __cam_isp_ctx_release_dev_in_top_state,
.config_dev = __cam_isp_ctx_config_dev_in_top_state, .config_dev = __cam_isp_ctx_config_dev_in_top_state,
.release_hw = __cam_isp_ctx_release_hw_in_top_state, .release_hw = __cam_isp_ctx_release_hw_in_top_state,
.shutdown_dev = __cam_isp_shutdown_dev,
}, },
.crm_ops = { .crm_ops = {
.unlink = __cam_isp_ctx_unlink_in_ready, .unlink = __cam_isp_ctx_unlink_in_ready,
@@ -6465,6 +6474,7 @@ static struct cam_ctx_ops
.release_dev = __cam_isp_ctx_release_dev_in_activated, .release_dev = __cam_isp_ctx_release_dev_in_activated,
.config_dev = __cam_isp_ctx_config_dev_in_flushed, .config_dev = __cam_isp_ctx_config_dev_in_flushed,
.release_hw = __cam_isp_ctx_release_hw_in_activated, .release_hw = __cam_isp_ctx_release_hw_in_activated,
.shutdown_dev = __cam_isp_shutdown_dev,
}, },
.crm_ops = { .crm_ops = {
.unlink = __cam_isp_ctx_unlink_in_ready, .unlink = __cam_isp_ctx_unlink_in_ready,
@@ -6481,6 +6491,7 @@ static struct cam_ctx_ops
.release_dev = __cam_isp_ctx_release_dev_in_activated, .release_dev = __cam_isp_ctx_release_dev_in_activated,
.config_dev = __cam_isp_ctx_config_dev_in_top_state, .config_dev = __cam_isp_ctx_config_dev_in_top_state,
.release_hw = __cam_isp_ctx_release_hw_in_activated, .release_hw = __cam_isp_ctx_release_hw_in_activated,
.shutdown_dev = __cam_isp_shutdown_dev,
}, },
.crm_ops = { .crm_ops = {
.unlink = __cam_isp_ctx_unlink_in_activated, .unlink = __cam_isp_ctx_unlink_in_activated,

View File

@@ -372,5 +372,16 @@ int cam_isp_context_init(struct cam_isp_context *ctx,
*/ */
int cam_isp_context_deinit(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__ */ #endif /* __CAM_ISP_CONTEXT_H__ */

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // 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 <linux/delay.h> #include <linux/delay.h>
@@ -55,7 +55,7 @@ static int cam_isp_subdev_open(struct v4l2_subdev *sd,
return 0; 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) struct v4l2_subdev_fh *fh)
{ {
int rc = 0; int rc = 0;
@@ -83,6 +83,18 @@ end:
return rc; 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 = { static const struct v4l2_subdev_internal_ops cam_isp_subdev_internal_ops = {
.close = cam_isp_subdev_close, .close = cam_isp_subdev_close,
.open = cam_isp_subdev_open, .open = cam_isp_subdev_open,
@@ -104,6 +116,7 @@ static int cam_isp_dev_component_bind(struct device *dev,
(const char **)&compat_str); (const char **)&compat_str);
g_isp_dev.sd.internal_ops = &cam_isp_subdev_internal_ops; 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) */ /* Initialize the v4l2 subdevice first. (create cam_node) */
if (strnstr(compat_str, "ife", strlen(compat_str))) { if (strnstr(compat_str, "ife", strlen(compat_str))) {
rc = cam_subdev_probe(&g_isp_dev.sd, pdev, CAM_ISP_DEV_NAME, rc = cam_subdev_probe(&g_isp_dev.sd, pdev, CAM_ISP_DEV_NAME,

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // 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 <linux/debugfs.h> #include <linux/debugfs.h>
@@ -135,6 +135,12 @@ static int __cam_jpeg_ctx_stop_dev_in_acquired(struct cam_context *ctx,
return rc; 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 */ /* top state machine */
static struct cam_ctx_ops static struct cam_ctx_ops
cam_jpeg_ctx_state_machine[CAM_CTX_STATE_MAX] = { cam_jpeg_ctx_state_machine[CAM_CTX_STATE_MAX] = {
@@ -148,6 +154,7 @@ static struct cam_ctx_ops
{ {
.ioctl_ops = { .ioctl_ops = {
.acquire_dev = __cam_jpeg_ctx_acquire_dev_in_available, .acquire_dev = __cam_jpeg_ctx_acquire_dev_in_available,
.shutdown_dev = __cam_jpeg_shutdown_dev,
}, },
.crm_ops = { }, .crm_ops = { },
.irq_ops = NULL, .irq_ops = NULL,
@@ -160,11 +167,30 @@ static struct cam_ctx_ops
.stop_dev = __cam_jpeg_ctx_stop_dev_in_acquired, .stop_dev = __cam_jpeg_ctx_stop_dev_in_acquired,
.flush_dev = __cam_jpeg_ctx_flush_dev_in_acquired, .flush_dev = __cam_jpeg_ctx_flush_dev_in_acquired,
.dump_dev = __cam_jpeg_ctx_dump_dev_in_acquired, .dump_dev = __cam_jpeg_ctx_dump_dev_in_acquired,
.shutdown_dev = __cam_jpeg_shutdown_dev,
}, },
.crm_ops = { }, .crm_ops = { },
.irq_ops = __cam_jpeg_ctx_handle_buf_done_in_acquired, .irq_ops = __cam_jpeg_ctx_handle_buf_done_in_acquired,
.pagefault_ops = cam_jpeg_context_dump_active_request, .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, int cam_jpeg_context_init(struct cam_jpeg_context *ctx,

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* 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_ #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); 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__ */ #endif /* __CAM_JPEG_CONTEXT_H__ */

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // 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 <linux/delay.h> #include <linux/delay.h>
@@ -56,13 +56,12 @@ static int cam_jpeg_subdev_open(struct v4l2_subdev *sd,
return 0; 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) struct v4l2_subdev_fh *fh)
{ {
int rc = 0; int rc = 0;
struct cam_node *node = v4l2_get_subdevdata(sd); struct cam_node *node = v4l2_get_subdevdata(sd);
mutex_lock(&g_jpeg_dev.jpeg_mutex); mutex_lock(&g_jpeg_dev.jpeg_mutex);
if (g_jpeg_dev.open_cnt <= 0) { if (g_jpeg_dev.open_cnt <= 0) {
CAM_DBG(CAM_JPEG, "JPEG subdev is already closed"); CAM_DBG(CAM_JPEG, "JPEG subdev is already closed");
@@ -86,6 +85,18 @@ end:
return rc; 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 = { static const struct v4l2_subdev_internal_ops cam_jpeg_subdev_internal_ops = {
.close = cam_jpeg_subdev_close, .close = cam_jpeg_subdev_close,
.open = cam_jpeg_subdev_open, .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); struct platform_device *pdev = to_platform_device(dev);
g_jpeg_dev.sd.internal_ops = &cam_jpeg_subdev_internal_ops; 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, rc = cam_subdev_probe(&g_jpeg_dev.sd, pdev, CAM_JPEG_DEV_NAME,
CAM_JPEG_DEVICE_TYPE); CAM_JPEG_DEVICE_TYPE);
if (rc) { if (rc) {

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // 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 <linux/module.h> #include <linux/module.h>
@@ -172,6 +172,12 @@ static int __cam_lrme_ctx_handle_irq_in_activated(void *context,
return rc; 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 */ /* top state machine */
static struct cam_ctx_ops static struct cam_ctx_ops
cam_lrme_ctx_state_machine[CAM_CTX_STATE_MAX] = { cam_lrme_ctx_state_machine[CAM_CTX_STATE_MAX] = {
@@ -185,6 +191,7 @@ static struct cam_ctx_ops
{ {
.ioctl_ops = { .ioctl_ops = {
.acquire_dev = __cam_lrme_ctx_acquire_dev_in_available, .acquire_dev = __cam_lrme_ctx_acquire_dev_in_available,
.shutdown_dev = __cam_lrme_shutdown_dev,
}, },
.crm_ops = {}, .crm_ops = {},
.irq_ops = NULL, .irq_ops = NULL,
@@ -195,18 +202,25 @@ static struct cam_ctx_ops
.config_dev = __cam_lrme_ctx_config_dev_in_activated, .config_dev = __cam_lrme_ctx_config_dev_in_activated,
.release_dev = __cam_lrme_ctx_release_dev_in_acquired, .release_dev = __cam_lrme_ctx_release_dev_in_acquired,
.start_dev = __cam_lrme_ctx_start_dev_in_acquired, .start_dev = __cam_lrme_ctx_start_dev_in_acquired,
.shutdown_dev = __cam_lrme_shutdown_dev,
}, },
.crm_ops = {}, .crm_ops = {},
.irq_ops = NULL, .irq_ops = NULL,
}, },
/* Ready */ /* Ready */
{ {
.ioctl_ops = {}, .ioctl_ops = {
.shutdown_dev = __cam_lrme_shutdown_dev,
},
.crm_ops = {}, .crm_ops = {},
.irq_ops = NULL, .irq_ops = NULL,
}, },
/* Flushed */ /* Flushed */
{}, {
.ioctl_ops = {
.shutdown_dev = __cam_lrme_shutdown_dev,
},
},
/* Activate */ /* Activate */
{ {
.ioctl_ops = { .ioctl_ops = {
@@ -215,6 +229,7 @@ static struct cam_ctx_ops
.stop_dev = __cam_lrme_ctx_stop_dev_in_activated, .stop_dev = __cam_lrme_ctx_stop_dev_in_activated,
.flush_dev = __cam_lrme_ctx_flush_dev_in_activated, .flush_dev = __cam_lrme_ctx_flush_dev_in_activated,
.dump_dev = __cam_lrme_ctx_dump_dev_in_activated, .dump_dev = __cam_lrme_ctx_dump_dev_in_activated,
.shutdown_dev = __cam_lrme_shutdown_dev,
}, },
.crm_ops = {}, .crm_ops = {},
.irq_ops = __cam_lrme_ctx_handle_irq_in_activated, .irq_ops = __cam_lrme_ctx_handle_irq_in_activated,

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* 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_ #ifndef _CAM_LRME_CONTEXT_H_
@@ -30,4 +30,16 @@ int cam_lrme_context_init(struct cam_lrme_context *lrme_ctx,
uint32_t index); uint32_t index);
int cam_lrme_context_deinit(struct cam_lrme_context *lrme_ctx); 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_ */ #endif /* _CAM_LRME_CONTEXT_H_ */

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // 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 <linux/device.h> #include <linux/device.h>
@@ -72,7 +72,7 @@ static int cam_lrme_dev_open(struct v4l2_subdev *sd,
return 0; 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) struct v4l2_subdev_fh *fh)
{ {
int rc = 0; int rc = 0;
@@ -106,6 +106,18 @@ end:
return rc; 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 = { static const struct v4l2_subdev_internal_ops cam_lrme_subdev_internal_ops = {
.open = cam_lrme_dev_open, .open = cam_lrme_dev_open,
.close = cam_lrme_dev_close, .close = cam_lrme_dev_close,
@@ -126,6 +138,7 @@ static int cam_lrme_component_bind(struct device *dev,
return -ENOMEM; return -ENOMEM;
} }
g_lrme_dev->sd.internal_ops = &cam_lrme_subdev_internal_ops; 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); mutex_init(&g_lrme_dev->lock);

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // 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 <linux/debugfs.h> #include <linux/debugfs.h>
@@ -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); 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 static struct cam_ctx_ops
cam_ope_ctx_state_machine[CAM_CTX_STATE_MAX] = { cam_ope_ctx_state_machine[CAM_CTX_STATE_MAX] = {
/* Uninit */ /* Uninit */
@@ -207,6 +213,7 @@ static struct cam_ctx_ops
{ {
.ioctl_ops = { .ioctl_ops = {
.acquire_dev = __cam_ope_acquire_dev_in_available, .acquire_dev = __cam_ope_acquire_dev_in_available,
.shutdown_dev = __cam_ope_shutdown_dev,
}, },
.crm_ops = {}, .crm_ops = {},
.irq_ops = NULL, .irq_ops = NULL,
@@ -219,6 +226,7 @@ static struct cam_ctx_ops
.config_dev = __cam_ope_config_dev_in_ready, .config_dev = __cam_ope_config_dev_in_ready,
.flush_dev = __cam_ope_flush_dev_in_ready, .flush_dev = __cam_ope_flush_dev_in_ready,
.dump_dev = __cam_ope_dump_dev_in_ready, .dump_dev = __cam_ope_dump_dev_in_ready,
.shutdown_dev = __cam_ope_shutdown_dev,
}, },
.crm_ops = {}, .crm_ops = {},
.irq_ops = __cam_ope_handle_buf_done_in_ready, .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, .config_dev = __cam_ope_config_dev_in_ready,
.flush_dev = __cam_ope_flush_dev_in_ready, .flush_dev = __cam_ope_flush_dev_in_ready,
.dump_dev = __cam_ope_dump_dev_in_ready, .dump_dev = __cam_ope_dump_dev_in_ready,
.shutdown_dev = __cam_ope_shutdown_dev,
}, },
.crm_ops = {}, .crm_ops = {},
.irq_ops = __cam_ope_handle_buf_done_in_ready, .irq_ops = __cam_ope_handle_buf_done_in_ready,
.pagefault_ops = cam_ope_context_dump_active_request, .pagefault_ops = cam_ope_context_dump_active_request,
}, },
/* Flushed */
{
.ioctl_ops = {
.shutdown_dev = __cam_ope_shutdown_dev,
},
},
/* Activated */ /* Activated */
{ {
.ioctl_ops = {}, .ioctl_ops = {
.shutdown_dev = __cam_ope_shutdown_dev,
},
.crm_ops = {}, .crm_ops = {},
.irq_ops = NULL, .irq_ops = NULL,
.pagefault_ops = cam_ope_context_dump_active_request, .pagefault_ops = cam_ope_context_dump_active_request,

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* 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_ #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); 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_ */ #endif /* _CAM_OPE_CONTEXT_H_ */

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // 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 <linux/delay.h> #include <linux/delay.h>
@@ -95,7 +95,7 @@ end:
return rc; 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) struct v4l2_subdev_fh *fh)
{ {
int rc = 0; int rc = 0;
@@ -134,6 +134,19 @@ end:
return rc; 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 = { const struct v4l2_subdev_internal_ops cam_ope_subdev_internal_ops = {
.open = cam_ope_subdev_open, .open = cam_ope_subdev_open,
.close = cam_ope_subdev_close, .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.pdev = pdev;
g_ope_dev.sd.internal_ops = &cam_ope_subdev_internal_ops; 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, rc = cam_subdev_probe(&g_ope_dev.sd, pdev, OPE_DEV_NAME,
CAM_OPE_DEVICE_TYPE); CAM_OPE_DEVICE_TYPE);
if (rc) { if (rc) {

View File

@@ -17,6 +17,7 @@
#include <media/v4l2-ioctl.h> #include <media/v4l2-ioctl.h>
#include <media/cam_req_mgr.h> #include <media/cam_req_mgr.h>
#include <media/cam_defs.h> #include <media/cam_defs.h>
#include <linux/list_sort.h>
#include "cam_req_mgr_dev.h" #include "cam_req_mgr_dev.h"
#include "cam_req_mgr_util.h" #include "cam_req_mgr_util.h"
@@ -32,6 +33,7 @@
static struct cam_req_mgr_device g_dev; static struct cam_req_mgr_device g_dev;
struct kmem_cache *g_cam_req_mgr_timer_cachep; 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 = static struct device_attribute camera_debug_sysfs_attr =
__ATTR(debug_node, 0600, NULL, cam_debug_sysfs_node_store); __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); spin_unlock_bh(&g_dev.cam_eventq_lock);
g_dev.open_cnt++; g_dev.open_cnt++;
g_dev.read_active_dev_id_hdls = 0;
rc = cam_mem_mgr_init(); rc = cam_mem_mgr_init();
if (rc) { if (rc) {
g_dev.open_cnt--; 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) static int cam_req_mgr_close(struct file *filep)
{ {
struct v4l2_subdev *sd; struct v4l2_subdev *sd;
struct cam_subdev *csd;
struct v4l2_fh *vfh = filep->private_data; struct v4l2_fh *vfh = filep->private_data;
struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); 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(); 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)) if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE))
continue; continue;
if (sd->internal_ops && sd->internal_ops->close) { if (sd->internal_ops) {
CAM_DBG(CAM_CRM, "Invoke subdev close for device %s", CAM_DBG(CAM_CRM, "Invoke subdev close for device %s",
sd->name); 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.open_cnt--;
g_dev.shutdown_state = false;
g_dev.read_active_dev_id_hdls = 0;
v4l2_fh_release(filep); v4l2_fh_release(filep);
spin_lock_bh(&g_dev.cam_eventq_lock); spin_lock_bh(&g_dev.cam_eventq_lock);
@@ -660,6 +669,51 @@ void cam_subdev_notify_message(u32 subdev_type,
} }
EXPORT_SYMBOL(cam_subdev_notify_message); 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) int cam_register_subdev(struct cam_subdev *csd)
{ {
struct v4l2_subdev *sd; struct v4l2_subdev *sd;
@@ -688,6 +742,10 @@ int cam_register_subdev(struct cam_subdev *csd)
sd->entity.pads = NULL; sd->entity.pads = NULL;
sd->entity.function = csd->ent_function; 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); rc = v4l2_device_register_subdev(g_dev.v4l2_dev, sd);
if (rc) { if (rc) {
CAM_ERR(CAM_CRM, "register subdev failed"); CAM_ERR(CAM_CRM, "register subdev failed");
@@ -754,6 +812,7 @@ static int cam_req_mgr_component_master_bind(struct device *dev)
goto video_setup_fail; goto video_setup_fail;
g_dev.open_cnt = 0; g_dev.open_cnt = 0;
g_dev.shutdown_state = false;
mutex_init(&g_dev.cam_lock); mutex_init(&g_dev.cam_lock);
spin_lock_init(&g_dev.cam_eventq_lock); spin_lock_init(&g_dev.cam_eventq_lock);
mutex_init(&g_dev.dev_lock); mutex_init(&g_dev.dev_lock);
@@ -771,6 +830,7 @@ static int cam_req_mgr_component_master_bind(struct device *dev)
} }
g_dev.state = true; g_dev.state = true;
INIT_LIST_HEAD(&cam_req_mgr_ordered_sd_list);
if (g_cam_req_mgr_timer_cachep == NULL) { if (g_cam_req_mgr_timer_cachep == NULL) {
g_cam_req_mgr_timer_cachep = kmem_cache_create("crm_timer", g_cam_req_mgr_timer_cachep = kmem_cache_create("crm_timer",

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* 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_ #ifndef _CAM_REQ_MGR_DEV_H_
@@ -19,6 +19,9 @@
* @cam_lock: per file handle lock * @cam_lock: per file handle lock
* @cam_eventq: event queue * @cam_eventq: event queue
* @cam_eventq_lock: lock for 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 cam_req_mgr_device {
struct video_device *video; struct video_device *video;
@@ -30,6 +33,9 @@ struct cam_req_mgr_device {
struct mutex cam_lock; struct mutex cam_lock;
struct v4l2_fh *cam_eventq; struct v4l2_fh *cam_eventq;
spinlock_t cam_eventq_lock; 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) \ #define CAM_REQ_MGR_GET_PAYLOAD_PTR(ev, type) \

View File

@@ -14,6 +14,7 @@
#include <media/cam_req_mgr.h> #include <media/cam_req_mgr.h>
#include "cam_req_mgr_util.h" #include "cam_req_mgr_util.h"
#include "cam_debug_util.h" #include "cam_debug_util.h"
#include "cam_context.h"
static struct cam_req_mgr_util_hdl_tbl *hdl_tbl; static struct cam_req_mgr_util_hdl_tbl *hdl_tbl;
static DEFINE_SPINLOCK(hdl_tbl_lock); 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; 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) void *cam_get_device_priv(int32_t dev_hdl)
{ {
int idx; int idx;

View File

@@ -166,4 +166,11 @@ int32_t cam_req_mgr_util_deinit(void);
*/ */
int32_t cam_req_mgr_util_free_hdls(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_ */ #endif /* _CAM_REQ_MGR_UTIL_API_H_ */

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* 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_ #ifndef _CAM_SUBDEV_H_
@@ -20,6 +20,13 @@ enum cam_subdev_message_type_t {
CAM_SUBDEV_MESSAGE_IRQ_ERR = 0x1 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 * 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: * @ent_function: Media entity function type. Can be:
* %CAM_IFE_DEVICE_TYPE - identifies as IFE device. * %CAM_IFE_DEVICE_TYPE - identifies as IFE device.
* %CAM_ICP_DEVICE_TYPE - identifies as ICP 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 * Each instance of a subdev driver should create this struct, either
* stand-alone or embedded in a larger struct. This structure should be * stand-alone or embedded in a larger struct. This structure should be
@@ -57,6 +66,8 @@ struct cam_subdev {
struct v4l2_subdev *sd, struct v4l2_subdev *sd,
enum cam_subdev_message_type_t msg_type, enum cam_subdev_message_type_t msg_type,
uint32_t data); 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); 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_ */ #endif /* _CAM_SUBDEV_H_ */

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // 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" #include "cam_actuator_dev.h"
@@ -10,6 +10,38 @@
#include "cam_trace.h" #include "cam_trace.h"
#include "camera_main.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, static long cam_actuator_subdev_ioctl(struct v4l2_subdev *sd,
unsigned int cmd, void *arg) unsigned int cmd, void *arg)
{ {
@@ -24,6 +56,14 @@ static long cam_actuator_subdev_ioctl(struct v4l2_subdev *sd,
CAM_ERR(CAM_ACTUATOR, CAM_ERR(CAM_ACTUATOR,
"Failed for driver_cmd: %d", rc); "Failed for driver_cmd: %d", rc);
break; 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: default:
CAM_ERR(CAM_ACTUATOR, "Invalid ioctl cmd: %u", cmd); CAM_ERR(CAM_ACTUATOR, "Invalid ioctl cmd: %u", cmd);
rc = -ENOIOCTLCMD; rc = -ENOIOCTLCMD;
@@ -77,24 +117,6 @@ static long cam_actuator_init_subdev_do_ioctl(struct v4l2_subdev *sd,
} }
#endif #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 = { static struct v4l2_subdev_core_ops cam_actuator_subdev_core_ops = {
.ioctl = cam_actuator_subdev_ioctl, .ioctl = cam_actuator_subdev_ioctl,
#ifdef CONFIG_COMPAT #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 = a_ctrl->v4l2_dev_str.ent_function =
CAM_ACTUATOR_DEVICE_TYPE; CAM_ACTUATOR_DEVICE_TYPE;
a_ctrl->v4l2_dev_str.token = a_ctrl; 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)); rc = cam_register_subdev(&(a_ctrl->v4l2_dev_str));
if (rc) 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; return rc;
} }

View File

@@ -92,29 +92,7 @@ static void cam_csiphy_debug_unregister(void)
root_dentry = NULL; root_dentry = NULL;
} }
static long cam_csiphy_subdev_ioctl(struct v4l2_subdev *sd, static int cam_csiphy_subdev_close_internal(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,
struct v4l2_subdev_fh *fh) struct v4l2_subdev_fh *fh)
{ {
struct csiphy_device *csiphy_dev = struct csiphy_device *csiphy_dev =
@@ -132,6 +110,49 @@ static int cam_csiphy_subdev_close(struct v4l2_subdev *sd,
return 0; 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 #ifdef CONFIG_COMPAT
static long cam_csiphy_subdev_compat_ioctl(struct v4l2_subdev *sd, static long cam_csiphy_subdev_compat_ioctl(struct v4l2_subdev *sd,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
@@ -246,6 +267,8 @@ static int cam_csiphy_component_bind(struct device *dev,
cam_csiphy_subdev_handle_message; cam_csiphy_subdev_handle_message;
new_csiphy_dev->v4l2_dev_str.token = new_csiphy_dev->v4l2_dev_str.token =
new_csiphy_dev; 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)); rc = cam_register_subdev(&(new_csiphy_dev->v4l2_dev_str));
if (rc < 0) { if (rc < 0) {

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // 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" #include "cam_eeprom_dev.h"
@@ -10,28 +10,7 @@
#include "cam_debug_util.h" #include "cam_debug_util.h"
#include "camera_main.h" #include "camera_main.h"
static long cam_eeprom_subdev_ioctl(struct v4l2_subdev *sd, static int cam_eeprom_subdev_close_internal(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,
struct v4l2_subdev_fh *fh) struct v4l2_subdev_fh *fh)
{ {
struct cam_eeprom_ctrl_t *e_ctrl = struct cam_eeprom_ctrl_t *e_ctrl =
@@ -49,6 +28,48 @@ static int cam_eeprom_subdev_close(struct v4l2_subdev *sd,
return 0; 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, int32_t cam_eeprom_update_i2c_info(struct cam_eeprom_ctrl_t *e_ctrl,
struct cam_eeprom_i2c_info_t *i2c_info) 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); (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.ent_function = CAM_EEPROM_DEVICE_TYPE;
e_ctrl->v4l2_dev_str.token = e_ctrl; 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)); rc = cam_register_subdev(&(e_ctrl->v4l2_dev_str));
if (rc) if (rc)

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // 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 <linux/module.h> #include <linux/module.h>
@@ -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, static long cam_flash_subdev_ioctl(struct v4l2_subdev *sd,
unsigned int cmd, void *arg) 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); "Failed in driver cmd: %d", rc);
break; 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: default:
CAM_ERR(CAM_FLASH, "Invalid ioctl cmd type"); CAM_ERR(CAM_FLASH, "Invalid ioctl cmd type");
rc = -ENOIOCTLCMD; rc = -ENOIOCTLCMD;
@@ -328,24 +367,6 @@ static int32_t cam_flash_i2c_driver_remove(struct i2c_client *client)
return rc; 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 = { static struct v4l2_subdev_core_ops cam_flash_subdev_core_ops = {
.ioctl = cam_flash_subdev_ioctl, .ioctl = cam_flash_subdev_ioctl,
#ifdef CONFIG_COMPAT #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; V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
fctrl->v4l2_dev_str.ent_function = CAM_FLASH_DEVICE_TYPE; fctrl->v4l2_dev_str.ent_function = CAM_FLASH_DEVICE_TYPE;
fctrl->v4l2_dev_str.token = fctrl; 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)); rc = cam_register_subdev(&(fctrl->v4l2_dev_str));
if (rc) if (rc)

View File

@@ -10,29 +10,7 @@
#include "cam_debug_util.h" #include "cam_debug_util.h"
#include "camera_main.h" #include "camera_main.h"
static long cam_ois_subdev_ioctl(struct v4l2_subdev *sd, static int cam_ois_subdev_close_internal(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,
struct v4l2_subdev_fh *fh) struct v4l2_subdev_fh *fh)
{ {
struct cam_ois_ctrl_t *o_ctrl = struct cam_ois_ctrl_t *o_ctrl =
@@ -50,6 +28,48 @@ static int cam_ois_subdev_close(struct v4l2_subdev *sd,
return 0; 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, static int32_t cam_ois_update_i2c_info(struct cam_ois_ctrl_t *o_ctrl,
struct cam_ois_i2c_info_t *i2c_info) 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); (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.ent_function = CAM_OIS_DEVICE_TYPE;
o_ctrl->v4l2_dev_str.token = o_ctrl; 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)); rc = cam_register_subdev(&(o_ctrl->v4l2_dev_str));
if (rc) if (rc)

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // 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" #include "cam_sensor_dev.h"
@@ -9,29 +9,7 @@
#include "cam_sensor_core.h" #include "cam_sensor_core.h"
#include "camera_main.h" #include "camera_main.h"
static long cam_sensor_subdev_ioctl(struct v4l2_subdev *sd, static int cam_sensor_subdev_close_internal(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,
struct v4l2_subdev_fh *fh) struct v4l2_subdev_fh *fh)
{ {
struct cam_sensor_ctrl_t *s_ctrl = struct cam_sensor_ctrl_t *s_ctrl =
@@ -49,6 +27,49 @@ static int cam_sensor_subdev_close(struct v4l2_subdev *sd,
return 0; 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 #ifdef CONFIG_COMPAT
static long cam_sensor_init_subdev_do_ioctl(struct v4l2_subdev *sd, static long cam_sensor_init_subdev_do_ioctl(struct v4l2_subdev *sd,
unsigned int cmd, unsigned long arg) 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 = s_ctrl->v4l2_dev_str.ent_function =
CAM_SENSOR_DEVICE_TYPE; CAM_SENSOR_DEVICE_TYPE;
s_ctrl->v4l2_dev_str.token = s_ctrl; 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)); rc = cam_register_subdev(&(s_ctrl->v4l2_dev_str));
if (rc) if (rc)