summaryrefslogtreecommitdiff
path: root/drivers/media/platform
diff options
context:
space:
mode:
authorMarcel Ziswiler <marcel.ziswiler@toradex.com>2017-11-29 14:56:42 +0100
committerMarcel Ziswiler <marcel.ziswiler@toradex.com>2017-11-29 14:56:42 +0100
commit2eecc3c4c63955c3d5860b44422dccd229ec7043 (patch)
treea3256780705eb959d17dd4c4a622a89f1001d90d /drivers/media/platform
parent9a315efc7e2646e75e8cc9d1d79e508589ad2202 (diff)
parentb271e8fa67a6d9c4600274a25636cfe00fdd1b68 (diff)
Merge tag 'tegra-l4t-r21.6' into toradex_tk1_l4t_r21.6
Merge NVIDIA's latest Linux for Tegra aka L4T R21.6 Linux kernel changes from git://nv-tegra.nvidia.com/linux-3.10.git commit: b271e8fa67a6d9c4600274a25636cfe00fdd1b68 Signed-off-by: Marcel Ziswiler <marcel.ziswiler@toradex.com> Acked-by: Dominik Sliwa <dominik.sliwa@toradex.com>
Diffstat (limited to 'drivers/media/platform')
-rw-r--r--drivers/media/platform/tegra/cam_dev/imx135.c6
-rw-r--r--drivers/media/platform/tegra/cam_dev/of_camera.c4
-rw-r--r--drivers/media/platform/tegra/cam_dev/virtual.c4
-rw-r--r--drivers/media/platform/tegra/camera.c85
-rw-r--r--drivers/media/platform/tegra/nvavp/nvavp_dev.c87
5 files changed, 149 insertions, 37 deletions
diff --git a/drivers/media/platform/tegra/cam_dev/imx135.c b/drivers/media/platform/tegra/cam_dev/imx135.c
index eaa085637aa4..7dd3e9bd61be 100644
--- a/drivers/media/platform/tegra/cam_dev/imx135.c
+++ b/drivers/media/platform/tegra/cam_dev/imx135.c
@@ -4,7 +4,7 @@
* the virtual PCL driver to handle some special features (hardware resources,
* sequences, etc.).
*
- * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2013-2016, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -42,11 +42,11 @@ struct imx135_info {
};
static int imx135_update(
- struct camera_device *cdev, struct cam_update *upd, int num)
+ struct camera_device *cdev, struct cam_update *upd, u32 num)
{
/* struct imx135_info *info = dev_get_drvdata(cdev->dev); */
int err = 0;
- int idx;
+ u32 idx;
dev_dbg(cdev->dev, "%s %d\n", __func__, num);
mutex_lock(&cdev->mutex);
diff --git a/drivers/media/platform/tegra/cam_dev/of_camera.c b/drivers/media/platform/tegra/cam_dev/of_camera.c
index 460ca1a844e8..f293b9a27cd0 100644
--- a/drivers/media/platform/tegra/cam_dev/of_camera.c
+++ b/drivers/media/platform/tegra/cam_dev/of_camera.c
@@ -1,7 +1,7 @@
/*
* debugfs.c
*
- * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2013-2016, NVIDIA CORPORATION. All rights reserved.
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -222,7 +222,7 @@ int of_camera_get_property(struct camera_info *cam, unsigned long arg)
}
/* sanity check */
- if (!param.sizeofvalue) {
+ if (!param.sizeofvalue || param.sizeofvalue > INT_MAX) {
dev_err(cam->dev, "%s invalid property name length %d\n",
__func__, param.sizeofvalue);
return -EBADF;
diff --git a/drivers/media/platform/tegra/cam_dev/virtual.c b/drivers/media/platform/tegra/cam_dev/virtual.c
index f08ad1563a73..d25becc1ec24 100644
--- a/drivers/media/platform/tegra/cam_dev/virtual.c
+++ b/drivers/media/platform/tegra/cam_dev/virtual.c
@@ -41,10 +41,10 @@ struct chip_config {
};
static int virtual_update(
- struct camera_device *cdev, struct cam_update *upd, int num)
+ struct camera_device *cdev, struct cam_update *upd, u32 num)
{
int err = 0;
- int idx;
+ u32 idx;
dev_dbg(cdev->dev, "%s %d\n", __func__, num);
mutex_lock(&cdev->mutex);
diff --git a/drivers/media/platform/tegra/camera.c b/drivers/media/platform/tegra/camera.c
index 2542f4210de6..9017e7fcd2cc 100644
--- a/drivers/media/platform/tegra/camera.c
+++ b/drivers/media/platform/tegra/camera.c
@@ -1,7 +1,7 @@
/*
* camera.c - generic camera device driver
*
- * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2013-2016, NVIDIA CORPORATION. All rights reserved.
*
* Contributors:
* Charlie Huang <chahuang@nvidia.com>
@@ -131,12 +131,12 @@ int camera_copy_user_params(unsigned long arg, struct nvc_param *prm)
}
#endif
-int camera_get_params(
+int __camera_get_params(
struct camera_info *cam, unsigned long arg, int u_size,
- struct nvc_param *prm, void **data)
+ struct nvc_param *prm, void **data, bool zero_size_ok)
{
void *buf;
- unsigned size;
+ size_t size;
#ifdef CONFIG_COMPAT
memset(prm, 0, sizeof(*prm));
@@ -156,9 +156,14 @@ int camera_get_params(
if (!data)
return 0;
+ if (zero_size_ok && prm->sizeofvalue == 0) {
+ *data = ZERO_SIZE_PTR;
+ return 0;
+ }
+
size = prm->sizeofvalue * u_size;
- buf = kzalloc(size, GFP_KERNEL);
- if (!buf) {
+ buf = kcalloc(prm->sizeofvalue, u_size, GFP_KERNEL);
+ if (ZERO_OR_NULL_PTR(buf)) {
dev_err(cam->dev, "%s allocate memory failed!\n", __func__);
return -ENOMEM;
}
@@ -173,6 +178,20 @@ int camera_get_params(
return 0;
}
+static int camera_validate_p_i2c_table(struct camera_info *cam,
+ const struct nvc_param *params,
+ const struct camera_reg *p_i2c_table, const char *caller)
+{
+ u32 idx, last_idx = params->sizeofvalue / sizeof(p_i2c_table[0]);
+
+ for (idx = 0; idx < last_idx; idx++)
+ if (p_i2c_table[idx].addr == CAMERA_TABLE_END)
+ return 0;
+
+ dev_err(cam->dev, "%s: table is not properly terminated\n", caller);
+ return -EINVAL;
+}
+
static int camera_seq_rd(struct camera_info *cam, unsigned long arg)
{
struct nvc_param params;
@@ -184,6 +203,10 @@ static int camera_seq_rd(struct camera_info *cam, unsigned long arg)
if (err)
return err;
+ err = camera_validate_p_i2c_table(cam, &params, p_i2c_table, __func__);
+ if (err)
+ goto seq_rd_end;
+
err = camera_dev_rd_table(cam->cdev, p_i2c_table);
if (!err && copy_to_user(MAKE_USER_PTR(params.p_value),
p_i2c_table, params.sizeofvalue)) {
@@ -192,6 +215,7 @@ static int camera_seq_rd(struct camera_info *cam, unsigned long arg)
err = -EINVAL;
}
+seq_rd_end:
kfree(p_i2c_table);
return err;
}
@@ -231,7 +255,7 @@ static int camera_seq_wr(struct camera_info *cam, unsigned long arg)
}
p_i2c_table = devm_kzalloc(cdev->dev, params.sizeofvalue, GFP_KERNEL);
- if (p_i2c_table == NULL) {
+ if (ZERO_OR_NULL_PTR(p_i2c_table)) {
dev_err(cam->dev, "%s devm_kzalloc err line %d\n",
__func__, __LINE__);
return -ENOMEM;
@@ -246,6 +270,10 @@ static int camera_seq_wr(struct camera_info *cam, unsigned long arg)
goto seq_wr_end;
}
+ err = camera_validate_p_i2c_table(cam, &params, p_i2c_table, __func__);
+ if (err)
+ goto seq_wr_end;
+
switch (params.param) {
case CAMERA_SEQ_REGISTER_EXEC:
case CAMERA_SEQ_REGISTER_ONLY:
@@ -498,13 +526,13 @@ static int camera_new_device(struct camera_info *cam, unsigned long arg)
next_dev->client->addr == dev_info.addr) {
dev_dbg(cam_desc.dev,
"%s: device already exists.\n", __func__);
- camera_remove_device(new_dev, false);
if (atomic_xchg(&next_dev->in_use, 1)) {
dev_err(cam_desc.dev, "%s device %s BUSY\n",
__func__, next_dev->name);
err = -EBUSY;
goto new_device_err;
- }
+ } else
+ camera_remove_device(new_dev, false);
new_dev = next_dev;
goto new_device_done;
}
@@ -586,7 +614,8 @@ static int camera_update(struct camera_info *cam, unsigned long arg)
return err;
}
- err = camera_get_params(cam, arg, sizeof(*upd), &param, (void **)&upd);
+ err = __camera_get_params(cam, arg, sizeof(*upd), &param, (void **)&upd,
+ true);
if (err)
return err;
@@ -657,9 +686,20 @@ static int camera_layout_get(struct camera_info *cam, unsigned long arg)
if (err)
return err;
+ if (param.variant > MAX_PARAM_VARIANT) {
+ dev_err(cam->dev, "%s param variant is too large: %u\n",
+ __func__, param.variant);
+ return -EINVAL;
+ }
+ if (param.sizeofvalue > MAX_PARAM_SIZE_OF_VALUE) {
+ dev_err(cam->dev, "%s size of param value is too large: %u\n",
+ __func__, param.sizeofvalue);
+ return -EINVAL;
+ }
+
len = (int)cam_desc.size_layout - param.variant;
if (len <= 0) {
- dev_err(cam->dev, "%s invalid offset %d\n",
+ dev_err(cam->dev, "%s invalid offset %u\n",
__func__, param.variant);
err = -EINVAL;
goto getlayout_end;
@@ -838,31 +878,46 @@ static long camera_ioctl(struct file *file,
break;
case PCLLK_IOCTL_DEV_DEL:
mutex_lock(cam_desc.d_mutex);
+ if (!cam->cdev) {
+ err = -ENODEV;
+ mutex_unlock(cam_desc.d_mutex);
+ break;
+ }
list_del(&cam->cdev->list);
- mutex_unlock(cam_desc.d_mutex);
camera_remove_device(cam->cdev, true);
+ mutex_unlock(cam_desc.d_mutex);
break;
case PCLLK_IOCTL_DEV_FREE:
err = camera_free_device(cam, arg);
break;
case PCLLK_IOCTL_SEQ_WR:
+ mutex_lock(cam_desc.d_mutex);
err = camera_seq_wr(cam, arg);
+ mutex_unlock(cam_desc.d_mutex);
break;
case PCLLK_IOCTL_SEQ_RD:
+ mutex_lock(cam_desc.d_mutex);
err = camera_seq_rd(cam, arg);
+ mutex_unlock(cam_desc.d_mutex);
break;
case PCLLK_IOCTL_PARAM_RD:
/* err = camera_param_rd(cam, arg); */
break;
case PCLLK_IOCTL_PWR_WR:
/* This is a Guaranteed Level of Service (GLOS) call */
+ mutex_lock(cam_desc.d_mutex);
err = camera_dev_pwr_set(cam, arg);
+ mutex_unlock(cam_desc.d_mutex);
break;
case PCLLK_IOCTL_PWR_RD:
+ mutex_lock(cam_desc.d_mutex);
err = camera_dev_pwr_get(cam, arg);
+ mutex_unlock(cam_desc.d_mutex);
break;
case PCLLK_IOCTL_UPDATE:
+ mutex_lock(cam_desc.d_mutex);
err = camera_update(cam, arg);
+ mutex_unlock(cam_desc.d_mutex);
break;
case PCLLK_IOCTL_LAYOUT_WR:
err = camera_layout_update(cam, arg);
@@ -884,16 +939,22 @@ static long camera_ioctl(struct file *file,
err = virtual_device_add(cam_desc.dev, arg);
break;
case PCLLK_IOCTL_32_SEQ_WR:
+ mutex_lock(cam_desc.d_mutex);
err = camera_seq_wr(cam, arg);
+ mutex_unlock(cam_desc.d_mutex);
break;
case PCLLK_IOCTL_32_SEQ_RD:
+ mutex_lock(cam_desc.d_mutex);
err = camera_seq_rd(cam, arg);
+ mutex_unlock(cam_desc.d_mutex);
break;
case PCLLK_IOCTL_32_PARAM_RD:
/* err = camera_param_rd(cam, arg); */
break;
case PCLLK_IOCTL_32_UPDATE:
+ mutex_lock(cam_desc.d_mutex);
err = camera_update(cam, arg);
+ mutex_unlock(cam_desc.d_mutex);
break;
case PCLLK_IOCTL_32_LAYOUT_WR:
err = camera_layout_update(cam, arg);
diff --git a/drivers/media/platform/tegra/nvavp/nvavp_dev.c b/drivers/media/platform/tegra/nvavp/nvavp_dev.c
index 843ea338c949..25dee33ea9aa 100644
--- a/drivers/media/platform/tegra/nvavp/nvavp_dev.c
+++ b/drivers/media/platform/tegra/nvavp/nvavp_dev.c
@@ -1,7 +1,7 @@
/*
* drivers/media/video/tegra/nvavp/nvavp_dev.c
*
- * Copyright (c) 2011-2016, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2011-2017, NVIDIA CORPORATION. All rights reserved.
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
@@ -135,6 +135,7 @@ struct nvavp_info {
int mbox_from_avp_pend_irq;
struct mutex open_lock;
+ struct mutex submit_lock;
int refcount;
int video_initialized;
int video_refcnt;
@@ -871,6 +872,7 @@ static int nvavp_pushbuffer_update(struct nvavp_info *nvavp, u32 phys_addr,
u32 wordcount = 0;
u32 index, value = -1;
int ret = 0;
+ u32 max_index = 0;
mutex_lock(&nvavp->open_lock);
nvavp_runtime_get(nvavp);
@@ -885,7 +887,9 @@ static int nvavp_pushbuffer_update(struct nvavp_info *nvavp, u32 phys_addr,
mutex_lock(&channel_info->pushbuffer_lock);
/* check for pushbuffer wrapping */
- if (channel_info->pushbuf_index >= channel_info->pushbuf_fence)
+ max_index = channel_info->pushbuf_fence;
+ max_index = ext_ucode_flag ? max_index : max_index - (sizeof(u32) * 4);
+ if (channel_info->pushbuf_index >= max_index)
channel_info->pushbuf_index = 0;
if (!ext_ucode_flag) {
@@ -1518,24 +1522,31 @@ static int nvavp_pushbuffer_submit_ioctl(struct file *filp, unsigned int cmd,
syncpt.id = NVSYNCPT_INVALID;
syncpt.value = 0;
+ mutex_lock(&nvavp->submit_lock);
if (_IOC_DIR(cmd) & _IOC_WRITE) {
if (copy_from_user(&hdr, (void __user *)arg,
- sizeof(struct nvavp_pushbuffer_submit_hdr)))
+ sizeof(struct nvavp_pushbuffer_submit_hdr))) {
+ mutex_unlock(&nvavp->submit_lock);
return -EFAULT;
+ }
}
- if (!hdr.cmdbuf.mem)
+ if (!hdr.cmdbuf.mem) {
+ mutex_unlock(&nvavp->submit_lock);
return 0;
+ }
if (hdr.num_relocs > NVAVP_MAX_RELOCATION_COUNT) {
dev_err(&nvavp->nvhost_dev->dev,
"invalid num_relocs %d\n", hdr.num_relocs);
+ mutex_unlock(&nvavp->submit_lock);
return -EINVAL;
}
if (copy_from_user(clientctx->relocs, (void __user *)hdr.relocs,
sizeof(struct nvavp_reloc) * hdr.num_relocs)) {
+ mutex_unlock(&nvavp->submit_lock);
return -EFAULT;
}
@@ -1543,6 +1554,7 @@ static int nvavp_pushbuffer_submit_ioctl(struct file *filp, unsigned int cmd,
if (IS_ERR(cmdbuf_dmabuf)) {
dev_err(&nvavp->nvhost_dev->dev,
"invalid cmd buffer handle %08x\n", hdr.cmdbuf.mem);
+ mutex_unlock(&nvavp->submit_lock);
return PTR_ERR(cmdbuf_dmabuf);
}
@@ -1679,6 +1691,7 @@ err_dmabuf_map:
dma_buf_detach(cmdbuf_dmabuf, cmdbuf_attach);
err_dmabuf_attach:
dma_buf_put(cmdbuf_dmabuf);
+ mutex_unlock(&nvavp->submit_lock);
return ret;
}
@@ -1692,19 +1705,26 @@ static int nvavp_pushbuffer_submit_compat_ioctl(struct file *filp,
struct nvavp_pushbuffer_submit_hdr_v32 hdr_v32;
struct nvavp_pushbuffer_submit_hdr __user *user_hdr;
int ret = 0;
+ mutex_lock(&nvavp->submit_lock);
if (_IOC_DIR(cmd) & _IOC_WRITE) {
if (copy_from_user(&hdr_v32, (void __user *)arg,
- sizeof(struct nvavp_pushbuffer_submit_hdr_v32)))
+ sizeof(struct nvavp_pushbuffer_submit_hdr_v32))) {
+ mutex_unlock(&nvavp->submit_lock);
return -EFAULT;
+ }
}
- if (!hdr_v32.cmdbuf.mem)
+ if (!hdr_v32.cmdbuf.mem) {
+ mutex_unlock(&nvavp->submit_lock);
return 0;
+ }
user_hdr = compat_alloc_user_space(sizeof(*user_hdr));
- if (!access_ok(VERIFY_WRITE, user_hdr, sizeof(*user_hdr)))
+ if (!access_ok(VERIFY_WRITE, user_hdr, sizeof(*user_hdr))) {
+ mutex_unlock(&nvavp->submit_lock);
return -EFAULT;
+ }
if (__put_user(hdr_v32.cmdbuf.mem, &user_hdr->cmdbuf.mem)
|| __put_user(hdr_v32.cmdbuf.offset, &user_hdr->cmdbuf.offset)
@@ -1714,21 +1734,29 @@ static int nvavp_pushbuffer_submit_compat_ioctl(struct file *filp,
|| __put_user(hdr_v32.num_relocs, &user_hdr->num_relocs)
|| __put_user((void __user *)(unsigned long)hdr_v32.syncpt,
&user_hdr->syncpt)
- || __put_user(hdr_v32.flags, &user_hdr->flags))
+ || __put_user(hdr_v32.flags, &user_hdr->flags)) {
+ mutex_unlock(&nvavp->submit_lock);
return -EFAULT;
+ }
+ mutex_unlock(&nvavp->submit_lock);
ret = nvavp_pushbuffer_submit_ioctl(filp, cmd, (unsigned long)user_hdr);
if (ret)
return ret;
- if (__get_user(hdr_v32.syncpt, &user_hdr->syncpt))
+ mutex_lock(&nvavp->submit_lock);
+ if (__get_user(hdr_v32.syncpt, (uintptr_t *)&user_hdr->syncpt))
+ {
+ mutex_unlock(&nvavp->submit_lock);
return -EFAULT;
+ }
if (copy_to_user((void __user *)arg, &hdr_v32,
sizeof(struct nvavp_pushbuffer_submit_hdr_v32))) {
ret = -EFAULT;
}
+ mutex_unlock(&nvavp->submit_lock);
return ret;
}
#endif
@@ -2009,10 +2037,17 @@ out:
static int tegra_nvavp_video_release(struct inode *inode, struct file *filp)
{
- struct nvavp_clientctx *clientctx = filp->private_data;
- struct nvavp_info *nvavp = clientctx->nvavp;
+ struct nvavp_clientctx *clientctx;
+ struct nvavp_info *nvavp;
int ret = 0;
+ clientctx = filp->private_data;
+ if (!clientctx)
+ return ret;
+ nvavp = clientctx->nvavp;
+ if (!nvavp)
+ return ret;
+
mutex_lock(&nvavp->open_lock);
filp->private_data = NULL;
ret = tegra_nvavp_release(clientctx, NVAVP_VIDEO_CHANNEL);
@@ -2025,10 +2060,17 @@ static int tegra_nvavp_video_release(struct inode *inode, struct file *filp)
static int tegra_nvavp_audio_release(struct inode *inode,
struct file *filp)
{
- struct nvavp_clientctx *clientctx = filp->private_data;
- struct nvavp_info *nvavp = clientctx->nvavp;
+ struct nvavp_clientctx *clientctx;
+ struct nvavp_info *nvavp;
int ret = 0;
+ clientctx = filp->private_data;
+ if (!clientctx)
+ return ret;
+ nvavp = clientctx->nvavp;
+ if (!nvavp)
+ return ret;
+
mutex_lock(&nvavp->open_lock);
filp->private_data = NULL;
ret = tegra_nvavp_release(clientctx, NVAVP_AUDIO_CHANNEL);
@@ -2040,9 +2082,15 @@ static int tegra_nvavp_audio_release(struct inode *inode,
int tegra_nvavp_audio_client_release(nvavp_clientctx_t client)
{
struct nvavp_clientctx *clientctx = client;
- struct nvavp_info *nvavp = clientctx->nvavp;
+ struct nvavp_info *nvavp;
int ret = 0;
+ if (!clientctx)
+ return ret;
+ nvavp = clientctx->nvavp;
+ if (!nvavp)
+ return ret;
+
mutex_lock(&nvavp->open_lock);
ret = tegra_nvavp_release(clientctx, NVAVP_AUDIO_CHANNEL);
mutex_unlock(&nvavp->open_lock);
@@ -2084,10 +2132,8 @@ nvavp_channel_open(struct file *filp, struct nvavp_channel_open_args *arg)
return err;
}
- fd_install(fd, file);
-
- nonseekable_open(file->f_inode, filp);
mutex_lock(&nvavp->open_lock);
+
err = tegra_nvavp_open(nvavp,
(struct nvavp_clientctx **)&file->private_data,
clientctx->channel_id);
@@ -2097,9 +2143,13 @@ nvavp_channel_open(struct file *filp, struct nvavp_channel_open_args *arg)
mutex_unlock(&nvavp->open_lock);
return err;
}
- mutex_unlock(&nvavp->open_lock);
arg->channel_fd = fd;
+
+ nonseekable_open(file->f_inode, filp);
+ fd_install(fd, file);
+
+ mutex_unlock(&nvavp->open_lock);
return err;
}
@@ -2380,6 +2430,7 @@ static int tegra_nvavp_probe(struct platform_device *ndev)
nvavp->mbox_from_avp_pend_irq = irq;
mutex_init(&nvavp->open_lock);
+ mutex_init(&nvavp->submit_lock);
for (channel_id = 0; channel_id < NVAVP_NUM_CHANNELS; channel_id++)
mutex_init(&nvavp->channel_info[channel_id].pushbuffer_lock);