summaryrefslogtreecommitdiff
path: root/drivers/media/platform/tegra
diff options
context:
space:
mode:
authorCharlie Huang <chahuang@nvidia.com>2014-05-16 16:05:04 -0700
committerMandar Padmawar <mpadmawar@nvidia.com>2014-05-30 03:31:37 -0700
commit0075c8317bfc9cb998f110e619680aa4e0638221 (patch)
treec4c223dcd0d63c2b2c57e5723962fbbeaed9f5b9 /drivers/media/platform/tegra
parent48981a07c22a9bd96030bf83de6f61fbf64dc13a (diff)
drivers: platform: tegra: camera: shutdown event
implement shutdown/suspend/resume functions to avoid i2c failures. add atomic cam_ref to prevent the conflict scenario of system shutdown but the user space still atempt to access the driver. bug 1503230 Change-Id: I3fe58b49c1391dcc312f096c307a0849b829689a Signed-off-by: Charlie Huang <chahuang@nvidia.com> Reviewed-on: http://git-master/r/411093 (cherry picked from commit c4a86a3b83dd0e71026b68e410b45897e7e284fc) Reviewed-on: http://git-master/r/415578 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Frank Chen <frankc@nvidia.com> Reviewed-by: Mitch Luban <mluban@nvidia.com>
Diffstat (limited to 'drivers/media/platform/tegra')
-rw-r--r--drivers/media/platform/tegra/camera.c100
1 files changed, 89 insertions, 11 deletions
diff --git a/drivers/media/platform/tegra/camera.c b/drivers/media/platform/tegra/camera.c
index d79afcfd8f99..41bf7b478b61 100644
--- a/drivers/media/platform/tegra/camera.c
+++ b/drivers/media/platform/tegra/camera.c
@@ -51,6 +51,9 @@ static struct camera_platform_data camera_dflt_pdata = {
.cfg = 0,
};
+static atomic_t cam_ref;
+static DEFINE_MUTEX(cam_mutex);
+
static DEFINE_MUTEX(app_mutex);
static DEFINE_MUTEX(dev_mutex);
static DEFINE_MUTEX(chip_mutex);
@@ -68,6 +71,47 @@ static struct camera_platform_info cam_desc = {
.chip_list = &chip_list,
};
+static inline void camera_ref_init(void)
+{
+ atomic_set(&cam_ref, 0);
+}
+
+static int camera_ref_raise(void)
+{
+ mutex_lock(&cam_mutex);
+ if (atomic_read(&cam_ref) < 0) {
+ mutex_unlock(&cam_mutex);
+ dev_err(cam_desc.dev, "%s - CAMERA DOWN.\n", __func__);
+ return -ENOTTY;
+ }
+ atomic_inc(&cam_ref);
+ mutex_unlock(&cam_mutex);
+
+ return 0;
+}
+
+static inline void camera_ref_down(void)
+{
+ atomic_dec(&cam_ref);
+}
+
+static void camera_ref_lock(void)
+{
+ int ref;
+
+ do {
+ mutex_lock(&cam_mutex);
+ ref = atomic_read(&cam_ref);
+ if (ref <= 0) {
+ atomic_set(&cam_ref, -1);
+ mutex_unlock(&cam_mutex);
+ break;
+ }
+ mutex_unlock(&cam_mutex);
+ usleep_range(10000, 10200);
+ } while (true);
+}
+
static int camera_get_params(
struct camera_info *cam, unsigned long arg, int u_size,
struct nvc_param *prm, void **data)
@@ -343,12 +387,13 @@ static int camera_remove_device(struct camera_device *cdev, bool ref_dec)
cam->dev = cam_desc.dev;
atomic_set(&cam->in_use, 0);
}
- if (cdev->chip)
+ if (cdev->chip) {
(cdev->chip->release)(cdev);
+ if (ref_dec)
+ atomic_dec(&cdev->chip->ref_cnt);
+ }
if (cdev->dev)
i2c_unregister_device(to_i2c_client(cdev->dev));
- if (ref_dec)
- atomic_dec(&cdev->chip->ref_cnt);
kfree(cdev);
return 0;
}
@@ -739,10 +784,13 @@ static long camera_ioctl(struct file *file,
unsigned int cmd,
unsigned long arg)
{
- struct camera_info *cam = file->private_data;
+ struct camera_info *cam;
int err = 0;
- dev_dbg(cam->dev, "%s %x %lx\n", __func__, cmd, arg);
+ if (camera_ref_raise())
+ return -ENOTTY;
+
+ cam = file->private_data;
if (!cam->cdev && ((cmd == PCLLK_IOCTL_SEQ_WR) ||
(cmd == PCLLK_IOCTL_PWR_WR) ||
(cmd == PCLLK_IOCTL_PWR_RD))) {
@@ -810,6 +858,7 @@ static long camera_ioctl(struct file *file,
}
ioctl_end:
+ camera_ref_down();
if (err)
dev_dbg(cam->dev, "err = %d\n", err);
@@ -820,8 +869,12 @@ static int camera_open(struct inode *inode, struct file *file)
{
struct camera_info *cam;
+ if (camera_ref_raise())
+ return -ENOTTY;
+
cam = kzalloc(sizeof(*cam), GFP_KERNEL);
if (!cam) {
+ camera_ref_down();
dev_err(cam_desc.dev,
"%s unable to allocate memory!\n", __func__);
return -ENOMEM;
@@ -837,22 +890,28 @@ static int camera_open(struct inode *inode, struct file *file)
list_add(&cam->list, cam_desc.app_list);
mutex_unlock(cam_desc.u_mutex);
+ camera_ref_down();
dev_dbg(cam_desc.dev, "%s\n", __func__);
return 0;
}
static int camera_release(struct inode *inode, struct file *file)
{
- struct camera_info *cam = file->private_data;
+ struct camera_info *cam;
dev_dbg(cam_desc.dev, "%s\n", __func__);
+ if (camera_ref_raise())
+ return -ENOTTY;
+
+ cam = file->private_data;
mutex_lock(cam_desc.u_mutex);
list_del(&cam->list);
mutex_unlock(cam_desc.u_mutex);
camera_app_remove(cam, true);
+ camera_ref_down();
file->private_data = NULL;
return 0;
}
@@ -873,6 +932,10 @@ static int camera_remove(struct platform_device *dev)
struct camera_device *cdev;
dev_dbg(cam_desc.dev, "%s\n", __func__);
+
+ camera_ref_lock();
+
+ atomic_xchg(&cam_desc.in_use, 0);
misc_deregister(&cam_desc.miscdev);
list_for_each_entry(cam, cam_desc.app_list, list) {
@@ -895,6 +958,8 @@ static int camera_remove(struct platform_device *dev)
camera_debugfs_remove();
kfree(cam_desc.layout);
+ cam_desc.layout = NULL;
+ cam_desc.size_layout = 0;
if (cam_desc.pdata->freeable)
kfree(cam_desc.pdata);
cam_desc.pdata = NULL;
@@ -911,6 +976,7 @@ static int camera_probe(struct platform_device *dev)
return -EBUSY;
}
+ camera_ref_lock();
cam_desc.dev = &dev->dev;
if (dev->dev.of_node) {
pd = of_camera_create_pdata(dev);
@@ -929,6 +995,12 @@ static int camera_probe(struct platform_device *dev)
strcpy(cam_desc.dname, "camera.pcl");
dev_set_drvdata(&dev->dev, &cam_desc);
+#ifdef TEGRA_12X_OR_HIGHER_CONFIG
+ camera_dev_sync_init();
+ tegra_isp_register_mfi_cb(camera_dev_sync_cb, NULL);
+#endif
+ of_camera_init(&cam_desc);
+
cam_desc.miscdev.name = cam_desc.dname;
cam_desc.miscdev.fops = &camera_fileops;
cam_desc.miscdev.minor = MISC_DYNAMIC_MINOR;
@@ -938,15 +1010,20 @@ static int camera_probe(struct platform_device *dev)
return -ENODEV;
}
-#ifdef TEGRA_12X_OR_HIGHER_CONFIG
- camera_dev_sync_init();
- tegra_isp_register_mfi_cb(camera_dev_sync_cb, NULL);
-#endif
- of_camera_init(&cam_desc);
camera_debugfs_init(&cam_desc);
+ camera_ref_init();
return 0;
}
+static void camera_shutdown(struct platform_device *dev)
+{
+ dev_dbg(&dev->dev, "%s ...\n", __func__);
+
+ camera_ref_lock();
+ atomic_xchg(&cam_desc.in_use, 0);
+ dev_info(&dev->dev, "%s locked.\n", __func__);
+}
+
static const struct platform_device_id camera_id[] = {
{ "pcl-generic", 0 },
{ },
@@ -962,6 +1039,7 @@ static struct platform_driver camera_driver = {
.id_table = camera_id,
.probe = camera_probe,
.remove = camera_remove,
+ .shutdown = camera_shutdown,
};
module_platform_driver(camera_driver);