Loading drivers/media/platform/msm/camera/Makefile +1 −1 Original line number Diff line number Diff line Loading @@ -2,4 +2,4 @@ ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_utils/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_core/ drivers/media/platform/msm/camera/cam_core/Makefile 0 → 100644 +3 −0 Original line number Diff line number Diff line ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr obj-$(CONFIG_SPECTRA_CAMERA) += cam_context.o cam_node.o cam_subdev.o drivers/media/platform/msm/camera/cam_core/cam_context.c 0 → 100644 +361 −0 Original line number Diff line number Diff line /* Copyright (c) 2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include <linux/slab.h> #include <linux/uaccess.h> #include "cam_context.h" static int cam_context_handle_hw_event(void *context, uint32_t evt_id, void *evt_data) { int rc = 0; struct cam_context *ctx = (struct cam_context *)context; if (!ctx || !ctx->state_machine) { pr_err("%s: Context is not ready.\n", __func__); return -EINVAL; } if (ctx->state_machine[ctx->state].irq_ops) rc = ctx->state_machine[ctx->state].irq_ops(ctx, evt_id, evt_data); else pr_debug("%s: No function to handle event %d in dev %d, state %d\n", __func__, evt_id, ctx->dev_hdl, ctx->state); return rc; } int cam_context_handle_get_dev_info(struct cam_context *ctx, struct cam_req_mgr_device_info *info) { int rc; if (!ctx->state_machine) { pr_err("%s: Context is not ready.\n'", __func__); return -EINVAL; } if (!info) { pr_err("%s: Invalid get device info payload.\n", __func__); return -EINVAL; } mutex_lock(&ctx->ctx_mutex); if (ctx->state_machine[ctx->state].crm_ops.get_dev_info) { rc = ctx->state_machine[ctx->state].crm_ops.get_dev_info( ctx, info); } else { pr_err("%s: No get device info in dev %d, state %d\n", __func__, ctx->dev_hdl, ctx->state); rc = -EPROTO; } mutex_unlock(&ctx->ctx_mutex); return rc; } int cam_context_handle_link(struct cam_context *ctx, struct cam_req_mgr_core_dev_link_setup *link) { int rc; if (!ctx->state_machine) { pr_err("%s: Context is not ready.\n", __func__); return -EINVAL; } if (!link) { pr_err("%s: Invalid link payload.\n", __func__); return -EINVAL; } mutex_lock(&ctx->ctx_mutex); if (ctx->state_machine[ctx->state].crm_ops.link) { rc = ctx->state_machine[ctx->state].crm_ops.link(ctx, link); } else { pr_err("%s: No crm link in dev %d, state %d\n", __func__, ctx->dev_hdl, ctx->state); rc = -EPROTO; } mutex_unlock(&ctx->ctx_mutex); return rc; } int cam_context_handle_unlink(struct cam_context *ctx, struct cam_req_mgr_core_dev_link_setup *unlink) { int rc; if (!ctx->state_machine) { pr_err("%s: Context is not ready!\n", __func__); return -EINVAL; } if (!unlink) { pr_err("%s: Invalid unlink payload.\n", __func__); return -EINVAL; } mutex_lock(&ctx->ctx_mutex); if (ctx->state_machine[ctx->state].crm_ops.unlink) { rc = ctx->state_machine[ctx->state].crm_ops.unlink( ctx, unlink); } else { pr_err("%s: No crm unlink in dev %d, state %d\n", __func__, ctx->dev_hdl, ctx->state); rc = -EPROTO; } mutex_unlock(&ctx->ctx_mutex); return rc; } int cam_context_handle_apply_req(struct cam_context *ctx, struct cam_req_mgr_apply_request *apply) { int rc; if (!ctx->state_machine) { pr_err("%s: Context is not ready.\n'", __func__); return -EINVAL; } if (!apply) { pr_err("%s: Invalid apply request payload.\n'", __func__); return -EINVAL; } mutex_lock(&ctx->ctx_mutex); if (ctx->state_machine[ctx->state].crm_ops.apply_req) { rc = ctx->state_machine[ctx->state].crm_ops.apply_req(ctx, apply); } else { pr_err("%s: No crm apply req in dev %d, state %d\n", __func__, ctx->dev_hdl, ctx->state); rc = -EPROTO; } mutex_unlock(&ctx->ctx_mutex); return rc; } int cam_context_handle_acquire_dev(struct cam_context *ctx, struct cam_acquire_dev_cmd *cmd) { int rc; if (!ctx->state_machine) { pr_err("%s: Context is not ready.\n", __func__); return -EINVAL; } if (!cmd) { pr_err("%s: Invalid acquire device command payload.\n", __func__); return -EINVAL; } mutex_lock(&ctx->ctx_mutex); if (ctx->state_machine[ctx->state].ioctl_ops.acquire_dev) { rc = ctx->state_machine[ctx->state].ioctl_ops.acquire_dev( ctx, cmd); } else { pr_err("%s: No acquire device in dev %d, state %d\n", __func__, cmd->dev_handle, ctx->state); rc = -EPROTO; } mutex_unlock(&ctx->ctx_mutex); return rc; } int cam_context_handle_release_dev(struct cam_context *ctx, struct cam_release_dev_cmd *cmd) { int rc; if (!ctx->state_machine) { pr_err("%s: Context is not ready.\n", __func__); return -EINVAL; } if (!cmd) { pr_err("%s: Invalid release device command payload.\n", __func__); return -EINVAL; } mutex_lock(&ctx->ctx_mutex); if (ctx->state_machine[ctx->state].ioctl_ops.release_dev) { rc = ctx->state_machine[ctx->state].ioctl_ops.release_dev( ctx, cmd); } else { pr_err("%s: No release device in dev %d, state %d\n", __func__, ctx->dev_hdl, ctx->state); rc = -EPROTO; } mutex_unlock(&ctx->ctx_mutex); return rc; } int cam_context_handle_config_dev(struct cam_context *ctx, struct cam_config_dev_cmd *cmd) { int rc; if (!ctx->state_machine) { pr_err("%s: context is not ready\n'", __func__); return -EINVAL; } if (!cmd) { pr_err("%s: Invalid config device command payload.\n", __func__); return -EINVAL; } mutex_lock(&ctx->ctx_mutex); if (ctx->state_machine[ctx->state].ioctl_ops.config_dev) { rc = ctx->state_machine[ctx->state].ioctl_ops.config_dev( ctx, cmd); } else { pr_err("%s: No config device in dev %d, state %d\n", __func__, ctx->dev_hdl, ctx->state); rc = -EPROTO; } mutex_unlock(&ctx->ctx_mutex); return rc; } int cam_context_handle_start_dev(struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd) { int rc = 0; if (!ctx->state_machine) { pr_err("%s: Context is not ready.\n", __func__); return -EINVAL; } if (!cmd) { pr_err("%s: Invalid start device command payload.\n", __func__); return -EINVAL; } mutex_lock(&ctx->ctx_mutex); if (ctx->state_machine[ctx->state].ioctl_ops.start_dev) rc = ctx->state_machine[ctx->state].ioctl_ops.start_dev( ctx, cmd); else /* start device can be optional for some driver */ pr_debug("%s: No start device in dev %d, state %d\n", __func__, ctx->dev_hdl, ctx->state); mutex_unlock(&ctx->ctx_mutex); return rc; } int cam_context_handle_stop_dev(struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd) { int rc = 0; if (!ctx->state_machine) { pr_err("%s: Context is not ready.\n'", __func__); return -EINVAL; } if (!cmd) { pr_err("%s: Invalid stop device command payload.\n", __func__); return -EINVAL; } mutex_lock(&ctx->ctx_mutex); if (ctx->state_machine[ctx->state].ioctl_ops.stop_dev) rc = ctx->state_machine[ctx->state].ioctl_ops.stop_dev( ctx, cmd); else /* stop device can be optional for some driver */ pr_warn("%s: No stop device in dev %d, state %d\n", __func__, ctx->dev_hdl, ctx->state); mutex_unlock(&ctx->ctx_mutex); return rc; } int cam_context_init(struct cam_context *ctx, struct cam_req_mgr_kmd_ops *crm_node_intf, struct cam_hw_mgr_intf *hw_mgr_intf, struct cam_ctx_request *req_list, uint32_t req_size) { int i; /* crm_node_intf is optinal */ if (!ctx || !hw_mgr_intf || !req_list) { pr_err("%s: Invalid input parameters\n", __func__); return -EINVAL; } memset(ctx, 0, sizeof(*ctx)); INIT_LIST_HEAD(&ctx->list); mutex_init(&ctx->ctx_mutex); spin_lock_init(&ctx->lock); ctx->ctx_crm_intf = NULL; ctx->crm_ctx_intf = crm_node_intf; ctx->hw_mgr_intf = hw_mgr_intf; ctx->irq_cb_intf = cam_context_handle_hw_event; INIT_LIST_HEAD(&ctx->active_req_list); INIT_LIST_HEAD(&ctx->wait_req_list); INIT_LIST_HEAD(&ctx->pending_req_list); INIT_LIST_HEAD(&ctx->free_req_list); ctx->req_list = req_list; ctx->req_size = req_size; for (i = 0; i < req_size; i++) { INIT_LIST_HEAD(&ctx->req_list[i].list); list_add_tail(&ctx->req_list[i].list, &ctx->free_req_list); } ctx->state = CAM_CTX_AVAILABLE; ctx->state_machine = NULL; ctx->ctx_priv = NULL; return 0; } int cam_context_deinit(struct cam_context *ctx) { if (!ctx) return -EINVAL; /** * This is called from platform device remove. * Everyting should be released at this moment. * so we just free the memory for the context */ if (ctx->state != CAM_CTX_AVAILABLE) pr_err("%s: Device did not shutdown cleanly.\n", __func__); memset(ctx, 0, sizeof(*ctx)); return 0; } drivers/media/platform/msm/camera/cam_core/cam_context.h 0 → 100644 +302 −0 Original line number Diff line number Diff line /* Copyright (c) 2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #ifndef _CAM_CONTEXT_H_ #define _CAM_CONTEXT_H_ #include <linux/spinlock.h> #include "cam_req_mgr_interface.h" #include "cam_hw_mgr_intf.h" /* Forward declarations */ struct cam_context; /* max request number */ #define CAM_CTX_REQ_MAX 20 /** * enum cam_ctx_state - context top level states * */ enum cam_context_state { CAM_CTX_UNINIT = 0, CAM_CTX_AVAILABLE = 1, CAM_CTX_ACQUIRED = 2, CAM_CTX_READY = 3, CAM_CTX_ACTIVATED = 4, CAM_CTX_STATE_MAX = 5, }; /** * struct cam_ctx_request - Common request structure for the context * * @list: Link list entry * @status: Request status * @request_id: Request id * @req_priv: Derived request object * */ struct cam_ctx_request { struct list_head list; uint32_t status; uint64_t request_id; void *req_priv; }; /** * struct cam_ctx_ioctl_ops - Function table for handling IOCTL calls * * @acquire_dev: Function pointer for acquire device * @release_dev: Function pointer for release device * @config_dev: Function pointer for config device * @start_dev: Function pointer for start device * @stop_dev: Function pointer for stop device * */ struct cam_ctx_ioctl_ops { int (*acquire_dev)(struct cam_context *ctx, struct cam_acquire_dev_cmd *cmd); int (*release_dev)(struct cam_context *ctx, struct cam_release_dev_cmd *cmd); int (*config_dev)(struct cam_context *ctx, struct cam_config_dev_cmd *cmd); int (*start_dev)(struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd); int (*stop_dev)(struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd); }; /** * struct cam_ctx_crm_ops - Function table for handling CRM to context calls * * @get_dev_info: Get device informaiton * @link: Link the context * @unlink: Unlink the context * @apply_req: Apply setting for the context * */ struct cam_ctx_crm_ops { int (*get_dev_info)(struct cam_context *ctx, struct cam_req_mgr_device_info *); int (*link)(struct cam_context *ctx, struct cam_req_mgr_core_dev_link_setup *link); int (*unlink)(struct cam_context *ctx, struct cam_req_mgr_core_dev_link_setup *unlink); int (*apply_req)(struct cam_context *ctx, struct cam_req_mgr_apply_request *apply); }; /** * struct cam_ctx_ops - Collection of the interface funciton tables * * @ioctl_ops: Ioctl funciton table * @crm_ops: CRM to context interface function table * @irq_ops: Hardware event handle function * */ struct cam_ctx_ops { struct cam_ctx_ioctl_ops ioctl_ops; struct cam_ctx_crm_ops crm_ops; cam_hw_event_cb_func irq_ops; }; /** * struct cam_context - camera context object for the subdevice node * * @list: Link list entry * @sessoin_hdl: Session handle * @dev_hdl: Device handle * @link_hdl: Link handle * @ctx_mutex: Mutex for ioctl calls * @lock: Spin lock * @active_req_list: Requests pending for done event * @pending_req_list: Requests pending for reg upd event * @wait_req_list: Requests waiting for apply * @free_req_list: Requests that are free * @req_list: Reference to the request storage * @req_size: Size of the request storage * @hw_mgr_intf: Context to HW interface * @ctx_crm_intf: Context to CRM interface * @crm_ctx_intf: CRM to context interface * @irq_cb_intf: HW to context callback interface * @state: Current state for top level state machine * @state_machine: Top level state machine * @ctx_priv: Private context pointer * */ struct cam_context { struct list_head list; int32_t session_hdl; int32_t dev_hdl; int32_t link_hdl; struct mutex ctx_mutex; spinlock_t lock; struct list_head active_req_list; struct list_head pending_req_list; struct list_head wait_req_list; struct list_head free_req_list; struct cam_ctx_request *req_list; uint32_t req_size; struct cam_hw_mgr_intf *hw_mgr_intf; struct cam_req_mgr_crm_cb *ctx_crm_intf; struct cam_req_mgr_kmd_ops *crm_ctx_intf; cam_hw_event_cb_func irq_cb_intf; enum cam_context_state state; struct cam_ctx_ops *state_machine; void *ctx_priv; }; /** * cam_context_handle_get_dev_info() * * @brief: Handle get device information command * * @ctx: Object pointer for cam_context * @info: Device information returned * */ int cam_context_handle_get_dev_info(struct cam_context *ctx, struct cam_req_mgr_device_info *info); /** * cam_context_handle_link() * * @brief: Handle link command * * @ctx: Object pointer for cam_context * @link: Link command payload * */ int cam_context_handle_link(struct cam_context *ctx, struct cam_req_mgr_core_dev_link_setup *link); /** * cam_context_handle_unlink() * * @brief: Handle unlink command * * @ctx: Object pointer for cam_context * @unlink: Unlink command payload * */ int cam_context_handle_unlink(struct cam_context *ctx, struct cam_req_mgr_core_dev_link_setup *unlink); /** * cam_context_handle_apply_req() * * @brief: Handle apply request command * * @ctx: Object pointer for cam_context * @apply: Apply request command payload * */ int cam_context_handle_apply_req(struct cam_context *ctx, struct cam_req_mgr_apply_request *apply); /** * cam_context_handle_acquire_dev() * * @brief: Handle acquire device command * * @ctx: Object pointer for cam_context * @cmd: Acquire device command payload * */ int cam_context_handle_acquire_dev(struct cam_context *ctx, struct cam_acquire_dev_cmd *cmd); /** * cam_context_handle_release_dev() * * @brief: Handle release device command * * @ctx: Object pointer for cam_context * @cmd: Release device command payload * */ int cam_context_handle_release_dev(struct cam_context *ctx, struct cam_release_dev_cmd *cmd); /** * cam_context_handle_config_dev() * * @brief: Handle config device command * * @ctx: Object pointer for cam_context * @cmd: Config device command payload * */ int cam_context_handle_config_dev(struct cam_context *ctx, struct cam_config_dev_cmd *cmd); /** * cam_context_handle_start_dev() * * @brief: Handle start device command * * @ctx: Object pointer for cam_context * @cmd: Start device command payload * */ int cam_context_handle_start_dev(struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd); /** * cam_context_handle_stop_dev() * * @brief: Handle stop device command * * @ctx: Object pointer for cam_context * @cmd: Stop device command payload * */ int cam_context_handle_stop_dev(struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd); /** * cam_context_deinit() * * @brief: Camera context deinitialize function * * @ctx: Object pointer for cam_context * */ int cam_context_deinit(struct cam_context *ctx); /** * cam_context_init() * * @brief: Camera context initialize function * * @ctx: Object pointer for cam_context * @crm_node_intf: Function table for crm to context interface * @hw_mgr_intf: Function table for context to hw interface * @req_list: Requests storage * @req_size: Size of the request storage * */ int cam_context_init(struct cam_context *ctx, struct cam_req_mgr_kmd_ops *crm_node_intf, struct cam_hw_mgr_intf *hw_mgr_intf, struct cam_ctx_request *req_list, uint32_t req_size); #endif /* _CAM_CONTEXT_H_ */ drivers/media/platform/msm/camera/cam_core/cam_hw.h 0 → 100644 +53 −0 Original line number Diff line number Diff line /* Copyright (c) 2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #ifndef _CAM_HW_H_ #define _CAM_HW_H_ #include "cam_soc_util.h" /* * This file declares Enums, Structures and APIs to be used as template * when writing any HW driver in the camera subsystem. */ /* Hardware state enum */ enum cam_hw_state { CAM_HW_STATE_POWER_DOWN, CAM_HW_STATE_POWER_UP, }; /** * struct cam_hw_info - Common hardware information * * @hw_mutex: Hardware mutex * @hw_lock: Hardware spinlock * @hw_complete: Hardware Completion * @open_count: Count to track the HW enable from the client * @hw_state: Hardware state * @soc_info: Platform SOC properties for hardware * @node_info: Private HW data related to nodes * @core_info: Private HW data related to core logic * */ struct cam_hw_info { struct mutex hw_mutex; spinlock_t hw_lock; struct completion hw_complete; uint32_t open_count; enum cam_hw_state hw_state; struct cam_hw_soc_info soc_info; void *node_info; void *core_info; }; #endif /* _CAM_HW_H_ */ Loading
drivers/media/platform/msm/camera/Makefile +1 −1 Original line number Diff line number Diff line Loading @@ -2,4 +2,4 @@ ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_utils/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_core/
drivers/media/platform/msm/camera/cam_core/Makefile 0 → 100644 +3 −0 Original line number Diff line number Diff line ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr obj-$(CONFIG_SPECTRA_CAMERA) += cam_context.o cam_node.o cam_subdev.o
drivers/media/platform/msm/camera/cam_core/cam_context.c 0 → 100644 +361 −0 Original line number Diff line number Diff line /* Copyright (c) 2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include <linux/slab.h> #include <linux/uaccess.h> #include "cam_context.h" static int cam_context_handle_hw_event(void *context, uint32_t evt_id, void *evt_data) { int rc = 0; struct cam_context *ctx = (struct cam_context *)context; if (!ctx || !ctx->state_machine) { pr_err("%s: Context is not ready.\n", __func__); return -EINVAL; } if (ctx->state_machine[ctx->state].irq_ops) rc = ctx->state_machine[ctx->state].irq_ops(ctx, evt_id, evt_data); else pr_debug("%s: No function to handle event %d in dev %d, state %d\n", __func__, evt_id, ctx->dev_hdl, ctx->state); return rc; } int cam_context_handle_get_dev_info(struct cam_context *ctx, struct cam_req_mgr_device_info *info) { int rc; if (!ctx->state_machine) { pr_err("%s: Context is not ready.\n'", __func__); return -EINVAL; } if (!info) { pr_err("%s: Invalid get device info payload.\n", __func__); return -EINVAL; } mutex_lock(&ctx->ctx_mutex); if (ctx->state_machine[ctx->state].crm_ops.get_dev_info) { rc = ctx->state_machine[ctx->state].crm_ops.get_dev_info( ctx, info); } else { pr_err("%s: No get device info in dev %d, state %d\n", __func__, ctx->dev_hdl, ctx->state); rc = -EPROTO; } mutex_unlock(&ctx->ctx_mutex); return rc; } int cam_context_handle_link(struct cam_context *ctx, struct cam_req_mgr_core_dev_link_setup *link) { int rc; if (!ctx->state_machine) { pr_err("%s: Context is not ready.\n", __func__); return -EINVAL; } if (!link) { pr_err("%s: Invalid link payload.\n", __func__); return -EINVAL; } mutex_lock(&ctx->ctx_mutex); if (ctx->state_machine[ctx->state].crm_ops.link) { rc = ctx->state_machine[ctx->state].crm_ops.link(ctx, link); } else { pr_err("%s: No crm link in dev %d, state %d\n", __func__, ctx->dev_hdl, ctx->state); rc = -EPROTO; } mutex_unlock(&ctx->ctx_mutex); return rc; } int cam_context_handle_unlink(struct cam_context *ctx, struct cam_req_mgr_core_dev_link_setup *unlink) { int rc; if (!ctx->state_machine) { pr_err("%s: Context is not ready!\n", __func__); return -EINVAL; } if (!unlink) { pr_err("%s: Invalid unlink payload.\n", __func__); return -EINVAL; } mutex_lock(&ctx->ctx_mutex); if (ctx->state_machine[ctx->state].crm_ops.unlink) { rc = ctx->state_machine[ctx->state].crm_ops.unlink( ctx, unlink); } else { pr_err("%s: No crm unlink in dev %d, state %d\n", __func__, ctx->dev_hdl, ctx->state); rc = -EPROTO; } mutex_unlock(&ctx->ctx_mutex); return rc; } int cam_context_handle_apply_req(struct cam_context *ctx, struct cam_req_mgr_apply_request *apply) { int rc; if (!ctx->state_machine) { pr_err("%s: Context is not ready.\n'", __func__); return -EINVAL; } if (!apply) { pr_err("%s: Invalid apply request payload.\n'", __func__); return -EINVAL; } mutex_lock(&ctx->ctx_mutex); if (ctx->state_machine[ctx->state].crm_ops.apply_req) { rc = ctx->state_machine[ctx->state].crm_ops.apply_req(ctx, apply); } else { pr_err("%s: No crm apply req in dev %d, state %d\n", __func__, ctx->dev_hdl, ctx->state); rc = -EPROTO; } mutex_unlock(&ctx->ctx_mutex); return rc; } int cam_context_handle_acquire_dev(struct cam_context *ctx, struct cam_acquire_dev_cmd *cmd) { int rc; if (!ctx->state_machine) { pr_err("%s: Context is not ready.\n", __func__); return -EINVAL; } if (!cmd) { pr_err("%s: Invalid acquire device command payload.\n", __func__); return -EINVAL; } mutex_lock(&ctx->ctx_mutex); if (ctx->state_machine[ctx->state].ioctl_ops.acquire_dev) { rc = ctx->state_machine[ctx->state].ioctl_ops.acquire_dev( ctx, cmd); } else { pr_err("%s: No acquire device in dev %d, state %d\n", __func__, cmd->dev_handle, ctx->state); rc = -EPROTO; } mutex_unlock(&ctx->ctx_mutex); return rc; } int cam_context_handle_release_dev(struct cam_context *ctx, struct cam_release_dev_cmd *cmd) { int rc; if (!ctx->state_machine) { pr_err("%s: Context is not ready.\n", __func__); return -EINVAL; } if (!cmd) { pr_err("%s: Invalid release device command payload.\n", __func__); return -EINVAL; } mutex_lock(&ctx->ctx_mutex); if (ctx->state_machine[ctx->state].ioctl_ops.release_dev) { rc = ctx->state_machine[ctx->state].ioctl_ops.release_dev( ctx, cmd); } else { pr_err("%s: No release device in dev %d, state %d\n", __func__, ctx->dev_hdl, ctx->state); rc = -EPROTO; } mutex_unlock(&ctx->ctx_mutex); return rc; } int cam_context_handle_config_dev(struct cam_context *ctx, struct cam_config_dev_cmd *cmd) { int rc; if (!ctx->state_machine) { pr_err("%s: context is not ready\n'", __func__); return -EINVAL; } if (!cmd) { pr_err("%s: Invalid config device command payload.\n", __func__); return -EINVAL; } mutex_lock(&ctx->ctx_mutex); if (ctx->state_machine[ctx->state].ioctl_ops.config_dev) { rc = ctx->state_machine[ctx->state].ioctl_ops.config_dev( ctx, cmd); } else { pr_err("%s: No config device in dev %d, state %d\n", __func__, ctx->dev_hdl, ctx->state); rc = -EPROTO; } mutex_unlock(&ctx->ctx_mutex); return rc; } int cam_context_handle_start_dev(struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd) { int rc = 0; if (!ctx->state_machine) { pr_err("%s: Context is not ready.\n", __func__); return -EINVAL; } if (!cmd) { pr_err("%s: Invalid start device command payload.\n", __func__); return -EINVAL; } mutex_lock(&ctx->ctx_mutex); if (ctx->state_machine[ctx->state].ioctl_ops.start_dev) rc = ctx->state_machine[ctx->state].ioctl_ops.start_dev( ctx, cmd); else /* start device can be optional for some driver */ pr_debug("%s: No start device in dev %d, state %d\n", __func__, ctx->dev_hdl, ctx->state); mutex_unlock(&ctx->ctx_mutex); return rc; } int cam_context_handle_stop_dev(struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd) { int rc = 0; if (!ctx->state_machine) { pr_err("%s: Context is not ready.\n'", __func__); return -EINVAL; } if (!cmd) { pr_err("%s: Invalid stop device command payload.\n", __func__); return -EINVAL; } mutex_lock(&ctx->ctx_mutex); if (ctx->state_machine[ctx->state].ioctl_ops.stop_dev) rc = ctx->state_machine[ctx->state].ioctl_ops.stop_dev( ctx, cmd); else /* stop device can be optional for some driver */ pr_warn("%s: No stop device in dev %d, state %d\n", __func__, ctx->dev_hdl, ctx->state); mutex_unlock(&ctx->ctx_mutex); return rc; } int cam_context_init(struct cam_context *ctx, struct cam_req_mgr_kmd_ops *crm_node_intf, struct cam_hw_mgr_intf *hw_mgr_intf, struct cam_ctx_request *req_list, uint32_t req_size) { int i; /* crm_node_intf is optinal */ if (!ctx || !hw_mgr_intf || !req_list) { pr_err("%s: Invalid input parameters\n", __func__); return -EINVAL; } memset(ctx, 0, sizeof(*ctx)); INIT_LIST_HEAD(&ctx->list); mutex_init(&ctx->ctx_mutex); spin_lock_init(&ctx->lock); ctx->ctx_crm_intf = NULL; ctx->crm_ctx_intf = crm_node_intf; ctx->hw_mgr_intf = hw_mgr_intf; ctx->irq_cb_intf = cam_context_handle_hw_event; INIT_LIST_HEAD(&ctx->active_req_list); INIT_LIST_HEAD(&ctx->wait_req_list); INIT_LIST_HEAD(&ctx->pending_req_list); INIT_LIST_HEAD(&ctx->free_req_list); ctx->req_list = req_list; ctx->req_size = req_size; for (i = 0; i < req_size; i++) { INIT_LIST_HEAD(&ctx->req_list[i].list); list_add_tail(&ctx->req_list[i].list, &ctx->free_req_list); } ctx->state = CAM_CTX_AVAILABLE; ctx->state_machine = NULL; ctx->ctx_priv = NULL; return 0; } int cam_context_deinit(struct cam_context *ctx) { if (!ctx) return -EINVAL; /** * This is called from platform device remove. * Everyting should be released at this moment. * so we just free the memory for the context */ if (ctx->state != CAM_CTX_AVAILABLE) pr_err("%s: Device did not shutdown cleanly.\n", __func__); memset(ctx, 0, sizeof(*ctx)); return 0; }
drivers/media/platform/msm/camera/cam_core/cam_context.h 0 → 100644 +302 −0 Original line number Diff line number Diff line /* Copyright (c) 2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #ifndef _CAM_CONTEXT_H_ #define _CAM_CONTEXT_H_ #include <linux/spinlock.h> #include "cam_req_mgr_interface.h" #include "cam_hw_mgr_intf.h" /* Forward declarations */ struct cam_context; /* max request number */ #define CAM_CTX_REQ_MAX 20 /** * enum cam_ctx_state - context top level states * */ enum cam_context_state { CAM_CTX_UNINIT = 0, CAM_CTX_AVAILABLE = 1, CAM_CTX_ACQUIRED = 2, CAM_CTX_READY = 3, CAM_CTX_ACTIVATED = 4, CAM_CTX_STATE_MAX = 5, }; /** * struct cam_ctx_request - Common request structure for the context * * @list: Link list entry * @status: Request status * @request_id: Request id * @req_priv: Derived request object * */ struct cam_ctx_request { struct list_head list; uint32_t status; uint64_t request_id; void *req_priv; }; /** * struct cam_ctx_ioctl_ops - Function table for handling IOCTL calls * * @acquire_dev: Function pointer for acquire device * @release_dev: Function pointer for release device * @config_dev: Function pointer for config device * @start_dev: Function pointer for start device * @stop_dev: Function pointer for stop device * */ struct cam_ctx_ioctl_ops { int (*acquire_dev)(struct cam_context *ctx, struct cam_acquire_dev_cmd *cmd); int (*release_dev)(struct cam_context *ctx, struct cam_release_dev_cmd *cmd); int (*config_dev)(struct cam_context *ctx, struct cam_config_dev_cmd *cmd); int (*start_dev)(struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd); int (*stop_dev)(struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd); }; /** * struct cam_ctx_crm_ops - Function table for handling CRM to context calls * * @get_dev_info: Get device informaiton * @link: Link the context * @unlink: Unlink the context * @apply_req: Apply setting for the context * */ struct cam_ctx_crm_ops { int (*get_dev_info)(struct cam_context *ctx, struct cam_req_mgr_device_info *); int (*link)(struct cam_context *ctx, struct cam_req_mgr_core_dev_link_setup *link); int (*unlink)(struct cam_context *ctx, struct cam_req_mgr_core_dev_link_setup *unlink); int (*apply_req)(struct cam_context *ctx, struct cam_req_mgr_apply_request *apply); }; /** * struct cam_ctx_ops - Collection of the interface funciton tables * * @ioctl_ops: Ioctl funciton table * @crm_ops: CRM to context interface function table * @irq_ops: Hardware event handle function * */ struct cam_ctx_ops { struct cam_ctx_ioctl_ops ioctl_ops; struct cam_ctx_crm_ops crm_ops; cam_hw_event_cb_func irq_ops; }; /** * struct cam_context - camera context object for the subdevice node * * @list: Link list entry * @sessoin_hdl: Session handle * @dev_hdl: Device handle * @link_hdl: Link handle * @ctx_mutex: Mutex for ioctl calls * @lock: Spin lock * @active_req_list: Requests pending for done event * @pending_req_list: Requests pending for reg upd event * @wait_req_list: Requests waiting for apply * @free_req_list: Requests that are free * @req_list: Reference to the request storage * @req_size: Size of the request storage * @hw_mgr_intf: Context to HW interface * @ctx_crm_intf: Context to CRM interface * @crm_ctx_intf: CRM to context interface * @irq_cb_intf: HW to context callback interface * @state: Current state for top level state machine * @state_machine: Top level state machine * @ctx_priv: Private context pointer * */ struct cam_context { struct list_head list; int32_t session_hdl; int32_t dev_hdl; int32_t link_hdl; struct mutex ctx_mutex; spinlock_t lock; struct list_head active_req_list; struct list_head pending_req_list; struct list_head wait_req_list; struct list_head free_req_list; struct cam_ctx_request *req_list; uint32_t req_size; struct cam_hw_mgr_intf *hw_mgr_intf; struct cam_req_mgr_crm_cb *ctx_crm_intf; struct cam_req_mgr_kmd_ops *crm_ctx_intf; cam_hw_event_cb_func irq_cb_intf; enum cam_context_state state; struct cam_ctx_ops *state_machine; void *ctx_priv; }; /** * cam_context_handle_get_dev_info() * * @brief: Handle get device information command * * @ctx: Object pointer for cam_context * @info: Device information returned * */ int cam_context_handle_get_dev_info(struct cam_context *ctx, struct cam_req_mgr_device_info *info); /** * cam_context_handle_link() * * @brief: Handle link command * * @ctx: Object pointer for cam_context * @link: Link command payload * */ int cam_context_handle_link(struct cam_context *ctx, struct cam_req_mgr_core_dev_link_setup *link); /** * cam_context_handle_unlink() * * @brief: Handle unlink command * * @ctx: Object pointer for cam_context * @unlink: Unlink command payload * */ int cam_context_handle_unlink(struct cam_context *ctx, struct cam_req_mgr_core_dev_link_setup *unlink); /** * cam_context_handle_apply_req() * * @brief: Handle apply request command * * @ctx: Object pointer for cam_context * @apply: Apply request command payload * */ int cam_context_handle_apply_req(struct cam_context *ctx, struct cam_req_mgr_apply_request *apply); /** * cam_context_handle_acquire_dev() * * @brief: Handle acquire device command * * @ctx: Object pointer for cam_context * @cmd: Acquire device command payload * */ int cam_context_handle_acquire_dev(struct cam_context *ctx, struct cam_acquire_dev_cmd *cmd); /** * cam_context_handle_release_dev() * * @brief: Handle release device command * * @ctx: Object pointer for cam_context * @cmd: Release device command payload * */ int cam_context_handle_release_dev(struct cam_context *ctx, struct cam_release_dev_cmd *cmd); /** * cam_context_handle_config_dev() * * @brief: Handle config device command * * @ctx: Object pointer for cam_context * @cmd: Config device command payload * */ int cam_context_handle_config_dev(struct cam_context *ctx, struct cam_config_dev_cmd *cmd); /** * cam_context_handle_start_dev() * * @brief: Handle start device command * * @ctx: Object pointer for cam_context * @cmd: Start device command payload * */ int cam_context_handle_start_dev(struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd); /** * cam_context_handle_stop_dev() * * @brief: Handle stop device command * * @ctx: Object pointer for cam_context * @cmd: Stop device command payload * */ int cam_context_handle_stop_dev(struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd); /** * cam_context_deinit() * * @brief: Camera context deinitialize function * * @ctx: Object pointer for cam_context * */ int cam_context_deinit(struct cam_context *ctx); /** * cam_context_init() * * @brief: Camera context initialize function * * @ctx: Object pointer for cam_context * @crm_node_intf: Function table for crm to context interface * @hw_mgr_intf: Function table for context to hw interface * @req_list: Requests storage * @req_size: Size of the request storage * */ int cam_context_init(struct cam_context *ctx, struct cam_req_mgr_kmd_ops *crm_node_intf, struct cam_hw_mgr_intf *hw_mgr_intf, struct cam_ctx_request *req_list, uint32_t req_size); #endif /* _CAM_CONTEXT_H_ */
drivers/media/platform/msm/camera/cam_core/cam_hw.h 0 → 100644 +53 −0 Original line number Diff line number Diff line /* Copyright (c) 2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #ifndef _CAM_HW_H_ #define _CAM_HW_H_ #include "cam_soc_util.h" /* * This file declares Enums, Structures and APIs to be used as template * when writing any HW driver in the camera subsystem. */ /* Hardware state enum */ enum cam_hw_state { CAM_HW_STATE_POWER_DOWN, CAM_HW_STATE_POWER_UP, }; /** * struct cam_hw_info - Common hardware information * * @hw_mutex: Hardware mutex * @hw_lock: Hardware spinlock * @hw_complete: Hardware Completion * @open_count: Count to track the HW enable from the client * @hw_state: Hardware state * @soc_info: Platform SOC properties for hardware * @node_info: Private HW data related to nodes * @core_info: Private HW data related to core logic * */ struct cam_hw_info { struct mutex hw_mutex; spinlock_t hw_lock; struct completion hw_complete; uint32_t open_count; enum cam_hw_state hw_state; struct cam_hw_soc_info soc_info; void *node_info; void *core_info; }; #endif /* _CAM_HW_H_ */