From 076025d4e103147cbc6a8ad177824e15ff0143d9 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Tue, 3 Mar 2009 15:44:45 -0800 Subject: v4l2: Move code to zero querybuf output struct to v4l2_ioctl From: Trent Piepho For VIDIOC_QUERYBUF only the first two fields, size and type, are used as input. The rest can be filled in by the driver as output. Most drivers do not actually use all the field and unused ones should be zeroed out. Some drivers have code to do this and some drivers should but don't. So put some zero out code in v4l2_ioctl so that all drivers using that system get it. The drivers that have zeroing code get that code removed. Some drivers checked that the type field was valid, but v4l2_ioctl already does this so those checks can be removed as well. Priority: normal Signed-off-by: Trent Piepho --- linux/drivers/media/video/v4l2-ioctl.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'linux/drivers/media/video/v4l2-ioctl.c') diff --git a/linux/drivers/media/video/v4l2-ioctl.c b/linux/drivers/media/video/v4l2-ioctl.c index ec139df5c..f2d74fedf 100644 --- a/linux/drivers/media/video/v4l2-ioctl.c +++ b/linux/drivers/media/video/v4l2-ioctl.c @@ -970,6 +970,11 @@ static long __video_do_ioctl(struct file *file, if (ret) break; + /* Zero out all fields starting with bytesysed, which is + * everything but index and type. */ + memset(0, &p->bytesused, + sizeof(*p) - offsetof(typeof(*p), bytesused)); + ret = ops->vidioc_querybuf(file, fh, p); if (!ret) dbgbuf(cmd, vfd, p); -- cgit v1.2.3 From 4f05fe5a173aafe4fd81efaa5a3288f2ab482ca1 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Tue, 3 Mar 2009 20:21:02 -0800 Subject: videodev: only copy needed part of RW ioctl's parameter From: Trent Piepho There are many RW ioctls() in v4l2 where userspace only supplies one or two of the first fields in the structure passed to the ioctl. The driver then fills in the rest of the fields. Instead of copying the entire structure from userspace to the kernel we only need to copy those fields that userspace is actually supposed to supply. What's more, the fields that are meant to be only be output from the driver can be zeroed out in the videodev code, in case the driver doesn't fill them all in. Many of the ioctl handlers in v4l2_ioctl do this already, but my patch does this at one common point and so all the memsets for each ioctl can be deleted. For VIDIOC_G_SLICED_VBI_CAP, which has one input field ('type') and other output-only fields, the input field is near the end of the structure instead of at the beginning. So there is still a memset in it's ioctl handler to zero out the beginning of the struct. There were a couple mistakes with the existing code: For VIDIOC_G_AUDIO the index field was preserved, but G_AUDIO is a read only ioctl so nothing is copied from userspace to preserve. For VIDIOC_G_FREQUENCY the tuner field was not preserved like it should have been. This would be a problem if there was any hardware with more than one tuner/modulator. For VIDIOC_ENUM_FRAMESIZES and VIDIOC_ENUM_FRAMEINTERVALS, none of the fields were preserved even though each ioctl has several field that are supposed to be inputs to the driver! Obviously these ioctls don't get used much. The index field is needed if the driver has multiple discrete sizes/rates and other fields can be used too, e.g. if the size depends on pixel format or frame rate depends on image size for example. Priority: normal Signed-off-by: Trent Piepho --- linux/drivers/media/video/v4l2-ioctl.c | 107 ++++++++++++++++----------------- 1 file changed, 52 insertions(+), 55 deletions(-) (limited to 'linux/drivers/media/video/v4l2-ioctl.c') diff --git a/linux/drivers/media/video/v4l2-ioctl.c b/linux/drivers/media/video/v4l2-ioctl.c index f2d74fedf..71e7633b5 100644 --- a/linux/drivers/media/video/v4l2-ioctl.c +++ b/linux/drivers/media/video/v4l2-ioctl.c @@ -727,16 +727,8 @@ static long __video_do_ioctl(struct file *file, case VIDIOC_ENUM_FMT: { struct v4l2_fmtdesc *f = arg; - enum v4l2_buf_type type; - unsigned int index; - index = f->index; - type = f->type; - memset(f, 0, sizeof(*f)); - f->index = index; - f->type = type; - - switch (type) { + switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: if (ops->vidioc_enum_fmt_vid_cap) ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f); @@ -773,8 +765,6 @@ static long __video_do_ioctl(struct file *file, { struct v4l2_format *f = (struct v4l2_format *)arg; - memset(f->fmt.raw_data, 0, sizeof(f->fmt.raw_data)); - /* FIXME: Should be one dump per type */ dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names)); @@ -970,11 +960,6 @@ static long __video_do_ioctl(struct file *file, if (ret) break; - /* Zero out all fields starting with bytesysed, which is - * everything but index and type. */ - memset(0, &p->bytesused, - sizeof(*p) - offsetof(typeof(*p), bytesused)); - ret = ops->vidioc_querybuf(file, fh, p); if (!ret) dbgbuf(cmd, vfd, p); @@ -1160,12 +1145,9 @@ static long __video_do_ioctl(struct file *file, case VIDIOC_ENUMINPUT: { struct v4l2_input *p = arg; - int i = p->index; if (!ops->vidioc_enum_input) break; - memset(p, 0, sizeof(*p)); - p->index = i; ret = ops->vidioc_enum_input(file, fh, p); if (!ret) @@ -1204,12 +1186,9 @@ static long __video_do_ioctl(struct file *file, case VIDIOC_ENUMOUTPUT: { struct v4l2_output *p = arg; - int i = p->index; if (!ops->vidioc_enum_output) break; - memset(p, 0, sizeof(*p)); - p->index = i; ret = ops->vidioc_enum_output(file, fh, p); if (!ret) @@ -1385,13 +1364,11 @@ static long __video_do_ioctl(struct file *file, case VIDIOC_G_AUDIO: { struct v4l2_audio *p = arg; - __u32 index = p->index; if (!ops->vidioc_g_audio) break; memset(p, 0, sizeof(*p)); - p->index = index; ret = ops->vidioc_g_audio(file, fh, p); if (!ret) dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " @@ -1486,15 +1463,10 @@ static long __video_do_ioctl(struct file *file, case VIDIOC_G_CROP: { struct v4l2_crop *p = arg; - __u32 type; if (!ops->vidioc_g_crop) break; - type = p->type; - memset(p, 0, sizeof(*p)); - p->type = type; - dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); ret = ops->vidioc_g_crop(file, fh, p); if (!ret) @@ -1515,16 +1487,11 @@ static long __video_do_ioctl(struct file *file, case VIDIOC_CROPCAP: { struct v4l2_cropcap *p = arg; - __u32 type; /*FIXME: Should also show v4l2_fract pixelaspect */ if (!ops->vidioc_cropcap) break; - type = p->type; - memset(p, 0, sizeof(*p)); - p->type = type; - dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); ret = ops->vidioc_cropcap(file, fh, p); if (!ret) { @@ -1582,7 +1549,6 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_encoder_cmd) break; - memset(&p->raw, 0, sizeof(p->raw)); ret = ops->vidioc_encoder_cmd(file, fh, p); if (!ret) dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); @@ -1594,7 +1560,6 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_try_encoder_cmd) break; - memset(&p->raw, 0, sizeof(p->raw)); ret = ops->vidioc_try_encoder_cmd(file, fh, p); if (!ret) dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); @@ -1603,10 +1568,6 @@ static long __video_do_ioctl(struct file *file, case VIDIOC_G_PARM: { struct v4l2_streamparm *p = arg; - __u32 type = p->type; - - memset(p, 0, sizeof(*p)); - p->type = type; if (ops->vidioc_g_parm) { ret = ops->vidioc_g_parm(file, fh, p); @@ -1639,14 +1600,10 @@ static long __video_do_ioctl(struct file *file, case VIDIOC_G_TUNER: { struct v4l2_tuner *p = arg; - __u32 index = p->index; if (!ops->vidioc_g_tuner) break; - memset(p, 0, sizeof(*p)); - p->index = index; - ret = ops->vidioc_g_tuner(file, fh, p); if (!ret) dbgarg(cmd, "index=%d, name=%s, type=%d, " @@ -1683,8 +1640,6 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_g_frequency) break; - memset(p->reserved, 0, sizeof(p->reserved)); - ret = ops->vidioc_g_frequency(file, fh, p); if (!ret) dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n", @@ -1705,12 +1660,13 @@ static long __video_do_ioctl(struct file *file, case VIDIOC_G_SLICED_VBI_CAP: { struct v4l2_sliced_vbi_cap *p = arg; - __u32 type = p->type; if (!ops->vidioc_g_sliced_vbi_cap) break; - memset(p, 0, sizeof(*p)); - p->type = type; + + /* Clear up to type, everything after type is zerod already */ + memset(p, 0, offsetof(struct v4l2_sliced_vbi_cap, type)); + dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); ret = ops->vidioc_g_sliced_vbi_cap(file, fh, p); if (!ret) @@ -1783,8 +1739,6 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_enum_framesizes) break; - memset(p, 0, sizeof(*p)); - ret = ops->vidioc_enum_framesizes(file, fh, p); dbgarg(cmd, "index=%d, pixelformat=%d, type=%d ", @@ -1816,8 +1770,6 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_enum_frameintervals) break; - memset(p, 0, sizeof(*p)); - ret = ops->vidioc_enum_frameintervals(file, fh, p); dbgarg(cmd, "index=%d, pixelformat=%d, width=%d, height=%d, type=%d ", @@ -1866,6 +1818,44 @@ static long __video_do_ioctl(struct file *file, return ret; } +/* In some cases, only a few fields are used as input, i.e. when the app sets + * "index" and then the driver fills in the rest of the structure for the thing + * with that index. We only need to copy up the first non-input field. */ +static unsigned long cmd_input_size(unsigned int cmd) +{ + /* Size of structure up to and including 'field' */ +#define CMDINSIZE(cmd, type, field) case _IOC_NR(VIDIOC_##cmd): return \ + offsetof(struct v4l2_##type, field) + \ + sizeof(((struct v4l2_##type *)0)->field); + + switch (_IOC_NR(cmd)) { + CMDINSIZE(ENUM_FMT, fmtdesc, type); + CMDINSIZE(G_FMT, format, type); + CMDINSIZE(QUERYBUF, buffer, type); + CMDINSIZE(G_PARM, streamparm, type); + CMDINSIZE(ENUMSTD, standard, index); + CMDINSIZE(ENUMINPUT, input, index); + CMDINSIZE(G_CTRL, control, id); + CMDINSIZE(G_TUNER, tuner, index); + CMDINSIZE(QUERYCTRL, queryctrl, id); + CMDINSIZE(QUERYMENU, querymenu, index); + CMDINSIZE(ENUMOUTPUT, output, index); + CMDINSIZE(G_MODULATOR, modulator, index); + CMDINSIZE(G_FREQUENCY, frequency, tuner); + CMDINSIZE(CROPCAP, cropcap, type); + CMDINSIZE(G_CROP, crop, type); + CMDINSIZE(ENUMAUDIO, audio, index); + CMDINSIZE(ENUMAUDOUT, audioout, index); + CMDINSIZE(ENCODER_CMD, encoder_cmd, flags); + CMDINSIZE(TRY_ENCODER_CMD, encoder_cmd, flags); + CMDINSIZE(G_SLICED_VBI_CAP, sliced_vbi_cap, type); + CMDINSIZE(ENUM_FRAMESIZES, frmsizeenum, pixel_format); + CMDINSIZE(ENUM_FRAMEINTERVALS, frmivalenum, height); + default: + return _IOC_SIZE(cmd); + } +} + long video_ioctl2(struct file *file, unsigned int cmd, unsigned long arg) { @@ -1902,9 +1892,16 @@ long video_ioctl2(struct file *file, } err = -EFAULT; - if (_IOC_DIR(cmd) & _IOC_WRITE) - if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) + if (_IOC_DIR(cmd) & _IOC_WRITE) { + unsigned long n = cmd_input_size(cmd); + + if (copy_from_user(parg, (void __user *)arg, n)) goto out; + + /* zero out anything we don't copy from userspace */ + if (n < _IOC_SIZE(cmd)) + memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n); + } break; } -- cgit v1.2.3 From f848a016635d7ec5b7624ef9235b5a39ca0afee7 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Tue, 3 Mar 2009 20:21:02 -0800 Subject: v4l2: Zero out read-only ioctls in one place From: Trent Piepho If an ioctl is read-only then the driver fills in all the fields. Lots of times drivers only care about some fields so it's best if video_ioctl2 takes care of zeroing out the entire structure before handing it to the driver. This saves code in each driver to do it and driver authors often forget. The existing memset code in some of the read-only ioctl handlers can be deleted. Convert a case statement to a single if statement. Deleted a debug line from ENUMAUDOUT that was copy-and-pasted to G_AUDOUT by mistake. Priority: normal Signed-off-by: Trent Piepho --- linux/drivers/media/video/v4l2-ioctl.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) (limited to 'linux/drivers/media/video/v4l2-ioctl.c') diff --git a/linux/drivers/media/video/v4l2-ioctl.c b/linux/drivers/media/video/v4l2-ioctl.c index 71e7633b5..90a58523b 100644 --- a/linux/drivers/media/video/v4l2-ioctl.c +++ b/linux/drivers/media/video/v4l2-ioctl.c @@ -656,8 +656,6 @@ static long __video_do_ioctl(struct file *file, if (cmd == VIDIOCGMBUF) { struct video_mbuf *p = arg; - memset(p, 0, sizeof(*p)); - if (!ops->vidiocgmbuf) return ret; ret = ops->vidiocgmbuf(file, fh, p); @@ -684,7 +682,6 @@ static long __video_do_ioctl(struct file *file, case VIDIOC_QUERYCAP: { struct v4l2_capability *cap = (struct v4l2_capability *)arg; - memset(cap, 0, sizeof(*cap)); if (!ops->vidioc_querycap) break; @@ -1368,7 +1365,6 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_g_audio) break; - memset(p, 0, sizeof(*p)); ret = ops->vidioc_g_audio(file, fh, p); if (!ret) dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " @@ -1410,7 +1406,7 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_g_audout) break; - dbgarg(cmd, "Enum for index=%d\n", p->index); + ret = ops->vidioc_g_audout(file, fh, p); if (!ret) dbgarg2("index=%d, name=%s, capability=%d, " @@ -1507,8 +1503,6 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_g_jpegcomp) break; - memset(p, 0, sizeof(*p)); - ret = ops->vidioc_g_jpegcomp(file, fh, p); if (!ret) dbgarg(cmd, "quality=%d, APPn=%d, " @@ -1874,13 +1868,7 @@ long video_ioctl2(struct file *file, cmd == VIDIOC_TRY_EXT_CTRLS); /* Copy arguments into temp kernel buffer */ - switch (_IOC_DIR(cmd)) { - case _IOC_NONE: - parg = NULL; - break; - case _IOC_READ: - case _IOC_WRITE: - case (_IOC_WRITE | _IOC_READ): + if (_IOC_DIR(cmd) != _IOC_NONE) { if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { parg = sbuf; } else { @@ -1901,8 +1889,10 @@ long video_ioctl2(struct file *file, /* zero out anything we don't copy from userspace */ if (n < _IOC_SIZE(cmd)) memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n); + } else { + /* read-only ioctl */ + memset(parg, 0, _IOC_SIZE(cmd)); } - break; } if (is_ext_ctrl) { -- cgit v1.2.3 From 524c72c90e185f6d07719ce31db5507dcf6bf85c Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Tue, 3 Mar 2009 20:21:02 -0800 Subject: v4l2: New function v4l2_video_std_frame_period From: Trent Piepho Some code was calling v4l2_video_std_construct() when all it cared about was the frame period. So make a function that just returns that and have v4l2_video_std_construct() use it. At this point there are no users of v4l2_video_std_construct() left outside of v4l2-ioctl, so it could be un-exported and made static. Change v4l2_video_std_construct() so that it doesn't zero out the struct v4l2_standard passed in. It's already been zeroed out in the common ioctl code. Priority: normal Signed-off-by: Trent Piepho --- linux/drivers/media/video/v4l2-ioctl.c | 39 ++++++++++++++++------------------ 1 file changed, 18 insertions(+), 21 deletions(-) (limited to 'linux/drivers/media/video/v4l2-ioctl.c') diff --git a/linux/drivers/media/video/v4l2-ioctl.c b/linux/drivers/media/video/v4l2-ioctl.c index 90a58523b..e079a343a 100644 --- a/linux/drivers/media/video/v4l2-ioctl.c +++ b/linux/drivers/media/video/v4l2-ioctl.c @@ -102,25 +102,27 @@ const char *v4l2_norm_to_name(v4l2_std_id id) } EXPORT_SYMBOL(v4l2_norm_to_name); +/* Returns frame period for the given standard */ +void v4l2_video_std_frame_period(int id, struct v4l2_fract *frameperiod) +{ + if (id & V4L2_STD_525_60) { + frameperiod->numerator = 1001; + frameperiod->denominator = 30000; + } else { + frameperiod->numerator = 1; + frameperiod->denominator = 25; + } +} +EXPORT_SYMBOL(v4l2_video_std_frame_period); + /* Fill in the fields of a v4l2_standard structure according to the 'id' and 'transmission' parameters. Returns negative on error. */ int v4l2_video_std_construct(struct v4l2_standard *vs, int id, const char *name) { - u32 index = vs->index; - - memset(vs, 0, sizeof(struct v4l2_standard)); - vs->index = index; - vs->id = id; - if (id & V4L2_STD_525_60) { - vs->frameperiod.numerator = 1001; - vs->frameperiod.denominator = 30000; - vs->framelines = 525; - } else { - vs->frameperiod.numerator = 1; - vs->frameperiod.denominator = 25; - vs->framelines = 625; - } + vs->id = id; + v4l2_video_std_frame_period(id, &vs->frameperiod); + vs->framelines = (id & V4L2_STD_525_60) ? 525 : 625; strlcpy(vs->name, name, sizeof(vs->name)); return 0; } @@ -1077,7 +1079,6 @@ static long __video_do_ioctl(struct file *file, return -EINVAL; v4l2_video_std_construct(p, curr_id, descr); - p->index = index; dbgarg(cmd, "index=%d, id=0x%Lx, name=%s, fps=%d/%d, " "framelines=%d\n", p->index, @@ -1566,15 +1567,11 @@ static long __video_do_ioctl(struct file *file, if (ops->vidioc_g_parm) { ret = ops->vidioc_g_parm(file, fh, p); } else { - struct v4l2_standard s; - if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - v4l2_video_std_construct(&s, vfd->current_norm, - v4l2_norm_to_name(vfd->current_norm)); - - p->parm.capture.timeperframe = s.frameperiod; + v4l2_video_std_frame_period(vfd->current_norm, + &p->parm.capture.timeperframe); ret = 0; } -- cgit v1.2.3 From b3e737a176ce96bee38fb7d0ee5cf6def9da8ad1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 9 Mar 2009 22:16:42 -0300 Subject: v4l2-ioctl: get rid of video_decoder.h From: Mauro Carvalho Chehab The V4L1 obsoleted header video_decoder.h is not used anymore by any driver. Only a name decoding function at v4l2-ioctl still implements it. Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/v4l2-ioctl.c | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'linux/drivers/media/video/v4l2-ioctl.c') diff --git a/linux/drivers/media/video/v4l2-ioctl.c b/linux/drivers/media/video/v4l2-ioctl.c index e079a343a..230299801 100644 --- a/linux/drivers/media/video/v4l2-ioctl.c +++ b/linux/drivers/media/video/v4l2-ioctl.c @@ -25,7 +25,6 @@ #include #include #include -#include #include "compat.h" #define dbgarg(cmd, fmt, arg...) \ @@ -277,19 +276,6 @@ static const char *v4l2_ioctls[] = { #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) static const char *v4l2_int_ioctls[] = { -#ifdef CONFIG_VIDEO_V4L1_COMPAT - [_IOC_NR(DECODER_GET_CAPABILITIES)] = "DECODER_GET_CAPABILITIES", - [_IOC_NR(DECODER_GET_STATUS)] = "DECODER_GET_STATUS", - [_IOC_NR(DECODER_SET_NORM)] = "DECODER_SET_NORM", - [_IOC_NR(DECODER_SET_INPUT)] = "DECODER_SET_INPUT", - [_IOC_NR(DECODER_SET_OUTPUT)] = "DECODER_SET_OUTPUT", - [_IOC_NR(DECODER_ENABLE_OUTPUT)] = "DECODER_ENABLE_OUTPUT", - [_IOC_NR(DECODER_SET_PICTURE)] = "DECODER_SET_PICTURE", - [_IOC_NR(DECODER_SET_GPIO)] = "DECODER_SET_GPIO", - [_IOC_NR(DECODER_INIT)] = "DECODER_INIT", - [_IOC_NR(DECODER_SET_VBI_BYPASS)] = "DECODER_SET_VBI_BYPASS", - [_IOC_NR(DECODER_DUMP)] = "DECODER_DUMP", -#endif [_IOC_NR(AUDC_SET_RADIO)] = "AUDC_SET_RADIO", [_IOC_NR(TUNER_SET_TYPE_ADDR)] = "TUNER_SET_TYPE_ADDR", -- cgit v1.2.3