diff options
Diffstat (limited to 'drivers/media/v4l2-core')
-rw-r--r-- | drivers/media/v4l2-core/Makefile | 2 | ||||
-rw-r--r-- | drivers/media/v4l2-core/v4l2-async.c | 180 | ||||
-rw-r--r-- | drivers/media/v4l2-core/v4l2-clk.c | 321 | ||||
-rw-r--r-- | drivers/media/v4l2-core/v4l2-common.c | 4 | ||||
-rw-r--r-- | drivers/media/v4l2-core/v4l2-ctrls.c | 19 | ||||
-rw-r--r-- | drivers/media/v4l2-core/v4l2-dev.c | 20 | ||||
-rw-r--r-- | drivers/media/v4l2-core/v4l2-event.c | 17 | ||||
-rw-r--r-- | drivers/media/v4l2-core/v4l2-fwnode.c | 17 | ||||
-rw-r--r-- | drivers/media/v4l2-core/v4l2-ioctl.c | 42 | ||||
-rw-r--r-- | drivers/media/v4l2-core/v4l2-mem2mem.c | 15 |
10 files changed, 188 insertions, 449 deletions
diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile index 2ef0c7c958a2..e4cd589b99a5 100644 --- a/drivers/media/v4l2-core/Makefile +++ b/drivers/media/v4l2-core/Makefile @@ -6,7 +6,7 @@ tuner-objs := tuner-core.o videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \ - v4l2-event.o v4l2-ctrls.o v4l2-subdev.o v4l2-clk.o \ + v4l2-event.o v4l2-ctrls.o v4l2-subdev.o \ v4l2-async.o v4l2-common.o videodev-$(CONFIG_COMPAT) += v4l2-compat-ioctl32.o videodev-$(CONFIG_TRACEPOINTS) += v4l2-trace.o diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index e3ab003a6c85..e638aa8aecb7 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -5,6 +5,7 @@ * Copyright (C) 2012-2013, Guennadi Liakhovetski <g.liakhovetski@gmx.de> */ +#include <linux/debugfs.h> #include <linux/device.h> #include <linux/err.h> #include <linux/i2c.h> @@ -14,6 +15,7 @@ #include <linux/mutex.h> #include <linux/of.h> #include <linux/platform_device.h> +#include <linux/seq_file.h> #include <linux/slab.h> #include <linux/types.h> @@ -64,12 +66,6 @@ static bool match_i2c(struct v4l2_async_notifier *notifier, #endif } -static bool match_devname(struct v4l2_async_notifier *notifier, - struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) -{ - return !strcmp(asd->match.device_name, dev_name(sd->dev)); -} - static bool match_fwnode(struct v4l2_async_notifier *notifier, struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) { @@ -88,6 +84,14 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier, return true; /* + * Check the same situation for any possible secondary assigned to the + * subdev's fwnode + */ + if (!IS_ERR_OR_NULL(sd->fwnode->secondary) && + sd->fwnode->secondary == asd->match.fwnode) + return true; + + /* * Otherwise, check if the sd fwnode and the asd fwnode refer to an * endpoint or a device. If they're of the same type, there's no match. * Technically speaking this checks if the nodes refer to a connected @@ -139,16 +143,6 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier, return true; } -static bool match_custom(struct v4l2_async_notifier *notifier, - struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) -{ - if (!asd->match.custom.match) - /* Match always */ - return true; - - return asd->match.custom.match(sd->dev, asd); -} - static LIST_HEAD(subdev_list); static LIST_HEAD(notifier_list); static DEFINE_MUTEX(list_lock); @@ -164,12 +158,6 @@ v4l2_async_find_match(struct v4l2_async_notifier *notifier, list_for_each_entry(asd, ¬ifier->waiting, list) { /* bus_type has been verified valid before */ switch (asd->match_type) { - case V4L2_ASYNC_MATCH_CUSTOM: - match = match_custom; - break; - case V4L2_ASYNC_MATCH_DEVNAME: - match = match_devname; - break; case V4L2_ASYNC_MATCH_I2C: match = match_i2c; break; @@ -198,9 +186,6 @@ static bool asd_equal(struct v4l2_async_subdev *asd_x, return false; switch (asd_x->match_type) { - case V4L2_ASYNC_MATCH_DEVNAME: - return strcmp(asd_x->match.device_name, - asd_y->match.device_name) == 0; case V4L2_ASYNC_MATCH_I2C: return asd_x->match.i2c.adapter_id == asd_y->match.i2c.adapter_id && @@ -467,8 +452,6 @@ static int v4l2_async_notifier_asd_valid(struct v4l2_async_notifier *notifier, return -EINVAL; switch (asd->match_type) { - case V4L2_ASYNC_MATCH_CUSTOM: - case V4L2_ASYNC_MATCH_DEVNAME: case V4L2_ASYNC_MATCH_I2C: case V4L2_ASYNC_MATCH_FWNODE: if (v4l2_async_notifier_has_async_subdev(notifier, asd, @@ -628,7 +611,7 @@ void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier) } EXPORT_SYMBOL_GPL(v4l2_async_notifier_cleanup); -int v4l2_async_notifier_add_subdev(struct v4l2_async_notifier *notifier, +int __v4l2_async_notifier_add_subdev(struct v4l2_async_notifier *notifier, struct v4l2_async_subdev *asd) { int ret; @@ -645,12 +628,12 @@ unlock: mutex_unlock(&list_lock); return ret; } -EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_subdev); +EXPORT_SYMBOL_GPL(__v4l2_async_notifier_add_subdev); struct v4l2_async_subdev * -v4l2_async_notifier_add_fwnode_subdev(struct v4l2_async_notifier *notifier, - struct fwnode_handle *fwnode, - unsigned int asd_struct_size) +__v4l2_async_notifier_add_fwnode_subdev(struct v4l2_async_notifier *notifier, + struct fwnode_handle *fwnode, + unsigned int asd_struct_size) { struct v4l2_async_subdev *asd; int ret; @@ -662,7 +645,7 @@ v4l2_async_notifier_add_fwnode_subdev(struct v4l2_async_notifier *notifier, asd->match_type = V4L2_ASYNC_MATCH_FWNODE; asd->match.fwnode = fwnode_handle_get(fwnode); - ret = v4l2_async_notifier_add_subdev(notifier, asd); + ret = __v4l2_async_notifier_add_subdev(notifier, asd); if (ret) { fwnode_handle_put(fwnode); kfree(asd); @@ -671,35 +654,35 @@ v4l2_async_notifier_add_fwnode_subdev(struct v4l2_async_notifier *notifier, return asd; } -EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_fwnode_subdev); +EXPORT_SYMBOL_GPL(__v4l2_async_notifier_add_fwnode_subdev); -int -v4l2_async_notifier_add_fwnode_remote_subdev(struct v4l2_async_notifier *notif, - struct fwnode_handle *endpoint, - struct v4l2_async_subdev *asd) +struct v4l2_async_subdev * +__v4l2_async_notifier_add_fwnode_remote_subdev(struct v4l2_async_notifier *notif, + struct fwnode_handle *endpoint, + unsigned int asd_struct_size) { + struct v4l2_async_subdev *asd; struct fwnode_handle *remote; - int ret; remote = fwnode_graph_get_remote_port_parent(endpoint); if (!remote) - return -ENOTCONN; - - asd->match_type = V4L2_ASYNC_MATCH_FWNODE; - asd->match.fwnode = remote; + return ERR_PTR(-ENOTCONN); - ret = v4l2_async_notifier_add_subdev(notif, asd); - if (ret) - fwnode_handle_put(remote); - - return ret; + asd = __v4l2_async_notifier_add_fwnode_subdev(notif, remote, + asd_struct_size); + /* + * Calling __v4l2_async_notifier_add_fwnode_subdev grabs a refcount, + * so drop the one we got in fwnode_graph_get_remote_port_parent. + */ + fwnode_handle_put(remote); + return asd; } -EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_fwnode_remote_subdev); +EXPORT_SYMBOL_GPL(__v4l2_async_notifier_add_fwnode_remote_subdev); struct v4l2_async_subdev * -v4l2_async_notifier_add_i2c_subdev(struct v4l2_async_notifier *notifier, - int adapter_id, unsigned short address, - unsigned int asd_struct_size) +__v4l2_async_notifier_add_i2c_subdev(struct v4l2_async_notifier *notifier, + int adapter_id, unsigned short address, + unsigned int asd_struct_size) { struct v4l2_async_subdev *asd; int ret; @@ -712,7 +695,7 @@ v4l2_async_notifier_add_i2c_subdev(struct v4l2_async_notifier *notifier, asd->match.i2c.adapter_id = adapter_id; asd->match.i2c.address = address; - ret = v4l2_async_notifier_add_subdev(notifier, asd); + ret = __v4l2_async_notifier_add_subdev(notifier, asd); if (ret) { kfree(asd); return ERR_PTR(ret); @@ -720,32 +703,7 @@ v4l2_async_notifier_add_i2c_subdev(struct v4l2_async_notifier *notifier, return asd; } -EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_i2c_subdev); - -struct v4l2_async_subdev * -v4l2_async_notifier_add_devname_subdev(struct v4l2_async_notifier *notifier, - const char *device_name, - unsigned int asd_struct_size) -{ - struct v4l2_async_subdev *asd; - int ret; - - asd = kzalloc(asd_struct_size, GFP_KERNEL); - if (!asd) - return ERR_PTR(-ENOMEM); - - asd->match_type = V4L2_ASYNC_MATCH_DEVNAME; - asd->match.device_name = device_name; - - ret = v4l2_async_notifier_add_subdev(notifier, asd); - if (ret) { - kfree(asd); - return ERR_PTR(ret); - } - - return asd; -} -EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_devname_subdev); +EXPORT_SYMBOL_GPL(__v4l2_async_notifier_add_i2c_subdev); int v4l2_async_register_subdev(struct v4l2_subdev *sd) { @@ -817,6 +775,9 @@ EXPORT_SYMBOL(v4l2_async_register_subdev); void v4l2_async_unregister_subdev(struct v4l2_subdev *sd) { + if (!sd->async_list.next) + return; + mutex_lock(&list_lock); __v4l2_async_notifier_unregister(sd->subdev_notifier); @@ -837,3 +798,64 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd) mutex_unlock(&list_lock); } EXPORT_SYMBOL(v4l2_async_unregister_subdev); + +static void print_waiting_subdev(struct seq_file *s, + struct v4l2_async_subdev *asd) +{ + switch (asd->match_type) { + case V4L2_ASYNC_MATCH_I2C: + seq_printf(s, " [i2c] dev=%d-%04x\n", asd->match.i2c.adapter_id, + asd->match.i2c.address); + break; + case V4L2_ASYNC_MATCH_FWNODE: { + struct fwnode_handle *devnode, *fwnode = asd->match.fwnode; + + devnode = fwnode_graph_is_endpoint(fwnode) ? + fwnode_graph_get_port_parent(fwnode) : + fwnode_handle_get(fwnode); + + seq_printf(s, " [fwnode] dev=%s, node=%pfw\n", + devnode->dev ? dev_name(devnode->dev) : "nil", + fwnode); + + fwnode_handle_put(devnode); + break; + } + } +} + +static const char * +v4l2_async_notifier_name(struct v4l2_async_notifier *notifier) +{ + if (notifier->v4l2_dev) + return notifier->v4l2_dev->name; + else if (notifier->sd) + return notifier->sd->name; + else + return "nil"; +} + +static int pending_subdevs_show(struct seq_file *s, void *data) +{ + struct v4l2_async_notifier *notif; + struct v4l2_async_subdev *asd; + + mutex_lock(&list_lock); + + list_for_each_entry(notif, ¬ifier_list, list) { + seq_printf(s, "%s:\n", v4l2_async_notifier_name(notif)); + list_for_each_entry(asd, ¬if->waiting, list) + print_waiting_subdev(s, asd); + } + + mutex_unlock(&list_lock); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(pending_subdevs); + +void v4l2_async_debug_init(struct dentry *debugfs_dir) +{ + debugfs_create_file("pending_async_subdevices", 0444, debugfs_dir, NULL, + &pending_subdevs_fops); +} diff --git a/drivers/media/v4l2-core/v4l2-clk.c b/drivers/media/v4l2-core/v4l2-clk.c deleted file mode 100644 index 91274eee6977..000000000000 --- a/drivers/media/v4l2-core/v4l2-clk.c +++ /dev/null @@ -1,321 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * V4L2 clock service - * - * Copyright (C) 2012-2013, Guennadi Liakhovetski <g.liakhovetski@gmx.de> - */ - -#include <linux/atomic.h> -#include <linux/clk.h> -#include <linux/device.h> -#include <linux/errno.h> -#include <linux/list.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/of.h> -#include <linux/slab.h> -#include <linux/string.h> - -#include <media/v4l2-clk.h> -#include <media/v4l2-subdev.h> - -static DEFINE_MUTEX(clk_lock); -static LIST_HEAD(clk_list); - -static struct v4l2_clk *v4l2_clk_find(const char *dev_id) -{ - struct v4l2_clk *clk; - - list_for_each_entry(clk, &clk_list, list) - if (!strcmp(dev_id, clk->dev_id)) - return clk; - - return ERR_PTR(-ENODEV); -} - -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); - - if (!IS_ERR_OR_NULL(ccf_clk)) { - clk = kzalloc(sizeof(*clk), GFP_KERNEL); - if (!clk) { - clk_put(ccf_clk); - return ERR_PTR(-ENOMEM); - } - clk->clk = ccf_clk; - - return clk; - } - - 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), dev->of_node); - clk = v4l2_clk_find(clk_name); - } - - if (!IS_ERR(clk)) - atomic_inc(&clk->use_count); - mutex_unlock(&clk_lock); - - return clk; -} -EXPORT_SYMBOL(v4l2_clk_get); - -void v4l2_clk_put(struct v4l2_clk *clk) -{ - struct v4l2_clk *tmp; - - if (IS_ERR(clk)) - return; - - if (clk->clk) { - clk_put(clk->clk); - kfree(clk); - return; - } - - mutex_lock(&clk_lock); - - list_for_each_entry(tmp, &clk_list, list) - if (tmp == clk) - atomic_dec(&clk->use_count); - - mutex_unlock(&clk_lock); -} -EXPORT_SYMBOL(v4l2_clk_put); - -static int v4l2_clk_lock_driver(struct v4l2_clk *clk) -{ - struct v4l2_clk *tmp; - int ret = -ENODEV; - - mutex_lock(&clk_lock); - - list_for_each_entry(tmp, &clk_list, list) - if (tmp == clk) { - ret = !try_module_get(clk->ops->owner); - if (ret) - ret = -EFAULT; - break; - } - - mutex_unlock(&clk_lock); - - return ret; -} - -static void v4l2_clk_unlock_driver(struct v4l2_clk *clk) -{ - module_put(clk->ops->owner); -} - -int v4l2_clk_enable(struct v4l2_clk *clk) -{ - int ret; - - if (clk->clk) - return clk_prepare_enable(clk->clk); - - ret = v4l2_clk_lock_driver(clk); - if (ret < 0) - return ret; - - mutex_lock(&clk->lock); - - if (++clk->enable == 1 && clk->ops->enable) { - ret = clk->ops->enable(clk); - if (ret < 0) - clk->enable--; - } - - mutex_unlock(&clk->lock); - - return ret; -} -EXPORT_SYMBOL(v4l2_clk_enable); - -/* - * You might Oops if you try to disabled a disabled clock, because then the - * driver isn't locked and could have been unloaded by now, so, don't do that - */ -void v4l2_clk_disable(struct v4l2_clk *clk) -{ - int enable; - - if (clk->clk) - return clk_disable_unprepare(clk->clk); - - mutex_lock(&clk->lock); - - enable = --clk->enable; - if (WARN(enable < 0, "Unbalanced %s() on %s!\n", __func__, - clk->dev_id)) - clk->enable++; - else if (!enable && clk->ops->disable) - clk->ops->disable(clk); - - mutex_unlock(&clk->lock); - - v4l2_clk_unlock_driver(clk); -} -EXPORT_SYMBOL(v4l2_clk_disable); - -unsigned long v4l2_clk_get_rate(struct v4l2_clk *clk) -{ - int ret; - - if (clk->clk) - return clk_get_rate(clk->clk); - - ret = v4l2_clk_lock_driver(clk); - if (ret < 0) - return ret; - - mutex_lock(&clk->lock); - if (!clk->ops->get_rate) - ret = -ENOSYS; - else - ret = clk->ops->get_rate(clk); - mutex_unlock(&clk->lock); - - v4l2_clk_unlock_driver(clk); - - return ret; -} -EXPORT_SYMBOL(v4l2_clk_get_rate); - -int v4l2_clk_set_rate(struct v4l2_clk *clk, unsigned long rate) -{ - int ret; - - if (clk->clk) { - long r = clk_round_rate(clk->clk, rate); - if (r < 0) - return r; - return clk_set_rate(clk->clk, r); - } - - ret = v4l2_clk_lock_driver(clk); - - if (ret < 0) - return ret; - - mutex_lock(&clk->lock); - if (!clk->ops->set_rate) - ret = -ENOSYS; - else - ret = clk->ops->set_rate(clk, rate); - mutex_unlock(&clk->lock); - - v4l2_clk_unlock_driver(clk); - - return ret; -} -EXPORT_SYMBOL(v4l2_clk_set_rate); - -struct v4l2_clk *v4l2_clk_register(const struct v4l2_clk_ops *ops, - const char *dev_id, - void *priv) -{ - struct v4l2_clk *clk; - int ret; - - if (!ops || !dev_id) - return ERR_PTR(-EINVAL); - - clk = kzalloc(sizeof(struct v4l2_clk), GFP_KERNEL); - if (!clk) - return ERR_PTR(-ENOMEM); - - clk->dev_id = kstrdup(dev_id, GFP_KERNEL); - if (!clk->dev_id) { - ret = -ENOMEM; - goto ealloc; - } - clk->ops = ops; - clk->priv = priv; - atomic_set(&clk->use_count, 0); - mutex_init(&clk->lock); - - mutex_lock(&clk_lock); - if (!IS_ERR(v4l2_clk_find(dev_id))) { - mutex_unlock(&clk_lock); - ret = -EEXIST; - goto eexist; - } - list_add_tail(&clk->list, &clk_list); - mutex_unlock(&clk_lock); - - return clk; - -eexist: -ealloc: - kfree(clk->dev_id); - kfree(clk); - return ERR_PTR(ret); -} -EXPORT_SYMBOL(v4l2_clk_register); - -void v4l2_clk_unregister(struct v4l2_clk *clk) -{ - if (WARN(atomic_read(&clk->use_count), - "%s(): Refusing to unregister ref-counted %s clock!\n", - __func__, clk->dev_id)) - return; - - mutex_lock(&clk_lock); - list_del(&clk->list); - mutex_unlock(&clk_lock); - - kfree(clk->dev_id); - kfree(clk); -} -EXPORT_SYMBOL(v4l2_clk_unregister); - -struct v4l2_clk_fixed { - unsigned long rate; - struct v4l2_clk_ops ops; -}; - -static unsigned long fixed_get_rate(struct v4l2_clk *clk) -{ - struct v4l2_clk_fixed *priv = clk->priv; - return priv->rate; -} - -struct v4l2_clk *__v4l2_clk_register_fixed(const char *dev_id, - unsigned long rate, struct module *owner) -{ - struct v4l2_clk *clk; - struct v4l2_clk_fixed *priv = kzalloc(sizeof(*priv), GFP_KERNEL); - - if (!priv) - return ERR_PTR(-ENOMEM); - - priv->rate = rate; - priv->ops.get_rate = fixed_get_rate; - priv->ops.owner = owner; - - clk = v4l2_clk_register(&priv->ops, dev_id, priv); - if (IS_ERR(clk)) - kfree(priv); - - return clk; -} -EXPORT_SYMBOL(__v4l2_clk_register_fixed); - -void v4l2_clk_unregister_fixed(struct v4l2_clk *clk) -{ - kfree(clk->priv); - v4l2_clk_unregister(clk); -} -EXPORT_SYMBOL(v4l2_clk_unregister_fixed); diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index 78007dba4677..133d20e40f82 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -442,7 +442,7 @@ int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat, } EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt); -s64 v4l2_get_link_rate(struct v4l2_ctrl_handler *handler, unsigned int mul, +s64 v4l2_get_link_freq(struct v4l2_ctrl_handler *handler, unsigned int mul, unsigned int div) { struct v4l2_ctrl *ctrl; @@ -473,4 +473,4 @@ s64 v4l2_get_link_rate(struct v4l2_ctrl_handler *handler, unsigned int mul, return freq > 0 ? freq : -EINVAL; } -EXPORT_SYMBOL_GPL(v4l2_get_link_rate); +EXPORT_SYMBOL_GPL(v4l2_get_link_freq); diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 5cbe0ffbf501..016cf6204cbb 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -920,6 +920,15 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP: return "H264 I-Frame Maximum QP Value"; case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP: return "H264 P-Frame Minimum QP Value"; case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP: return "H264 P-Frame Maximum QP Value"; + case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MIN_QP: return "H264 B-Frame Minimum QP Value"; + case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP: return "H264 B-Frame Maximum QP Value"; + case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR: return "H264 Hierarchical Lay 0 Bitrate"; + case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR: return "H264 Hierarchical Lay 1 Bitrate"; + case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR: return "H264 Hierarchical Lay 2 Bitrate"; + case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR: return "H264 Hierarchical Lay 3 Bitrate"; + case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR: return "H264 Hierarchical Lay 4 Bitrate"; + case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR: return "H264 Hierarchical Lay 5 Bitrate"; + case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L6_BR: return "H264 Hierarchical Lay 6 Bitrate"; case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: return "MPEG2 Level"; case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: return "MPEG2 Profile"; case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: return "MPEG4 I-Frame QP Value"; @@ -941,6 +950,7 @@ const char *v4l2_ctrl_get_name(u32 id) 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"; case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: return "Force Key Frame"; + case V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID: return "Base Layer Priority ID"; case V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS: return "MPEG-2 Slice Parameters"; case V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION: return "MPEG-2 Quantization Matrices"; case V4L2_CID_FWHT_I_FRAME_QP: return "FWHT I-Frame QP Value"; @@ -969,6 +979,12 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP: return "HEVC B-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP: return "HEVC Minimum QP Value"; case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP: return "HEVC Maximum QP Value"; + case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP: return "HEVC I-Frame Minimum QP Value"; + case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP: return "HEVC I-Frame Maximum QP Value"; + case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP: return "HEVC P-Frame Minimum QP Value"; + case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP: return "HEVC P-Frame Maximum QP Value"; + case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP: return "HEVC B-Frame Minimum QP Value"; + case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP: return "HEVC B-Frame Maximum QP Value"; case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: return "HEVC Profile"; case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: return "HEVC Level"; case V4L2_CID_MPEG_VIDEO_HEVC_TIER: return "HEVC Tier"; @@ -2165,7 +2181,8 @@ static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx, case V4L2_CTRL_TYPE_INTEGER_MENU: if (ptr.p_s32[idx] < ctrl->minimum || ptr.p_s32[idx] > ctrl->maximum) return -ERANGE; - if (ctrl->menu_skip_mask & (1ULL << ptr.p_s32[idx])) + if (ptr.p_s32[idx] < BITS_PER_LONG_LONG && + (ctrl->menu_skip_mask & BIT_ULL(ptr.p_s32[idx]))) return -EINVAL; if (ctrl->type == V4L2_CTRL_TYPE_MENU && ctrl->qmenu[ptr.p_s32[idx]][0] == '\0') diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index a593ea0598b5..b6a72d297775 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -14,6 +14,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/debugfs.h> #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> @@ -28,6 +29,7 @@ #include <media/v4l2-common.h> #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-event.h> #define VIDEO_NUM_DEVICES 256 #define VIDEO_NAME "video4linux" @@ -37,6 +39,7 @@ __func__, ##arg); \ } while (0) +static struct dentry *v4l2_debugfs_dir; /* * sysfs stuff @@ -338,12 +341,14 @@ static ssize_t v4l2_write(struct file *filp, const char __user *buf, static __poll_t v4l2_poll(struct file *filp, struct poll_table_struct *poll) { struct video_device *vdev = video_devdata(filp); - __poll_t res = EPOLLERR | EPOLLHUP; + __poll_t res = EPOLLERR | EPOLLHUP | EPOLLPRI; - if (!vdev->fops->poll) - return DEFAULT_POLLMASK; - if (video_is_registered(vdev)) - res = vdev->fops->poll(filp, poll); + if (video_is_registered(vdev)) { + if (!vdev->fops->poll) + res = DEFAULT_POLLMASK; + else + res = vdev->fops->poll(filp, poll); + } if (vdev->dev_debug & V4L2_DEV_DEBUG_POLL) dprintk("%s: poll: %08x\n", video_device_node_name(vdev), res); @@ -1086,6 +1091,8 @@ void video_unregister_device(struct video_device *vdev) */ clear_bit(V4L2_FL_REGISTERED, &vdev->flags); mutex_unlock(&videodev_lock); + if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags)) + v4l2_event_wake_all(vdev); device_unregister(&vdev->dev); } EXPORT_SYMBOL(video_unregister_device); @@ -1113,6 +1120,8 @@ static int __init videodev_init(void) return -EIO; } + v4l2_debugfs_dir = debugfs_create_dir("video4linux", NULL); + v4l2_async_debug_init(v4l2_debugfs_dir); return 0; } @@ -1120,6 +1129,7 @@ static void __exit videodev_exit(void) { dev_t dev = MKDEV(VIDEO_MAJOR, 0); + debugfs_remove_recursive(v4l2_debugfs_dir); class_unregister(&video_class); unregister_chrdev_region(dev, VIDEO_NUM_DEVICES); } diff --git a/drivers/media/v4l2-core/v4l2-event.c b/drivers/media/v4l2-core/v4l2-event.c index 290c6b213179..caad58bde326 100644 --- a/drivers/media/v4l2-core/v4l2-event.c +++ b/drivers/media/v4l2-core/v4l2-event.c @@ -187,6 +187,23 @@ int v4l2_event_pending(struct v4l2_fh *fh) } EXPORT_SYMBOL_GPL(v4l2_event_pending); +void v4l2_event_wake_all(struct video_device *vdev) +{ + struct v4l2_fh *fh; + unsigned long flags; + + if (!vdev) + return; + + spin_lock_irqsave(&vdev->fh_lock, flags); + + list_for_each_entry(fh, &vdev->fh_list, list) + wake_up_all(&fh->wait); + + spin_unlock_irqrestore(&vdev->fh_lock, flags); +} +EXPORT_SYMBOL_GPL(v4l2_event_wake_all); + static void __v4l2_event_unsubscribe(struct v4l2_subscribed_event *sev) { struct v4l2_fh *fh = sev->fh; diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index 5353e37eb950..2283ff3b8e1d 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -28,17 +28,6 @@ #include <media/v4l2-fwnode.h> #include <media/v4l2-subdev.h> -enum v4l2_fwnode_bus_type { - V4L2_FWNODE_BUS_TYPE_GUESS = 0, - V4L2_FWNODE_BUS_TYPE_CSI2_CPHY, - V4L2_FWNODE_BUS_TYPE_CSI1, - V4L2_FWNODE_BUS_TYPE_CCP2, - V4L2_FWNODE_BUS_TYPE_CSI2_DPHY, - V4L2_FWNODE_BUS_TYPE_PARALLEL, - V4L2_FWNODE_BUS_TYPE_BT656, - NR_OF_V4L2_FWNODE_BUS_TYPE, -}; - static const struct v4l2_fwnode_bus_conv { enum v4l2_fwnode_bus_type fwnode_bus_type; enum v4l2_mbus_type mbus_type; @@ -833,7 +822,7 @@ v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev, if (ret < 0) goto out_err; - ret = v4l2_async_notifier_add_subdev(notifier, asd); + ret = __v4l2_async_notifier_add_subdev(notifier, asd); if (ret < 0) { /* not an error if asd already exists */ if (ret == -EEXIST) @@ -955,7 +944,7 @@ static int v4l2_fwnode_reference_parse(struct device *dev, asd = v4l2_async_notifier_add_fwnode_subdev(notifier, args.fwnode, - sizeof(*asd)); + struct v4l2_async_subdev); fwnode_handle_put(args.fwnode); if (IS_ERR(asd)) { /* not an error if asd already exists */ @@ -1255,7 +1244,7 @@ v4l2_fwnode_reference_parse_int_props(struct device *dev, struct v4l2_async_subdev *asd; asd = v4l2_async_notifier_add_fwnode_subdev(notifier, fwnode, - sizeof(*asd)); + struct v4l2_async_subdev); fwnode_handle_put(fwnode); if (IS_ERR(asd)) { ret = PTR_ERR(asd); diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 3198abdd538c..31d1342e61e8 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -518,9 +518,9 @@ static void v4l_print_create_buffers(const void *arg, bool write_only) { const struct v4l2_create_buffers *p = arg; - pr_cont("index=%d, count=%d, memory=%s, ", - p->index, p->count, - prt_names(p->memory, v4l2_memory_names)); + pr_cont("index=%d, count=%d, memory=%s, capabilities=0x%08x, ", + p->index, p->count, prt_names(p->memory, v4l2_memory_names), + p->capabilities); v4l_print_format(&p->format, write_only); } @@ -3283,7 +3283,7 @@ video_usercopy(struct file *file, unsigned int orig_cmd, unsigned long arg, v4l2_kioctl func) { char sbuf[128]; - void *mbuf = NULL; + void *mbuf = NULL, *array_buf = NULL; void *parg = (void *)arg; long err = -EINVAL; bool has_array_args; @@ -3300,7 +3300,7 @@ video_usercopy(struct file *file, unsigned int orig_cmd, unsigned long arg, parg = sbuf; } else { /* too big to allocate from stack */ - mbuf = kvmalloc(ioc_size, GFP_KERNEL); + mbuf = kmalloc(ioc_size, GFP_KERNEL); if (NULL == mbuf) return -ENOMEM; parg = mbuf; @@ -3318,27 +3318,21 @@ video_usercopy(struct file *file, unsigned int orig_cmd, unsigned long arg, has_array_args = err; if (has_array_args) { - /* - * When adding new types of array args, make sure that the - * parent argument to ioctl (which contains the pointer to the - * array) fits into sbuf (so that mbuf will still remain - * unused up to here). - */ - mbuf = kvmalloc(array_size, GFP_KERNEL); + array_buf = kvmalloc(array_size, GFP_KERNEL); err = -ENOMEM; - if (NULL == mbuf) + if (array_buf == NULL) goto out_array_args; err = -EFAULT; if (in_compat_syscall()) - err = v4l2_compat_get_array_args(file, mbuf, user_ptr, - array_size, orig_cmd, - parg); + err = v4l2_compat_get_array_args(file, array_buf, + user_ptr, array_size, + orig_cmd, parg); else - err = copy_from_user(mbuf, user_ptr, array_size) ? + err = copy_from_user(array_buf, user_ptr, array_size) ? -EFAULT : 0; if (err) goto out_array_args; - *kernel_ptr = mbuf; + *kernel_ptr = array_buf; } /* Handles IOCTL */ @@ -3360,12 +3354,13 @@ video_usercopy(struct file *file, unsigned int orig_cmd, unsigned long arg, if (in_compat_syscall()) { int put_err; - put_err = v4l2_compat_put_array_args(file, user_ptr, mbuf, - array_size, orig_cmd, - parg); + put_err = v4l2_compat_put_array_args(file, user_ptr, + array_buf, + array_size, + orig_cmd, parg); if (put_err) err = put_err; - } else if (copy_to_user(user_ptr, mbuf, array_size)) { + } else if (copy_to_user(user_ptr, array_buf, array_size)) { err = -EFAULT; } goto out_array_args; @@ -3381,7 +3376,8 @@ out_array_args: if (video_put_user((void __user *)arg, parg, cmd, orig_cmd)) err = -EFAULT; out: - kvfree(mbuf); + kvfree(array_buf); + kfree(mbuf); return err; } diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index b221b4e438a1..e7f4bf5bc8dd 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -887,9 +887,6 @@ static __poll_t v4l2_m2m_poll_for_data(struct file *file, src_q = v4l2_m2m_get_src_vq(m2m_ctx); dst_q = v4l2_m2m_get_dst_vq(m2m_ctx); - poll_wait(file, &src_q->done_wq, wait); - poll_wait(file, &dst_q->done_wq, wait); - /* * There has to be at least one buffer queued on each queued_list, which * means either in driver already or waiting for driver to claim it @@ -922,9 +919,21 @@ __poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, struct poll_table_struct *wait) { struct video_device *vfd = video_devdata(file); + struct vb2_queue *src_q = v4l2_m2m_get_src_vq(m2m_ctx); + struct vb2_queue *dst_q = v4l2_m2m_get_dst_vq(m2m_ctx); __poll_t req_events = poll_requested_events(wait); __poll_t rc = 0; + /* + * poll_wait() MUST be called on the first invocation on all the + * potential queues of interest, even if we are not interested in their + * events during this first call. Failure to do so will result in + * queue's events to be ignored because the poll_table won't be capable + * of adding new wait queues thereafter. + */ + poll_wait(file, &src_q->done_wq, wait); + poll_wait(file, &dst_q->done_wq, wait); + if (req_events & (EPOLLOUT | EPOLLWRNORM | EPOLLIN | EPOLLRDNORM)) rc = v4l2_m2m_poll_for_data(file, m2m_ctx, wait); |