aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/v4l2-core
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/v4l2-core')
-rw-r--r--drivers/media/v4l2-core/tuner-core.c10
-rw-r--r--drivers/media/v4l2-core/v4l2-common.c9
-rw-r--r--drivers/media/v4l2-core/v4l2-compat-ioctl32.c30
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls.c6
-rw-r--r--drivers/media/v4l2-core/v4l2-dv-timings.c3
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c6
-rw-r--r--drivers/media/v4l2-core/v4l2-subdev.c9
-rw-r--r--drivers/media/v4l2-core/videobuf-core.c11
-rw-r--r--drivers/media/v4l2-core/videobuf-dma-sg.c6
-rw-r--r--drivers/media/v4l2-core/videobuf2-core.c66
10 files changed, 87 insertions, 69 deletions
diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c
index 06c18ba..559f837 100644
--- a/drivers/media/v4l2-core/tuner-core.c
+++ b/drivers/media/v4l2-core/tuner-core.c
@@ -601,7 +601,7 @@ static int tuner_probe(struct i2c_client *client,
t->name = "(tuner unset)";
t->type = UNSET;
t->audmode = V4L2_TUNER_MODE_STEREO;
- t->standby = 1;
+ t->standby = true;
t->radio_freq = 87.5 * 16000; /* Initial freq range */
t->tv_freq = 400 * 16; /* Sets freq to VHF High - needed for some PLL's to properly start */
@@ -1260,7 +1260,9 @@ static int tuner_suspend(struct device *dev)
tuner_dbg("suspend\n");
- if (!t->standby && analog_ops->standby)
+ if (t->fe.ops.tuner_ops.suspend)
+ t->fe.ops.tuner_ops.suspend(&t->fe);
+ else if (!t->standby && analog_ops->standby)
analog_ops->standby(&t->fe);
return 0;
@@ -1273,7 +1275,9 @@ static int tuner_resume(struct device *dev)
tuner_dbg("resume\n");
- if (!t->standby)
+ if (t->fe.ops.tuner_ops.resume)
+ t->fe.ops.tuner_ops.resume(&t->fe);
+ else if (!t->standby)
if (set_mode(t, t->mode) == 0)
set_freq(t, 0);
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index ccaa38f..2e9d81f 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -435,16 +435,13 @@ static unsigned int clamp_align(unsigned int x, unsigned int min,
/* Bits that must be zero to be aligned */
unsigned int mask = ~((1 << align) - 1);
+ /* Clamp to aligned min and max */
+ x = clamp(x, (min + ~mask) & mask, max & mask);
+
/* Round to nearest aligned value */
if (align)
x = (x + (1 << (align - 1))) & mask;
- /* Clamp to aligned value of min and max */
- if (x < min)
- x = (min + ~mask) & mask;
- else if (x > max)
- x = max & mask;
-
return x;
}
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index cca6c2f..e502a5f 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -328,7 +328,7 @@ struct v4l2_buffer32 {
__u32 reserved;
};
-static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32,
+static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
enum v4l2_memory memory)
{
void __user *up_pln;
@@ -357,7 +357,7 @@ static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32,
return 0;
}
-static int put_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32,
+static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
enum v4l2_memory memory)
{
if (copy_in_user(up32, up, 2 * sizeof(__u32)) ||
@@ -427,7 +427,7 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
* by passing a very big num_planes value */
uplane = compat_alloc_user_space(num_planes *
sizeof(struct v4l2_plane));
- kp->m.planes = uplane;
+ kp->m.planes = (__force struct v4l2_plane *)uplane;
while (--num_planes >= 0) {
ret = get_v4l2_plane32(uplane, uplane32, kp->memory);
@@ -498,7 +498,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
if (num_planes == 0)
return 0;
- uplane = kp->m.planes;
+ uplane = (__force struct v4l2_plane __user *)kp->m.planes;
if (get_user(p, &up->m.planes))
return -EFAULT;
uplane32 = compat_ptr(p);
@@ -562,7 +562,7 @@ static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_frame
get_user(kp->flags, &up->flags) ||
copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt)))
return -EFAULT;
- kp->base = compat_ptr(tmp);
+ kp->base = (__force void *)compat_ptr(tmp);
return 0;
}
@@ -667,11 +667,15 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
n * sizeof(struct v4l2_ext_control32)))
return -EFAULT;
kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
- kp->controls = kcontrols;
+ kp->controls = (__force struct v4l2_ext_control *)kcontrols;
while (--n >= 0) {
+ u32 id;
+
if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols)))
return -EFAULT;
- if (ctrl_is_pointer(kcontrols->id)) {
+ if (get_user(id, &kcontrols->id))
+ return -EFAULT;
+ if (ctrl_is_pointer(id)) {
void __user *s;
if (get_user(p, &ucontrols->string))
@@ -689,7 +693,8 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
{
struct v4l2_ext_control32 __user *ucontrols;
- struct v4l2_ext_control __user *kcontrols = kp->controls;
+ struct v4l2_ext_control __user *kcontrols =
+ (__force struct v4l2_ext_control __user *)kp->controls;
int n = kp->count;
compat_caddr_t p;
@@ -711,11 +716,14 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
while (--n >= 0) {
unsigned size = sizeof(*ucontrols);
+ u32 id;
+ if (get_user(id, &kcontrols->id))
+ return -EFAULT;
/* Do not modify the pointer when copying a pointer control.
The contents of the pointer was changed, not the pointer
itself. */
- if (ctrl_is_pointer(kcontrols->id))
+ if (ctrl_is_pointer(id))
size -= sizeof(ucontrols->value64);
if (copy_in_user(ucontrols, kcontrols, size))
return -EFAULT;
@@ -770,7 +778,7 @@ static int get_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
get_user(tmp, &up->edid) ||
copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
return -EFAULT;
- kp->edid = compat_ptr(tmp);
+ kp->edid = (__force u8 *)compat_ptr(tmp);
return 0;
}
@@ -783,7 +791,7 @@ static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
put_user(kp->start_block, &up->start_block) ||
put_user(kp->blocks, &up->blocks) ||
put_user(tmp, &up->edid) ||
- copy_to_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
+ copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
return -EFAULT;
return 0;
}
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index f030d6a..8601214 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -796,6 +796,8 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_AUTO_FOCUS_STOP: return "Auto Focus, Stop";
case V4L2_CID_AUTO_FOCUS_STATUS: return "Auto Focus, Status";
case V4L2_CID_AUTO_FOCUS_RANGE: return "Auto Focus, Range";
+ case V4L2_CID_PAN_SPEED: return "Pan, Speed";
+ case V4L2_CID_TILT_SPEED: return "Tilt, Speed";
/* FM Radio Modulator controls */
/* Keep the order of the 'case's the same as in v4l2-controls.h! */
@@ -859,6 +861,10 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_VBLANK: return "Vertical Blanking";
case V4L2_CID_HBLANK: return "Horizontal Blanking";
case V4L2_CID_ANALOGUE_GAIN: return "Analogue Gain";
+ case V4L2_CID_TEST_PATTERN_RED: return "Red Pixel Value";
+ case V4L2_CID_TEST_PATTERN_GREENR: return "Green (Red) Pixel Value";
+ case V4L2_CID_TEST_PATTERN_BLUE: return "Blue Pixel Value";
+ case V4L2_CID_TEST_PATTERN_GREENB: return "Green (Blue) Pixel Value";
/* Image processing controls */
/* Keep the order of the 'case's the same as in v4l2-controls.h! */
diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c
index ce1c9f5..b1d8dbb 100644
--- a/drivers/media/v4l2-core/v4l2-dv-timings.c
+++ b/drivers/media/v4l2-core/v4l2-dv-timings.c
@@ -164,7 +164,8 @@ bool v4l2_valid_dv_timings(const struct v4l2_dv_timings *t,
bt->width > cap->max_width ||
bt->pixelclock < cap->min_pixelclock ||
bt->pixelclock > cap->max_pixelclock ||
- (cap->standards && !(bt->standards & cap->standards)) ||
+ (cap->standards && bt->standards &&
+ !(bt->standards & cap->standards)) ||
(bt->interlaced && !(caps & V4L2_DV_BT_CAP_INTERLACED)) ||
(!bt->interlaced && !(caps & V4L2_DV_BT_CAP_PROGRESSIVE)))
return false;
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index d15e1673..9ccb19a 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -562,7 +562,7 @@ static void v4l_print_ext_controls(const void *arg, bool write_only)
pr_cont("class=0x%x, count=%d, error_idx=%d",
p->ctrl_class, p->count, p->error_idx);
for (i = 0; i < p->count; i++) {
- if (p->controls[i].size)
+ if (!p->controls[i].size)
pr_cont(", id/val=0x%x/0x%x",
p->controls[i].id, p->controls[i].value);
else
@@ -1153,9 +1153,9 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
switch (p->type) {
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: {
- struct v4l2_clip *clips = p->fmt.win.clips;
+ struct v4l2_clip __user *clips = p->fmt.win.clips;
u32 clipcount = p->fmt.win.clipcount;
- void *bitmap = p->fmt.win.bitmap;
+ void __user *bitmap = p->fmt.win.bitmap;
memset(&p->fmt, 0, sizeof(p->fmt));
p->fmt.win.clips = clips;
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index b4d235c..543631c 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -501,11 +501,20 @@ int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
struct v4l2_subdev_format *source_fmt,
struct v4l2_subdev_format *sink_fmt)
{
+ /* The width, height and code must match. */
if (source_fmt->format.width != sink_fmt->format.width
|| source_fmt->format.height != sink_fmt->format.height
|| source_fmt->format.code != sink_fmt->format.code)
return -EINVAL;
+ /* The field order must match, or the sink field order must be NONE
+ * to support interlaced hardware connected to bridges that support
+ * progressive formats only.
+ */
+ if (source_fmt->format.field != sink_fmt->format.field &&
+ sink_fmt->format.field != V4L2_FIELD_NONE)
+ return -EINVAL;
+
return 0;
}
EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate_default);
diff --git a/drivers/media/v4l2-core/videobuf-core.c b/drivers/media/v4l2-core/videobuf-core.c
index fb5ee5d..b91a266 100644
--- a/drivers/media/v4l2-core/videobuf-core.c
+++ b/drivers/media/v4l2-core/videobuf-core.c
@@ -441,11 +441,6 @@ int videobuf_reqbufs(struct videobuf_queue *q,
unsigned int size, count;
int retval;
- if (req->count < 1) {
- dprintk(1, "reqbufs: count invalid (%d)\n", req->count);
- return -EINVAL;
- }
-
if (req->memory != V4L2_MEMORY_MMAP &&
req->memory != V4L2_MEMORY_USERPTR &&
req->memory != V4L2_MEMORY_OVERLAY) {
@@ -471,6 +466,12 @@ int videobuf_reqbufs(struct videobuf_queue *q,
goto done;
}
+ if (req->count == 0) {
+ dprintk(1, "reqbufs: count invalid (%d)\n", req->count);
+ retval = __videobuf_free(q);
+ goto done;
+ }
+
count = req->count;
if (count > VIDEO_MAX_FRAME)
count = VIDEO_MAX_FRAME;
diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c
index 3c8cc02..3ff15f1 100644
--- a/drivers/media/v4l2-core/videobuf-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf-dma-sg.c
@@ -253,9 +253,11 @@ int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction,
return 0;
out_free_pages:
while (i > 0) {
- void *addr = page_address(dma->vaddr_pages[i]);
- dma_free_coherent(dma->dev, PAGE_SIZE, addr, dma->dma_addr[i]);
+ void *addr;
+
i--;
+ addr = page_address(dma->vaddr_pages[i]);
+ dma_free_coherent(dma->dev, PAGE_SIZE, addr, dma->dma_addr[i]);
}
kfree(dma->dma_addr);
dma->dma_addr = NULL;
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
index 25d3ae2..f2e43de 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -36,7 +36,7 @@ module_param(debug, int, 0644);
#define dprintk(level, fmt, arg...) \
do { \
if (debug >= level) \
- pr_debug("vb2: %s: " fmt, __func__, ## arg); \
+ pr_info("vb2: %s: " fmt, __func__, ## arg); \
} while (0)
#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -882,7 +882,9 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
* We already have buffers allocated, so first check if they
* are not in use and can be freed.
*/
+ mutex_lock(&q->mmap_lock);
if (q->memory == V4L2_MEMORY_MMAP && __buffers_in_use(q)) {
+ mutex_unlock(&q->mmap_lock);
dprintk(1, "memory in use, cannot free\n");
return -EBUSY;
}
@@ -894,6 +896,7 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
*/
__vb2_queue_cancel(q);
ret = __vb2_queue_free(q, q->num_buffers);
+ mutex_unlock(&q->mmap_lock);
if (ret)
return ret;
@@ -955,6 +958,7 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
*/
}
+ mutex_lock(&q->mmap_lock);
q->num_buffers = allocated_buffers;
if (ret < 0) {
@@ -963,8 +967,10 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
* from q->num_buffers.
*/
__vb2_queue_free(q, allocated_buffers);
+ mutex_unlock(&q->mmap_lock);
return ret;
}
+ mutex_unlock(&q->mmap_lock);
/*
* Return the number of successfully allocated buffers
@@ -1063,6 +1069,7 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create
*/
}
+ mutex_lock(&q->mmap_lock);
q->num_buffers += allocated_buffers;
if (ret < 0) {
@@ -1071,8 +1078,10 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create
* from q->num_buffers.
*/
__vb2_queue_free(q, allocated_buffers);
+ mutex_unlock(&q->mmap_lock);
return -ENOMEM;
}
+ mutex_unlock(&q->mmap_lock);
/*
* Return the number of successfully allocated buffers
@@ -1581,7 +1590,6 @@ static void __enqueue_in_driver(struct vb2_buffer *vb)
static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
{
struct vb2_queue *q = vb->vb2_queue;
- struct rw_semaphore *mmap_sem;
int ret;
ret = __verify_length(vb, b);
@@ -1618,26 +1626,9 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
ret = __qbuf_mmap(vb, b);
break;
case V4L2_MEMORY_USERPTR:
- /*
- * In case of user pointer buffers vb2 allocators need to get
- * direct access to userspace pages. This requires getting
- * the mmap semaphore for read access in the current process
- * structure. The same semaphore is taken before calling mmap
- * operation, while both qbuf/prepare_buf and mmap are called
- * by the driver or v4l2 core with the driver's lock held.
- * To avoid an AB-BA deadlock (mmap_sem then driver's lock in
- * mmap and driver's lock then mmap_sem in qbuf/prepare_buf),
- * the videobuf2 core releases the driver's lock, takes
- * mmap_sem and then takes the driver's lock again.
- */
- mmap_sem = &current->mm->mmap_sem;
- call_void_qop(q, wait_prepare, q);
- down_read(mmap_sem);
- call_void_qop(q, wait_finish, q);
-
+ down_read(&current->mm->mmap_sem);
ret = __qbuf_userptr(vb, b);
-
- up_read(mmap_sem);
+ up_read(&current->mm->mmap_sem);
break;
case V4L2_MEMORY_DMABUF:
ret = __qbuf_dmabuf(vb, b);
@@ -2504,7 +2495,9 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
return -EINVAL;
}
+ mutex_lock(&q->mmap_lock);
ret = call_memop(vb, mmap, vb->planes[plane].mem_priv, vma);
+ mutex_unlock(&q->mmap_lock);
if (ret)
return ret;
@@ -2523,6 +2516,7 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
unsigned long off = pgoff << PAGE_SHIFT;
struct vb2_buffer *vb;
unsigned int buffer, plane;
+ void *vaddr;
int ret;
if (q->memory != V4L2_MEMORY_MMAP) {
@@ -2539,7 +2533,8 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
vb = q->bufs[buffer];
- return (unsigned long)vb2_plane_vaddr(vb, plane);
+ vaddr = vb2_plane_vaddr(vb, plane);
+ return vaddr ? (unsigned long)vaddr : -EINVAL;
}
EXPORT_SYMBOL_GPL(vb2_get_unmapped_area);
#endif
@@ -2686,6 +2681,7 @@ int vb2_queue_init(struct vb2_queue *q)
INIT_LIST_HEAD(&q->queued_list);
INIT_LIST_HEAD(&q->done_list);
spin_lock_init(&q->done_lock);
+ mutex_init(&q->mmap_lock);
init_waitqueue_head(&q->done_wq);
if (q->buf_struct_size == 0)
@@ -2707,7 +2703,9 @@ void vb2_queue_release(struct vb2_queue *q)
{
__vb2_cleanup_fileio(q);
__vb2_queue_cancel(q);
+ mutex_lock(&q->mmap_lock);
__vb2_queue_free(q, q->num_buffers);
+ mutex_unlock(&q->mmap_lock);
}
EXPORT_SYMBOL_GPL(vb2_queue_release);
@@ -2985,6 +2983,12 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
buf->queued = 0;
buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0)
: vb2_plane_size(q->bufs[index], 0);
+ /* Compensate for data_offset on read in the multiplanar case. */
+ if (is_multiplanar && read &&
+ fileio->b.m.planes[0].data_offset < buf->size) {
+ buf->pos = fileio->b.m.planes[0].data_offset;
+ buf->size -= buf->pos;
+ }
} else {
buf = &fileio->bufs[index];
}
@@ -3372,15 +3376,8 @@ EXPORT_SYMBOL_GPL(vb2_ioctl_expbuf);
int vb2_fop_mmap(struct file *file, struct vm_area_struct *vma)
{
struct video_device *vdev = video_devdata(file);
- struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock;
- int err;
- if (lock && mutex_lock_interruptible(lock))
- return -ERESTARTSYS;
- err = vb2_mmap(vdev->queue, vma);
- if (lock)
- mutex_unlock(lock);
- return err;
+ return vb2_mmap(vdev->queue, vma);
}
EXPORT_SYMBOL_GPL(vb2_fop_mmap);
@@ -3499,15 +3496,8 @@ unsigned long vb2_fop_get_unmapped_area(struct file *file, unsigned long addr,
unsigned long len, unsigned long pgoff, unsigned long flags)
{
struct video_device *vdev = video_devdata(file);
- struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock;
- int ret;
- if (lock && mutex_lock_interruptible(lock))
- return -ERESTARTSYS;
- ret = vb2_get_unmapped_area(vdev->queue, addr, len, pgoff, flags);
- if (lock)
- mutex_unlock(lock);
- return ret;
+ return vb2_get_unmapped_area(vdev->queue, addr, len, pgoff, flags);
}
EXPORT_SYMBOL_GPL(vb2_fop_get_unmapped_area);
#endif

Privacy Policy