From: Arnd Bergmann <arnd@arndb.de>
The adv7842 and si4713 drivers each define one private ioctl command that
are handled through the subdev_ioctl() helpers, but that don't work in
compat mode because this does not handle private ioctl commands.
The compat_ioctl32 callback for subdevs has outdated calling conventions,
but as there are no users of that, it is easy to change the function
pointer type and the caller to make it behave the same way as the normal
ioctl callback and hook in the two drivers that need no argument
conversion.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/media/i2c/adv7842.c | 3 +++
drivers/media/radio/si4713/si4713.c | 3 +++
drivers/media/v4l2-core/v4l2-subdev.c | 19 ++++++++++++++++---
include/media/v4l2-subdev.h | 3 +--
4 files changed, 23 insertions(+), 5 deletions(-)
@@ -3293,6 +3293,9 @@ static const struct v4l2_ctrl_ops adv7842_ctrl_ops = {
static const struct v4l2_subdev_core_ops adv7842_core_ops = {
.log_status = adv7842_log_status,
.ioctl = adv7842_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl32 = adv7842_ioctl,
+#endif
.interrupt_service_routine = adv7842_isr,
.subscribe_event = adv7842_subscribe_event,
.unsubscribe_event = v4l2_event_subdev_unsubscribe,
@@ -1398,6 +1398,9 @@ static const struct v4l2_ctrl_ops si4713_ctrl_ops = {
static const struct v4l2_subdev_core_ops si4713_subdev_core_ops = {
.ioctl = si4713_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl32 = si4713_ioctl,
+#endif
};
static const struct v4l2_subdev_tuner_ops si4713_subdev_tuner_ops = {
@@ -686,13 +686,26 @@ static long subdev_ioctl(struct file *file, unsigned int cmd,
}
#ifdef CONFIG_COMPAT
-static long subdev_compat_ioctl32(struct file *file, unsigned int cmd,
- unsigned long arg)
+static long subdev_do_compat_ioctl32(struct file *file, unsigned int cmd, void *arg)
{
struct video_device *vdev = video_devdata(file);
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+ struct mutex *lock = vdev->lock;
+ long ret = -ENODEV;
- return v4l2_subdev_call(sd, core, compat_ioctl32, cmd, arg);
+ if (lock && mutex_lock_interruptible(lock))
+ return -ERESTARTSYS;
+ if (video_is_registered(vdev))
+ ret = v4l2_subdev_call(sd, core, compat_ioctl32, cmd, arg);
+ if (lock)
+ mutex_unlock(lock);
+ return ret;
+}
+
+static long subdev_compat_ioctl32(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return video_usercopy(file, cmd, arg, subdev_do_compat_ioctl32);
}
#endif
@@ -195,8 +195,7 @@ struct v4l2_subdev_core_ops {
int (*s_gpio)(struct v4l2_subdev *sd, u32 val);
long (*ioctl)(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
#ifdef CONFIG_COMPAT
- long (*compat_ioctl32)(struct v4l2_subdev *sd, unsigned int cmd,
- unsigned long arg);
+ long (*compat_ioctl32)(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
#endif
#ifdef CONFIG_VIDEO_ADV_DEBUG
int (*g_register)(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg);