diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/v4l2-ioctl.c | 103 |
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 | ||
395 | struct v4l2_ioctl_info { | 395 | struct 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 | ||
412 | static struct v4l2_ioctl_info v4l2_ioctls[] = { | 417 | static 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. */ | ||
2112 | static 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 | |||
2148 | static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, | 2114 | static 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; |