diff options
Diffstat (limited to 'drivers/media/v4l2-core')
-rw-r--r-- | drivers/media/v4l2-core/v4l2-clk.c | 9 | ||||
-rw-r--r-- | drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 6 | ||||
-rw-r--r-- | drivers/media/v4l2-core/v4l2-ctrls.c | 77 | ||||
-rw-r--r-- | drivers/media/v4l2-core/v4l2-device.c | 21 | ||||
-rw-r--r-- | drivers/media/v4l2-core/v4l2-dv-timings.c | 16 | ||||
-rw-r--r-- | drivers/media/v4l2-core/v4l2-ioctl.c | 14 | ||||
-rw-r--r-- | drivers/media/v4l2-core/videobuf2-core.c | 926 | ||||
-rw-r--r-- | drivers/media/v4l2-core/videobuf2-internal.h | 161 | ||||
-rw-r--r-- | drivers/media/v4l2-core/videobuf2-v4l2.c | 703 |
9 files changed, 1010 insertions, 923 deletions
diff --git a/drivers/media/v4l2-core/v4l2-clk.c b/drivers/media/v4l2-core/v4l2-clk.c index 34e416a554f6..297e10e69898 100644 --- a/drivers/media/v4l2-core/v4l2-clk.c +++ b/drivers/media/v4l2-core/v4l2-clk.c @@ -15,6 +15,7 @@ #include <linux/list.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/of.h> #include <linux/slab.h> #include <linux/string.h> @@ -39,6 +40,7 @@ struct v4l2_clk *v4l2_clk_get(struct device *dev, const char *id) { struct v4l2_clk *clk; struct clk *ccf_clk = clk_get(dev, id); + char clk_name[V4L2_CLK_NAME_SIZE]; if (PTR_ERR(ccf_clk) == -EPROBE_DEFER) return ERR_PTR(-EPROBE_DEFER); @@ -57,6 +59,13 @@ struct v4l2_clk *v4l2_clk_get(struct device *dev, const char *id) mutex_lock(&clk_lock); clk = v4l2_clk_find(dev_name(dev)); + /* if dev_name is not found, try use the OF name to find again */ + if (PTR_ERR(clk) == -ENODEV && dev->of_node) { + v4l2_clk_name_of(clk_name, sizeof(clk_name), + of_node_full_name(dev->of_node)); + clk = v4l2_clk_find(clk_name); + } + if (!IS_ERR(clk)) atomic_inc(&clk->use_count); mutex_unlock(&clk_lock); diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 327e83ac2469..8fd84a67478a 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -630,7 +630,7 @@ static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __ } struct v4l2_ext_controls32 { - __u32 ctrl_class; + __u32 which; __u32 count; __u32 error_idx; __u32 reserved[2]; @@ -673,7 +673,7 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext compat_caddr_t p; if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) || - get_user(kp->ctrl_class, &up->ctrl_class) || + get_user(kp->which, &up->which) || get_user(kp->count, &up->count) || get_user(kp->error_idx, &up->error_idx) || copy_from_user(kp->reserved, up->reserved, @@ -723,7 +723,7 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext compat_caddr_t p; if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) || - put_user(kp->ctrl_class, &up->ctrl_class) || + put_user(kp->which, &up->which) || put_user(kp->count, &up->count) || put_user(kp->error_idx, &up->error_idx) || copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 4a1d9fdd14bb..c9d5537b6af7 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1491,6 +1491,17 @@ static int new_to_user(struct v4l2_ext_control *c, return ptr_to_user(c, ctrl, ctrl->p_new); } +/* Helper function: copy the initial control value back to the caller */ +static int def_to_user(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl) +{ + int idx; + + for (idx = 0; idx < ctrl->elems; idx++) + ctrl->type_ops->init(ctrl, idx, ctrl->p_new); + + return ptr_to_user(c, ctrl, ctrl->p_new); +} + /* Helper function: copy the caller-provider value to the given control value */ static int user_to_ptr(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl, @@ -1762,7 +1773,7 @@ static struct v4l2_ctrl_ref *find_private_ref( list_for_each_entry(ref, &hdl->ctrl_refs, node) { /* Search for private user controls that are compatible with VIDIOC_G/S_CTRL. */ - if (V4L2_CTRL_ID2CLASS(ref->ctrl->id) == V4L2_CTRL_CLASS_USER && + if (V4L2_CTRL_ID2WHICH(ref->ctrl->id) == V4L2_CTRL_CLASS_USER && V4L2_CTRL_DRIVER_PRIV(ref->ctrl->id)) { if (!ref->ctrl->is_int) continue; @@ -1831,7 +1842,7 @@ static int handler_new_ref(struct v4l2_ctrl_handler *hdl, struct v4l2_ctrl_ref *ref; struct v4l2_ctrl_ref *new_ref; u32 id = ctrl->id; - u32 class_ctrl = V4L2_CTRL_ID2CLASS(id) | 1; + u32 class_ctrl = V4L2_CTRL_ID2WHICH(id) | 1; int bucket = id % hdl->nr_of_buckets; /* which bucket to use */ /* @@ -2253,9 +2264,9 @@ EXPORT_SYMBOL(v4l2_ctrl_add_handler); bool v4l2_ctrl_radio_filter(const struct v4l2_ctrl *ctrl) { - if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_FM_TX) + if (V4L2_CTRL_ID2WHICH(ctrl->id) == V4L2_CTRL_CLASS_FM_TX) return true; - if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_FM_RX) + if (V4L2_CTRL_ID2WHICH(ctrl->id) == V4L2_CTRL_CLASS_FM_RX) return true; switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -2710,7 +2721,9 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl, cs->error_idx = i; - if (cs->ctrl_class && V4L2_CTRL_ID2CLASS(id) != cs->ctrl_class) + if (cs->which && + cs->which != V4L2_CTRL_WHICH_DEF_VAL && + V4L2_CTRL_ID2WHICH(id) != cs->which) return -EINVAL; /* Old-style private controls are not allowed for @@ -2787,11 +2800,11 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl, /* Handles the corner case where cs->count == 0. It checks whether the specified control class exists. If that class ID is 0, then it checks whether there are any controls at all. */ -static int class_check(struct v4l2_ctrl_handler *hdl, u32 ctrl_class) +static int class_check(struct v4l2_ctrl_handler *hdl, u32 which) { - if (ctrl_class == 0) + if (which == 0 || which == V4L2_CTRL_WHICH_DEF_VAL) return list_empty(&hdl->ctrl_refs) ? -EINVAL : 0; - return find_ref_lock(hdl, ctrl_class | 1) ? 0 : -EINVAL; + return find_ref_lock(hdl, which | 1) ? 0 : -EINVAL; } @@ -2803,15 +2816,18 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs struct v4l2_ctrl_helper *helpers = helper; int ret; int i, j; + bool def_value; + + def_value = (cs->which == V4L2_CTRL_WHICH_DEF_VAL); cs->error_idx = cs->count; - cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class); + cs->which = V4L2_CTRL_ID2WHICH(cs->which); if (hdl == NULL) return -EINVAL; if (cs->count == 0) - return class_check(hdl, cs->ctrl_class); + return class_check(hdl, cs->which); if (cs->count > ARRAY_SIZE(helper)) { helpers = kmalloc_array(cs->count, sizeof(helper[0]), @@ -2829,9 +2845,11 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs for (i = 0; !ret && i < cs->count; i++) { int (*ctrl_to_user)(struct v4l2_ext_control *c, - struct v4l2_ctrl *ctrl) = cur_to_user; + struct v4l2_ctrl *ctrl); struct v4l2_ctrl *master; + ctrl_to_user = def_value ? def_to_user : cur_to_user; + if (helpers[i].mref == NULL) continue; @@ -2841,8 +2859,9 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs v4l2_ctrl_lock(master); /* g_volatile_ctrl will update the new control values */ - if ((master->flags & V4L2_CTRL_FLAG_VOLATILE) || - (master->has_volatiles && !is_cur_manual(master))) { + if (!def_value && + ((master->flags & V4L2_CTRL_FLAG_VOLATILE) || + (master->has_volatiles && !is_cur_manual(master)))) { for (j = 0; j < master->ncontrols; j++) cur_to_new(master->cluster[j]); ret = call_op(master, g_volatile_ctrl); @@ -3064,13 +3083,18 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl, int ret; cs->error_idx = cs->count; - cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class); + + /* Default value cannot be changed */ + if (cs->which == V4L2_CTRL_WHICH_DEF_VAL) + return -EINVAL; + + cs->which = V4L2_CTRL_ID2WHICH(cs->which); if (hdl == NULL) return -EINVAL; if (cs->count == 0) - return class_check(hdl, cs->ctrl_class); + return class_check(hdl, cs->which); if (cs->count > ARRAY_SIZE(helper)) { helpers = kmalloc_array(cs->count, sizeof(helper[0]), @@ -3300,7 +3324,8 @@ EXPORT_SYMBOL(v4l2_ctrl_notify); int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl, s64 min, s64 max, u64 step, s64 def) { - bool changed; + bool value_changed; + bool range_changed = false; int ret; lockdep_assert_held(ctrl->handler->lock); @@ -3324,10 +3349,14 @@ int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl, default: return -EINVAL; } - ctrl->minimum = min; - ctrl->maximum = max; - ctrl->step = step; - ctrl->default_value = def; + if ((ctrl->minimum != min) || (ctrl->maximum != max) || + (ctrl->step != step) || ctrl->default_value != def) { + range_changed = true; + ctrl->minimum = min; + ctrl->maximum = max; + ctrl->step = step; + ctrl->default_value = def; + } cur_to_new(ctrl); if (validate_new(ctrl, ctrl->p_new)) { if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64) @@ -3337,12 +3366,12 @@ int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl, } if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64) - changed = *ctrl->p_new.p_s64 != *ctrl->p_cur.p_s64; + value_changed = *ctrl->p_new.p_s64 != *ctrl->p_cur.p_s64; else - changed = *ctrl->p_new.p_s32 != *ctrl->p_cur.p_s32; - if (changed) + value_changed = *ctrl->p_new.p_s32 != *ctrl->p_cur.p_s32; + if (value_changed) ret = set_ctrl(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE); - else + else if (range_changed) send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE); return ret; } diff --git a/drivers/media/v4l2-core/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c index 5b0a30b9252b..7129e438f29e 100644 --- a/drivers/media/v4l2-core/v4l2-device.c +++ b/drivers/media/v4l2-core/v4l2-device.c @@ -118,11 +118,20 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev) if (sd->flags & V4L2_SUBDEV_FL_IS_I2C) { struct i2c_client *client = v4l2_get_subdevdata(sd); - /* We need to unregister the i2c client explicitly. - We cannot rely on i2c_del_adapter to always - unregister clients for us, since if the i2c bus - is a platform bus, then it is never deleted. */ - if (client) + /* + * We need to unregister the i2c client + * explicitly. We cannot rely on + * i2c_del_adapter to always unregister + * clients for us, since if the i2c bus is a + * platform bus, then it is never deleted. + * + * Device tree or ACPI based devices must not + * be unregistered as they have not been + * registered by us, and would not be + * re-created by just probing the V4L2 driver. + */ + if (client && + !client->dev.of_node && !client->dev.fwnode) i2c_unregister_device(client); continue; } @@ -131,7 +140,7 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev) if (sd->flags & V4L2_SUBDEV_FL_IS_SPI) { struct spi_device *spi = v4l2_get_subdevdata(sd); - if (spi) + if (spi && !spi->dev.of_node && !spi->dev.fwnode) spi_unregister_device(spi); continue; } diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index 6a83d6191684..ec258b73001a 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c @@ -209,8 +209,13 @@ bool v4l2_find_dv_timings_cap(struct v4l2_dv_timings *t, if (v4l2_valid_dv_timings(v4l2_dv_timings_presets + i, cap, fnc, fnc_handle) && v4l2_match_dv_timings(t, v4l2_dv_timings_presets + i, - pclock_delta)) { + pclock_delta, false)) { + u32 flags = t->bt.flags & V4L2_DV_FL_REDUCED_FPS; + *t = v4l2_dv_timings_presets[i]; + if (can_reduce_fps(&t->bt)) + t->bt.flags |= flags; + return true; } } @@ -223,12 +228,14 @@ EXPORT_SYMBOL_GPL(v4l2_find_dv_timings_cap); * @t1 - compare this v4l2_dv_timings struct... * @t2 - with this struct. * @pclock_delta - the allowed pixelclock deviation. + * @match_reduced_fps - if true, then fail if V4L2_DV_FL_REDUCED_FPS does not + * match. * * Compare t1 with t2 with a given margin of error for the pixelclock. */ bool v4l2_match_dv_timings(const struct v4l2_dv_timings *t1, const struct v4l2_dv_timings *t2, - unsigned pclock_delta) + unsigned pclock_delta, bool match_reduced_fps) { if (t1->type != t2->type || t1->type != V4L2_DV_BT_656_1120) return false; @@ -239,9 +246,14 @@ bool v4l2_match_dv_timings(const struct v4l2_dv_timings *t1, t1->bt.pixelclock >= t2->bt.pixelclock - pclock_delta && t1->bt.pixelclock <= t2->bt.pixelclock + pclock_delta && t1->bt.hfrontporch == t2->bt.hfrontporch && + t1->bt.hsync == t2->bt.hsync && + t1->bt.hbackporch == t2->bt.hbackporch && t1->bt.vfrontporch == t2->bt.vfrontporch && t1->bt.vsync == t2->bt.vsync && t1->bt.vbackporch == t2->bt.vbackporch && + (!match_reduced_fps || + (t1->bt.flags & V4L2_DV_FL_REDUCED_FPS) == + (t2->bt.flags & V4L2_DV_FL_REDUCED_FPS)) && (!t1->bt.interlaced || (t1->bt.il_vfrontporch == t2->bt.il_vfrontporch && t1->bt.il_vsync == t2->bt.il_vsync && diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 7486af2c8ae4..8a018c6dd16a 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -565,8 +565,8 @@ static void v4l_print_ext_controls(const void *arg, bool write_only) const struct v4l2_ext_controls *p = arg; int i; - pr_cont("class=0x%x, count=%d, error_idx=%d", - p->ctrl_class, p->count, p->error_idx); + pr_cont("which=0x%x, count=%d, error_idx=%d", + p->which, p->count, p->error_idx); for (i = 0; i < p->count; i++) { if (!p->controls[i].size) pr_cont(", id/val=0x%x/0x%x", @@ -902,13 +902,13 @@ static int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv) Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL is it allowed for backwards compatibility. */ - if (!allow_priv && c->ctrl_class == V4L2_CID_PRIVATE_BASE) + if (!allow_priv && c->which == V4L2_CID_PRIVATE_BASE) return 0; - if (c->ctrl_class == 0) + if (!c->which) return 1; /* Check that all controls are from the same control class. */ for (i = 0; i < c->count; i++) { - if (V4L2_CTRL_ID2CLASS(c->controls[i].id) != c->ctrl_class) { + if (V4L2_CTRL_ID2WHICH(c->controls[i].id) != c->which) { c->error_idx = i; return 0; } @@ -1969,7 +1969,7 @@ static int v4l_g_ctrl(const struct v4l2_ioctl_ops *ops, if (ops->vidioc_g_ext_ctrls == NULL) return -ENOTTY; - ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id); + ctrls.which = V4L2_CTRL_ID2WHICH(p->id); ctrls.count = 1; ctrls.controls = &ctrl; ctrl.id = p->id; @@ -2003,7 +2003,7 @@ static int v4l_s_ctrl(const struct v4l2_ioctl_ops *ops, if (ops->vidioc_s_ext_ctrls == NULL) return -ENOTTY; - ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id); + ctrls.which = V4L2_CTRL_ID2WHICH(p->id); ctrls.count = 1; ctrls.controls = &ctrl; ctrl.id = p->id; diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 33bdd81065e8..c5d49d7a0d76 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -28,11 +28,161 @@ #include <trace/events/vb2.h> -#include "videobuf2-internal.h" +static int debug; +module_param(debug, int, 0644); -int vb2_debug; -EXPORT_SYMBOL_GPL(vb2_debug); -module_param_named(debug, vb2_debug, int, 0644); +#define dprintk(level, fmt, arg...) \ + do { \ + if (debug >= level) \ + pr_info("vb2-core: %s: " fmt, __func__, ## arg); \ + } while (0) + +#ifdef CONFIG_VIDEO_ADV_DEBUG + +/* + * If advanced debugging is on, then count how often each op is called + * successfully, which can either be per-buffer or per-queue. + * + * This makes it easy to check that the 'init' and 'cleanup' + * (and variations thereof) stay balanced. + */ + +#define log_memop(vb, op) \ + dprintk(2, "call_memop(%p, %d, %s)%s\n", \ + (vb)->vb2_queue, (vb)->index, #op, \ + (vb)->vb2_queue->mem_ops->op ? "" : " (nop)") + +#define call_memop(vb, op, args...) \ +({ \ + struct vb2_queue *_q = (vb)->vb2_queue; \ + int err; \ + \ + log_memop(vb, op); \ + err = _q->mem_ops->op ? _q->mem_ops->op(args) : 0; \ + if (!err) \ + (vb)->cnt_mem_ ## op++; \ + err; \ +}) + +#define call_ptr_memop(vb, op, args...) \ +({ \ + struct vb2_queue *_q = (vb)->vb2_queue; \ + void *ptr; \ + \ + log_memop(vb, op); \ + ptr = _q->mem_ops->op ? _q->mem_ops->op(args) : NULL; \ + if (!IS_ERR_OR_NULL(ptr)) \ + (vb)->cnt_mem_ ## op++; \ + ptr; \ +}) + +#define call_void_memop(vb, op, args...) \ +({ \ + struct vb2_queue *_q = (vb)->vb2_queue; \ + \ + log_memop(vb, op); \ + if (_q->mem_ops->op) \ + _q->mem_ops->op(args); \ + (vb)->cnt_mem_ ## op++; \ +}) + +#define log_qop(q, op) \ + dprintk(2, "call_qop(%p, %s)%s\n", q, #op, \ + (q)->ops->op ? "" : " (nop)") + +#define call_qop(q, op, args...) \ +({ \ + int err; \ + \ + log_qop(q, op); \ + err = (q)->ops->op ? (q)->ops->op(args) : 0; \ + if (!err) \ + (q)->cnt_ ## op++; \ + err; \ +}) + +#define call_void_qop(q, op, args...) \ +({ \ + log_qop(q, op); \ + if ((q)->ops->op) \ + (q)->ops->op(args); \ + (q)->cnt_ ## op++; \ +}) + +#define log_vb_qop(vb, op, args...) \ + dprintk(2, "call_vb_qop(%p, %d, %s)%s\n", \ + (vb)->vb2_queue, (vb)->index, #op, \ + (vb)->vb2_queue->ops->op ? "" : " (nop)") + +#define call_vb_qop(vb, op, args...) \ +({ \ + int err; \ + \ + log_vb_qop(vb, op); \ + err = (vb)->vb2_queue->ops->op ? \ + (vb)->vb2_queue->ops->op(args) : 0; \ + if (!err) \ + (vb)->cnt_ ## op++; \ + err; \ +}) + +#define call_void_vb_qop(vb, op, args...) \ +({ \ + log_vb_qop(vb, op); \ + if ((vb)->vb2_queue->ops->op) \ + (vb)->vb2_queue->ops->op(args); \ + (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 call_ptr_memop(vb, op, args...) \ + ((vb)->vb2_queue->mem_ops->op ? \ + (vb)->vb2_queue->mem_ops->op(args) : NULL) + +#define call_void_memop(vb, op, args...) \ + do { \ + if ((vb)->vb2_queue->mem_ops->op) \ + (vb)->vb2_queue->mem_ops->op(args); \ + } while (0) + +#define call_qop(q, op, args...) \ + ((q)->ops->op ? (q)->ops->op(args) : 0) + +#define call_void_qop(q, op, args...) \ + do { \ + if ((q)->ops->op) \ + (q)->ops->op(args); \ + } while (0) + +#define call_vb_qop(vb, op, args...) \ + ((vb)->vb2_queue->ops->op ? (vb)->vb2_queue->ops->op(args) : 0) + +#define call_void_vb_qop(vb, op, args...) \ + do { \ + if ((vb)->vb2_queue->ops->op) \ + (vb)->vb2_queue->ops->op(args); \ + } while (0) + +#endif + +#define call_bufop(q, op, args...) \ +({ \ + int ret = 0; \ + if (q && q->buf_ops && q->buf_ops->op) \ + ret = q->buf_ops->op(args); \ + ret; \ +}) + +#define call_void_bufop(q, op, args...) \ +({ \ + if (q && q->buf_ops && q->buf_ops->op) \ + q->buf_ops->op(args); \ +}) static void __vb2_queue_cancel(struct vb2_queue *q); static void __enqueue_in_driver(struct vb2_buffer *vb); @@ -53,7 +203,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) * NOTE: mmapped areas should be page aligned */ for (plane = 0; plane < vb->num_planes; ++plane) { - unsigned long size = PAGE_ALIGN(q->plane_sizes[plane]); + unsigned long size = PAGE_ALIGN(vb->planes[plane].length); mem_priv = call_ptr_memop(vb, alloc, q->alloc_ctx[plane], size, dma_dir, q->gfp_flags); @@ -62,7 +212,6 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) /* Associate allocator private data with this plane */ vb->planes[plane].mem_priv = mem_priv; - vb->planes[plane].length = q->plane_sizes[plane]; } return 0; @@ -137,57 +286,30 @@ static void __vb2_buf_dmabuf_put(struct vb2_buffer *vb) } /** - * __setup_lengths() - setup initial lengths for every plane in - * every buffer on the queue - */ -static void __setup_lengths(struct vb2_queue *q, unsigned int n) -{ - unsigned int buffer, plane; - struct vb2_buffer *vb; - - for (buffer = q->num_buffers; buffer < q->num_buffers + n; ++buffer) { - vb = q->bufs[buffer]; - if (!vb) - continue; - - for (plane = 0; plane < vb->num_planes; ++plane) - vb->planes[plane].length = q->plane_sizes[plane]; - } -} - -/** * __setup_offsets() - setup unique offsets ("cookies") for every plane in - * every buffer on the queue + * the buffer. */ -static void __setup_offsets(struct vb2_queue *q, unsigned int n) +static void __setup_offsets(struct vb2_buffer *vb) { - unsigned int buffer, plane; - struct vb2_buffer *vb; - unsigned long off; + struct vb2_queue *q = vb->vb2_queue; + unsigned int plane; + unsigned long off = 0; + + if (vb->index) { + struct vb2_buffer *prev = q->bufs[vb->index - 1]; + struct vb2_plane *p = &prev->planes[prev->num_planes - 1]; - if (q->num_buffers) { - struct vb2_plane *p; - vb = q->bufs[q->num_buffers - 1]; - p = &vb->planes[vb->num_planes - 1]; off = PAGE_ALIGN(p->m.offset + p->length); - } else { - off = 0; } - for (buffer = q->num_buffers; buffer < q->num_buffers + n; ++buffer) { - vb = q->bufs[buffer]; - if (!vb) - continue; - - for (plane = 0; plane < vb->num_planes; ++plane) { - vb->planes[plane].m.offset = off; + for (plane = 0; plane < vb->num_planes; ++plane) { + vb->planes[plane].m.offset = off; - dprintk(3, "buffer %d, plane %d offset 0x%08lx\n", - buffer, plane, off); + dprintk(3, "buffer %d, plane %d offset 0x%08lx\n", + vb->index, plane, off); - off += vb->planes[plane].length; - off = PAGE_ALIGN(off); - } + off += vb->planes[plane].length; + off = PAGE_ALIGN(off); } } @@ -199,9 +321,10 @@ static void __setup_offsets(struct vb2_queue *q, unsigned int n) * Returns the number of buffers successfully allocated. */ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, - unsigned int num_buffers, unsigned int num_planes) + unsigned int num_buffers, unsigned int num_planes, + const unsigned plane_sizes[VB2_MAX_PLANES]) { - unsigned int buffer; + unsigned int buffer, plane; struct vb2_buffer *vb; int ret; @@ -219,6 +342,11 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, vb->index = q->num_buffers + buffer; vb->type = q->type; vb->memory = memory; + for (plane = 0; plane < num_planes; ++plane) { + vb->planes[plane].length = plane_sizes[plane]; + vb->planes[plane].min_length = plane_sizes[plane]; + } + q->bufs[vb->index] = vb; /* Allocate video buffer memory for the MMAP type */ if (memory == VB2_MEMORY_MMAP) { @@ -226,9 +354,11 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, if (ret) { dprintk(1, "failed allocating memory for " "buffer %d\n", buffer); + q->bufs[vb->index] = NULL; kfree(vb); break; } + __setup_offsets(vb); /* * Call the driver-provided buffer initialization * callback, if given. An error in initialization @@ -239,18 +369,13 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, dprintk(1, "buffer %d %p initialization" " failed\n", buffer, vb); __vb2_buf_mem_free(vb); + q->bufs[vb->index] = NULL; kfree(vb); break; } } - - q->bufs[q->num_buffers + buffer] = vb; } - __setup_lengths(q, buffer); - if (memory == VB2_MEMORY_MMAP) - __setup_offsets(q, buffer); - dprintk(1, "allocated %d buffers, %d plane(s) each\n", buffer, num_planes); @@ -330,7 +455,7 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) bool unbalanced = q->cnt_start_streaming != q->cnt_stop_streaming || q->cnt_wait_prepare != q->cnt_wait_finish; - if (unbalanced || vb2_debug) { + 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", @@ -356,7 +481,7 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) vb->cnt_buf_prepare != vb->cnt_buf_finish || vb->cnt_buf_init != vb->cnt_buf_cleanup; - if (unbalanced || vb2_debug) { + 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", @@ -442,13 +567,10 @@ static bool __buffers_in_use(struct vb2_queue *q) * Should be called from vidioc_querybuf ioctl handler in driver. * The passed buffer should have been verified. * This function fills the relevant information for the userspace. - * - * The return values from this function are intended to be directly returned - * from vidioc_querybuf handler in driver. */ -int vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb) +void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb) { - return call_bufop(q, fill_user_buffer, q->bufs[index], pb); + call_void_bufop(q, fill_user_buffer, q->bufs[index], pb); } EXPORT_SYMBOL_GPL(vb2_core_querybuf); @@ -570,6 +692,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, unsigned int *count) { unsigned int num_buffers, allocated_buffers, num_planes = 0; + unsigned plane_sizes[VB2_MAX_PLANES] = { }; int ret; if (q->streaming) { @@ -613,7 +736,6 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, */ num_buffers = min_t(unsigned int, *count, VB2_MAX_FRAME); num_buffers = max_t(unsigned int, num_buffers, q->min_buffers_needed); - memset(q->plane_sizes, 0, sizeof(q->plane_sizes)); memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx)); q->memory = memory; @@ -621,14 +743,14 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, * Ask the driver how many buffers and planes per buffer it requires. * Driver also sets the size and allocator context for each plane. */ - ret = call_qop(q, queue_setup, q, NULL, &num_buffers, &num_planes, - q->plane_sizes, q->alloc_ctx); + ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes, + plane_sizes, q->alloc_ctx); if (ret) return ret; /* Finally, allocate buffers and video memory */ allocated_buffers = - __vb2_queue_alloc(q, memory, num_buffers, num_planes); + __vb2_queue_alloc(q, memory, num_buffers, num_planes, plane_sizes); if (allocated_buffers == 0) { dprintk(1, "memory allocation failed\n"); return -ENOMEM; @@ -646,9 +768,16 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, */ if (!ret && allocated_buffers < num_buffers) { num_buffers = allocated_buffers; + /* + * num_planes is set by the previous queue_setup(), but since it + * signals to queue_setup() whether it is called from create_bufs() + * vs reqbufs() we zero it here to signal that queue_setup() is + * called for the reqbufs() case. + */ + num_planes = 0; - ret = call_qop(q, queue_setup, q, NULL, &num_buffers, - &num_planes, q->plane_sizes, q->alloc_ctx); + ret = call_qop(q, queue_setup, q, &num_buffers, + &num_planes, plane_sizes, q->alloc_ctx); if (!ret && allocated_buffers < num_buffers) ret = -ENOMEM; @@ -701,9 +830,11 @@ EXPORT_SYMBOL_GPL(vb2_core_reqbufs); * from vidioc_create_bufs handler in driver. */ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, - unsigned int *count, const void *parg) + unsigned int *count, unsigned requested_planes, + const unsigned requested_sizes[]) { unsigned int num_planes = 0, num_buffers, allocated_buffers; + unsigned plane_sizes[VB2_MAX_PLANES] = { }; int ret; if (q->num_buffers == VB2_MAX_FRAME) { @@ -712,7 +843,6 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, } if (!q->num_buffers) { - memset(q->plane_sizes, 0, sizeof(q->plane_sizes)); memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx)); q->memory = memory; q->waiting_for_buffers = !q->is_output; @@ -720,18 +850,23 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, num_buffers = min(*count, VB2_MAX_FRAME - q->num_buffers); + if (requested_planes && requested_sizes) { + num_planes = requested_planes; + memcpy(plane_sizes, requested_sizes, sizeof(plane_sizes)); + } + /* * Ask the driver, whether the requested number of buffers, planes per * buffer and their sizes are acceptable */ - ret = call_qop(q, queue_setup, q, parg, &num_buffers, - &num_planes, q->plane_sizes, q->alloc_ctx); + ret = call_qop(q, queue_setup, q, &num_buffers, + &num_planes, plane_sizes, q->alloc_ctx); if (ret) return ret; /* Finally, allocate buffers and video memory */ allocated_buffers = __vb2_queue_alloc(q, memory, num_buffers, - num_planes); + num_planes, plane_sizes); if (allocated_buffers == 0) { dprintk(1, "memory allocation failed\n"); return -ENOMEM; @@ -747,8 +882,8 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, * q->num_buffers contains the total number of buffers, that the * queue driver has set up */ - ret = call_qop(q, queue_setup, q, parg, &num_buffers, - &num_planes, q->plane_sizes, q->alloc_ctx); + ret = call_qop(q, queue_setup, q, &num_buffers, + &num_planes, plane_sizes, q->alloc_ctx); if (!ret && allocated_buffers < num_buffers) ret = -ENOMEM; @@ -964,11 +1099,12 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const void *pb) "reacquiring memory\n", plane); /* Check if the provided plane buffer is large enough */ - if (planes[plane].length < q->plane_sizes[plane]) { + if (planes[plane].length < vb->planes[plane].min_length) { dprintk(1, "provided buffer size %u is less than " "setup size %u for plane %d\n", planes[plane].length, - q->plane_sizes[plane], plane); + vb->planes[plane].min_length, + plane); ret = -EINVAL; goto err; } @@ -1081,7 +1217,7 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const void *pb) if (planes[plane].length == 0) planes[plane].length = dbuf->size; - if (planes[plane].length < q->plane_sizes[plane]) { + if (planes[plane].length < vb->planes[plane].min_length) { dprintk(1, "invalid dmabuf length for plane %d\n", plane); ret = -EINVAL; @@ -1263,9 +1399,7 @@ int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb) return ret; /* Fill buffer information for the userspace */ - ret = call_bufop(q, fill_user_buffer, vb, pb); - if (ret) - return ret; + call_void_bufop(q, fill_user_buffer, vb, pb); dprintk(1, "prepare of buffer %d succeeded\n", vb->index); @@ -1386,7 +1520,7 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb) q->waiting_for_buffers = false; vb->state = VB2_BUF_STATE_QUEUED; - call_bufop(q, set_timestamp, vb, pb); + call_void_bufop(q, copy_timestamp, vb, pb); trace_vb2_qbuf(q, vb); @@ -1398,9 +1532,7 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb) __enqueue_in_driver(vb); /* Fill buffer information for the userspace */ - ret = call_bufop(q, fill_user_buffer, vb, pb); - if (ret) - return ret; + call_void_bufop(q, fill_user_buffer, vb, pb); /* * If streamon has been called, and we haven't yet called @@ -1623,9 +1755,7 @@ int vb2_core_dqbuf(struct vb2_queue *q, void *pb, bool nonblocking) call_void_vb_qop(vb, buf_finish, vb); /* Fill buffer information for the userspace */ - ret = call_bufop(q, fill_user_buffer, vb, pb); - if (ret) - return ret; + call_void_bufop(q, fill_user_buffer, vb, pb); /* Remove from videobuf queue */ list_del(&vb->queued_entry); @@ -2073,6 +2203,8 @@ int vb2_core_queue_init(struct vb2_queue *q) } EXPORT_SYMBOL_GPL(vb2_core_queue_init); +static int __vb2_init_fileio(struct vb2_queue *q, int read); +static int __vb2_cleanup_fileio(struct vb2_queue *q); /** * vb2_core_queue_release() - stop streaming, release the queue and free memory * @q: videobuf2 queue @@ -2083,6 +2215,7 @@ EXPORT_SYMBOL_GPL(vb2_core_queue_init); */ void vb2_core_queue_release(struct vb2_queue *q) { + __vb2_cleanup_fileio(q); __vb2_queue_cancel(q); mutex_lock(&q->mmap_lock); __vb2_queue_free(q, q->num_buffers); @@ -2090,6 +2223,619 @@ void vb2_core_queue_release(struct vb2_queue *q) } EXPORT_SYMBOL_GPL(vb2_core_queue_release); -MODULE_DESCRIPTION("Driver helper framework for Video for Linux 2"); +/** + * vb2_core_poll() - implements poll userspace operation + * @q: videobuf2 queue + * @file: file argument passed to the poll file operation handler + * @wait: wait argument passed to the poll file operation handler + * + * This function implements poll file operation handler for a driver. + * For CAPTURE queues, if a buffer is ready to be dequeued, the userspace will + * be informed that the file descriptor of a video device is available for + * reading. + * For OUTPUT queues, if a buffer is ready to be dequeued, the file descriptor + * will be reported as available for writing. + * + * The return values from this function are intended to be directly returned + * from poll handler in driver. + */ +unsigned int vb2_core_poll(struct vb2_queue *q, struct file *file, + poll_table *wait) +{ + unsigned long req_events = poll_requested_events(wait); + struct vb2_buffer *vb = NULL; + unsigned long flags; + + if (!q->is_output && !(req_events & (POLLIN | POLLRDNORM))) + return 0; + if (q->is_output && !(req_events & (POLLOUT | POLLWRNORM))) + return 0; + + /* + * Start file I/O emulator only if streaming API has not been used yet. + */ + if (q->num_buffers == 0 && !vb2_fileio_is_active(q)) { + if (!q->is_output && (q->io_modes & VB2_READ) && + (req_events & (POLLIN | POLLRDNORM))) { + if (__vb2_init_fileio(q, 1)) + return POLLERR; + } + if (q->is_output && (q->io_modes & VB2_WRITE) && + (req_events & (POLLOUT | POLLWRNORM))) { + if (__vb2_init_fileio(q, 0)) + return POLLERR; + /* + * Write to OUTPUT queue can be done immediately. + */ + return POLLOUT | POLLWRNORM; + } + } + + /* + * There is nothing to wait for if the queue isn't streaming, or if the + * error flag is set. + */ + if (!vb2_is_streaming(q) || q->error) + return POLLERR; + + /* + * For output streams you can call write() as long as there are fewer + * buffers queued than there are buffers available. + */ + if (q->is_output && q->fileio && q->queued_count < q->num_buffers) + return POLLOUT | POLLWRNORM; + + if (list_empty(&q->done_list)) { + /* + * If the last buffer was dequeued from a capture queue, + * return immediately. DQBUF will return -EPIPE. + */ + if (q->last_buffer_dequeued) + return POLLIN | POLLRDNORM; + + poll_wait(file, &q->done_wq, wait); + } + + /* + * Take first buffer available for dequeuing. + */ + spin_lock_irqsave(&q->done_lock, flags); + if (!list_empty(&q->done_list)) + vb = list_first_entry(&q->done_list, struct vb2_buffer, + done_entry); + spin_unlock_irqrestore(&q->done_lock, flags); + + if (vb && (vb->state == VB2_BUF_STATE_DONE + || vb->state == VB2_BUF_STATE_ERROR)) { + return (q->is_output) ? + POLLOUT | POLLWRNORM : + POLLIN | POLLRDNORM; + } + return 0; +} +EXPORT_SYMBOL_GPL(vb2_core_poll); + +/** + * struct vb2_fileio_buf - buffer context used by file io emulator + * + * vb2 provides a compatibility layer and emulator of file io (read and + * write) calls on top of streaming API. This structure is used for + * tracking context related to the buffers. + */ +struct vb2_fileio_buf { + void *vaddr; + unsigned int size; + unsigned int pos; + unsigned int queued:1; +}; + +/** + * 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 + * or write function. + */ +struct vb2_fileio_data { + unsigned int count; + unsigned int type; + unsigned int memory; + struct vb2_buffer *b; + struct vb2_fileio_buf bufs[VB2_MAX_FRAME]; + unsigned int cur_index; + unsigned int initial_index; + unsigned int q_count; + unsigned int dq_count; + unsigned read_once:1; + unsigned write_immediately:1; +}; + +/** + * __vb2_init_fileio() - initialize file io emulator + * @q: videobuf2 queue + * @read: mode selector (1 means read, 0 means write) + */ +static int __vb2_init_fileio(struct vb2_queue *q, int read) +{ + struct vb2_fileio_data *fileio; + int i, ret; + unsigned int count = 0; + + /* + * Sanity check + */ + 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. + */ + if (!q->mem_ops->vaddr) + return -EBUSY; + + /* + * Check if streaming api has not been already activated. + */ + if (q->streaming || q->num_buffers > 0) + return -EBUSY; + + /* + * Start with count 1, driver can increase it in queue_setup() + */ + count = 1; + + dprintk(3, "setting up file io: mode %s, count %d, read_once %d, write_immediately %d\n", + (read) ? "read" : "write", count, q->fileio_read_once, + q->fileio_write_immediately); + + fileio = kzalloc(sizeof(*fileio), GFP_KERNEL); + if (fileio == NULL) + return -ENOMEM; + + fileio->b = kzalloc(q->buf_struct_size, GFP_KERNEL); + if (fileio->b == NULL) { + kfree(fileio); + return -ENOMEM; + } + + fileio->read_once = q->fileio_read_once; + fileio->write_immediately = q->fileio_write_immediately; + + /* + * Request buffers and use MMAP type to force driver + * to allocate buffers by itself. + */ + fileio->count = count; + fileio->memory = VB2_MEMORY_MMAP; + fileio->type = q->type; + q->fileio = fileio; + ret = vb2_core_reqbufs(q, fileio->memory, &fileio->count); + if (ret) + goto err_kfree; + + /* + * Check if plane_count is correct + * (multiplane buffers are not supported). + */ + if (q->bufs[0]->num_planes != 1) { + ret = -EBUSY; + goto err_reqbufs; + } + + /* + * Get kernel address of each buffer. + */ + for (i = 0; i < q->num_buffers; i++) { + fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0); + if (fileio->bufs[i].vaddr == NULL) { + ret = -EINVAL; + goto err_reqbufs; + } + fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0); + } + + /* + * Read mode requires pre queuing of all buffers. + */ + if (read) { + /* + * Queue all buffers. + */ + for (i = 0; i < q->num_buffers; i++) { + struct vb2_buffer *b = fileio->b; + + memset(b, 0, q->buf_struct_size); + b->type = q->type; + b->memory = q->memory; + b->index = i; + ret = vb2_core_qbuf(q, i, b); + if (ret) + goto err_reqbufs; + fileio->bufs[i].queued = 1; + } + /* + * 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; + } + + /* + * Start streaming. + */ + ret = vb2_core_streamon(q, q->type); + if (ret) + goto err_reqbufs; + + return ret; + +err_reqbufs: + fileio->count = 0; + vb2_core_reqbufs(q, fileio->memory, &fileio->count); + +err_kfree: + q->fileio = NULL; + kfree(fileio); + return ret; +} + +/** + * __vb2_cleanup_fileio() - free resourced used by file io emulator + * @q: videobuf2 queue + */ +static int __vb2_cleanup_fileio(struct vb2_queue *q) +{ + struct vb2_fileio_data *fileio = q->fileio; + + if (fileio) { + vb2_core_streamoff(q, q->type); + q->fileio = NULL; + fileio->count = 0; + vb2_core_reqbufs(q, fileio->memory, &fileio->count); + kfree(fileio->b); + kfree(fileio); + dprintk(3, "file io emulator closed\n"); + } + return 0; +} + +/** + * __vb2_perform_fileio() - perform a single file io (read or write) operation + * @q: videobuf2 queue + * @data: pointed to target userspace buffer + * @count: number of bytes to read or write + * @ppos: file handle position tracking pointer + * @nonblock: mode selector (1 means blocking calls, 0 means nonblocking) + * @read: access mode selector (1 means read, 0 means write) + */ +static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_t count, + loff_t *ppos, int nonblock, int read) +{ + struct vb2_fileio_data *fileio; + struct vb2_fileio_buf *buf; + bool is_multiplanar = q->is_multiplanar; + /* + * When using write() to write data to an output video node the vb2 core + * should copy timestamps if V4L2_BUF_FLAG_TIMESTAMP_COPY is set. Nobody + * else is able to provide this information with the write() operation. + */ + bool copy_timestamp = !read && q->copy_timestamp; + int ret, index; + + dprintk(3, "mode %s, offset %ld, count %zd, %sblocking\n", + read ? "read" : "write", (long)*ppos, count, + nonblock ? "non" : ""); + + if (!data) + return -EINVAL; + + /* + * Initialize emulator on first call. + */ + if (!vb2_fileio_is_active(q)) { + ret = __vb2_init_fileio(q, read); + dprintk(3, "vb2_init_fileio result: %d\n", ret); + if (ret) + return ret; + } + fileio = q->fileio; + + /* + * Check if we need to dequeue the buffer. + */ + index = fileio->cur_index; + if (index >= q->num_buffers) { + struct vb2_buffer *b = fileio->b; + + /* + * Call vb2_dqbuf to get buffer back. + */ + memset(b, 0, q->buf_struct_size); + b->type = q->type; + b->memory = q->memory; + ret = vb2_core_dqbuf(q, b, nonblock); + dprintk(5, "vb2_dqbuf result: %d\n", ret); + if (ret) + return ret; + fileio->dq_count += 1; + + fileio->cur_index = index = b->index; + buf = &fileio->bufs[index]; + + /* + * Get number of bytes filled by the driver + */ + buf->pos = 0; + buf->queued = 0; + buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0) + : vb2_plane_size(q->bufs[index], 0); + /* Compensate for data_offset on read in the multiplanar case. */ + if (is_multiplanar && read && + b->planes[0].data_offset < buf->size) { + buf->pos = b->planes[0].data_offset; + buf->size -= buf->pos; + } + } else { + buf = &fileio->bufs[index]; + } + + /* + * Limit count on last few bytes of the buffer. + */ + if (buf->pos + count > buf->size) { + count = buf->size - buf->pos; + dprintk(5, "reducing read count: %zd\n", count); + } + + /* + * Transfer data to userspace. + */ + dprintk(3, "copying %zd bytes - buffer %d, offset %u\n", + count, index, buf->pos); + if (read) + ret = copy_to_user(data, buf->vaddr + buf->pos, count); + else + ret = copy_from_user(buf->vaddr + buf->pos, data, count); + if (ret) { + dprintk(3, "error copying data\n"); + return -EFAULT; + } + + /* + * Update counters. + */ + buf->pos += count; + *ppos += count; + + /* + * Queue next buffer if required. + */ + if (buf->pos == buf->size || (!read && fileio->write_immediately)) { + struct vb2_buffer *b = fileio->b; + + /* + * Check if this is the last buffer to read. + */ + if (read && fileio->read_once && fileio->dq_count == 1) { + dprintk(3, "read limit reached\n"); + return __vb2_cleanup_fileio(q); + } + + /* + * Call vb2_qbuf and give buffer to the driver. + */ + memset(b, 0, q->buf_struct_size); + b->type = q->type; + b->memory = q->memory; + b->index = index; + b->planes[0].bytesused = buf->pos; + + if (copy_timestamp) + b->timestamp = ktime_get_ns(); + ret = vb2_core_qbuf(q, index, b); + dprintk(5, "vb2_dbuf result: %d\n", ret); + if (ret) + return ret; + + /* + * Buffer has been queued, update the status + */ + buf->pos = 0; + buf->queued = 1; + buf->size = vb2_plane_size(q->bufs[index], 0); + fileio->q_count += 1; + /* + * 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; + } + + /* + * Return proper number of bytes processed. + */ + if (ret == 0) + ret = count; + return ret; +} + +size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count, + loff_t *ppos, int nonblocking) +{ + return __vb2_perform_fileio(q, data, count, ppos, nonblocking, 1); +} +EXPORT_SYMBOL_GPL(vb2_read); + +size_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count, + loff_t *ppos, int nonblocking) +{ + return __vb2_perform_fileio(q, (char __user *) data, count, + ppos, nonblocking, 0); +} +EXPORT_SYMBOL_GPL(vb2_write); + +struct vb2_threadio_data { + struct task_struct *thread; + vb2_thread_fnc fnc; + void *priv; + bool stop; +}; + +static int vb2_thread(void *data) +{ + struct vb2_queue *q = data; + struct vb2_threadio_data *threadio = q->threadio; + struct vb2_fileio_data *fileio = q->fileio; + bool copy_timestamp = false; + int prequeue = 0; + int index = 0; + int ret = 0; + + if (q->is_output) { + prequeue = q->num_buffers; + copy_timestamp = q->copy_timestamp; + } + + set_freezable(); + + for (;;) { + struct vb2_buffer *vb; + struct vb2_buffer *b = fileio->b; + + /* + * Call vb2_dqbuf to get buffer back. + */ + memset(b, 0, q->buf_struct_size); + b->type = q->type; + b->memory = q->memory; + if (prequeue) { + b->index = index++; + prequeue--; + } else { + call_void_qop(q, wait_finish, q); + if (!threadio->stop) + ret = vb2_core_dqbuf(q, b, 0); + call_void_qop(q, wait_prepare, q); + dprintk(5, "file io: vb2_dqbuf result: %d\n", ret); + } + if (ret || threadio->stop) + break; + try_to_freeze(); + + vb = q->bufs[b->index]; + if (b->state == VB2_BUF_STATE_DONE) + if (threadio->fnc(vb, threadio->priv)) + break; + call_void_qop(q, wait_finish, q); + if (copy_timestamp) + b->timestamp = ktime_get_ns();; + if (!threadio->stop) + ret = vb2_core_qbuf(q, b->index, b); + call_void_qop(q, wait_prepare, q); + if (ret || threadio->stop) + break; + } + + /* Hmm, linux becomes *very* unhappy without this ... */ + while (!kthread_should_stop()) { + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + } + return 0; +} + +/* + * This function should not be used for anything else but the videobuf2-dvb + * support. If you think you have another good use-case for this, then please + * contact the linux-media mailinglist first. + */ +int vb2_thread_start(struct vb2_queue *q, vb2_thread_fnc fnc, void *priv, + const char *thread_name) +{ + struct vb2_threadio_data *threadio; + int ret = 0; + + if (q->threadio) + return -EBUSY; + if (vb2_is_busy(q)) + return -EBUSY; + if (WARN_ON(q->fileio)) + return -EBUSY; + + threadio = kzalloc(sizeof(*threadio), GFP_KERNEL); + if (threadio == NULL) + return -ENOMEM; + threadio->fnc = fnc; + threadio->priv = priv; + + ret = __vb2_init_fileio(q, !q->is_output); + dprintk(3, "file io: vb2_init_fileio result: %d\n", ret); + if (ret) + goto nomem; + q->threadio = threadio; + threadio->thread = kthread_run(vb2_thread, q, "vb2-%s", thread_name); + if (IS_ERR(threadio->thread)) { + ret = PTR_ERR(threadio->thread); + threadio->thread = NULL; + goto nothread; + } + return 0; + +nothread: + __vb2_cleanup_fileio(q); +nomem: + kfree(threadio); + return ret; +} +EXPORT_SYMBOL_GPL(vb2_thread_start); + +int vb2_thread_stop(struct vb2_queue *q) +{ + struct vb2_threadio_data *threadio = q->threadio; + int err; + + if (threadio == NULL) + return 0; + threadio->stop = true; + /* Wake up all pending sleeps in the thread */ + vb2_queue_error(q); + err = kthread_stop(threadio->thread); + __vb2_cleanup_fileio(q); + threadio->thread = NULL; + kfree(threadio); + q->threadio = NULL; + return err; +} +EXPORT_SYMBOL_GPL(vb2_thread_stop); + +MODULE_DESCRIPTION("Media buffer core framework"); MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>, Marek Szyprowski"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/v4l2-core/videobuf2-internal.h b/drivers/media/v4l2-core/videobuf2-internal.h deleted file mode 100644 index 79018c749282..000000000000 --- a/drivers/media/v4l2-core/videobuf2-internal.h +++ /dev/null @@ -1,161 +0,0 @@ -#ifndef _MEDIA_VIDEOBUF2_INTERNAL_H -#define _MEDIA_VIDEOBUF2_INTERNAL_H - -#include <linux/err.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <media/videobuf2-core.h> - -extern int vb2_debug; - -#define dprintk(level, fmt, arg...) \ - do { \ - if (vb2_debug >= level) \ - pr_info("vb2: %s: " fmt, __func__, ## arg); \ - } while (0) - -#ifdef CONFIG_VIDEO_ADV_DEBUG - -/* - * If advanced debugging is on, then count how often each op is called - * successfully, which can either be per-buffer or per-queue. - * - * This makes it easy to check that the 'init' and 'cleanup' - * (and variations thereof) stay balanced. - */ - -#define log_memop(vb, op) \ - dprintk(2, "call_memop(%p, %d, %s)%s\n", \ - (vb)->vb2_queue, (vb)->index, #op, \ - (vb)->vb2_queue->mem_ops->op ? "" : " (nop)") - -#define call_memop(vb, op, args...) \ -({ \ - struct vb2_queue *_q = (vb)->vb2_queue; \ - int err; \ - \ - log_memop(vb, op); \ - err = _q->mem_ops->op ? _q->mem_ops->op(args) : 0; \ - if (!err) \ - (vb)->cnt_mem_ ## op++; \ - err; \ -}) - -#define call_ptr_memop(vb, op, args...) \ -({ \ - struct vb2_queue *_q = (vb)->vb2_queue; \ - void *ptr; \ - \ - log_memop(vb, op); \ - ptr = _q->mem_ops->op ? _q->mem_ops->op(args) : NULL; \ - if (!IS_ERR_OR_NULL(ptr)) \ - (vb)->cnt_mem_ ## op++; \ - ptr; \ -}) - -#define call_void_memop(vb, op, args...) \ -({ \ - struct vb2_queue *_q = (vb)->vb2_queue; \ - \ - log_memop(vb, op); \ - if (_q->mem_ops->op) \ - _q->mem_ops->op(args); \ - (vb)->cnt_mem_ ## op++; \ -}) - -#define log_qop(q, op) \ - dprintk(2, "call_qop(%p, %s)%s\n", q, #op, \ - (q)->ops->op ? "" : " (nop)") - -#define call_qop(q, op, args...) \ -({ \ - int err; \ - \ - log_qop(q, op); \ - err = (q)->ops->op ? (q)->ops->op(args) : 0; \ - if (!err) \ - (q)->cnt_ ## op++; \ - err; \ -}) - -#define call_void_qop(q, op, args...) \ -({ \ - log_qop(q, op); \ - if ((q)->ops->op) \ - (q)->ops->op(args); \ - (q)->cnt_ ## op++; \ -}) - -#define log_vb_qop(vb, op, args...) \ - dprintk(2, "call_vb_qop(%p, %d, %s)%s\n", \ - (vb)->vb2_queue, (vb)->index, #op, \ - (vb)->vb2_queue->ops->op ? "" : " (nop)") - -#define call_vb_qop(vb, op, args...) \ -({ \ - int err; \ - \ - log_vb_qop(vb, op); \ - err = (vb)->vb2_queue->ops->op ? \ - (vb)->vb2_queue->ops->op(args) : 0; \ - if (!err) \ - (vb)->cnt_ ## op++; \ - err; \ -}) - -#define call_void_vb_qop(vb, op, args...) \ -({ \ - log_vb_qop(vb, op); \ - if ((vb)->vb2_queue->ops->op) \ - (vb)->vb2_queue->ops->op(args); \ - (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 call_ptr_memop(vb, op, args...) \ - ((vb)->vb2_queue->mem_ops->op ? \ - (vb)->vb2_queue->mem_ops->op(args) : NULL) - -#define call_void_memop(vb, op, args...) \ - do { \ - if ((vb)->vb2_queue->mem_ops->op) \ - (vb)->vb2_queue->mem_ops->op(args); \ - } while (0) - -#define call_qop(q, op, args...) \ - ((q)->ops->op ? (q)->ops->op(args) : 0) - -#define call_void_qop(q, op, args...) \ - do { \ - if ((q)->ops->op) \ - (q)->ops->op(args); \ - } while (0) - -#define call_vb_qop(vb, op, args...) \ - ((vb)->vb2_queue->ops->op ? (vb)->vb2_queue->ops->op(args) : 0) - -#define call_void_vb_qop(vb, op, args...) \ - do { \ - if ((vb)->vb2_queue->ops->op) \ - (vb)->vb2_queue->ops->op(args); \ - } while (0) - -#endif - -#define call_bufop(q, op, args...) \ -({ \ - int ret = 0; \ - if (q && q->buf_ops && q->buf_ops->op) \ - ret = q->buf_ops->op(args); \ - ret; \ -}) - -bool vb2_buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb); -int vb2_verify_memory_type(struct vb2_queue *q, - enum vb2_memory memory, unsigned int type); -#endif /* _MEDIA_VIDEOBUF2_INTERNAL_H */ diff --git a/drivers/media/v4l2-core/videobuf2-v4l2.c b/drivers/media/v4l2-core/videobuf2-v4l2.c index 27b4b9e7c0c2..c9a28605511a 100644 --- a/drivers/media/v4l2-core/videobuf2-v4l2.c +++ b/drivers/media/v4l2-core/videobuf2-v4l2.c @@ -31,7 +31,14 @@ #include <media/videobuf2-v4l2.h> -#include "videobuf2-internal.h" +static int debug; +module_param(debug, int, 0644); + +#define dprintk(level, fmt, arg...) \ + do { \ + if (debug >= level) \ + pr_info("vb2-v4l2: %s: " fmt, __func__, ## arg); \ + } while (0) /* Flags that are set by the vb2 core */ #define V4L2_BUFFER_MASK_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \ @@ -52,7 +59,7 @@ static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer return 0; /* Is memory for copying plane information present? */ - if (NULL == b->m.planes) { + if (b->m.planes == NULL) { dprintk(1, "multi-planar buffer passed but " "planes array not provided\n"); return -EINVAL; @@ -107,7 +114,7 @@ static int __verify_length(struct vb2_buffer *vb, const struct v4l2_buffer *b) return 0; } -static int __set_timestamp(struct vb2_buffer *vb, const void *pb) +static void __copy_timestamp(struct vb2_buffer *vb, const void *pb) { const struct v4l2_buffer *b = pb; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); @@ -118,14 +125,12 @@ static int __set_timestamp(struct vb2_buffer *vb, const void *pb) * 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) - vbuf->timestamp = b->timestamp; + if (q->copy_timestamp) + vb->timestamp = timeval_to_ns(&b->timestamp); vbuf->flags |= b->flags & V4L2_BUF_FLAG_TIMECODE; if (b->flags & V4L2_BUF_FLAG_TIMECODE) vbuf->timecode = b->timecode; } - return 0; }; static void vb2_warn_zero_bytesused(struct vb2_buffer *vb) @@ -176,7 +181,7 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b, * __fill_v4l2_buffer() - fill in a struct v4l2_buffer with information to be * returned to userspace */ -static int __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb) +static void __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb) { struct v4l2_buffer *b = pb; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); @@ -191,7 +196,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb) b->flags = vbuf->flags; b->field = vbuf->field; - b->timestamp = vbuf->timestamp; + b->timestamp = ns_to_timeval(vb->timestamp); b->timecode = vbuf->timecode; b->sequence = vbuf->sequence; b->reserved2 = 0; @@ -238,8 +243,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb) */ b->flags &= ~V4L2_BUFFER_MASK_FLAGS; b->flags |= q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK; - if ((q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) != - V4L2_BUF_FLAG_TIMESTAMP_COPY) { + if (!q->copy_timestamp) { /* * For non-COPY timestamps, drop timestamp source bits * and obtain the timestamp source from the queue. @@ -272,7 +276,10 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb) if (vb2_buffer_in_use(q, vb)) b->flags |= V4L2_BUF_FLAG_MAPPED; - return 0; + if (!q->is_output && + b->flags & V4L2_BUF_FLAG_DONE && + b->flags & V4L2_BUF_FLAG_LAST) + q->last_buffer_dequeued = true; } /** @@ -308,8 +315,7 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, "for an output buffer\n"); return -EINVAL; } - vbuf->timestamp.tv_sec = 0; - vbuf->timestamp.tv_usec = 0; + vb->timestamp = 0; vbuf->sequence = 0; if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) { @@ -404,8 +410,7 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, /* Zero flags that the vb2 core handles */ vbuf->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)) { + if (!vb->vb2_queue->copy_timestamp || !V4L2_TYPE_IS_OUTPUT(b->type)) { /* * Non-COPY timestamps and non-OUTPUT queues will get * their timestamp and timestamp source flags from the @@ -434,7 +439,7 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, static const struct vb2_buf_ops v4l2_buf_ops = { .fill_user_buffer = __fill_v4l2_buffer, .fill_vb2_buffer = __fill_vb2_buffer, - .set_timestamp = __set_timestamp, + .copy_timestamp = __copy_timestamp, }; /** @@ -466,8 +471,9 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b) } vb = q->bufs[b->index]; ret = __verify_planes_array(vb, b); - - return ret ? ret : vb2_core_querybuf(q, b->index, b); + if (!ret) + vb2_core_querybuf(q, b->index, b); + return ret; } EXPORT_SYMBOL(vb2_querybuf); @@ -525,14 +531,52 @@ EXPORT_SYMBOL_GPL(vb2_prepare_buf); */ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) { - int ret = vb2_verify_memory_type(q, create->memory, - create->format.type); + unsigned requested_planes = 1; + unsigned requested_sizes[VIDEO_MAX_PLANES]; + struct v4l2_format *f = &create->format; + int ret = vb2_verify_memory_type(q, create->memory, f->type); + unsigned i; create->index = q->num_buffers; if (create->count == 0) return ret != -EBUSY ? ret : 0; + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + requested_planes = f->fmt.pix_mp.num_planes; + if (requested_planes == 0 || + requested_planes > VIDEO_MAX_PLANES) + return -EINVAL; + for (i = 0; i < requested_planes; i++) + requested_sizes[i] = + f->fmt.pix_mp.plane_fmt[i].sizeimage; + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + requested_sizes[0] = f->fmt.pix.sizeimage; + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + requested_sizes[0] = f->fmt.vbi.samples_per_line * + (f->fmt.vbi.count[0] + f->fmt.vbi.count[1]); + break; + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + requested_sizes[0] = f->fmt.sliced.io_size; + break; + case V4L2_BUF_TYPE_SDR_CAPTURE: + case V4L2_BUF_TYPE_SDR_OUTPUT: + requested_sizes[0] = f->fmt.sdr.buffersize; + break; + default: + return -EINVAL; + } + for (i = 0; i < requested_planes; i++) + if (requested_sizes[i] == 0) + return -EINVAL; return ret ? ret : vb2_core_create_bufs(q, create->memory, - &create->count, &create->format); + &create->count, requested_planes, requested_sizes); } EXPORT_SYMBOL_GPL(vb2_create_bufs); @@ -583,10 +627,6 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, ret = vb2_core_dqbuf(q, b, nonblocking); - if (!ret && !q->is_output && - b->flags & V4L2_BUF_FLAG_LAST) - q->last_buffer_dequeued = true; - return ret; } @@ -723,14 +763,13 @@ int vb2_queue_init(struct vb2_queue *q) q->buf_ops = &v4l2_buf_ops; q->is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(q->type); q->is_output = V4L2_TYPE_IS_OUTPUT(q->type); + q->copy_timestamp = (q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) + == V4L2_BUF_FLAG_TIMESTAMP_COPY; return vb2_core_queue_init(q); } EXPORT_SYMBOL_GPL(vb2_queue_init); -static int __vb2_init_fileio(struct vb2_queue *q, int read); -static int __vb2_cleanup_fileio(struct vb2_queue *q); - /** * vb2_queue_release() - stop streaming, release the queue and free memory * @q: videobuf2 queue @@ -741,7 +780,6 @@ static int __vb2_cleanup_fileio(struct vb2_queue *q); */ void vb2_queue_release(struct vb2_queue *q) { - __vb2_cleanup_fileio(q); vb2_core_queue_release(q); } EXPORT_SYMBOL_GPL(vb2_queue_release); @@ -769,9 +807,7 @@ unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait) { struct video_device *vfd = video_devdata(file); unsigned long req_events = poll_requested_events(wait); - struct vb2_buffer *vb = NULL; unsigned int res = 0; - unsigned long flags; if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) { struct v4l2_fh *fh = file->private_data; @@ -782,611 +818,18 @@ unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait) poll_wait(file, &fh->wait, wait); } - if (!q->is_output && !(req_events & (POLLIN | POLLRDNORM))) - return res; - if (q->is_output && !(req_events & (POLLOUT | POLLWRNORM))) - return res; - - /* - * Start file I/O emulator only if streaming API has not been used yet. - */ - if (q->num_buffers == 0 && !vb2_fileio_is_active(q)) { - if (!q->is_output && (q->io_modes & VB2_READ) && - (req_events & (POLLIN | POLLRDNORM))) { - if (__vb2_init_fileio(q, 1)) - return res | POLLERR; - } - if (q->is_output && (q->io_modes & VB2_WRITE) && - (req_events & (POLLOUT | POLLWRNORM))) { - if (__vb2_init_fileio(q, 0)) - return res | POLLERR; - /* - * Write to OUTPUT queue can be done immediately. - */ - return res | POLLOUT | POLLWRNORM; - } - } - - /* - * There is nothing to wait for if the queue isn't streaming, or if the - * error flag is set. - */ - if (!vb2_is_streaming(q) || q->error) - return res | POLLERR; /* * For compatibility with vb1: if QBUF hasn't been called yet, then * return POLLERR as well. This only affects capture queues, output * queues will always initialize waiting_for_buffers to false. */ - if (q->waiting_for_buffers) - return res | POLLERR; - - /* - * For output streams you can write as long as there are fewer buffers - * queued than there are buffers available. - */ - if (q->is_output && q->queued_count < q->num_buffers) - return res | POLLOUT | POLLWRNORM; - - if (list_empty(&q->done_list)) { - /* - * If the last buffer was dequeued from a capture queue, - * return immediately. DQBUF will return -EPIPE. - */ - if (q->last_buffer_dequeued) - return res | POLLIN | POLLRDNORM; - - poll_wait(file, &q->done_wq, wait); - } + if (q->waiting_for_buffers && (req_events & (POLLIN | POLLRDNORM))) + return POLLERR; - /* - * Take first buffer available for dequeuing. - */ - spin_lock_irqsave(&q->done_lock, flags); - if (!list_empty(&q->done_list)) - vb = list_first_entry(&q->done_list, struct vb2_buffer, - done_entry); - spin_unlock_irqrestore(&q->done_lock, flags); - - if (vb && (vb->state == VB2_BUF_STATE_DONE - || vb->state == VB2_BUF_STATE_ERROR)) { - return (q->is_output) ? - res | POLLOUT | POLLWRNORM : - res | POLLIN | POLLRDNORM; - } - return res; + return res | vb2_core_poll(q, file, wait); } EXPORT_SYMBOL_GPL(vb2_poll); -/** - * struct vb2_fileio_buf - buffer context used by file io emulator - * - * vb2 provides a compatibility layer and emulator of file io (read and - * write) calls on top of streaming API. This structure is used for - * tracking context related to the buffers. - */ -struct vb2_fileio_buf { - void *vaddr; - unsigned int size; - unsigned int pos; - unsigned int queued:1; -}; - -/** - * 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 - * or write function. - */ -struct vb2_fileio_data { - struct v4l2_requestbuffers req; - struct v4l2_plane p; - struct v4l2_buffer b; - struct vb2_fileio_buf bufs[VB2_MAX_FRAME]; - unsigned int cur_index; - unsigned int initial_index; - unsigned int q_count; - unsigned int dq_count; - unsigned read_once:1; - unsigned write_immediately:1; -}; - -/** - * __vb2_init_fileio() - initialize file io emulator - * @q: videobuf2 queue - * @read: mode selector (1 means read, 0 means write) - */ -static int __vb2_init_fileio(struct vb2_queue *q, int read) -{ - struct vb2_fileio_data *fileio; - int i, ret; - unsigned int count = 0; - - /* - * Sanity check - */ - 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. - */ - if (!q->mem_ops->vaddr) - return -EBUSY; - - /* - * Check if streaming api has not been already activated. - */ - if (q->streaming || q->num_buffers > 0) - return -EBUSY; - - /* - * Start with count 1, driver can increase it in queue_setup() - */ - count = 1; - - dprintk(3, "setting up file io: mode %s, count %d, read_once %d, write_immediately %d\n", - (read) ? "read" : "write", count, q->fileio_read_once, - q->fileio_write_immediately); - - fileio = kzalloc(sizeof(struct vb2_fileio_data), GFP_KERNEL); - if (fileio == NULL) - return -ENOMEM; - - fileio->read_once = q->fileio_read_once; - fileio->write_immediately = q->fileio_write_immediately; - - /* - * Request buffers and use MMAP type to force driver - * to allocate buffers by itself. - */ - fileio->req.count = count; - fileio->req.memory = VB2_MEMORY_MMAP; - fileio->req.type = q->type; - q->fileio = fileio; - ret = vb2_core_reqbufs(q, fileio->req.memory, &fileio->req.count); - if (ret) - goto err_kfree; - - /* - * Check if plane_count is correct - * (multiplane buffers are not supported). - */ - if (q->bufs[0]->num_planes != 1) { - ret = -EBUSY; - goto err_reqbufs; - } - - /* - * Get kernel address of each buffer. - */ - for (i = 0; i < q->num_buffers; i++) { - fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0); - if (fileio->bufs[i].vaddr == NULL) { - ret = -EINVAL; - goto err_reqbufs; - } - fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0); - } - - /* - * Read mode requires pre queuing of all buffers. - */ - if (read) { - bool is_multiplanar = q->is_multiplanar; - - /* - * Queue all buffers. - */ - for (i = 0; i < q->num_buffers; i++) { - struct v4l2_buffer *b = &fileio->b; - - memset(b, 0, sizeof(*b)); - b->type = q->type; - if (is_multiplanar) { - memset(&fileio->p, 0, sizeof(fileio->p)); - b->m.planes = &fileio->p; - b->length = 1; - } - b->memory = q->memory; - b->index = i; - ret = vb2_internal_qbuf(q, b); - if (ret) - goto err_reqbufs; - fileio->bufs[i].queued = 1; - } - /* - * 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; - } - - /* - * Start streaming. - */ - ret = vb2_core_streamon(q, q->type); - if (ret) - goto err_reqbufs; - - return ret; - -err_reqbufs: - fileio->req.count = 0; - vb2_core_reqbufs(q, fileio->req.memory, &fileio->req.count); - -err_kfree: - q->fileio = NULL; - kfree(fileio); - return ret; -} - -/** - * __vb2_cleanup_fileio() - free resourced used by file io emulator - * @q: videobuf2 queue - */ -static int __vb2_cleanup_fileio(struct vb2_queue *q) -{ - struct vb2_fileio_data *fileio = q->fileio; - - if (fileio) { - vb2_core_streamoff(q, q->type); - q->fileio = NULL; - fileio->req.count = 0; - vb2_reqbufs(q, &fileio->req); - kfree(fileio); - dprintk(3, "file io emulator closed\n"); - } - return 0; -} - -/** - * __vb2_perform_fileio() - perform a single file io (read or write) operation - * @q: videobuf2 queue - * @data: pointed to target userspace buffer - * @count: number of bytes to read or write - * @ppos: file handle position tracking pointer - * @nonblock: mode selector (1 means blocking calls, 0 means nonblocking) - * @read: access mode selector (1 means read, 0 means write) - */ -static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_t count, - loff_t *ppos, int nonblock, int read) -{ - struct vb2_fileio_data *fileio; - struct vb2_fileio_buf *buf; - bool is_multiplanar = q->is_multiplanar; - /* - * When using write() to write data to an output video node the vb2 core - * should set timestamps if V4L2_BUF_FLAG_TIMESTAMP_COPY is set. Nobody - * else is able to provide this information with the write() operation. - */ - bool set_timestamp = !read && - (q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) == - V4L2_BUF_FLAG_TIMESTAMP_COPY; - int ret, index; - - dprintk(3, "mode %s, offset %ld, count %zd, %sblocking\n", - read ? "read" : "write", (long)*ppos, count, - nonblock ? "non" : ""); - - if (!data) - return -EINVAL; - - /* - * Initialize emulator on first call. - */ - if (!vb2_fileio_is_active(q)) { - ret = __vb2_init_fileio(q, read); - dprintk(3, "vb2_init_fileio result: %d\n", ret); - if (ret) - return ret; - } - fileio = q->fileio; - - /* - * Check if we need to dequeue the buffer. - */ - index = fileio->cur_index; - if (index >= q->num_buffers) { - /* - * Call vb2_dqbuf to get buffer back. - */ - memset(&fileio->b, 0, sizeof(fileio->b)); - fileio->b.type = q->type; - fileio->b.memory = q->memory; - if (is_multiplanar) { - memset(&fileio->p, 0, sizeof(fileio->p)); - fileio->b.m.planes = &fileio->p; - fileio->b.length = 1; - } - ret = vb2_internal_dqbuf(q, &fileio->b, nonblock); - dprintk(5, "vb2_dqbuf result: %d\n", ret); - if (ret) - return ret; - fileio->dq_count += 1; - - fileio->cur_index = index = fileio->b.index; - buf = &fileio->bufs[index]; - - /* - * Get number of bytes filled by the driver - */ - buf->pos = 0; - buf->queued = 0; - buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0) - : vb2_plane_size(q->bufs[index], 0); - /* Compensate for data_offset on read in the multiplanar case. */ - if (is_multiplanar && read && - fileio->b.m.planes[0].data_offset < buf->size) { - buf->pos = fileio->b.m.planes[0].data_offset; - buf->size -= buf->pos; - } - } else { - buf = &fileio->bufs[index]; - } - - /* - * Limit count on last few bytes of the buffer. - */ - if (buf->pos + count > buf->size) { - count = buf->size - buf->pos; - dprintk(5, "reducing read count: %zd\n", count); - } - - /* - * Transfer data to userspace. - */ - dprintk(3, "copying %zd bytes - buffer %d, offset %u\n", - count, index, buf->pos); - if (read) - ret = copy_to_user(data, buf->vaddr + buf->pos, count); - else - ret = copy_from_user(buf->vaddr + buf->pos, data, count); - if (ret) { - dprintk(3, "error copying data\n"); - return -EFAULT; - } - - /* - * Update counters. - */ - buf->pos += count; - *ppos += count; - - /* - * Queue next buffer if required. - */ - if (buf->pos == buf->size || (!read && fileio->write_immediately)) { - /* - * Check if this is the last buffer to read. - */ - if (read && fileio->read_once && fileio->dq_count == 1) { - dprintk(3, "read limit reached\n"); - return __vb2_cleanup_fileio(q); - } - - /* - * Call vb2_qbuf and give buffer to the driver. - */ - memset(&fileio->b, 0, sizeof(fileio->b)); - fileio->b.type = q->type; - fileio->b.memory = q->memory; - fileio->b.index = index; - fileio->b.bytesused = buf->pos; - if (is_multiplanar) { - memset(&fileio->p, 0, sizeof(fileio->p)); - fileio->p.bytesused = buf->pos; - fileio->b.m.planes = &fileio->p; - fileio->b.length = 1; - } - if (set_timestamp) - v4l2_get_timestamp(&fileio->b.timestamp); - ret = vb2_internal_qbuf(q, &fileio->b); - dprintk(5, "vb2_dbuf result: %d\n", ret); - if (ret) - return ret; - - /* - * Buffer has been queued, update the status - */ - buf->pos = 0; - buf->queued = 1; - buf->size = vb2_plane_size(q->bufs[index], 0); - fileio->q_count += 1; - /* - * 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; - } - - /* - * Return proper number of bytes processed. - */ - if (ret == 0) - ret = count; - return ret; -} - -size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count, - loff_t *ppos, int nonblocking) -{ - return __vb2_perform_fileio(q, data, count, ppos, nonblocking, 1); -} -EXPORT_SYMBOL_GPL(vb2_read); - -size_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count, - loff_t *ppos, int nonblocking) -{ - return __vb2_perform_fileio(q, (char __user *) data, count, - ppos, nonblocking, 0); -} -EXPORT_SYMBOL_GPL(vb2_write); - -struct vb2_threadio_data { - struct task_struct *thread; - vb2_thread_fnc fnc; - void *priv; - bool stop; -}; - -static int vb2_thread(void *data) -{ - struct vb2_queue *q = data; - struct vb2_threadio_data *threadio = q->threadio; - struct vb2_fileio_data *fileio = q->fileio; - bool set_timestamp = false; - int prequeue = 0; - int index = 0; - int ret = 0; - - if (q->is_output) { - prequeue = q->num_buffers; - set_timestamp = - (q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) == - V4L2_BUF_FLAG_TIMESTAMP_COPY; - } - - set_freezable(); - - for (;;) { - struct vb2_buffer *vb; - - /* - * Call vb2_dqbuf to get buffer back. - */ - memset(&fileio->b, 0, sizeof(fileio->b)); - fileio->b.type = q->type; - fileio->b.memory = q->memory; - if (prequeue) { - fileio->b.index = index++; - prequeue--; - } else { - call_void_qop(q, wait_finish, q); - if (!threadio->stop) - ret = vb2_internal_dqbuf(q, &fileio->b, 0); - call_void_qop(q, wait_prepare, q); - dprintk(5, "file io: vb2_dqbuf result: %d\n", ret); - } - if (ret || threadio->stop) - break; - try_to_freeze(); - - vb = q->bufs[fileio->b.index]; - if (!(fileio->b.flags & V4L2_BUF_FLAG_ERROR)) - if (threadio->fnc(vb, threadio->priv)) - break; - call_void_qop(q, wait_finish, q); - if (set_timestamp) - v4l2_get_timestamp(&fileio->b.timestamp); - if (!threadio->stop) - ret = vb2_internal_qbuf(q, &fileio->b); - call_void_qop(q, wait_prepare, q); - if (ret || threadio->stop) - break; - } - - /* Hmm, linux becomes *very* unhappy without this ... */ - while (!kthread_should_stop()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule(); - } - return 0; -} - -/* - * This function should not be used for anything else but the videobuf2-dvb - * support. If you think you have another good use-case for this, then please - * contact the linux-media mailinglist first. - */ -int vb2_thread_start(struct vb2_queue *q, vb2_thread_fnc fnc, void *priv, - const char *thread_name) -{ - struct vb2_threadio_data *threadio; - int ret = 0; - - if (q->threadio) - return -EBUSY; - if (vb2_is_busy(q)) - return -EBUSY; - if (WARN_ON(q->fileio)) - return -EBUSY; - - threadio = kzalloc(sizeof(*threadio), GFP_KERNEL); - if (threadio == NULL) - return -ENOMEM; - threadio->fnc = fnc; - threadio->priv = priv; - - ret = __vb2_init_fileio(q, !q->is_output); - dprintk(3, "file io: vb2_init_fileio result: %d\n", ret); - if (ret) - goto nomem; - q->threadio = threadio; - threadio->thread = kthread_run(vb2_thread, q, "vb2-%s", thread_name); - if (IS_ERR(threadio->thread)) { - ret = PTR_ERR(threadio->thread); - threadio->thread = NULL; - goto nothread; - } - return 0; - -nothread: - __vb2_cleanup_fileio(q); -nomem: - kfree(threadio); - return ret; -} -EXPORT_SYMBOL_GPL(vb2_thread_start); - -int vb2_thread_stop(struct vb2_queue *q) -{ - struct vb2_threadio_data *threadio = q->threadio; - int err; - - if (threadio == NULL) - return 0; - threadio->stop = true; - /* Wake up all pending sleeps in the thread */ - vb2_queue_error(q); - err = kthread_stop(threadio->thread); - __vb2_cleanup_fileio(q); - threadio->thread = NULL; - kfree(threadio); - q->threadio = NULL; - return err; -} -EXPORT_SYMBOL_GPL(vb2_thread_stop); - /* * The following functions are not part of the vb2 core API, but are helper * functions that plug into struct v4l2_ioctl_ops, struct v4l2_file_operations @@ -1440,8 +883,8 @@ int vb2_ioctl_create_bufs(struct file *file, void *priv, return res; if (vb2_queue_is_busy(vdev, file)) return -EBUSY; - res = vb2_core_create_bufs(vdev->queue, p->memory, &p->count, - &p->format); + + res = vb2_create_bufs(vdev->queue, p); if (res == 0) vdev->queue->owner = file->private_data; return res; |