[media] v4l2-subdev: Allow 32-bit compat ioctls

Add support for 32-bit ioctls with v4l-subdev device nodes.

Rather than keep adding new ioctls to the list in v4l2-compat-ioctl32.c, just check
if the ioctl is a non-private V4L2 ioctl and if so, call the conversion code.

We keep forgetting to add new ioctls, so this is a more robust solution.

In addition extend the subdev API with support for a compat32 function to
convert custom v4l-subdev ioctls.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Tested-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
This commit is contained in:
Hans Verkuil 2014-02-10 08:08:44 -03:00 committed by Mauro Carvalho Chehab
parent ab3cacf6d9
commit ab58a30162
3 changed files with 24 additions and 95 deletions

View file

@ -1006,103 +1006,14 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
if (!file->f_op->unlocked_ioctl) if (!file->f_op->unlocked_ioctl)
return ret; return ret;
switch (cmd) { if (_IOC_TYPE(cmd) == 'V' && _IOC_NR(cmd) < BASE_VIDIOC_PRIVATE)
case VIDIOC_QUERYCAP:
case VIDIOC_RESERVED:
case VIDIOC_ENUM_FMT:
case VIDIOC_G_FMT32:
case VIDIOC_S_FMT32:
case VIDIOC_REQBUFS:
case VIDIOC_QUERYBUF32:
case VIDIOC_G_FBUF32:
case VIDIOC_S_FBUF32:
case VIDIOC_OVERLAY32:
case VIDIOC_QBUF32:
case VIDIOC_EXPBUF:
case VIDIOC_DQBUF32:
case VIDIOC_STREAMON32:
case VIDIOC_STREAMOFF32:
case VIDIOC_G_PARM:
case VIDIOC_S_PARM:
case VIDIOC_G_STD:
case VIDIOC_S_STD:
case VIDIOC_ENUMSTD32:
case VIDIOC_ENUMINPUT32:
case VIDIOC_G_CTRL:
case VIDIOC_S_CTRL:
case VIDIOC_G_TUNER:
case VIDIOC_S_TUNER:
case VIDIOC_G_AUDIO:
case VIDIOC_S_AUDIO:
case VIDIOC_QUERYCTRL:
case VIDIOC_QUERYMENU:
case VIDIOC_G_INPUT32:
case VIDIOC_S_INPUT32:
case VIDIOC_G_OUTPUT32:
case VIDIOC_S_OUTPUT32:
case VIDIOC_ENUMOUTPUT:
case VIDIOC_G_AUDOUT:
case VIDIOC_S_AUDOUT:
case VIDIOC_G_MODULATOR:
case VIDIOC_S_MODULATOR:
case VIDIOC_S_FREQUENCY:
case VIDIOC_G_FREQUENCY:
case VIDIOC_CROPCAP:
case VIDIOC_G_CROP:
case VIDIOC_S_CROP:
case VIDIOC_G_SELECTION:
case VIDIOC_S_SELECTION:
case VIDIOC_G_JPEGCOMP:
case VIDIOC_S_JPEGCOMP:
case VIDIOC_QUERYSTD:
case VIDIOC_TRY_FMT32:
case VIDIOC_ENUMAUDIO:
case VIDIOC_ENUMAUDOUT:
case VIDIOC_G_PRIORITY:
case VIDIOC_S_PRIORITY:
case VIDIOC_G_SLICED_VBI_CAP:
case VIDIOC_LOG_STATUS:
case VIDIOC_G_EXT_CTRLS32:
case VIDIOC_S_EXT_CTRLS32:
case VIDIOC_TRY_EXT_CTRLS32:
case VIDIOC_ENUM_FRAMESIZES:
case VIDIOC_ENUM_FRAMEINTERVALS:
case VIDIOC_G_ENC_INDEX:
case VIDIOC_ENCODER_CMD:
case VIDIOC_TRY_ENCODER_CMD:
case VIDIOC_DECODER_CMD:
case VIDIOC_TRY_DECODER_CMD:
case VIDIOC_DBG_S_REGISTER:
case VIDIOC_DBG_G_REGISTER:
case VIDIOC_S_HW_FREQ_SEEK:
case VIDIOC_S_DV_TIMINGS:
case VIDIOC_G_DV_TIMINGS:
case VIDIOC_DQEVENT:
case VIDIOC_DQEVENT32:
case VIDIOC_SUBSCRIBE_EVENT:
case VIDIOC_UNSUBSCRIBE_EVENT:
case VIDIOC_CREATE_BUFS32:
case VIDIOC_PREPARE_BUF32:
case VIDIOC_ENUM_DV_TIMINGS:
case VIDIOC_QUERY_DV_TIMINGS:
case VIDIOC_DV_TIMINGS_CAP:
case VIDIOC_ENUM_FREQ_BANDS:
case VIDIOC_SUBDEV_G_EDID32:
case VIDIOC_SUBDEV_S_EDID32:
ret = do_video_ioctl(file, cmd, arg); ret = do_video_ioctl(file, cmd, arg);
break; else if (vdev->fops->compat_ioctl32)
ret = vdev->fops->compat_ioctl32(file, cmd, arg);
default: if (ret == -ENOIOCTLCMD)
if (vdev->fops->compat_ioctl32) pr_warn("compat_ioctl32: unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
ret = vdev->fops->compat_ioctl32(file, cmd, arg); _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), cmd);
if (ret == -ENOIOCTLCMD)
printk(KERN_WARNING "compat_ioctl32: "
"unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
_IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd),
cmd);
break;
}
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(v4l2_compat_ioctl32); EXPORT_SYMBOL_GPL(v4l2_compat_ioctl32);

View file

@ -368,6 +368,17 @@ static long subdev_ioctl(struct file *file, unsigned int cmd,
return video_usercopy(file, cmd, arg, subdev_do_ioctl); return video_usercopy(file, cmd, arg, subdev_do_ioctl);
} }
#ifdef CONFIG_COMPAT
static long subdev_compat_ioctl32(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct video_device *vdev = video_devdata(file);
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
return v4l2_subdev_call(sd, core, compat_ioctl32, cmd, arg);
}
#endif
static unsigned int subdev_poll(struct file *file, poll_table *wait) static unsigned int subdev_poll(struct file *file, poll_table *wait)
{ {
struct video_device *vdev = video_devdata(file); struct video_device *vdev = video_devdata(file);
@ -389,6 +400,9 @@ const struct v4l2_file_operations v4l2_subdev_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = subdev_open, .open = subdev_open,
.unlocked_ioctl = subdev_ioctl, .unlocked_ioctl = subdev_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl32 = subdev_compat_ioctl32,
#endif
.release = subdev_close, .release = subdev_close,
.poll = subdev_poll, .poll = subdev_poll,
}; };

View file

@ -162,6 +162,10 @@ struct v4l2_subdev_core_ops {
int (*g_std)(struct v4l2_subdev *sd, v4l2_std_id *norm); int (*g_std)(struct v4l2_subdev *sd, v4l2_std_id *norm);
int (*s_std)(struct v4l2_subdev *sd, v4l2_std_id norm); int (*s_std)(struct v4l2_subdev *sd, v4l2_std_id norm);
long (*ioctl)(struct v4l2_subdev *sd, unsigned int cmd, void *arg); 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);
#endif
#ifdef CONFIG_VIDEO_ADV_DEBUG #ifdef CONFIG_VIDEO_ADV_DEBUG
int (*g_register)(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg); int (*g_register)(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg);
int (*s_register)(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg); int (*s_register)(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg);