aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2012-06-09 07:55:31 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-07-06 16:17:30 -0400
commit27cd2aba172dffb7819b9ca49a6a8acdbb8cf7e5 (patch)
treef72347600e5fe939bfd07462ea41ab38ffb1e1a4 /drivers
parent4839e6c2ac7c1a25d285b66240e702bb9b5fdcbf (diff)
[media] v4l2-ioctl.c: introduce INFO_FL_CLEAR to replace switch
The switch statement that determines how much data should be copied from userspace is replaced by a table lookup. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/video/v4l2-ioctl.c103
1 files changed, 41 insertions, 62 deletions
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 46fd95327630..e2f77bc15954 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -394,7 +394,7 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type)
394 394
395struct v4l2_ioctl_info { 395struct v4l2_ioctl_info {
396 unsigned int ioctl; 396 unsigned int ioctl;
397 u16 flags; 397 u32 flags;
398 const char * const name; 398 const char * const name;
399}; 399};
400 400
@@ -402,6 +402,11 @@ struct v4l2_ioctl_info {
402#define INFO_FL_PRIO (1 << 0) 402#define INFO_FL_PRIO (1 << 0)
403/* This control can be valid if the filehandle passes a control handler. */ 403/* This control can be valid if the filehandle passes a control handler. */
404#define INFO_FL_CTRL (1 << 1) 404#define INFO_FL_CTRL (1 << 1)
405/* Zero struct from after the field to the end */
406#define INFO_FL_CLEAR(v4l2_struct, field) \
407 ((offsetof(struct v4l2_struct, field) + \
408 sizeof(((struct v4l2_struct *)0)->field)) << 16)
409#define INFO_FL_CLEAR_MASK (_IOC_SIZEMASK << 16)
405 410
406#define IOCTL_INFO(_ioctl, _flags) [_IOC_NR(_ioctl)] = { \ 411#define IOCTL_INFO(_ioctl, _flags) [_IOC_NR(_ioctl)] = { \
407 .ioctl = _ioctl, \ 412 .ioctl = _ioctl, \
@@ -411,11 +416,11 @@ struct v4l2_ioctl_info {
411 416
412static struct v4l2_ioctl_info v4l2_ioctls[] = { 417static struct v4l2_ioctl_info v4l2_ioctls[] = {
413 IOCTL_INFO(VIDIOC_QUERYCAP, 0), 418 IOCTL_INFO(VIDIOC_QUERYCAP, 0),
414 IOCTL_INFO(VIDIOC_ENUM_FMT, 0), 419 IOCTL_INFO(VIDIOC_ENUM_FMT, INFO_FL_CLEAR(v4l2_fmtdesc, type)),
415 IOCTL_INFO(VIDIOC_G_FMT, 0), 420 IOCTL_INFO(VIDIOC_G_FMT, INFO_FL_CLEAR(v4l2_format, type)),
416 IOCTL_INFO(VIDIOC_S_FMT, INFO_FL_PRIO), 421 IOCTL_INFO(VIDIOC_S_FMT, INFO_FL_PRIO),
417 IOCTL_INFO(VIDIOC_REQBUFS, INFO_FL_PRIO), 422 IOCTL_INFO(VIDIOC_REQBUFS, INFO_FL_PRIO),
418 IOCTL_INFO(VIDIOC_QUERYBUF, 0), 423 IOCTL_INFO(VIDIOC_QUERYBUF, INFO_FL_CLEAR(v4l2_buffer, length)),
419 IOCTL_INFO(VIDIOC_G_FBUF, 0), 424 IOCTL_INFO(VIDIOC_G_FBUF, 0),
420 IOCTL_INFO(VIDIOC_S_FBUF, INFO_FL_PRIO), 425 IOCTL_INFO(VIDIOC_S_FBUF, INFO_FL_PRIO),
421 IOCTL_INFO(VIDIOC_OVERLAY, INFO_FL_PRIO), 426 IOCTL_INFO(VIDIOC_OVERLAY, INFO_FL_PRIO),
@@ -423,33 +428,33 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = {
423 IOCTL_INFO(VIDIOC_DQBUF, 0), 428 IOCTL_INFO(VIDIOC_DQBUF, 0),
424 IOCTL_INFO(VIDIOC_STREAMON, INFO_FL_PRIO), 429 IOCTL_INFO(VIDIOC_STREAMON, INFO_FL_PRIO),
425 IOCTL_INFO(VIDIOC_STREAMOFF, INFO_FL_PRIO), 430 IOCTL_INFO(VIDIOC_STREAMOFF, INFO_FL_PRIO),
426 IOCTL_INFO(VIDIOC_G_PARM, 0), 431 IOCTL_INFO(VIDIOC_G_PARM, INFO_FL_CLEAR(v4l2_streamparm, type)),
427 IOCTL_INFO(VIDIOC_S_PARM, INFO_FL_PRIO), 432 IOCTL_INFO(VIDIOC_S_PARM, INFO_FL_PRIO),
428 IOCTL_INFO(VIDIOC_G_STD, 0), 433 IOCTL_INFO(VIDIOC_G_STD, 0),
429 IOCTL_INFO(VIDIOC_S_STD, INFO_FL_PRIO), 434 IOCTL_INFO(VIDIOC_S_STD, INFO_FL_PRIO),
430 IOCTL_INFO(VIDIOC_ENUMSTD, 0), 435 IOCTL_INFO(VIDIOC_ENUMSTD, INFO_FL_CLEAR(v4l2_standard, index)),
431 IOCTL_INFO(VIDIOC_ENUMINPUT, 0), 436 IOCTL_INFO(VIDIOC_ENUMINPUT, INFO_FL_CLEAR(v4l2_input, index)),
432 IOCTL_INFO(VIDIOC_G_CTRL, INFO_FL_CTRL), 437 IOCTL_INFO(VIDIOC_G_CTRL, INFO_FL_CTRL),
433 IOCTL_INFO(VIDIOC_S_CTRL, INFO_FL_PRIO | INFO_FL_CTRL), 438 IOCTL_INFO(VIDIOC_S_CTRL, INFO_FL_PRIO | INFO_FL_CTRL),
434 IOCTL_INFO(VIDIOC_G_TUNER, 0), 439 IOCTL_INFO(VIDIOC_G_TUNER, INFO_FL_CLEAR(v4l2_tuner, index)),
435 IOCTL_INFO(VIDIOC_S_TUNER, INFO_FL_PRIO), 440 IOCTL_INFO(VIDIOC_S_TUNER, INFO_FL_PRIO),
436 IOCTL_INFO(VIDIOC_G_AUDIO, 0), 441 IOCTL_INFO(VIDIOC_G_AUDIO, 0),
437 IOCTL_INFO(VIDIOC_S_AUDIO, INFO_FL_PRIO), 442 IOCTL_INFO(VIDIOC_S_AUDIO, INFO_FL_PRIO),
438 IOCTL_INFO(VIDIOC_QUERYCTRL, INFO_FL_CTRL), 443 IOCTL_INFO(VIDIOC_QUERYCTRL, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_queryctrl, id)),
439 IOCTL_INFO(VIDIOC_QUERYMENU, INFO_FL_CTRL), 444 IOCTL_INFO(VIDIOC_QUERYMENU, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_querymenu, index)),
440 IOCTL_INFO(VIDIOC_G_INPUT, 0), 445 IOCTL_INFO(VIDIOC_G_INPUT, 0),
441 IOCTL_INFO(VIDIOC_S_INPUT, INFO_FL_PRIO), 446 IOCTL_INFO(VIDIOC_S_INPUT, INFO_FL_PRIO),
442 IOCTL_INFO(VIDIOC_G_OUTPUT, 0), 447 IOCTL_INFO(VIDIOC_G_OUTPUT, INFO_FL_CLEAR(v4l2_output, index)),
443 IOCTL_INFO(VIDIOC_S_OUTPUT, INFO_FL_PRIO), 448 IOCTL_INFO(VIDIOC_S_OUTPUT, INFO_FL_PRIO),
444 IOCTL_INFO(VIDIOC_ENUMOUTPUT, 0), 449 IOCTL_INFO(VIDIOC_ENUMOUTPUT, 0),
445 IOCTL_INFO(VIDIOC_G_AUDOUT, 0), 450 IOCTL_INFO(VIDIOC_G_AUDOUT, 0),
446 IOCTL_INFO(VIDIOC_S_AUDOUT, INFO_FL_PRIO), 451 IOCTL_INFO(VIDIOC_S_AUDOUT, INFO_FL_PRIO),
447 IOCTL_INFO(VIDIOC_G_MODULATOR, 0), 452 IOCTL_INFO(VIDIOC_G_MODULATOR, INFO_FL_CLEAR(v4l2_modulator, index)),
448 IOCTL_INFO(VIDIOC_S_MODULATOR, INFO_FL_PRIO), 453 IOCTL_INFO(VIDIOC_S_MODULATOR, INFO_FL_PRIO),
449 IOCTL_INFO(VIDIOC_G_FREQUENCY, 0), 454 IOCTL_INFO(VIDIOC_G_FREQUENCY, INFO_FL_CLEAR(v4l2_frequency, tuner)),
450 IOCTL_INFO(VIDIOC_S_FREQUENCY, INFO_FL_PRIO), 455 IOCTL_INFO(VIDIOC_S_FREQUENCY, INFO_FL_PRIO),
451 IOCTL_INFO(VIDIOC_CROPCAP, 0), 456 IOCTL_INFO(VIDIOC_CROPCAP, INFO_FL_CLEAR(v4l2_cropcap, type)),
452 IOCTL_INFO(VIDIOC_G_CROP, 0), 457 IOCTL_INFO(VIDIOC_G_CROP, INFO_FL_CLEAR(v4l2_crop, type)),
453 IOCTL_INFO(VIDIOC_S_CROP, INFO_FL_PRIO), 458 IOCTL_INFO(VIDIOC_S_CROP, INFO_FL_PRIO),
454 IOCTL_INFO(VIDIOC_G_SELECTION, 0), 459 IOCTL_INFO(VIDIOC_G_SELECTION, 0),
455 IOCTL_INFO(VIDIOC_S_SELECTION, INFO_FL_PRIO), 460 IOCTL_INFO(VIDIOC_S_SELECTION, INFO_FL_PRIO),
@@ -457,20 +462,20 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = {
457 IOCTL_INFO(VIDIOC_S_JPEGCOMP, INFO_FL_PRIO), 462 IOCTL_INFO(VIDIOC_S_JPEGCOMP, INFO_FL_PRIO),
458 IOCTL_INFO(VIDIOC_QUERYSTD, 0), 463 IOCTL_INFO(VIDIOC_QUERYSTD, 0),
459 IOCTL_INFO(VIDIOC_TRY_FMT, 0), 464 IOCTL_INFO(VIDIOC_TRY_FMT, 0),
460 IOCTL_INFO(VIDIOC_ENUMAUDIO, 0), 465 IOCTL_INFO(VIDIOC_ENUMAUDIO, INFO_FL_CLEAR(v4l2_audio, index)),
461 IOCTL_INFO(VIDIOC_ENUMAUDOUT, 0), 466 IOCTL_INFO(VIDIOC_ENUMAUDOUT, INFO_FL_CLEAR(v4l2_audioout, index)),
462 IOCTL_INFO(VIDIOC_G_PRIORITY, 0), 467 IOCTL_INFO(VIDIOC_G_PRIORITY, 0),
463 IOCTL_INFO(VIDIOC_S_PRIORITY, INFO_FL_PRIO), 468 IOCTL_INFO(VIDIOC_S_PRIORITY, INFO_FL_PRIO),
464 IOCTL_INFO(VIDIOC_G_SLICED_VBI_CAP, 0), 469 IOCTL_INFO(VIDIOC_G_SLICED_VBI_CAP, INFO_FL_CLEAR(v4l2_sliced_vbi_cap, type)),
465 IOCTL_INFO(VIDIOC_LOG_STATUS, 0), 470 IOCTL_INFO(VIDIOC_LOG_STATUS, 0),
466 IOCTL_INFO(VIDIOC_G_EXT_CTRLS, INFO_FL_CTRL), 471 IOCTL_INFO(VIDIOC_G_EXT_CTRLS, INFO_FL_CTRL),
467 IOCTL_INFO(VIDIOC_S_EXT_CTRLS, INFO_FL_PRIO | INFO_FL_CTRL), 472 IOCTL_INFO(VIDIOC_S_EXT_CTRLS, INFO_FL_PRIO | INFO_FL_CTRL),
468 IOCTL_INFO(VIDIOC_TRY_EXT_CTRLS, 0), 473 IOCTL_INFO(VIDIOC_TRY_EXT_CTRLS, 0),
469 IOCTL_INFO(VIDIOC_ENUM_FRAMESIZES, 0), 474 IOCTL_INFO(VIDIOC_ENUM_FRAMESIZES, INFO_FL_CLEAR(v4l2_frmsizeenum, pixel_format)),
470 IOCTL_INFO(VIDIOC_ENUM_FRAMEINTERVALS, 0), 475 IOCTL_INFO(VIDIOC_ENUM_FRAMEINTERVALS, INFO_FL_CLEAR(v4l2_frmivalenum, height)),
471 IOCTL_INFO(VIDIOC_G_ENC_INDEX, 0), 476 IOCTL_INFO(VIDIOC_G_ENC_INDEX, 0),
472 IOCTL_INFO(VIDIOC_ENCODER_CMD, INFO_FL_PRIO), 477 IOCTL_INFO(VIDIOC_ENCODER_CMD, INFO_FL_PRIO | INFO_FL_CLEAR(v4l2_encoder_cmd, flags)),
473 IOCTL_INFO(VIDIOC_TRY_ENCODER_CMD, 0), 478 IOCTL_INFO(VIDIOC_TRY_ENCODER_CMD, INFO_FL_CLEAR(v4l2_encoder_cmd, flags)),
474 IOCTL_INFO(VIDIOC_DECODER_CMD, INFO_FL_PRIO), 479 IOCTL_INFO(VIDIOC_DECODER_CMD, INFO_FL_PRIO),
475 IOCTL_INFO(VIDIOC_TRY_DECODER_CMD, 0), 480 IOCTL_INFO(VIDIOC_TRY_DECODER_CMD, 0),
476#ifdef CONFIG_VIDEO_ADV_DEBUG 481#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -2106,45 +2111,6 @@ static long __video_do_ioctl(struct file *file,
2106 return ret; 2111 return ret;
2107} 2112}
2108 2113
2109/* In some cases, only a few fields are used as input, i.e. when the app sets
2110 * "index" and then the driver fills in the rest of the structure for the thing
2111 * with that index. We only need to copy up the first non-input field. */
2112static unsigned long cmd_input_size(unsigned int cmd)
2113{
2114 /* Size of structure up to and including 'field' */
2115#define CMDINSIZE(cmd, type, field) \
2116 case VIDIOC_##cmd: \
2117 return offsetof(struct v4l2_##type, field) + \
2118 sizeof(((struct v4l2_##type *)0)->field);
2119
2120 switch (cmd) {
2121 CMDINSIZE(ENUM_FMT, fmtdesc, type);
2122 CMDINSIZE(G_FMT, format, type);
2123 CMDINSIZE(QUERYBUF, buffer, length);
2124 CMDINSIZE(G_PARM, streamparm, type);
2125 CMDINSIZE(ENUMSTD, standard, index);
2126 CMDINSIZE(ENUMINPUT, input, index);
2127 CMDINSIZE(G_CTRL, control, id);
2128 CMDINSIZE(G_TUNER, tuner, index);
2129 CMDINSIZE(QUERYCTRL, queryctrl, id);
2130 CMDINSIZE(QUERYMENU, querymenu, index);
2131 CMDINSIZE(ENUMOUTPUT, output, index);
2132 CMDINSIZE(G_MODULATOR, modulator, index);
2133 CMDINSIZE(G_FREQUENCY, frequency, tuner);
2134 CMDINSIZE(CROPCAP, cropcap, type);
2135 CMDINSIZE(G_CROP, crop, type);
2136 CMDINSIZE(ENUMAUDIO, audio, index);
2137 CMDINSIZE(ENUMAUDOUT, audioout, index);
2138 CMDINSIZE(ENCODER_CMD, encoder_cmd, flags);
2139 CMDINSIZE(TRY_ENCODER_CMD, encoder_cmd, flags);
2140 CMDINSIZE(G_SLICED_VBI_CAP, sliced_vbi_cap, type);
2141 CMDINSIZE(ENUM_FRAMESIZES, frmsizeenum, pixel_format);
2142 CMDINSIZE(ENUM_FRAMEINTERVALS, frmivalenum, height);
2143 default:
2144 return _IOC_SIZE(cmd);
2145 }
2146}
2147
2148static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, 2114static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
2149 void * __user *user_ptr, void ***kernel_ptr) 2115 void * __user *user_ptr, void ***kernel_ptr)
2150{ 2116{
@@ -2219,7 +2185,20 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
2219 2185
2220 err = -EFAULT; 2186 err = -EFAULT;
2221 if (_IOC_DIR(cmd) & _IOC_WRITE) { 2187 if (_IOC_DIR(cmd) & _IOC_WRITE) {
2222 unsigned long n = cmd_input_size(cmd); 2188 unsigned int n = _IOC_SIZE(cmd);
2189
2190 /*
2191 * In some cases, only a few fields are used as input,
2192 * i.e. when the app sets "index" and then the driver
2193 * fills in the rest of the structure for the thing
2194 * with that index. We only need to copy up the first
2195 * non-input field.
2196 */
2197 if (v4l2_is_known_ioctl(cmd)) {
2198 u32 flags = v4l2_ioctls[_IOC_NR(cmd)].flags;
2199 if (flags & INFO_FL_CLEAR_MASK)
2200 n = (flags & INFO_FL_CLEAR_MASK) >> 16;
2201 }
2223 2202
2224 if (copy_from_user(parg, (void __user *)arg, n)) 2203 if (copy_from_user(parg, (void __user *)arg, n))
2225 goto out; 2204 goto out;