diff options
Diffstat (limited to 'drivers/media/v4l2-core')
-rw-r--r-- | drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 135 | ||||
-rw-r--r-- | drivers/media/v4l2-core/v4l2-ctrls.c | 33 | ||||
-rw-r--r-- | drivers/media/v4l2-core/v4l2-dev.c | 32 | ||||
-rw-r--r-- | drivers/media/v4l2-core/v4l2-dv-timings.c | 8 | ||||
-rw-r--r-- | drivers/media/v4l2-core/v4l2-ioctl.c | 91 | ||||
-rw-r--r-- | drivers/media/v4l2-core/v4l2-of.c | 133 | ||||
-rw-r--r-- | drivers/media/v4l2-core/v4l2-subdev.c | 18 | ||||
-rw-r--r-- | drivers/media/v4l2-core/videobuf2-core.c | 658 | ||||
-rw-r--r-- | drivers/media/v4l2-core/videobuf2-dma-contig.c | 2 |
9 files changed, 684 insertions, 426 deletions
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 8f7a6a454a4c..04b2daf567be 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -733,14 +733,14 @@ static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *u copy_to_user(&up->u, &kp->u, sizeof(kp->u)) || put_user(kp->pending, &up->pending) || put_user(kp->sequence, &up->sequence) || - put_compat_timespec(&kp->timestamp, &up->timestamp) || + compat_put_timespec(&kp->timestamp, &up->timestamp) || put_user(kp->id, &up->id) || copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32))) return -EFAULT; return 0; } -struct v4l2_subdev_edid32 { +struct v4l2_edid32 { __u32 pad; __u32 start_block; __u32 blocks; @@ -748,11 +748,11 @@ struct v4l2_subdev_edid32 { compat_caddr_t edid; }; -static int get_v4l2_subdev_edid32(struct v4l2_subdev_edid *kp, struct v4l2_subdev_edid32 __user *up) +static int get_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) { u32 tmp; - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_subdev_edid32)) || + if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_edid32)) || get_user(kp->pad, &up->pad) || get_user(kp->start_block, &up->start_block) || get_user(kp->blocks, &up->blocks) || @@ -763,11 +763,11 @@ static int get_v4l2_subdev_edid32(struct v4l2_subdev_edid *kp, struct v4l2_subde return 0; } -static int put_v4l2_subdev_edid32(struct v4l2_subdev_edid *kp, struct v4l2_subdev_edid32 __user *up) +static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) { u32 tmp = (u32)((unsigned long)kp->edid); - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_subdev_edid32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_edid32)) || put_user(kp->pad, &up->pad) || put_user(kp->start_block, &up->start_block) || put_user(kp->blocks, &up->blocks) || @@ -787,8 +787,8 @@ static int put_v4l2_subdev_edid32(struct v4l2_subdev_edid *kp, struct v4l2_subde #define VIDIOC_DQBUF32 _IOWR('V', 17, struct v4l2_buffer32) #define VIDIOC_ENUMSTD32 _IOWR('V', 25, struct v4l2_standard32) #define VIDIOC_ENUMINPUT32 _IOWR('V', 26, struct v4l2_input32) -#define VIDIOC_SUBDEV_G_EDID32 _IOWR('V', 63, struct v4l2_subdev_edid32) -#define VIDIOC_SUBDEV_S_EDID32 _IOWR('V', 64, struct v4l2_subdev_edid32) +#define VIDIOC_G_EDID32 _IOWR('V', 40, struct v4l2_edid32) +#define VIDIOC_S_EDID32 _IOWR('V', 41, struct v4l2_edid32) #define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32) #define VIDIOC_G_EXT_CTRLS32 _IOWR('V', 71, struct v4l2_ext_controls32) #define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32) @@ -816,7 +816,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar struct v4l2_ext_controls v2ecs; struct v4l2_event v2ev; struct v4l2_create_buffers v2crt; - struct v4l2_subdev_edid v2edid; + struct v4l2_edid v2edid; unsigned long vx; int vi; } karg; @@ -849,8 +849,8 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break; case VIDIOC_CREATE_BUFS32: cmd = VIDIOC_CREATE_BUFS; break; case VIDIOC_PREPARE_BUF32: cmd = VIDIOC_PREPARE_BUF; break; - case VIDIOC_SUBDEV_G_EDID32: cmd = VIDIOC_SUBDEV_G_EDID; break; - case VIDIOC_SUBDEV_S_EDID32: cmd = VIDIOC_SUBDEV_S_EDID; break; + case VIDIOC_G_EDID32: cmd = VIDIOC_G_EDID; break; + case VIDIOC_S_EDID32: cmd = VIDIOC_S_EDID; break; } switch (cmd) { @@ -868,9 +868,9 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar compatible_arg = 0; break; - case VIDIOC_SUBDEV_G_EDID: - case VIDIOC_SUBDEV_S_EDID: - err = get_v4l2_subdev_edid32(&karg.v2edid, up); + case VIDIOC_G_EDID: + case VIDIOC_S_EDID: + err = get_v4l2_edid32(&karg.v2edid, up); compatible_arg = 0; break; @@ -966,9 +966,9 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar err = put_v4l2_event32(&karg.v2ev, up); break; - case VIDIOC_SUBDEV_G_EDID: - case VIDIOC_SUBDEV_S_EDID: - err = put_v4l2_subdev_edid32(&karg.v2edid, up); + case VIDIOC_G_EDID: + case VIDIOC_S_EDID: + err = put_v4l2_edid32(&karg.v2edid, up); break; case VIDIOC_G_FMT: @@ -1006,103 +1006,14 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) if (!file->f_op->unlocked_ioctl) return ret; - switch (cmd) { - 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: + if (_IOC_TYPE(cmd) == 'V' && _IOC_NR(cmd) < BASE_VIDIOC_PRIVATE) ret = do_video_ioctl(file, cmd, arg); - break; + else if (vdev->fops->compat_ioctl32) + ret = vdev->fops->compat_ioctl32(file, cmd, arg); - default: - if (vdev->fops->compat_ioctl32) - ret = vdev->fops->compat_ioctl32(file, cmd, arg); - - 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; - } + if (ret == -ENOIOCTLCMD) + pr_warn("compat_ioctl32: unknown ioctl '%c', dir=%d, #%d (0x%08x)\n", + _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), cmd); return ret; } EXPORT_SYMBOL_GPL(v4l2_compat_ioctl32); diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 6ff002bd5909..55c683254102 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -735,6 +735,8 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_DEC_PTS: return "Video Decoder PTS"; case V4L2_CID_MPEG_VIDEO_DEC_FRAME: return "Video Decoder Frame Count"; case V4L2_CID_MPEG_VIDEO_VBV_DELAY: return "Initial Delay for VBV Control"; + case V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE: return "Horizontal MV Search Range"; + case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE: return "Vertical MV Search Range"; case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER: return "Repeat Sequence Header"; /* VPX controls */ @@ -857,6 +859,17 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_FM_RX_CLASS: return "FM Radio Receiver Controls"; case V4L2_CID_TUNE_DEEMPHASIS: return "De-Emphasis"; case V4L2_CID_RDS_RECEPTION: return "RDS Reception"; + + case V4L2_CID_RF_TUNER_CLASS: return "RF Tuner Controls"; + case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO: return "LNA Gain, Auto"; + case V4L2_CID_RF_TUNER_LNA_GAIN: return "LNA Gain"; + case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO: return "Mixer Gain, Auto"; + case V4L2_CID_RF_TUNER_MIXER_GAIN: return "Mixer Gain"; + case V4L2_CID_RF_TUNER_IF_GAIN_AUTO: return "IF Gain, Auto"; + case V4L2_CID_RF_TUNER_IF_GAIN: return "IF Gain"; + case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: return "Bandwidth, Auto"; + case V4L2_CID_RF_TUNER_BANDWIDTH: return "Bandwidth"; + case V4L2_CID_RF_TUNER_PLL_LOCK: return "PLL Lock"; default: return NULL; } @@ -906,10 +919,19 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_WIDE_DYNAMIC_RANGE: case V4L2_CID_IMAGE_STABILIZATION: case V4L2_CID_RDS_RECEPTION: + case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO: + case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO: + case V4L2_CID_RF_TUNER_IF_GAIN_AUTO: + case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: + case V4L2_CID_RF_TUNER_PLL_LOCK: *type = V4L2_CTRL_TYPE_BOOLEAN; *min = 0; *max = *step = 1; break; + case V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE: + case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE: + *type = V4L2_CTRL_TYPE_INTEGER; + break; case V4L2_CID_PAN_RESET: case V4L2_CID_TILT_RESET: case V4L2_CID_FLASH_STROBE: @@ -991,6 +1013,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_IMAGE_PROC_CLASS: case V4L2_CID_DV_CLASS: case V4L2_CID_FM_RX_CLASS: + case V4L2_CID_RF_TUNER_CLASS: *type = V4L2_CTRL_TYPE_CTRL_CLASS; /* You can neither read not write these */ *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY; @@ -1063,6 +1086,10 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_PILOT_TONE_FREQUENCY: case V4L2_CID_TUNE_POWER_LEVEL: case V4L2_CID_TUNE_ANTENNA_CAPACITOR: + case V4L2_CID_RF_TUNER_LNA_GAIN: + case V4L2_CID_RF_TUNER_MIXER_GAIN: + case V4L2_CID_RF_TUNER_IF_GAIN: + case V4L2_CID_RF_TUNER_BANDWIDTH: *flags |= V4L2_CTRL_FLAG_SLIDER; break; case V4L2_CID_PAN_RELATIVE: @@ -1081,6 +1108,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_DV_RX_POWER_PRESENT: *flags |= V4L2_CTRL_FLAG_READ_ONLY; break; + case V4L2_CID_RF_TUNER_PLL_LOCK: + *flags |= V4L2_CTRL_FLAG_VOLATILE; + break; } } EXPORT_SYMBOL(v4l2_ctrl_fill); @@ -1921,7 +1951,8 @@ void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls) int i; /* The first control is the master control and it must not be NULL */ - BUG_ON(ncontrols == 0 || controls[0] == NULL); + if (WARN_ON(ncontrols == 0 || controls[0] == NULL)) + return; for (i = 0; i < ncontrols; i++) { if (controls[i]) { diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 0a30dbf3d05c..634d863c05b4 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -554,6 +554,7 @@ static void determine_valid_ioctls(struct video_device *vdev) bool is_vid = vdev->vfl_type == VFL_TYPE_GRABBER; bool is_vbi = vdev->vfl_type == VFL_TYPE_VBI; bool is_radio = vdev->vfl_type == VFL_TYPE_RADIO; + bool is_sdr = vdev->vfl_type == VFL_TYPE_SDR; bool is_rx = vdev->vfl_dir != VFL_DIR_TX; bool is_tx = vdev->vfl_dir != VFL_DIR_RX; @@ -662,9 +663,20 @@ static void determine_valid_ioctls(struct video_device *vdev) ops->vidioc_try_fmt_sliced_vbi_out))) set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls); SET_VALID_IOCTL(ops, VIDIOC_G_SLICED_VBI_CAP, vidioc_g_sliced_vbi_cap); + } else if (is_sdr) { + /* SDR specific ioctls */ + if (ops->vidioc_enum_fmt_sdr_cap) + set_bit(_IOC_NR(VIDIOC_ENUM_FMT), valid_ioctls); + if (ops->vidioc_g_fmt_sdr_cap) + set_bit(_IOC_NR(VIDIOC_G_FMT), valid_ioctls); + if (ops->vidioc_s_fmt_sdr_cap) + set_bit(_IOC_NR(VIDIOC_S_FMT), valid_ioctls); + if (ops->vidioc_try_fmt_sdr_cap) + set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls); } - if (!is_radio) { - /* ioctls valid for video or vbi */ + + if (is_vid || is_vbi || is_sdr) { + /* ioctls valid for video, vbi or sdr */ SET_VALID_IOCTL(ops, VIDIOC_REQBUFS, vidioc_reqbufs); SET_VALID_IOCTL(ops, VIDIOC_QUERYBUF, vidioc_querybuf); SET_VALID_IOCTL(ops, VIDIOC_QBUF, vidioc_qbuf); @@ -672,6 +684,10 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_DQBUF, vidioc_dqbuf); SET_VALID_IOCTL(ops, VIDIOC_CREATE_BUFS, vidioc_create_bufs); SET_VALID_IOCTL(ops, VIDIOC_PREPARE_BUF, vidioc_prepare_buf); + } + + if (is_vid || is_vbi) { + /* ioctls valid for video or vbi */ if (ops->vidioc_s_std) set_bit(_IOC_NR(VIDIOC_ENUMSTD), valid_ioctls); SET_VALID_IOCTL(ops, VIDIOC_S_STD, vidioc_s_std); @@ -685,6 +701,7 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_G_AUDIO, vidioc_g_audio); SET_VALID_IOCTL(ops, VIDIOC_S_AUDIO, vidioc_s_audio); SET_VALID_IOCTL(ops, VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings); + SET_VALID_IOCTL(ops, VIDIOC_S_EDID, vidioc_s_edid); } if (is_tx) { SET_VALID_IOCTL(ops, VIDIOC_ENUMOUTPUT, vidioc_enum_output); @@ -710,9 +727,10 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_G_DV_TIMINGS, vidioc_g_dv_timings); SET_VALID_IOCTL(ops, VIDIOC_ENUM_DV_TIMINGS, vidioc_enum_dv_timings); SET_VALID_IOCTL(ops, VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap); + SET_VALID_IOCTL(ops, VIDIOC_G_EDID, vidioc_g_edid); } - if (is_tx) { - /* transmitter only ioctls */ + if (is_tx && (is_radio || is_sdr)) { + /* radio transmitter only ioctls */ SET_VALID_IOCTL(ops, VIDIOC_G_MODULATOR, vidioc_g_modulator); SET_VALID_IOCTL(ops, VIDIOC_S_MODULATOR, vidioc_s_modulator); } @@ -758,6 +776,8 @@ static void determine_valid_ioctls(struct video_device *vdev) * %VFL_TYPE_RADIO - A radio card * * %VFL_TYPE_SUBDEV - A subdevice + * + * %VFL_TYPE_SDR - Software Defined Radio */ int __video_register_device(struct video_device *vdev, int type, int nr, int warn_if_nr_in_use, struct module *owner) @@ -797,6 +817,10 @@ int __video_register_device(struct video_device *vdev, int type, int nr, case VFL_TYPE_SUBDEV: name_base = "v4l-subdev"; break; + case VFL_TYPE_SDR: + /* Use device name 'swradio' because 'sdr' was already taken. */ + name_base = "swradio"; + break; default: printk(KERN_ERR "%s called with unknown type: %d\n", __func__, type); diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index f7902fe8a526..48b20dfcc4d0 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c @@ -26,6 +26,10 @@ #include <linux/v4l2-dv-timings.h> #include <media/v4l2-dv-timings.h> +MODULE_AUTHOR("Hans Verkuil"); +MODULE_DESCRIPTION("V4L2 DV Timings Helper Functions"); +MODULE_LICENSE("GPL"); + const struct v4l2_dv_timings v4l2_dv_timings_presets[] = { V4L2_DV_BT_CEA_640X480P59_94, V4L2_DV_BT_CEA_720X480I59_94, @@ -324,6 +328,10 @@ EXPORT_SYMBOL_GPL(v4l2_print_dv_timings); * This function will attempt to detect if the given values correspond to a * valid CVT format. If so, then it will return true, and fmt will be filled * in with the found CVT timings. + * + * TODO: VESA defined a new version 2 of their reduced blanking + * formula. Support for that is currently missing in this CVT + * detection function. */ bool v4l2_detect_cvt(unsigned frame_height, unsigned hfreq, unsigned vsync, u32 polarities, struct v4l2_dv_timings *fmt) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 707aef705a47..d9113cc71c77 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -152,6 +152,7 @@ const char *v4l2_type_names[] = { [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "vid-out-overlay", [V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE] = "vid-cap-mplane", [V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE] = "vid-out-mplane", + [V4L2_BUF_TYPE_SDR_CAPTURE] = "sdr-cap", }; EXPORT_SYMBOL(v4l2_type_names); @@ -245,6 +246,7 @@ static void v4l_print_format(const void *arg, bool write_only) const struct v4l2_vbi_format *vbi; const struct v4l2_sliced_vbi_format *sliced; const struct v4l2_window *win; + const struct v4l2_sdr_format *sdr; unsigned i; pr_cont("type=%s", prt_names(p->type, v4l2_type_names)); @@ -318,6 +320,14 @@ static void v4l_print_format(const void *arg, bool write_only) sliced->service_lines[0][i], sliced->service_lines[1][i]); break; + case V4L2_BUF_TYPE_SDR_CAPTURE: + sdr = &p->fmt.sdr; + pr_cont(", pixelformat=%c%c%c%c\n", + (sdr->pixelformat >> 0) & 0xff, + (sdr->pixelformat >> 8) & 0xff, + (sdr->pixelformat >> 16) & 0xff, + (sdr->pixelformat >> 24) & 0xff); + break; } } @@ -834,6 +844,14 @@ static void v4l_print_freq_band(const void *arg, bool write_only) p->rangehigh, p->modulation); } +static void v4l_print_edid(const void *arg, bool write_only) +{ + const struct v4l2_edid *p = arg; + + pr_cont("pad=%u, start_block=%u, blocks=%u\n", + p->pad, p->start_block, p->blocks); +} + static void v4l_print_u32(const void *arg, bool write_only) { pr_cont("value=%u\n", *(const u32 *)arg); @@ -881,6 +899,7 @@ static int check_fmt(struct file *file, enum v4l2_buf_type type) const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER; bool is_vbi = vfd->vfl_type == VFL_TYPE_VBI; + bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR; bool is_rx = vfd->vfl_dir != VFL_DIR_TX; bool is_tx = vfd->vfl_dir != VFL_DIR_RX; @@ -930,6 +949,10 @@ static int check_fmt(struct file *file, enum v4l2_buf_type type) if (is_vbi && is_tx && ops->vidioc_g_fmt_sliced_vbi_out) return 0; break; + case V4L2_BUF_TYPE_SDR_CAPTURE: + if (is_sdr && is_rx && ops->vidioc_g_fmt_sdr_cap) + return 0; + break; default: break; } @@ -1049,6 +1072,10 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops, if (unlikely(!is_tx || !ops->vidioc_enum_fmt_vid_out_mplane)) break; return ops->vidioc_enum_fmt_vid_out_mplane(file, fh, arg); + case V4L2_BUF_TYPE_SDR_CAPTURE: + if (unlikely(!is_rx || !ops->vidioc_enum_fmt_sdr_cap)) + break; + return ops->vidioc_enum_fmt_sdr_cap(file, fh, arg); } return -EINVAL; } @@ -1059,6 +1086,7 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops, struct v4l2_format *p = arg; struct video_device *vfd = video_devdata(file); bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER; + bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR; bool is_rx = vfd->vfl_dir != VFL_DIR_TX; bool is_tx = vfd->vfl_dir != VFL_DIR_RX; @@ -1103,6 +1131,10 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops, if (unlikely(!is_tx || is_vid || !ops->vidioc_g_fmt_sliced_vbi_out)) break; return ops->vidioc_g_fmt_sliced_vbi_out(file, fh, arg); + case V4L2_BUF_TYPE_SDR_CAPTURE: + if (unlikely(!is_rx || !is_sdr || !ops->vidioc_g_fmt_sdr_cap)) + break; + return ops->vidioc_g_fmt_sdr_cap(file, fh, arg); } return -EINVAL; } @@ -1113,6 +1145,7 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, struct v4l2_format *p = arg; struct video_device *vfd = video_devdata(file); bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER; + bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR; bool is_rx = vfd->vfl_dir != VFL_DIR_TX; bool is_tx = vfd->vfl_dir != VFL_DIR_RX; @@ -1167,6 +1200,11 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, break; CLEAR_AFTER_FIELD(p, fmt.sliced); return ops->vidioc_s_fmt_sliced_vbi_out(file, fh, arg); + case V4L2_BUF_TYPE_SDR_CAPTURE: + if (unlikely(!is_rx || !is_sdr || !ops->vidioc_s_fmt_sdr_cap)) + break; + CLEAR_AFTER_FIELD(p, fmt.sdr); + return ops->vidioc_s_fmt_sdr_cap(file, fh, arg); } return -EINVAL; } @@ -1177,6 +1215,7 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, struct v4l2_format *p = arg; struct video_device *vfd = video_devdata(file); bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER; + bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR; bool is_rx = vfd->vfl_dir != VFL_DIR_TX; bool is_tx = vfd->vfl_dir != VFL_DIR_RX; @@ -1231,6 +1270,11 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, break; CLEAR_AFTER_FIELD(p, fmt.sliced); return ops->vidioc_try_fmt_sliced_vbi_out(file, fh, arg); + case V4L2_BUF_TYPE_SDR_CAPTURE: + if (unlikely(!is_rx || !is_sdr || !ops->vidioc_try_fmt_sdr_cap)) + break; + CLEAR_AFTER_FIELD(p, fmt.sdr); + return ops->vidioc_try_fmt_sdr_cap(file, fh, arg); } return -EINVAL; } @@ -1291,8 +1335,11 @@ static int v4l_g_frequency(const struct v4l2_ioctl_ops *ops, struct video_device *vfd = video_devdata(file); struct v4l2_frequency *p = arg; - p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ? - V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + if (vfd->vfl_type == VFL_TYPE_SDR) + p->type = V4L2_TUNER_ADC; + else + p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ? + V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; return ops->vidioc_g_frequency(file, fh, p); } @@ -1303,10 +1350,15 @@ static int v4l_s_frequency(const struct v4l2_ioctl_ops *ops, const struct v4l2_frequency *p = arg; enum v4l2_tuner_type type; - type = (vfd->vfl_type == VFL_TYPE_RADIO) ? - V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - if (p->type != type) - return -EINVAL; + if (vfd->vfl_type == VFL_TYPE_SDR) { + if (p->type != V4L2_TUNER_ADC && p->type != V4L2_TUNER_RF) + return -EINVAL; + } else { + type = (vfd->vfl_type == VFL_TYPE_RADIO) ? + V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + if (type != p->type) + return -EINVAL; + } return ops->vidioc_s_frequency(file, fh, p); } @@ -1386,6 +1438,10 @@ static int v4l_s_hw_freq_seek(const struct v4l2_ioctl_ops *ops, struct v4l2_hw_freq_seek *p = arg; enum v4l2_tuner_type type; + /* s_hw_freq_seek is not supported for SDR for now */ + if (vfd->vfl_type == VFL_TYPE_SDR) + return -EINVAL; + type = (vfd->vfl_type == VFL_TYPE_RADIO) ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; if (p->type != type) @@ -1885,11 +1941,16 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops, enum v4l2_tuner_type type; int err; - type = (vfd->vfl_type == VFL_TYPE_RADIO) ? - V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - - if (type != p->type) - return -EINVAL; + if (vfd->vfl_type == VFL_TYPE_SDR) { + if (p->type != V4L2_TUNER_ADC && p->type != V4L2_TUNER_RF) + return -EINVAL; + type = p->type; + } else { + type = (vfd->vfl_type == VFL_TYPE_RADIO) ? + V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + if (type != p->type) + return -EINVAL; + } if (ops->vidioc_enum_freq_bands) return ops->vidioc_enum_freq_bands(file, fh, p); if (is_valid_ioctl(vfd, VIDIOC_G_TUNER)) { @@ -2009,6 +2070,8 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = { IOCTL_INFO_FNC(VIDIOC_QUERYMENU, v4l_querymenu, v4l_print_querymenu, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_querymenu, index)), IOCTL_INFO_STD(VIDIOC_G_INPUT, vidioc_g_input, v4l_print_u32, 0), IOCTL_INFO_FNC(VIDIOC_S_INPUT, v4l_s_input, v4l_print_u32, INFO_FL_PRIO), + IOCTL_INFO_STD(VIDIOC_G_EDID, vidioc_g_edid, v4l_print_edid, INFO_FL_CLEAR(v4l2_edid, edid)), + IOCTL_INFO_STD(VIDIOC_S_EDID, vidioc_s_edid, v4l_print_edid, INFO_FL_PRIO | INFO_FL_CLEAR(v4l2_edid, edid)), IOCTL_INFO_STD(VIDIOC_G_OUTPUT, vidioc_g_output, v4l_print_u32, 0), IOCTL_INFO_FNC(VIDIOC_S_OUTPUT, v4l_s_output, v4l_print_u32, INFO_FL_PRIO), IOCTL_INFO_FNC(VIDIOC_ENUMOUTPUT, v4l_enumoutput, v4l_print_enumoutput, INFO_FL_CLEAR(v4l2_output, index)), @@ -2221,9 +2284,9 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, break; } - case VIDIOC_SUBDEV_G_EDID: - case VIDIOC_SUBDEV_S_EDID: { - struct v4l2_subdev_edid *edid = parg; + case VIDIOC_G_EDID: + case VIDIOC_S_EDID: { + struct v4l2_edid *edid = parg; if (edid->blocks) { if (edid->blocks > 256) { diff --git a/drivers/media/v4l2-core/v4l2-of.c b/drivers/media/v4l2-core/v4l2-of.c index 42e3e8a5e361..b4ed9a955fbe 100644 --- a/drivers/media/v4l2-core/v4l2-of.c +++ b/drivers/media/v4l2-core/v4l2-of.c @@ -127,17 +127,9 @@ static void v4l2_of_parse_parallel_bus(const struct device_node *node, int v4l2_of_parse_endpoint(const struct device_node *node, struct v4l2_of_endpoint *endpoint) { - struct device_node *port_node = of_get_parent(node); - - memset(endpoint, 0, offsetof(struct v4l2_of_endpoint, head)); - - endpoint->local_node = node; - /* - * It doesn't matter whether the two calls below succeed. - * If they don't then the default value 0 is used. - */ - of_property_read_u32(port_node, "reg", &endpoint->port); - of_property_read_u32(node, "reg", &endpoint->id); + of_graph_parse_endpoint(node, &endpoint->base); + endpoint->bus_type = 0; + memset(&endpoint->bus, 0, sizeof(endpoint->bus)); v4l2_of_parse_csi_bus(node, endpoint); /* @@ -147,125 +139,6 @@ int v4l2_of_parse_endpoint(const struct device_node *node, if (endpoint->bus.mipi_csi2.flags == 0) v4l2_of_parse_parallel_bus(node, endpoint); - of_node_put(port_node); - return 0; } EXPORT_SYMBOL(v4l2_of_parse_endpoint); - -/** - * v4l2_of_get_next_endpoint() - get next endpoint node - * @parent: pointer to the parent device node - * @prev: previous endpoint node, or NULL to get first - * - * Return: An 'endpoint' node pointer with refcount incremented. Refcount - * of the passed @prev node is not decremented, the caller have to use - * of_node_put() on it when done. - */ -struct device_node *v4l2_of_get_next_endpoint(const struct device_node *parent, - struct device_node *prev) -{ - struct device_node *endpoint; - struct device_node *port = NULL; - - if (!parent) - return NULL; - - if (!prev) { - struct device_node *node; - /* - * It's the first call, we have to find a port subnode - * within this node or within an optional 'ports' node. - */ - node = of_get_child_by_name(parent, "ports"); - if (node) - parent = node; - - port = of_get_child_by_name(parent, "port"); - - if (port) { - /* Found a port, get an endpoint. */ - endpoint = of_get_next_child(port, NULL); - of_node_put(port); - } else { - endpoint = NULL; - } - - if (!endpoint) - pr_err("%s(): no endpoint nodes specified for %s\n", - __func__, parent->full_name); - of_node_put(node); - } else { - port = of_get_parent(prev); - if (!port) - /* Hm, has someone given us the root node ?... */ - return NULL; - - /* Avoid dropping prev node refcount to 0. */ - of_node_get(prev); - endpoint = of_get_next_child(port, prev); - if (endpoint) { - of_node_put(port); - return endpoint; - } - - /* No more endpoints under this port, try the next one. */ - do { - port = of_get_next_child(parent, port); - if (!port) - return NULL; - } while (of_node_cmp(port->name, "port")); - - /* Pick up the first endpoint in this port. */ - endpoint = of_get_next_child(port, NULL); - of_node_put(port); - } - - return endpoint; -} -EXPORT_SYMBOL(v4l2_of_get_next_endpoint); - -/** - * v4l2_of_get_remote_port_parent() - get remote port's parent node - * @node: pointer to a local endpoint device_node - * - * Return: Remote device node associated with remote endpoint node linked - * to @node. Use of_node_put() on it when done. - */ -struct device_node *v4l2_of_get_remote_port_parent( - const struct device_node *node) -{ - struct device_node *np; - unsigned int depth; - - /* Get remote endpoint node. */ - np = of_parse_phandle(node, "remote-endpoint", 0); - - /* Walk 3 levels up only if there is 'ports' node. */ - for (depth = 3; depth && np; depth--) { - np = of_get_next_parent(np); - if (depth == 2 && of_node_cmp(np->name, "ports")) - break; - } - return np; -} -EXPORT_SYMBOL(v4l2_of_get_remote_port_parent); - -/** - * v4l2_of_get_remote_port() - get remote port node - * @node: pointer to a local endpoint device_node - * - * Return: Remote port node associated with remote endpoint node linked - * to @node. Use of_node_put() on it when done. - */ -struct device_node *v4l2_of_get_remote_port(const struct device_node *node) -{ - struct device_node *np; - - /* Get remote endpoint node. */ - np = of_parse_phandle(node, "remote-endpoint", 0); - if (!np) - return NULL; - return of_get_next_parent(np); -} -EXPORT_SYMBOL(v4l2_of_get_remote_port); diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 996c248dea42..aea84ac5688a 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -349,10 +349,10 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) sd, pad, set_selection, subdev_fh, sel); } - case VIDIOC_SUBDEV_G_EDID: + case VIDIOC_G_EDID: return v4l2_subdev_call(sd, pad, get_edid, arg); - case VIDIOC_SUBDEV_S_EDID: + case VIDIOC_S_EDID: return v4l2_subdev_call(sd, pad, set_edid, arg); #endif default: @@ -368,6 +368,17 @@ static long subdev_ioctl(struct file *file, unsigned int cmd, 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) { struct video_device *vdev = video_devdata(file); @@ -389,6 +400,9 @@ const struct v4l2_file_operations v4l2_subdev_fops = { .owner = THIS_MODULE, .open = subdev_open, .unlocked_ioctl = subdev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = subdev_compat_ioctl32, +#endif .release = subdev_close, .poll = subdev_poll, }; diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index a127925c9d61..f9059bb73840 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -33,17 +33,74 @@ module_param(debug, int, 0644); printk(KERN_DEBUG "vb2: " fmt, ## arg); \ } while (0) -#define call_memop(q, op, args...) \ - (((q)->mem_ops->op) ? \ - ((q)->mem_ops->op(args)) : 0) +#ifdef CONFIG_VIDEO_ADV_DEBUG + +/* + * If advanced debugging is on, then count how often each op is called, + * which can either be per-buffer or per-queue. + * + * If the op failed then the 'fail_' variant is called to decrease the + * counter. That makes it easy to check that the 'init' and 'cleanup' + * (and variations thereof) stay balanced. + */ + +#define call_memop(vb, op, args...) \ +({ \ + struct vb2_queue *_q = (vb)->vb2_queue; \ + dprintk(2, "call_memop(%p, %d, %s)%s\n", \ + _q, (vb)->v4l2_buf.index, #op, \ + _q->mem_ops->op ? "" : " (nop)"); \ + (vb)->cnt_mem_ ## op++; \ + _q->mem_ops->op ? _q->mem_ops->op(args) : 0; \ +}) +#define fail_memop(vb, op) ((vb)->cnt_mem_ ## op--) + +#define call_qop(q, op, args...) \ +({ \ + dprintk(2, "call_qop(%p, %s)%s\n", q, #op, \ + (q)->ops->op ? "" : " (nop)"); \ + (q)->cnt_ ## op++; \ + (q)->ops->op ? (q)->ops->op(args) : 0; \ +}) +#define fail_qop(q, op) ((q)->cnt_ ## op--) + +#define call_vb_qop(vb, op, args...) \ +({ \ + struct vb2_queue *_q = (vb)->vb2_queue; \ + dprintk(2, "call_vb_qop(%p, %d, %s)%s\n", \ + _q, (vb)->v4l2_buf.index, #op, \ + _q->ops->op ? "" : " (nop)"); \ + (vb)->cnt_ ## op++; \ + _q->ops->op ? _q->ops->op(args) : 0; \ +}) +#define fail_vb_qop(vb, op) ((vb)->cnt_ ## op--) + +#else + +#define call_memop(vb, op, args...) \ + ((vb)->vb2_queue->mem_ops->op ? (vb)->vb2_queue->mem_ops->op(args) : 0) +#define fail_memop(vb, op) #define call_qop(q, op, args...) \ - (((q)->ops->op) ? ((q)->ops->op(args)) : 0) + ((q)->ops->op ? (q)->ops->op(args) : 0) +#define fail_qop(q, op) +#define call_vb_qop(vb, op, args...) \ + ((vb)->vb2_queue->ops->op ? (vb)->vb2_queue->ops->op(args) : 0) +#define fail_vb_qop(vb, op) + +#endif + +/* Flags that are set by the vb2 core */ #define V4L2_BUFFER_MASK_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \ V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR | \ V4L2_BUF_FLAG_PREPARED | \ V4L2_BUF_FLAG_TIMESTAMP_MASK) +/* Output buffer flags that should be passed on to the driver */ +#define V4L2_BUFFER_OUT_FLAGS (V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_BFRAME | \ + V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_TIMECODE) + +static void __vb2_queue_cancel(struct vb2_queue *q); /** * __vb2_buf_mem_alloc() - allocate video memory for the given buffer @@ -61,7 +118,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) for (plane = 0; plane < vb->num_planes; ++plane) { unsigned long size = PAGE_ALIGN(q->plane_sizes[plane]); - mem_priv = call_memop(q, alloc, q->alloc_ctx[plane], + mem_priv = call_memop(vb, alloc, q->alloc_ctx[plane], size, q->gfp_flags); if (IS_ERR_OR_NULL(mem_priv)) goto free; @@ -73,9 +130,10 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) return 0; free: + fail_memop(vb, alloc); /* Free already allocated memory if one of the allocations failed */ for (; plane > 0; --plane) { - call_memop(q, put, vb->planes[plane - 1].mem_priv); + call_memop(vb, put, vb->planes[plane - 1].mem_priv); vb->planes[plane - 1].mem_priv = NULL; } @@ -87,11 +145,10 @@ free: */ static void __vb2_buf_mem_free(struct vb2_buffer *vb) { - struct vb2_queue *q = vb->vb2_queue; unsigned int plane; for (plane = 0; plane < vb->num_planes; ++plane) { - call_memop(q, put, vb->planes[plane].mem_priv); + call_memop(vb, put, vb->planes[plane].mem_priv); vb->planes[plane].mem_priv = NULL; dprintk(3, "Freed plane %d of buffer %d\n", plane, vb->v4l2_buf.index); @@ -104,12 +161,11 @@ static void __vb2_buf_mem_free(struct vb2_buffer *vb) */ static void __vb2_buf_userptr_put(struct vb2_buffer *vb) { - struct vb2_queue *q = vb->vb2_queue; unsigned int plane; for (plane = 0; plane < vb->num_planes; ++plane) { if (vb->planes[plane].mem_priv) - call_memop(q, put_userptr, vb->planes[plane].mem_priv); + call_memop(vb, put_userptr, vb->planes[plane].mem_priv); vb->planes[plane].mem_priv = NULL; } } @@ -118,15 +174,15 @@ static void __vb2_buf_userptr_put(struct vb2_buffer *vb) * __vb2_plane_dmabuf_put() - release memory associated with * a DMABUF shared plane */ -static void __vb2_plane_dmabuf_put(struct vb2_queue *q, struct vb2_plane *p) +static void __vb2_plane_dmabuf_put(struct vb2_buffer *vb, struct vb2_plane *p) { if (!p->mem_priv) return; if (p->dbuf_mapped) - call_memop(q, unmap_dmabuf, p->mem_priv); + call_memop(vb, unmap_dmabuf, p->mem_priv); - call_memop(q, detach_dmabuf, p->mem_priv); + call_memop(vb, detach_dmabuf, p->mem_priv); dma_buf_put(p->dbuf); memset(p, 0, sizeof(*p)); } @@ -137,11 +193,10 @@ static void __vb2_plane_dmabuf_put(struct vb2_queue *q, struct vb2_plane *p) */ static void __vb2_buf_dmabuf_put(struct vb2_buffer *vb) { - struct vb2_queue *q = vb->vb2_queue; unsigned int plane; for (plane = 0; plane < vb->num_planes; ++plane) - __vb2_plane_dmabuf_put(q, &vb->planes[plane]); + __vb2_plane_dmabuf_put(vb, &vb->planes[plane]); } /** @@ -246,10 +301,11 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory, * callback, if given. An error in initialization * results in queue setup failure. */ - ret = call_qop(q, buf_init, vb); + ret = call_vb_qop(vb, buf_init, vb); if (ret) { dprintk(1, "Buffer %d %p initialization" " failed\n", buffer, vb); + fail_vb_qop(vb, buf_init); __vb2_buf_mem_free(vb); kfree(vb); break; @@ -321,18 +377,79 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) } /* Call driver-provided cleanup function for each buffer, if provided */ - if (q->ops->buf_cleanup) { - for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; - ++buffer) { - if (NULL == q->bufs[buffer]) - continue; - q->ops->buf_cleanup(q->bufs[buffer]); - } + for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; + ++buffer) { + struct vb2_buffer *vb = q->bufs[buffer]; + + if (vb && vb->planes[0].mem_priv) + call_vb_qop(vb, buf_cleanup, vb); } /* Release video buffer memory */ __vb2_free_mem(q, buffers); +#ifdef CONFIG_VIDEO_ADV_DEBUG + /* + * Check that all the calls were balances during the life-time of this + * queue. If not (or if the debug level is 1 or up), then dump the + * counters to the kernel log. + */ + if (q->num_buffers) { + bool unbalanced = q->cnt_start_streaming != q->cnt_stop_streaming || + q->cnt_wait_prepare != q->cnt_wait_finish; + + if (unbalanced || debug) { + pr_info("vb2: counters for queue %p:%s\n", q, + unbalanced ? " UNBALANCED!" : ""); + pr_info("vb2: setup: %u start_streaming: %u stop_streaming: %u\n", + q->cnt_queue_setup, q->cnt_start_streaming, + q->cnt_stop_streaming); + pr_info("vb2: wait_prepare: %u wait_finish: %u\n", + q->cnt_wait_prepare, q->cnt_wait_finish); + } + q->cnt_queue_setup = 0; + q->cnt_wait_prepare = 0; + q->cnt_wait_finish = 0; + q->cnt_start_streaming = 0; + q->cnt_stop_streaming = 0; + } + for (buffer = 0; buffer < q->num_buffers; ++buffer) { + struct vb2_buffer *vb = q->bufs[buffer]; + bool unbalanced = vb->cnt_mem_alloc != vb->cnt_mem_put || + vb->cnt_mem_prepare != vb->cnt_mem_finish || + vb->cnt_mem_get_userptr != vb->cnt_mem_put_userptr || + vb->cnt_mem_attach_dmabuf != vb->cnt_mem_detach_dmabuf || + vb->cnt_mem_map_dmabuf != vb->cnt_mem_unmap_dmabuf || + vb->cnt_buf_queue != vb->cnt_buf_done || + vb->cnt_buf_prepare != vb->cnt_buf_finish || + vb->cnt_buf_init != vb->cnt_buf_cleanup; + + if (unbalanced || debug) { + pr_info("vb2: counters for queue %p, buffer %d:%s\n", + q, buffer, unbalanced ? " UNBALANCED!" : ""); + pr_info("vb2: buf_init: %u buf_cleanup: %u buf_prepare: %u buf_finish: %u\n", + vb->cnt_buf_init, vb->cnt_buf_cleanup, + vb->cnt_buf_prepare, vb->cnt_buf_finish); + pr_info("vb2: buf_queue: %u buf_done: %u\n", + vb->cnt_buf_queue, vb->cnt_buf_done); + pr_info("vb2: alloc: %u put: %u prepare: %u finish: %u mmap: %u\n", + vb->cnt_mem_alloc, vb->cnt_mem_put, + vb->cnt_mem_prepare, vb->cnt_mem_finish, + vb->cnt_mem_mmap); + pr_info("vb2: get_userptr: %u put_userptr: %u\n", + vb->cnt_mem_get_userptr, vb->cnt_mem_put_userptr); + pr_info("vb2: attach_dmabuf: %u detach_dmabuf: %u map_dmabuf: %u unmap_dmabuf: %u\n", + vb->cnt_mem_attach_dmabuf, vb->cnt_mem_detach_dmabuf, + vb->cnt_mem_map_dmabuf, vb->cnt_mem_unmap_dmabuf); + pr_info("vb2: get_dmabuf: %u num_users: %u vaddr: %u cookie: %u\n", + vb->cnt_mem_get_dmabuf, + vb->cnt_mem_num_users, + vb->cnt_mem_vaddr, + vb->cnt_mem_cookie); + } + } +#endif + /* Free videobuf buffers */ for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; ++buffer) { @@ -341,9 +458,10 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) } q->num_buffers -= buffers; - if (!q->num_buffers) + if (!q->num_buffers) { q->memory = 0; - INIT_LIST_HEAD(&q->queued_list); + INIT_LIST_HEAD(&q->queued_list); + } return 0; } @@ -424,7 +542,7 @@ static bool __buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb) * case anyway. If num_users() returns more than 1, * we are not the only user of the plane's memory. */ - if (mem_priv && call_memop(q, num_users, mem_priv) > 1) + if (mem_priv && call_memop(vb, num_users, mem_priv) > 1) return true; } return false; @@ -484,7 +602,16 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) * Clear any buffer state related flags. */ b->flags &= ~V4L2_BUFFER_MASK_FLAGS; - b->flags |= q->timestamp_type; + b->flags |= q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK; + if ((q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) != + V4L2_BUF_FLAG_TIMESTAMP_COPY) { + /* + * For non-COPY timestamps, drop timestamp source bits + * and obtain the timestamp source from the queue. + */ + b->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + b->flags |= q->timestamp_flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + } switch (vb->state) { case VB2_BUF_STATE_QUEUED: @@ -677,6 +804,12 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) return -EBUSY; } + /* + * Call queue_cancel to clean up any buffers in the PREPARED or + * QUEUED state which is possible if buffers were prepared or + * queued without ever calling STREAMON. + */ + __vb2_queue_cancel(q); ret = __vb2_queue_free(q, q->num_buffers); if (ret) return ret; @@ -693,6 +826,7 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) * Make sure the requested values and current defaults are sane. */ num_buffers = min_t(unsigned int, req->count, VIDEO_MAX_FRAME); + num_buffers = max_t(unsigned int, req->count, q->min_buffers_needed); memset(q->plane_sizes, 0, sizeof(q->plane_sizes)); memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx)); q->memory = req->memory; @@ -703,26 +837,35 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) */ ret = call_qop(q, queue_setup, q, NULL, &num_buffers, &num_planes, q->plane_sizes, q->alloc_ctx); - if (ret) + if (ret) { + fail_qop(q, queue_setup); return ret; + } /* Finally, allocate buffers and video memory */ - ret = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes); - if (ret == 0) { + allocated_buffers = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes); + if (allocated_buffers == 0) { dprintk(1, "Memory allocation failed\n"); return -ENOMEM; } - allocated_buffers = ret; + /* + * There is no point in continuing if we can't allocate the minimum + * number of buffers needed by this vb2_queue. + */ + if (allocated_buffers < q->min_buffers_needed) + ret = -ENOMEM; /* * Check if driver can handle the allocated number of buffers. */ - if (allocated_buffers < num_buffers) { + if (!ret && allocated_buffers < num_buffers) { num_buffers = allocated_buffers; ret = call_qop(q, queue_setup, q, NULL, &num_buffers, &num_planes, q->plane_sizes, q->alloc_ctx); + if (ret) + fail_qop(q, queue_setup); if (!ret && allocated_buffers < num_buffers) ret = -ENOMEM; @@ -736,6 +879,10 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) q->num_buffers = allocated_buffers; if (ret < 0) { + /* + * Note: __vb2_queue_free() will subtract 'allocated_buffers' + * from q->num_buffers. + */ __vb2_queue_free(q, allocated_buffers); return ret; } @@ -803,24 +950,24 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create */ ret = call_qop(q, queue_setup, q, &create->format, &num_buffers, &num_planes, q->plane_sizes, q->alloc_ctx); - if (ret) + if (ret) { + fail_qop(q, queue_setup); return ret; + } /* Finally, allocate buffers and video memory */ - ret = __vb2_queue_alloc(q, create->memory, num_buffers, + allocated_buffers = __vb2_queue_alloc(q, create->memory, num_buffers, num_planes); - if (ret == 0) { + if (allocated_buffers == 0) { dprintk(1, "Memory allocation failed\n"); return -ENOMEM; } - allocated_buffers = ret; - /* * Check if driver can handle the so far allocated number of buffers. */ - if (ret < num_buffers) { - num_buffers = ret; + if (allocated_buffers < num_buffers) { + num_buffers = allocated_buffers; /* * q->num_buffers contains the total number of buffers, that the @@ -828,6 +975,8 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create */ ret = call_qop(q, queue_setup, q, &create->format, &num_buffers, &num_planes, q->plane_sizes, q->alloc_ctx); + if (ret) + fail_qop(q, queue_setup); if (!ret && allocated_buffers < num_buffers) ret = -ENOMEM; @@ -841,6 +990,10 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create q->num_buffers += allocated_buffers; if (ret < 0) { + /* + * Note: __vb2_queue_free() will subtract 'allocated_buffers' + * from q->num_buffers. + */ __vb2_queue_free(q, allocated_buffers); return -ENOMEM; } @@ -882,12 +1035,10 @@ EXPORT_SYMBOL_GPL(vb2_create_bufs); */ void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no) { - struct vb2_queue *q = vb->vb2_queue; - if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv) return NULL; - return call_memop(q, vaddr, vb->planes[plane_no].mem_priv); + return call_memop(vb, vaddr, vb->planes[plane_no].mem_priv); } EXPORT_SYMBOL_GPL(vb2_plane_vaddr); @@ -905,12 +1056,10 @@ EXPORT_SYMBOL_GPL(vb2_plane_vaddr); */ void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no) { - struct vb2_queue *q = vb->vb2_queue; - if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv) return NULL; - return call_memop(q, cookie, vb->planes[plane_no].mem_priv); + return call_memop(vb, cookie, vb->planes[plane_no].mem_priv); } EXPORT_SYMBOL_GPL(vb2_plane_cookie); @@ -918,13 +1067,20 @@ EXPORT_SYMBOL_GPL(vb2_plane_cookie); * vb2_buffer_done() - inform videobuf that an operation on a buffer is finished * @vb: vb2_buffer returned from the driver * @state: either VB2_BUF_STATE_DONE if the operation finished successfully - * or VB2_BUF_STATE_ERROR if the operation finished with an error + * or VB2_BUF_STATE_ERROR if the operation finished with an error. + * If start_streaming fails then it should return buffers with state + * VB2_BUF_STATE_QUEUED to put them back into the queue. * * This function should be called by the driver after a hardware operation on * a buffer is finished and the buffer may be returned to userspace. The driver * cannot use this buffer anymore until it is queued back to it by videobuf * by the means of buf_queue callback. Only buffers previously queued to the * driver by buf_queue can be passed to this function. + * + * While streaming a buffer can only be returned in state DONE or ERROR. + * The start_streaming op can also return them in case the DMA engine cannot + * be started for some reason. In that case the buffers should be returned with + * state QUEUED. */ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) { @@ -932,26 +1088,43 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) unsigned long flags; unsigned int plane; - if (vb->state != VB2_BUF_STATE_ACTIVE) + if (WARN_ON(vb->state != VB2_BUF_STATE_ACTIVE)) return; - if (state != VB2_BUF_STATE_DONE && state != VB2_BUF_STATE_ERROR) - return; + if (!q->start_streaming_called) { + if (WARN_ON(state != VB2_BUF_STATE_QUEUED)) + state = VB2_BUF_STATE_QUEUED; + } else if (!WARN_ON(!q->start_streaming_called)) { + if (WARN_ON(state != VB2_BUF_STATE_DONE && + state != VB2_BUF_STATE_ERROR)) + state = VB2_BUF_STATE_ERROR; + } +#ifdef CONFIG_VIDEO_ADV_DEBUG + /* + * Although this is not a callback, it still does have to balance + * with the buf_queue op. So update this counter manually. + */ + vb->cnt_buf_done++; +#endif dprintk(4, "Done processing on buffer %d, state: %d\n", vb->v4l2_buf.index, state); /* sync buffers */ for (plane = 0; plane < vb->num_planes; ++plane) - call_memop(q, finish, vb->planes[plane].mem_priv); + call_memop(vb, finish, vb->planes[plane].mem_priv); /* Add the buffer to the done buffers list */ spin_lock_irqsave(&q->done_lock, flags); vb->state = state; - list_add_tail(&vb->done_entry, &q->done_list); - atomic_dec(&q->queued_count); + if (state != VB2_BUF_STATE_QUEUED) + list_add_tail(&vb->done_entry, &q->done_list); + atomic_dec(&q->owned_by_drv_count); spin_unlock_irqrestore(&q->done_lock, flags); + if (state == VB2_BUF_STATE_QUEUED) + return; + /* Inform any processes that may be waiting for buffers */ wake_up(&q->done_wq); } @@ -1025,9 +1198,31 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b } - vb->v4l2_buf.field = b->field; - vb->v4l2_buf.timestamp = b->timestamp; + /* Zero flags that the vb2 core handles */ vb->v4l2_buf.flags = b->flags & ~V4L2_BUFFER_MASK_FLAGS; + if ((vb->vb2_queue->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) != + V4L2_BUF_FLAG_TIMESTAMP_COPY || !V4L2_TYPE_IS_OUTPUT(b->type)) { + /* + * Non-COPY timestamps and non-OUTPUT queues will get + * their timestamp and timestamp source flags from the + * queue. + */ + vb->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + } + + if (V4L2_TYPE_IS_OUTPUT(b->type)) { + /* + * For output buffers mask out the timecode flag: + * this will be handled later in vb2_internal_qbuf(). + * The 'field' is valid metadata for this output buffer + * and so that needs to be copied here. + */ + vb->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TIMECODE; + vb->v4l2_buf.field = b->field; + } else { + /* Zero any output buffer flags as this is a capture buffer */ + vb->v4l2_buf.flags &= ~V4L2_BUFFER_OUT_FLAGS; + } } /** @@ -1041,6 +1236,7 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) unsigned int plane; int ret; int write = !V4L2_TYPE_IS_OUTPUT(q->type); + bool reacquired = vb->planes[0].mem_priv == NULL; /* Copy relevant information provided by the userspace */ __fill_vb2_buffer(vb, b, planes); @@ -1066,20 +1262,25 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) } /* Release previously acquired memory if present */ - if (vb->planes[plane].mem_priv) - call_memop(q, put_userptr, vb->planes[plane].mem_priv); + if (vb->planes[plane].mem_priv) { + if (!reacquired) { + reacquired = true; + call_vb_qop(vb, buf_cleanup, vb); + } + call_memop(vb, put_userptr, vb->planes[plane].mem_priv); + } vb->planes[plane].mem_priv = NULL; - vb->v4l2_planes[plane].m.userptr = 0; - vb->v4l2_planes[plane].length = 0; + memset(&vb->v4l2_planes[plane], 0, sizeof(struct v4l2_plane)); /* Acquire each plane's memory */ - mem_priv = call_memop(q, get_userptr, q->alloc_ctx[plane], + mem_priv = call_memop(vb, get_userptr, q->alloc_ctx[plane], planes[plane].m.userptr, planes[plane].length, write); if (IS_ERR_OR_NULL(mem_priv)) { dprintk(1, "qbuf: failed acquiring userspace " "memory for plane %d\n", plane); + fail_memop(vb, get_userptr); ret = mem_priv ? PTR_ERR(mem_priv) : -EINVAL; goto err; } @@ -1087,28 +1288,40 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) } /* - * Call driver-specific initialization on the newly acquired buffer, - * if provided. - */ - ret = call_qop(q, buf_init, vb); - if (ret) { - dprintk(1, "qbuf: buffer initialization failed\n"); - goto err; - } - - /* * Now that everything is in order, copy relevant information * provided by userspace. */ for (plane = 0; plane < vb->num_planes; ++plane) vb->v4l2_planes[plane] = planes[plane]; + if (reacquired) { + /* + * One or more planes changed, so we must call buf_init to do + * the driver-specific initialization on the newly acquired + * buffer, if provided. + */ + ret = call_vb_qop(vb, buf_init, vb); + if (ret) { + dprintk(1, "qbuf: buffer initialization failed\n"); + fail_vb_qop(vb, buf_init); + goto err; + } + } + + ret = call_vb_qop(vb, buf_prepare, vb); + if (ret) { + dprintk(1, "qbuf: buffer preparation failed\n"); + fail_vb_qop(vb, buf_prepare); + call_vb_qop(vb, buf_cleanup, vb); + goto err; + } + return 0; err: /* In case of errors, release planes that were already acquired */ for (plane = 0; plane < vb->num_planes; ++plane) { if (vb->planes[plane].mem_priv) - call_memop(q, put_userptr, vb->planes[plane].mem_priv); + call_memop(vb, put_userptr, vb->planes[plane].mem_priv); vb->planes[plane].mem_priv = NULL; vb->v4l2_planes[plane].m.userptr = 0; vb->v4l2_planes[plane].length = 0; @@ -1122,8 +1335,13 @@ err: */ static int __qbuf_mmap(struct vb2_buffer *vb, const struct v4l2_buffer *b) { + int ret; + __fill_vb2_buffer(vb, b, vb->v4l2_planes); - return 0; + ret = call_vb_qop(vb, buf_prepare, vb); + if (ret) + fail_vb_qop(vb, buf_prepare); + return ret; } /** @@ -1137,6 +1355,7 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b) unsigned int plane; int ret; int write = !V4L2_TYPE_IS_OUTPUT(q->type); + bool reacquired = vb->planes[0].mem_priv == NULL; /* Copy relevant information provided by the userspace */ __fill_vb2_buffer(vb, b, planes); @@ -1172,15 +1391,21 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b) dprintk(1, "qbuf: buffer for plane %d changed\n", plane); + if (!reacquired) { + reacquired = true; + call_vb_qop(vb, buf_cleanup, vb); + } + /* Release previously acquired memory if present */ - __vb2_plane_dmabuf_put(q, &vb->planes[plane]); + __vb2_plane_dmabuf_put(vb, &vb->planes[plane]); memset(&vb->v4l2_planes[plane], 0, sizeof(struct v4l2_plane)); /* Acquire each plane's memory */ - mem_priv = call_memop(q, attach_dmabuf, q->alloc_ctx[plane], + mem_priv = call_memop(vb, attach_dmabuf, q->alloc_ctx[plane], dbuf, planes[plane].length, write); if (IS_ERR(mem_priv)) { dprintk(1, "qbuf: failed to attach dmabuf\n"); + fail_memop(vb, attach_dmabuf); ret = PTR_ERR(mem_priv); dma_buf_put(dbuf); goto err; @@ -1195,32 +1420,44 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b) * the buffer(s).. */ for (plane = 0; plane < vb->num_planes; ++plane) { - ret = call_memop(q, map_dmabuf, vb->planes[plane].mem_priv); + ret = call_memop(vb, map_dmabuf, vb->planes[plane].mem_priv); if (ret) { dprintk(1, "qbuf: failed to map dmabuf for plane %d\n", plane); + fail_memop(vb, map_dmabuf); goto err; } vb->planes[plane].dbuf_mapped = 1; } /* - * Call driver-specific initialization on the newly acquired buffer, - * if provided. - */ - ret = call_qop(q, buf_init, vb); - if (ret) { - dprintk(1, "qbuf: buffer initialization failed\n"); - goto err; - } - - /* * Now that everything is in order, copy relevant information * provided by userspace. */ for (plane = 0; plane < vb->num_planes; ++plane) vb->v4l2_planes[plane] = planes[plane]; + if (reacquired) { + /* + * Call driver-specific initialization on the newly acquired buffer, + * if provided. + */ + ret = call_vb_qop(vb, buf_init, vb); + if (ret) { + dprintk(1, "qbuf: buffer initialization failed\n"); + fail_vb_qop(vb, buf_init); + goto err; + } + } + + ret = call_vb_qop(vb, buf_prepare, vb); + if (ret) { + dprintk(1, "qbuf: buffer preparation failed\n"); + fail_vb_qop(vb, buf_prepare); + call_vb_qop(vb, buf_cleanup, vb); + goto err; + } + return 0; err: /* In case of errors, release planes that were already acquired */ @@ -1238,13 +1475,13 @@ static void __enqueue_in_driver(struct vb2_buffer *vb) unsigned int plane; vb->state = VB2_BUF_STATE_ACTIVE; - atomic_inc(&q->queued_count); + atomic_inc(&q->owned_by_drv_count); /* sync buffers */ for (plane = 0; plane < vb->num_planes; ++plane) - call_memop(q, prepare, vb->planes[plane].mem_priv); + call_memop(vb, prepare, vb->planes[plane].mem_priv); - q->ops->buf_queue(vb); + call_vb_qop(vb, buf_queue, vb); } static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) @@ -1261,6 +1498,10 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) } vb->state = VB2_BUF_STATE_PREPARING; + vb->v4l2_buf.timestamp.tv_sec = 0; + vb->v4l2_buf.timestamp.tv_usec = 0; + vb->v4l2_buf.sequence = 0; + switch (q->memory) { case V4L2_MEMORY_MMAP: ret = __qbuf_mmap(vb, b); @@ -1295,8 +1536,6 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) ret = -EINVAL; } - if (!ret) - ret = call_qop(q, buf_prepare, vb); if (ret) dprintk(1, "qbuf: buffer preparation failed: %d\n", ret); vb->state = ret ? VB2_BUF_STATE_DEQUEUED : VB2_BUF_STATE_PREPARED; @@ -1382,32 +1621,49 @@ EXPORT_SYMBOL_GPL(vb2_prepare_buf); * vb2_start_streaming() - Attempt to start streaming. * @q: videobuf2 queue * - * If there are not enough buffers, then retry_start_streaming is set to - * 1 and 0 is returned. The next time a buffer is queued and - * retry_start_streaming is 1, this function will be called again to - * retry starting the DMA engine. + * Attempt to start streaming. When this function is called there must be + * at least q->min_buffers_needed buffers queued up (i.e. the minimum + * number of buffers required for the DMA engine to function). If the + * @start_streaming op fails it is supposed to return all the driver-owned + * buffers back to vb2 in state QUEUED. Check if that happened and if + * not warn and reclaim them forcefully. */ static int vb2_start_streaming(struct vb2_queue *q) { + struct vb2_buffer *vb; int ret; - /* Tell the driver to start streaming */ - ret = call_qop(q, start_streaming, q, atomic_read(&q->queued_count)); - /* - * If there are not enough buffers queued to start streaming, then - * the start_streaming operation will return -ENOBUFS and you have to - * retry when the next buffer is queued. + * If any buffers were queued before streamon, + * we can now pass them to driver for processing. */ - if (ret == -ENOBUFS) { - dprintk(1, "qbuf: not enough buffers, retry when more buffers are queued.\n"); - q->retry_start_streaming = 1; + list_for_each_entry(vb, &q->queued_list, queued_entry) + __enqueue_in_driver(vb); + + /* Tell the driver to start streaming */ + ret = call_qop(q, start_streaming, q, + atomic_read(&q->owned_by_drv_count)); + q->start_streaming_called = ret == 0; + if (!ret) return 0; + + fail_qop(q, start_streaming); + dprintk(1, "qbuf: driver refused to start streaming\n"); + if (WARN_ON(atomic_read(&q->owned_by_drv_count))) { + unsigned i; + + /* + * Forcefully reclaim buffers if the driver did not + * correctly return them to vb2. + */ + for (i = 0; i < q->num_buffers; ++i) { + vb = q->bufs[i]; + if (vb->state == VB2_BUF_STATE_ACTIVE) + vb2_buffer_done(vb, VB2_BUF_STATE_QUEUED); + } + /* Must be zero now */ + WARN_ON(atomic_read(&q->owned_by_drv_count)); } - if (ret) - dprintk(1, "qbuf: driver refused to start streaming\n"); - else - q->retry_start_streaming = 0; return ret; } @@ -1420,11 +1676,6 @@ static int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) return ret; vb = q->bufs[b->index]; - if (vb->state != VB2_BUF_STATE_DEQUEUED) { - dprintk(1, "%s(): invalid buffer state %d\n", __func__, - vb->state); - return -EINVAL; - } switch (vb->state) { case VB2_BUF_STATE_DEQUEUED: @@ -1438,7 +1689,8 @@ static int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) dprintk(1, "qbuf: buffer still being prepared\n"); return -EINVAL; default: - dprintk(1, "qbuf: buffer already in use\n"); + dprintk(1, "%s(): invalid buffer state %d\n", __func__, + vb->state); return -EINVAL; } @@ -1447,19 +1699,39 @@ static int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) * dequeued in dqbuf. */ list_add_tail(&vb->queued_entry, &q->queued_list); + q->queued_count++; vb->state = VB2_BUF_STATE_QUEUED; + if (V4L2_TYPE_IS_OUTPUT(q->type)) { + /* + * For output buffers copy the timestamp if needed, + * and the timecode field and flag if needed. + */ + if ((q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) == + V4L2_BUF_FLAG_TIMESTAMP_COPY) + vb->v4l2_buf.timestamp = b->timestamp; + vb->v4l2_buf.flags |= b->flags & V4L2_BUF_FLAG_TIMECODE; + if (b->flags & V4L2_BUF_FLAG_TIMECODE) + vb->v4l2_buf.timecode = b->timecode; + } /* * If already streaming, give the buffer to driver for processing. * If not, the buffer will be given to driver on next streamon. */ - if (q->streaming) + if (q->start_streaming_called) __enqueue_in_driver(vb); /* Fill buffer information for the userspace */ __fill_v4l2_buffer(vb, b); - if (q->retry_start_streaming) { + /* + * If streamon has been called, and we haven't yet called + * start_streaming() since not enough buffers were queued, and + * we now have reached the minimum number of queued buffers, + * then we can finally call start_streaming(). + */ + if (q->streaming && !q->start_streaming_called && + q->queued_count >= q->min_buffers_needed) { ret = vb2_start_streaming(q); if (ret) return ret; @@ -1614,8 +1886,8 @@ int vb2_wait_for_all_buffers(struct vb2_queue *q) return -EINVAL; } - if (!q->retry_start_streaming) - wait_event(q->done_wq, !atomic_read(&q->queued_count)); + if (q->start_streaming_called) + wait_event(q->done_wq, !atomic_read(&q->owned_by_drv_count)); return 0; } EXPORT_SYMBOL_GPL(vb2_wait_for_all_buffers); @@ -1639,7 +1911,7 @@ static void __vb2_dqbuf(struct vb2_buffer *vb) for (i = 0; i < vb->num_planes; ++i) { if (!vb->planes[i].dbuf_mapped) continue; - call_memop(q, unmap_dmabuf, vb->planes[i].mem_priv); + call_memop(vb, unmap_dmabuf, vb->planes[i].mem_priv); vb->planes[i].dbuf_mapped = 0; } } @@ -1657,12 +1929,6 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool n if (ret < 0) return ret; - ret = call_qop(q, buf_finish, vb); - if (ret) { - dprintk(1, "dqbuf: buffer finish failed\n"); - return ret; - } - switch (vb->state) { case VB2_BUF_STATE_DONE: dprintk(3, "dqbuf: Returning done buffer\n"); @@ -1675,10 +1941,13 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool n return -EINVAL; } + call_vb_qop(vb, buf_finish, vb); + /* Fill buffer information for the userspace */ __fill_v4l2_buffer(vb, b); /* Remove from videobuf queue */ list_del(&vb->queued_entry); + q->queued_count--; /* go back to dequeued state */ __vb2_dqbuf(vb); @@ -1729,18 +1998,23 @@ static void __vb2_queue_cancel(struct vb2_queue *q) { unsigned int i; - if (q->retry_start_streaming) { - q->retry_start_streaming = 0; - q->streaming = 0; - } - /* * Tell driver to stop all transactions and release all queued * buffers. */ - if (q->streaming) + if (q->start_streaming_called) call_qop(q, stop_streaming, q); q->streaming = 0; + q->start_streaming_called = 0; + q->queued_count = 0; + + if (WARN_ON(atomic_read(&q->owned_by_drv_count))) { + for (i = 0; i < q->num_buffers; ++i) + if (q->bufs[i]->state == VB2_BUF_STATE_ACTIVE) + vb2_buffer_done(q->bufs[i], VB2_BUF_STATE_ERROR); + /* Must be zero now */ + WARN_ON(atomic_read(&q->owned_by_drv_count)); + } /* * Remove all buffers from videobuf's list... @@ -1751,19 +2025,31 @@ static void __vb2_queue_cancel(struct vb2_queue *q) * has not already dequeued before initiating cancel. */ INIT_LIST_HEAD(&q->done_list); - atomic_set(&q->queued_count, 0); + atomic_set(&q->owned_by_drv_count, 0); wake_up_all(&q->done_wq); /* * Reinitialize all buffers for next use. + * Make sure to call buf_finish for any queued buffers. Normally + * that's done in dqbuf, but that's not going to happen when we + * cancel the whole queue. Note: this code belongs here, not in + * __vb2_dqbuf() since in vb2_internal_dqbuf() there is a critical + * call to __fill_v4l2_buffer() after buf_finish(). That order can't + * be changed, so we can't move the buf_finish() to __vb2_dqbuf(). */ - for (i = 0; i < q->num_buffers; ++i) - __vb2_dqbuf(q->bufs[i]); + for (i = 0; i < q->num_buffers; ++i) { + struct vb2_buffer *vb = q->bufs[i]; + + if (vb->state != VB2_BUF_STATE_DEQUEUED) { + vb->state = VB2_BUF_STATE_PREPARED; + call_vb_qop(vb, buf_finish, vb); + } + __vb2_dqbuf(vb); + } } static int vb2_internal_streamon(struct vb2_queue *q, enum v4l2_buf_type type) { - struct vb2_buffer *vb; int ret; if (type != q->type) { @@ -1781,18 +2067,26 @@ static int vb2_internal_streamon(struct vb2_queue *q, enum v4l2_buf_type type) return -EINVAL; } + if (!q->num_buffers) { + dprintk(1, "streamon: no buffers have been allocated\n"); + return -EINVAL; + } + if (q->num_buffers < q->min_buffers_needed) { + dprintk(1, "streamon: need at least %u allocated buffers\n", + q->min_buffers_needed); + return -EINVAL; + } + /* - * If any buffers were queued before streamon, - * we can now pass them to driver for processing. + * Tell driver to start streaming provided sufficient buffers + * are available. */ - list_for_each_entry(vb, &q->queued_list, queued_entry) - __enqueue_in_driver(vb); - - /* Tell driver to start streaming. */ - ret = vb2_start_streaming(q); - if (ret) { - __vb2_queue_cancel(q); - return ret; + if (q->queued_count >= q->min_buffers_needed) { + ret = vb2_start_streaming(q); + if (ret) { + __vb2_queue_cancel(q); + return ret; + } } q->streaming = 1; @@ -1831,14 +2125,14 @@ static int vb2_internal_streamoff(struct vb2_queue *q, enum v4l2_buf_type type) return -EINVAL; } - if (!q->streaming) { - dprintk(3, "streamoff successful: not streaming\n"); - return 0; - } - /* * Cancel will pause streaming and remove all buffers from the driver * and videobuf, effectively returning control over them to userspace. + * + * Note that we do this even if q->streaming == 0: if you prepare or + * queue buffers, and then call streamoff without ever having called + * streamon, you would still expect those buffers to be returned to + * their normal dequeued state. */ __vb2_queue_cancel(q); @@ -1950,10 +2244,11 @@ int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb) vb_plane = &vb->planes[eb->plane]; - dbuf = call_memop(q, get_dmabuf, vb_plane->mem_priv, eb->flags & O_ACCMODE); + dbuf = call_memop(vb, get_dmabuf, vb_plane->mem_priv, eb->flags & O_ACCMODE); if (IS_ERR_OR_NULL(dbuf)) { dprintk(1, "Failed to export buffer %d, plane %d\n", eb->index, eb->plane); + fail_memop(vb, get_dmabuf); return -EINVAL; } @@ -2045,9 +2340,11 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) return -EINVAL; } - ret = call_memop(q, mmap, vb->planes[plane].mem_priv, vma); - if (ret) + ret = call_memop(vb, mmap, vb->planes[plane].mem_priv, vma); + if (ret) { + fail_memop(vb, mmap); return ret; + } dprintk(3, "Buffer %d, plane %d successfully mapped\n", buffer, plane); return 0; @@ -2200,11 +2497,14 @@ int vb2_queue_init(struct vb2_queue *q) WARN_ON(!q->io_modes) || WARN_ON(!q->ops->queue_setup) || WARN_ON(!q->ops->buf_queue) || - WARN_ON(q->timestamp_type & ~V4L2_BUF_FLAG_TIMESTAMP_MASK)) + WARN_ON(q->timestamp_flags & + ~(V4L2_BUF_FLAG_TIMESTAMP_MASK | + V4L2_BUF_FLAG_TSTAMP_SRC_MASK))) return -EINVAL; /* Warn that the driver should choose an appropriate timestamp type */ - WARN_ON(q->timestamp_type == V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN); + WARN_ON((q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) == + V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN); INIT_LIST_HEAD(&q->queued_list); INIT_LIST_HEAD(&q->done_list); @@ -2251,6 +2551,22 @@ struct vb2_fileio_buf { /** * struct vb2_fileio_data - queue context used by file io emulator * + * @cur_index: the index of the buffer currently being read from or + * written to. If equal to q->num_buffers then a new buffer + * must be dequeued. + * @initial_index: in the read() case all buffers are queued up immediately + * in __vb2_init_fileio() and __vb2_perform_fileio() just cycles + * buffers. However, in the write() case no buffers are initially + * queued, instead whenever a buffer is full it is queued up by + * __vb2_perform_fileio(). Only once all available buffers have + * been queued up will __vb2_perform_fileio() start to dequeue + * buffers. This means that initially __vb2_perform_fileio() + * needs to know what buffer index to use when it is queuing up + * the buffers for the first time. That initial index is stored + * in this field. Once it is equal to q->num_buffers all + * available buffers have been queued and __vb2_perform_fileio() + * should start the normal dequeue/queue cycle. + * * vb2 provides a compatibility layer and emulator of file io (read and * write) calls on top of streaming API. For proper operation it required * this structure to save the driver state between each call of the read @@ -2260,7 +2576,8 @@ struct vb2_fileio_data { struct v4l2_requestbuffers req; struct v4l2_buffer b; struct vb2_fileio_buf bufs[VIDEO_MAX_FRAME]; - unsigned int index; + unsigned int cur_index; + unsigned int initial_index; unsigned int q_count; unsigned int dq_count; unsigned int flags; @@ -2280,9 +2597,9 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) /* * Sanity check */ - if ((read && !(q->io_modes & VB2_READ)) || - (!read && !(q->io_modes & VB2_WRITE))) - BUG(); + if (WARN_ON((read && !(q->io_modes & VB2_READ)) || + (!read && !(q->io_modes & VB2_WRITE)))) + return -EINVAL; /* * Check if device supports mapping buffers to kernel virtual space. @@ -2360,7 +2677,12 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) goto err_reqbufs; fileio->bufs[i].queued = 1; } - fileio->index = q->num_buffers; + /* + * All buffers have been queued, so mark that by setting + * initial_index to q->num_buffers + */ + fileio->initial_index = q->num_buffers; + fileio->cur_index = q->num_buffers; } /* @@ -2439,7 +2761,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ /* * Check if we need to dequeue the buffer. */ - index = fileio->index; + index = fileio->cur_index; if (index >= q->num_buffers) { /* * Call vb2_dqbuf to get buffer back. @@ -2453,7 +2775,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ return ret; fileio->dq_count += 1; - index = fileio->b.index; + fileio->cur_index = index = fileio->b.index; buf = &fileio->bufs[index]; /* @@ -2529,8 +2851,20 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ buf->queued = 1; buf->size = vb2_plane_size(q->bufs[index], 0); fileio->q_count += 1; - if (fileio->index < q->num_buffers) - fileio->index++; + /* + * If we are queuing up buffers for the first time, then + * increase initial_index by one. + */ + if (fileio->initial_index < q->num_buffers) + fileio->initial_index++; + /* + * The next buffer to use is either a buffer that's going to be + * queued for the first time (initial_index < q->num_buffers) + * or it is equal to q->num_buffers, meaning that the next + * time we need to dequeue a buffer since we've now queued up + * all the 'first time' buffers. + */ + fileio->cur_index = fileio->initial_index; } /* diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index 33d3871d1e13..880be0782dd9 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c @@ -719,7 +719,7 @@ static int vb2_dc_map_dmabuf(void *mem_priv) /* get the associated scatterlist for this buffer */ sgt = dma_buf_map_attachment(buf->db_attach, buf->dma_dir); - if (IS_ERR_OR_NULL(sgt)) { + if (IS_ERR(sgt)) { pr_err("Error getting dmabuf scatterlist\n"); return -EINVAL; } |