Unified fwnode endpoint parser, async sub-device notifier support, N9 flash DTS
Subsystems (20)
v14 cover Unified fwnode endpoint parser, async sub-device notifier support, N9 flash DTS
Hi folks,
We have a large influx of new, unmerged, drivers that are now parsing fwnode endpoints and each one of them is doing this a little bit differently. The needs are still exactly the same for the graph data structure is device independent. This is still a non-trivial task and the majority of the driver implementations are buggy, just buggy in different ways.
Facilitate parsing endpoints by adding a convenience function for parsing the endpoints, and make the omap3isp and rcar-vin drivers use them as an example.
To show where we're getting with this, I've added support for async sub-device notifier support that is notifiers that can be registered by sub-device drivers as well as V4L2 fwnode improvements to make use of them and the DTS changes for the Nokia N9. Some of these patches I've posted previously in this set here:
<URL:http://www.spinics.net/lists/linux-media/msg118764.html>
Since that, the complete callback of the master notifier registering the V4L2 device is only called once all sub-notifiers have been completed as well. This way the device node creation can be postponed until all devices have been successfully initialised.
With this, the as3645a driver successfully registers a sub-device to the media device created by the omap3isp driver. The kernel also has the information it's related to the sensor driven by the smiapp driver but we don't have a way to expose that information yet.
The patches have a dependency to the as3645a driver fixes:
<URL:https://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds.git/log/?h=fixes-4.14-rc3>
since v13:
- Add patch "v4l: fwnode: Add a convenience function for registering sensors" and make the sensor driver changes a lot smaller.
- Fix v4l2_async_notifier_parse_fwnode_endpoints() error handling for omap3isp.
- Return -ENODEV in rcar-vin if no async sub-device is available. I.e. fix a bug in previous versions of "rcar-vin: Use generic parser for parsing fwnode endpoints".
- Rework notifier completion in patch "v4l: async: Allow binding notifiers to sub-devices". This fixes calling complete notifiers more than once; they are now all called once when all async sub-devices in all related notifiers have been bound.
- Split the same patch ("v4l: async: Allow binding notifiers to sub-devices") into two, first one that prepares for async sub-devices and another that implements the bulk of support for sub-device notifiers.
- Postpone sub-device bound callback until v4l2_device is available in all cases. This also applies to the media device. The notifier's bound callback was in some cases called before having v4l2_device in v13.
- Prevent registering fwnodes as async sub-devices more than once.
- Use list_move instead of list_del and list_add in v4l2_async_notifier_unbind_all_subdevs.
- Call v4l2_async_notifier_release v4l2_async_notifier_cleanup instead. It's a cleanup function and does not release the object passed to it.
- In v4l2_async_notifier_fwnode_parse_endpoint, set match_type field with the fwnode.fwnode field, not later.
- In debug and other messages, use port@number/endpoint@number format.
- Call fwnode_handle_put() to release references obtained using e.g. fwnode_graph_get_port_parent.
- Multiple KernelDoc documentation fixes.
since v12:
- Merge patches "v4l: fwnode: Support generic parsing of graph endpoints in a device" and "v4l: fwnode: Support generic parsing of graph endpoints, per port". Improve the commit and KernelDoc documentation as well.
- Reformat loop conditions in v4l2_async_notifier_try_complete() and v4l2_fwnode_reference_get_int_prop(). Improve comments in fwnode_property_get_reference_args() return value handling. Also check for -ENODATA in v4l2_fwnode_reference_parse_int_props().
- Add an ACPI example for v4l2_fwnode_reference_get_int_prop().
- Document index parameter, document nprops parameter better and fix -EINVAL error code documentation for v4l2_fwnode_reference_get_int_prop().
- Use WARN_ON_ONCE(true) instead of WARN_ON_ONCE(1) in v4l2_async_notifier_release().
since v11:
- Add patch "et8ek8: Add support for flash and lens devices".
- Add patch "v4l: fwnode: Support generic parsing of graph endpoints, per port". The use case for this is to parse only upstream ports in a device with sources and sinks. The downstream ports have already been parsed by other drivers.
- Rename v4l2_fwnode_reference_parse_sensor_common as v4l2_async_notifier_parse_fwnode_sensor_common. This is in line with other functions that parse information using fwnode API and set up async sub-devices in the notifier.
since v10:
- Rename v4l2_async_get_subdev_notifier as v4l2_async_find_subdev_notifier, as this is what it effectively does:
finds a notifier for a sub-device. Same for v4l2_async_notifier_get_v4l2_dev / v4l2_async_notifier_get_v4l2_dev.
- Initialise lists before calling v4l2_async_notifier_call_complete() if there are no sub-devices in a notifier.
- Warn on missing sub-device or existing v4l2_device on sub-device notifier register, and conversely missing v4l2_device or existing sub-device for a master notifier.
- Set notifier's sd and v4l2_dev fields NULL when the sub-device is unregistered.
- Document the newly added helper functions for parsing external references in v4l2-fwnode.c better.
- Return -ENOENT in v4l2_fwnode_reference_parse if no entries are found, and other errors as they occur.
- Turn the loop in v4l2_fwnode_reference_get_int_prop a while loop (was for).
- Don't put fwnodes in v4l2_fwnode_reference_parse_int_props.
- Fix description of parent field in struct v4l2_async_notifier.
- In the documentation of v4l2_async_notifier_release, document that this function must be called also after v4l2_fwnode_reference_parse_sensor_common, not just v4l2_async_notifier_parse_fwnode_endpoints. The same goes for v4l2_async_notifier_parse_fwnode_endpoints as well as v4l2_fwnode_reference_parse_sensor_common.
since v9:
- Drop "as3645a: Switch to fwnode property API" and "ACPI: Document how to refer to LEDs from remote nodes" patches. They're better off separately from this set.
- Address property documentation redundancy in smiapp DT binding documentation.
- Add patches "ov5670: Add support for flash and lens devices" and "ov13858: Add support for flash and lens devices".
since v8:
- Improve terminology for notifiers. Instead of master / subdev, we have root, parent and subdev notifiers.
- Renamed "flash" property as "flash-leds". There are many, and currently we make assumptions in a lot of places (e.g. LED bindings) that these are LEDs. While we don't have any other types of flashes supported right now (e.g. Xenon), it's safer to assume we might have them in the future.
- Use ENOTCONN instead of EPERM to tell from driver's callback function that an endpoint is to be skipped but not handled as an error.
- Avoid accessing notifier's subdevs array as well as num_subdevs field from rcar-vin driver.
- Add a patch "v4l: async: Allow async notifier register call succeed with no subdevs", which allows, well, what the subject says.
- Move checks for subdev / v4l2_dev from __v4l2_async_notifier_register() to v4l2_async_notifier_register() and v4l2_async_subdev_notifier_register().
- Don't initialise notifier->list. There was no need to do so, as this is the entry added to the list and not used otherwise. I.e. regarding this, the state before this patchset is restored.
- Clean up error handling in v4l2_async_notifier_fwnode_parse_endpoint().
- WARN_ON() in v4l2_async_notifier_parse_fwnode_endpoints() if the asd_struct_size is smaller than size of struct v4l2_async_subdev.
- Make v4l2_fwnode_reference_parse() static as there should be no need to use it outside the V4L2 fwnode framework. Also, remove the callback function as well as other arguments that always have the same value in current usage. (This can be changed later on if needed without affecting drivers.)
- Add the patch "v4l: fwnode: Add a helper function to obtain device / interger references", which allows similar use than v4l2_fwnode_reference_parse() but is more useful on ACPI based systems --- on ACPI, you can only refer to device nodes (corresponding struct deice in Linux), not to data extension nodes under the devices.
- Improve v4l2_fwnode_reference_parse_sensor_common() to work on ACPI based systems.
- Add patch "ACPI: Document how to refer to LEDs from remote nodes" to document using and referring to LEDs on ACPI.
- Rebase the set on AS3645A fixes I just sent ("AS3645A fixes")
- In v4l2_fwnode_reference_parse_sensor_common(), tell if parsing a property failed.
- Improved documentation for v4l2_async_notifier_parse_fwnode_endpoints().
- Fix v4l2_async_notifier_try_all_subdevs(); it is allowed that the list entry being iterated over is deleted but no other changes to the list are allowed. This could be the case if a sub-device driver's notifier binds a sub-device. Restart the loop whenever a match is found.
- Add patch "as3645a: Switch to fwnode property API" which also adds ACPI support.
since v7:
- Added three more patches:
v4l: async: Remove re-probing support
v4l: async: Use more intuitive names for internal functions
dt: bindings: smiapp: Document lens-focus and flash properties
The last one was already sent previously after the rest of the patchset.
- Removed re-probing support. This is hard to support and only useful in special cases. It can be reintroduced later on if there's really a need --- note that in e.g. omap3isp this was always broken and no-one ever complained.
- Remove smiapp driver's async complete callback (and ops). It is
redundant: the sub-device nodes are created through the master notifier.
- Improve flash property documentation in video-interfaces.txt.
- Introduce helper functions to call notifier operations, one for each operation.
- Rename v4l2_async_test_notify as v4l2_async_match_notify and v4l2_async_belongs to v4l2_async_find_match.
- v4l2_async_notifier_test_all_subdevs() renamed as v4l2_async_notifier_try_all_subdevs().
- Made notifier_v4l2_dev a function (it was a macro).
- Registering subdev notifiers from sub-device drivers that control sub-devices created through sub-notifiers is now supported. In other words, subdev notifiers may be registered through other subdev notifiers. This is the source of the bulk of the changes between v7 and v8.
- Add explanatory comments to helper functions used by V4L2 async framework. This should help understanding the internal workings of the framework.
- Removed the "notifiers" list in struct v4l2_async_notifier. The information can be found from existing data structures.
- Explicitly check that registering a non-subdev notifier has v4l2_dev and a subdev notifier has a sub-device pointer.
- Unified several code paths between subdev notifiers and non-subdev notifiers.
- Fixed v4l2_async_notifier_release() --- calling it on a notifier for which the driver had allocated the subdevs array would lead calling kvfree() on that array. Now notifier->max_subdevs is checked before proceeding.
- Fixed a use-after-free issue in
v4l2_async_notifier_fwnode_parse_endpoints().
- Small fixes to KernelDoc documentation for
v4l2_async_notifier_parse_fwnode_endpoints().
since v6:
- Drop the last patch that added variant for parsing endpoints given specific port and endpoints numbers.
- Separate driver changes from the fwnode endpoint parser patch into two patches. rcar-vin driver is now using the name function.
- Use -ENOTCONN to tell the parser that and endpoint (or a reference) is to be ignored.
- parse_endpoint and parse_single callback functions are now optional and documented as such.
- Added Laurent's patch adding notifier operations struct which I rebase on the fwnode parser patchset. I wrote another patch to call the notifier operations through macros.
- Add DT bindings for flash and lens devices.
- V4L2 fwnode parser for references (such as flash and lens).
- Added smiapp driver support for async sub-devices (lens and flash).
- Added a few fixes for omap3isp.
since v5:
- Use v4l2_async_ prefix for static functions as well (4th patch)
- Use memcpy() to copy array rather than a loop
- Document that the v4l2_async_subdev pointer in driver specific struct must be the first member
- Improve documentation of the added functions (4th and 5th patches)
- Arguments
- More thorough explation of the purpose, usage and object lifetime
- Added acks
since v4:
- Prepend the set with three documentation fixes.
- The driver's async struct must begin with struct v4l2_async_subdev. Fix this for omap3isp and document it.
- Improve documentation for new functions.
- Don't use devm_ family of functions for allocating memory. Introduce v4l2_async_notifier_release() to release memory resources.
- Rework both v4l2_async_notifier_fwnode_parse_endpoints() and v4l2_async_notifier_fwnode_parse_endpoint() and the local functions they call. This should make the code cleaner. Despite the name, for linking and typical usage reasons the functions remain in v4l2-fwnode.c.
- Convert rcar-vin to use v4l2_async_notifier_fwnode_parse_endpoint().
- Use kvmalloc() for allocating the notifier's subdevs array.
- max_subdevs argument for notifier_realloc is now the total maximum number of subdevs, not the number of available subdevs.
- Use fwnode_device_is_available() to make sure the device actually exists.
- Move the note telling v4l2_async_notifier_fwnode_parse_endpoints() should not be used by new drivers to the last patch adding v4l2_async_notifier_fwnode_parse_endpoint().
since v3:
- Rebase on current mediatree master.
since v2:
- Rebase on CCP2 support patches.
- Prepend a patch cleaning up omap3isp driver a little.
since v1:
- The first patch has been merged (it was a bugfix).
- In anticipation that the parsing can take place over several iterations, take the existing number of async sub-devices into account when re-allocating an array of async sub-devices.
- Rework the first patch to better anticipate parsing single endpoint at a time by a driver.
- Add a second patch that adds a function for parsing endpoints one at a time based on port and endpoint numbers.
Laurent Pinchart (1):
v4l: async: Move async subdev notifier operations to a separate
structure
Sakari Ailus (27):
v4l: fwnode: Move KernelDoc documentation to the header
v4l: async: Remove re-probing support
v4l: async: Use more intuitive names for internal functions
v4l: async: Add V4L2 async documentation to the documentation build
v4l: fwnode: Support generic parsing of graph endpoints in a device
omap3isp: Use generic parser for parsing fwnode endpoints
rcar-vin: Use generic parser for parsing fwnode endpoints
omap3isp: Fix check for our own sub-devices
omap3isp: Print the name of the entity where no source pads could be
found
v4l: async: Introduce helpers for calling async ops callbacks
v4l: async: Register sub-devices before calling bound callback
v4l: async: Allow async notifier register call succeed with no subdevs
v4l: async: Prepare for async sub-device notifiers
v4l: async: Allow binding notifiers to sub-devices
v4l: async: Ensure only unique fwnodes are registered to notifiers
dt: bindings: Add a binding for flash LED devices associated to a
sensor
dt: bindings: Add lens-focus binding for image sensors
v4l: fwnode: Add a helper function for parsing generic references
v4l: fwnode: Add a helper function to obtain device / integer
references
v4l: fwnode: Add convenience function for parsing common external refs
v4l: fwnode: Add a convenience function for registering sensors
dt: bindings: smiapp: Document lens-focus and flash-leds properties
smiapp: Add support for flash and lens devices
et8ek8: Add support for flash and lens devices
ov5670: Add support for flash and lens devices
ov13858: Add support for flash and lens devices
arm: dts: omap3: N9/N950: Add flash references to the camera
.../devicetree/bindings/media/i2c/nokia,smia.txt | 2 + .../devicetree/bindings/media/video-interfaces.txt | 10 + Documentation/media/kapi/v4l2-async.rst | 3 + Documentation/media/kapi/v4l2-core.rst | 1 + arch/arm/boot/dts/omap3-n9.dts | 1 + arch/arm/boot/dts/omap3-n950-n9.dtsi | 4 +- arch/arm/boot/dts/omap3-n950.dts | 1 + drivers/media/i2c/et8ek8/et8ek8_driver.c | 2 +- drivers/media/i2c/ov13858.c | 2 +- drivers/media/i2c/ov5670.c | 2 +- drivers/media/i2c/smiapp/smiapp-core.c | 2 +- drivers/media/platform/am437x/am437x-vpfe.c | 8 +- drivers/media/platform/atmel/atmel-isc.c | 10 +- drivers/media/platform/atmel/atmel-isi.c | 10 +- drivers/media/platform/davinci/vpif_capture.c | 8 +- drivers/media/platform/davinci/vpif_display.c | 8 +- drivers/media/platform/exynos4-is/media-dev.c | 8 +- drivers/media/platform/omap3isp/isp.c | 133 ++--- drivers/media/platform/omap3isp/isp.h | 5 +- drivers/media/platform/pxa_camera.c | 8 +- drivers/media/platform/qcom/camss-8x16/camss.c | 8 +- drivers/media/platform/rcar-vin/rcar-core.c | 117 ++-- drivers/media/platform/rcar-vin/rcar-dma.c | 10 +- drivers/media/platform/rcar-vin/rcar-v4l2.c | 14 +- drivers/media/platform/rcar-vin/rcar-vin.h | 4 +- drivers/media/platform/rcar_drif.c | 10 +- drivers/media/platform/soc_camera/soc_camera.c | 14 +- drivers/media/platform/stm32/stm32-dcmi.c | 10 +- drivers/media/platform/ti-vpe/cal.c | 8 +- drivers/media/platform/xilinx/xilinx-vipp.c | 8 +- drivers/media/v4l2-core/v4l2-async.c | 469 ++++++++++++---- drivers/media/v4l2-core/v4l2-fwnode.c | 617 ++++++++++++++++++--- drivers/staging/media/imx/imx-media-dev.c | 8 +- include/media/v4l2-async.h | 91 ++- include/media/v4l2-fwnode.h | 220 +++++++- include/media/v4l2-subdev.h | 3 + 36 files changed, 1424 insertions(+), 415 deletions(-) create mode 100644 Documentation/media/kapi/v4l2-async.rst
Signature · 6 lines
2.11.0 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): 20170925222540.371-1-sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected]
PATCH v14 1/28 v4l: fwnode: Move KernelDoc documentation to the header
In V4L2 the practice is to have the KernelDoc documentation in the header and not in .c source code files. This consequently makes the V4L2 fwnode function documentation part of the Media documentation build.
Also correct the link related function and argument naming in documentation.
--- drivers/media/v4l2-core/v4l2-fwnode.c | 75 -------------------------------- include/media/v4l2-fwnode.h | 81 ++++++++++++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 76 deletions(-)
drivers/media/v4l2-core/v4l2-fwnode.c +0 -75
@@ -181,25 +181,6 @@ v4l2_fwnode_endpoint_parse_csi1_bus(struct fwnode_handle *fwnode, vep->bus_type =V4L2_MBUS_CSI1 ; } -/** -* v4l2_fwnode_endpoint_parse() - parse all fwnode node properties -* @fwnode: pointer to the endpoint's fwnode handle -* @vep: pointer to the V4L2 fwnode data structure -* -* All properties are optional. If none are found, we don't set any flags. This -* means the port has a static configuration and no properties have to be -* specified explicitly. If any properties that identify the bus as parallel -* are found and slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if -* we recognise the bus as serial CSI-2 and clock-noncontinuous isn't set, we -* set the V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. The caller should hold a -* reference to @fwnode. -* -* NOTE: This function does not parse properties the size of which is variable -* without a low fixed limit. Please use v4l2_fwnode_endpoint_alloc_parse() in -* new drivers instead. -* -* Return: 0 on success or a negative error code on failure. -*/ int v4l2_fwnode_endpoint_parse (struct fwnode_handle *fwnode,struct v4l2_fwnode_endpoint *vep) {
@@ -239,14 +220,6 @@ int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode, }EXPORT_SYMBOL_GPL (v4l2_fwnode_endpoint_parse); -/* -* v4l2_fwnode_endpoint_free() - free the V4L2 fwnode acquired by -* v4l2_fwnode_endpoint_alloc_parse() -* @vep - the V4L2 fwnode the resources of which are to be released -* -* It is safe to call this function with NULL argument or on a V4L2 fwnode the -* parsing of which failed. -*/ void v4l2_fwnode_endpoint_free (struct v4l2_fwnode_endpoint *vep) {if (IS_ERR_OR_NULL (vep))
@@ -257,29 +230,6 @@ void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep) }EXPORT_SYMBOL_GPL (v4l2_fwnode_endpoint_free); -/** -* v4l2_fwnode_endpoint_alloc_parse() - parse all fwnode node properties -* @fwnode: pointer to the endpoint's fwnode handle -* -* All properties are optional. If none are found, we don't set any flags. This -* means the port has a static configuration and no properties have to be -* specified explicitly. If any properties that identify the bus as parallel -* are found and slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if -* we recognise the bus as serial CSI-2 and clock-noncontinuous isn't set, we -* set the V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. The caller should hold a -* reference to @fwnode. -* -* v4l2_fwnode_endpoint_alloc_parse() has two important differences to -* v4l2_fwnode_endpoint_parse(): -* -* 1. It also parses variable size data. -* -* 2. The memory it has allocated to store the variable size data must be freed -* using v4l2_fwnode_endpoint_free() when no longer needed. -* -* Return: Pointer to v4l2_fwnode_endpoint if successful, on an error pointer -* on error. -*/ struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse (struct fwnode_handle *fwnode) {
@@ -322,24 +272,6 @@ struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse( }EXPORT_SYMBOL_GPL (v4l2_fwnode_endpoint_alloc_parse); -/** -* v4l2_fwnode_endpoint_parse_link() - parse a link between two endpoints -* @__fwnode: pointer to the endpoint's fwnode at the local end of the link -* @link: pointer to the V4L2 fwnode link data structure -* -* Fill the link structure with the local and remote nodes and port numbers. -* The local_node and remote_node fields are set to point to the local and -* remote port's parent nodes respectively (the port parent node being the -* parent node of the port node if that node isn't a 'ports' node, or the -* grand-parent node of the port node otherwise). -* -* A reference is taken to both the local and remote nodes, the caller must use -* v4l2_fwnode_endpoint_put_link() to drop the references when done with the -* link. -* -* Return: 0 on success, or -ENOLINK if the remote endpoint fwnode can't be -* found. -*/ int v4l2_fwnode_parse_link (struct fwnode_handle *__fwnode,struct v4l2_fwnode_link *link) {
@@ -374,13 +306,6 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *__fwnode, }EXPORT_SYMBOL_GPL (v4l2_fwnode_parse_link); -/** -* v4l2_fwnode_put_link() - drop references to nodes in a link -* @link: pointer to the V4L2 fwnode link data structure -* -* Drop references to the local and remote nodes in the link. This function -* must be called on every link parsed with v4l2_fwnode_parse_link(). -*/ void v4l2_fwnode_put_link (struct v4l2_fwnode_link *link) {fwnode_handle_put (link->local_node);
include/media/v4l2-fwnode.h +80 -1
93 lines not on this page · raw message
Signature · 6 lines
2.11.0 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v14 7/28 rcar-vin: Use generic parser for parsing fwnode endpoints
In reply to a message not in the archiveInstead of using a custom driver implementation, use v4l2_async_notifier_parse_fwnode_endpoints() to parse the fwnode endpoints of the device.
--- drivers/media/platform/rcar-vin/rcar-core.c | 107 +++++++++------------------- drivers/media/platform/rcar-vin/rcar-dma.c | 10 +-- drivers/media/platform/rcar-vin/rcar-v4l2.c | 14 ++-- drivers/media/platform/rcar-vin/rcar-vin.h | 4 +- 4 files changed, 46 insertions(+), 89 deletions(-)
drivers/media/platform/rcar-vin/rcar-core.c +32 -75
@@ -21,6 +21,7 @@#include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <media/v4l2-async.h> #include <media/v4l2-fwnode.h> #include "rcar-vin.h"
@@ -77,14 +78,14 @@ static int rvin_digital_notify_complete(struct v4l2_async_notifier *notifier)int ret;/* Verify subdevices mbus format */ -if (!rvin_mbus_supported (&vin->digital)) { +if (!rvin_mbus_supported (vin->digital)) {vin_err (vin,"Unsupported media bus format for %s\n" , - vin->digital.subdev->name); + vin->digital->subdev->name);return -EINVAL ; }vin_dbg (vin,"Found media bus format for %s: %d\n" , - vin->digital.subdev->name, vin->digital.code); + vin->digital->subdev->name, vin->digital->code); ret =v4l2_device_register_subdev_nodes (&vin->v4l2_dev);if (ret <0 ) {
@@ -103,7 +104,7 @@ static void rvin_digital_notify_unbind(struct v4l2_async_notifier *notifier,vin_dbg (vin,"unbind digital subdev %s\n" , subdev->name);rvin_v4l2_remove (vin); - vin->digital.subdev =NULL ; + vin->digital->subdev =NULL ; } static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier,
@@ -120,117 +121,71 @@ static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier, ret =rvin_find_pad (subdev,MEDIA_PAD_FL_SOURCE );if (ret <0 )return ret; - vin->digital.source_pad = ret; + vin->digital->source_pad = ret; ret =rvin_find_pad (subdev,MEDIA_PAD_FL_SINK ); - vin->digital.sink_pad = ret <0 ?0 : ret; + vin->digital->sink_pad = ret <0 ?0 : ret; - vin->digital.subdev = subdev; + vin->digital->subdev = subdev;vin_dbg (vin,"bound subdev %s source pad: %u sink pad: %u\n" , - subdev->name, vin->digital.source_pad, - vin->digital.sink_pad); + subdev->name, vin->digital->source_pad, + vin->digital->sink_pad);return 0 ; } -static int rvin_digitial_parse_v4l2 (struct rvin_dev *vin, -struct device_node *ep, -struct v4l2_mbus_config *mbus_cfg) +static int rvin_digital_parse_v4l2 (struct device *dev, +struct v4l2_fwnode_endpoint *vep, +struct v4l2_async_subdev *asd) { -struct v4l2_fwnode_endpoint v4l2_ep; -int ret; +struct rvin_dev *vin =dev_get_drvdata (dev); +struct rvin_graph_entity *rvge = + container_of(asd, struct rvin_graph_entity, asd); - ret =v4l2_fwnode_endpoint_parse (of_fwnode_handle (ep), &v4l2_ep); -if (ret) { -vin_err (vin,"Could not parse v4l2 endpoint\n" ); -return -EINVAL ; - } +if (vep->base.port || vep->base.id) +return -ENOTCONN ; - mbus_cfg->type = v4l2_ep.bus_type; + rvge->mbus_cfg.type = vep->bus_type; -switch (mbus_cfg->type) { +switch (rvge->mbus_cfg.type) {case V4L2_MBUS_PARALLEL :vin_dbg (vin,"Found PARALLEL media bus\n" ); - mbus_cfg->flags = v4l2_ep.bus.parallel.flags; + rvge->mbus_cfg.flags = vep->bus.parallel.flags;break ;case V4L2_MBUS_BT656 :vin_dbg (vin,"Found BT656 media bus\n" ); - mbus_cfg->flags =0 ; + rvge->mbus_cfg.flags =0 ;break ;default :vin_err (vin,"Unknown media bus type\n" );return -EINVAL ; } -return 0 ; -} - -static int rvin_digital_graph_parse (struct rvin_dev *vin) -{ -struct device_node *ep, *np; -int ret; - - vin->digital.asd.match.fwnode.fwnode =NULL ; - vin->digital.subdev =NULL ; - -/* -* Port 0 id 0 is local digital input, try to get it. -* Not all instances can or will have this, that is OK -*/ - ep =of_graph_get_endpoint_by_regs (vin->dev->of_node,0 ,0 ); -if (!ep) -return 0 ; - - np =of_graph_get_remote_port_parent (ep); -if (!np) { -vin_err (vin,"No remote parent for digital input\n" ); -of_node_put (ep); -return -EINVAL ; - } -of_node_put (np); - - ret =rvin_digitial_parse_v4l2 (vin, ep, &vin->digital.mbus_cfg); -of_node_put (ep); -if (ret) -return ret; - - vin->digital.asd.match.fwnode.fwnode =of_fwnode_handle (np); - vin->digital.asd.match_type =V4L2_ASYNC_MATCH_FWNODE ; + vin->digital = rvge;return 0 ; }static int rvin_digital_graph_init (struct rvin_dev *vin) { -struct v4l2_async_subdev **subdevs =NULL ;int ret; - ret =rvin_digital_graph_parse (vin); + ret =v4l2_async_notifier_parse_fwnode_endpoints ( + vin->dev, &vin->notifier, +sizeof (struct rvin_graph_entity ), rvin_digital_parse_v4l2);if (ret)return ret; -if (!vin->digital.asd.match.fwnode.fwnode) { -vin_dbg (vin,"No digital subdevice found\n" ); +if (!vin->digital)return -ENODEV ; - } - -/* Register the subdevices notifier. */ - subdevs =devm_kzalloc (vin->dev,sizeof (*subdevs),GFP_KERNEL ); -if (subdevs ==NULL ) -return -ENOMEM ; - - subdevs[0 ] = &vin->digital.asd;vin_dbg (vin,"Found digital subdevice %pOF\n" , -to_of_node (subdevs[0 ]->match.fwnode.fwnode)); +to_of_node (vin->digital->asd.match.fwnode.fwnode)); - vin->notifier.num_subdevs =1 ; - vin->notifier.subdevs = subdevs; vin->notifier.bound = rvin_digital_notify_bound; vin->notifier.unbind = rvin_digital_notify_unbind; vin->notifier.complete = rvin_digital_notify_complete; - ret =v4l2_async_notifier_register (&vin->v4l2_dev, &vin->notifier);if (ret <0 ) {vin_err (vin,"Notifier registration failed\n" );
@@ -290,6 +245,8 @@ static int rcar_vin_probe(struct platform_device *pdev)if (ret)return ret; +platform_set_drvdata (pdev, vin); + ret =rvin_digital_graph_init (vin);if (ret <0 ) goto error;
@@ -297,11 +254,10 @@ static int rcar_vin_probe(struct platform_device *pdev)pm_suspend_ignore_children (&pdev->dev, true);pm_runtime_enable (&pdev->dev); -platform_set_drvdata (pdev, vin); -return 0 ; error:rvin_dma_remove (vin); +v4l2_async_notifier_cleanup (&vin->notifier);return ret; }
@@ -313,6 +269,7 @@ static int rcar_vin_remove(struct platform_device *pdev)pm_runtime_disable (&pdev->dev);v4l2_async_notifier_unregister (&vin->notifier); +v4l2_async_notifier_cleanup (&vin->notifier);rvin_dma_remove (vin);
drivers/media/platform/rcar-vin/rcar-dma.c +5 -5
@@ -183,7 +183,7 @@ static int rvin_setup(struct rvin_dev *vin)/* * Input interface */ -switch (vin->digital.code) { +switch (vin->digital->code) {case MEDIA_BUS_FMT_YUYV8_1X16 :/* BT.601/BT.1358 16bit YCbCr422 */ vnmc |=VNMC_INF_YUV16 ;
@@ -191,7 +191,7 @@ static int rvin_setup(struct rvin_dev *vin)break ;case MEDIA_BUS_FMT_UYVY8_2X8 :/* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */ - vnmc |= vin->digital.mbus_cfg.type ==V4L2_MBUS_BT656 ? + vnmc |= vin->digital->mbus_cfg.type ==V4L2_MBUS_BT656 ?VNMC_INF_YUV8_BT656 :VNMC_INF_YUV8_BT601 ; input_is_yuv = true;break ;
@@ -200,7 +200,7 @@ static int rvin_setup(struct rvin_dev *vin)break ;case MEDIA_BUS_FMT_UYVY10_2X10 :/* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */ - vnmc |= vin->digital.mbus_cfg.type ==V4L2_MBUS_BT656 ? + vnmc |= vin->digital->mbus_cfg.type ==V4L2_MBUS_BT656 ?VNMC_INF_YUV10_BT656 :VNMC_INF_YUV10_BT601 ; input_is_yuv = true;break ;
@@ -212,11 +212,11 @@ static int rvin_setup(struct rvin_dev *vin) dmr2 =VNDMR2_FTEV |VNDMR2_VLV (1 );/* Hsync Signal Polarity Select */ -if (!(vin->digital.mbus_cfg.flags &V4L2_MBUS_HSYNC_ACTIVE_LOW )) +if (!(vin->digital->mbus_cfg.flags &V4L2_MBUS_HSYNC_ACTIVE_LOW )) dmr2 |=VNDMR2_HPS ;/* Vsync Signal Polarity Select */ -if (!(vin->digital.mbus_cfg.flags &V4L2_MBUS_VSYNC_ACTIVE_LOW )) +if (!(vin->digital->mbus_cfg.flags &V4L2_MBUS_VSYNC_ACTIVE_LOW )) dmr2 |=VNDMR2_VPS ;/*
drivers/media/platform/rcar-vin/rcar-v4l2.c +7 -7
@@ -111,7 +111,7 @@ static int rvin_reset_format(struct rvin_dev *vin)struct v4l2_mbus_framefmt *mf = &fmt.format;int ret; - fmt.pad = vin->digital.source_pad; + fmt.pad = vin->digital->source_pad; ret =v4l2_subdev_call (vin_to_source (vin), pad, get_fmt,NULL , &fmt);if (ret)
@@ -172,13 +172,13 @@ static int __rvin_try_format_source(struct rvin_dev *vin, sd =vin_to_source (vin); -v4l2_fill_mbus_format (&format.format, pix, vin->digital.code); +v4l2_fill_mbus_format (&format.format, pix, vin->digital->code); pad_cfg =v4l2_subdev_alloc_pad_config (sd);if (pad_cfg ==NULL )return -ENOMEM ; - format.pad = vin->digital.source_pad; + format.pad = vin->digital->source_pad; field = pix->field;
@@ -555,7 +555,7 @@ static int rvin_enum_dv_timings(struct file *file, void *priv_fh,if (timings->pad)return -EINVAL ; - timings->pad = vin->digital.sink_pad; + timings->pad = vin->digital->sink_pad; ret =v4l2_subdev_call (sd, pad, enum_dv_timings, timings);
@@ -607,7 +607,7 @@ static int rvin_dv_timings_cap(struct file *file, void *priv_fh,if (cap->pad)return -EINVAL ; - cap->pad = vin->digital.sink_pad; + cap->pad = vin->digital->sink_pad; ret =v4l2_subdev_call (sd, pad, dv_timings_cap, cap);
@@ -625,7 +625,7 @@ static int rvin_g_edid(struct file *file, void *fh, struct v4l2_edid *edid)if (edid->pad)return -EINVAL ; - edid->pad = vin->digital.sink_pad; + edid->pad = vin->digital->sink_pad; ret =v4l2_subdev_call (sd, pad, get_edid, edid);
@@ -643,7 +643,7 @@ static int rvin_s_edid(struct file *file, void *fh, struct v4l2_edid *edid)if (edid->pad)return -EINVAL ; - edid->pad = vin->digital.sink_pad; + edid->pad = vin->digital->sink_pad; ret =v4l2_subdev_call (sd, pad, set_edid, edid);
drivers/media/platform/rcar-vin/rcar-vin.h +2 -2
@@ -126,7 +126,7 @@ struct rvin_dev {struct v4l2_device v4l2_dev;struct v4l2_ctrl_handler ctrl_handler;struct v4l2_async_notifier notifier; -struct rvin_graph_entity digital; +struct rvin_graph_entity *digital;struct mutex lock;struct vb2_queue queue;
@@ -145,7 +145,7 @@ struct rvin_dev {struct v4l2_rect compose; }; -#define vin_to_source (vin) vin->digital.subdev +#define vin_to_source (vin) ((vin)->digital->subdev)/* Debug */ #define vin_dbg(d, fmt, arg...) dev_dbg(d->dev, fmt, ##arg)
Signature · 6 lines
2.11.0 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v14 07/28] rcar-vin: Use generic parser for parsing fwnode endpoints
Hi Sakari,
Thanks for your patch, I like it. Unfortunately it causes issues :-(
I picked the first 7 patches of this series on top of media-next and it produce problems when tested on Koelsch with CONFIG_OF_DYNAMIC=y.
1. It print's 'OF: ERROR: Bad of_node_put() on /video@e6ef0000/port' messages during boot.
OF: ERROR: Bad of_node_put() on /video@e6ef0000/port
CPU: 1 PID: 1 Comm: swapper/0 Not tainted 4.13.0-rc4-00632-gfae12f9c98a8c567 #7
Hardware name: Generic R8A7791 (Flattened Device Tree)
Backtrace:
[<c010b16c>] (dump_backtrace) from [<c010b3b8>] (show_stack+0x18/0x1c)
r7:00000001 r6:60000013 r5:00000000 r4:c0a7c88c
[<c010b3a0>] (show_stack) from [<c06d9034>] (dump_stack+0x84/0xa0)
[<c06d8fb0>] (dump_stack) from [<c05814ac>] (of_node_release+0x2c/0x94)
r7:00000001 r6:c0a6fc4c r5:eb1284c0 r4:eb7c7a00
[<c0581480>] (of_node_release) from [<c06dcd3c>] (kobject_put+0xbc/0xdc)
r7:00000001 r6:c0a6fc4c r5:eb1284c0 r4:eb7c7a00
[<c06dcc80>] (kobject_put) from [<c0580d48>] (of_node_put+0x1c/0x20)
r6:eb7c7af8 r5:eb7c79e0 r4:eb7c7798
[<c0580d2c>] (of_node_put) from [<c057fc18>] (of_fwnode_put+0x38/0x44)
[<c057fbe0>] (of_fwnode_put) from [<c04244a8>] (fwnode_handle_put+0x30/0x34)
[<c0424478>] (fwnode_handle_put) from [<c0424714>] (fwnode_graph_get_port_parent+0x44/0x4c)
[<c04246d0>] (fwnode_graph_get_port_parent) from [<c0514820>] (__v4l2_async_notifier_parse_fwnode_endpoints+0x1dc/0x2d8)
r5:eaa56bd8 r4:00000000
[<c0514644>] (__v4l2_async_notifier_parse_fwnode_endpoints) from [<c0514a9c>] (v4l2_async_notifier_parse_fwnode_endpoints+0x20/0x28)
r10:00000000 r9:eaa56bd8 r8:c0a6c504 r7:eb251a10 r6:eb251a00 r5:00000000
r4:eaa56810
[<c0514a7c>] (v4l2_async_notifier_parse_fwnode_endpoints) from [<c05433b8>] (rcar_vin_probe+0xcc/0x178)
[<c05432ec>] (rcar_vin_probe) from [<c0420a3c>] (platform_drv_probe+0x58/0xa4)
r9:00000000 r8:c0a6c504 r7:00000000 r6:c0a6c504 r5:eb251a10 r4:c05432ec
[<c04209e4>] (platform_drv_probe) from [<c041f320>] (driver_probe_device+0x210/0x2d8)
r7:00000000 r6:c0ac72d4 r5:c0ac72c8 r4:eb251a10
[<c041f110>] (driver_probe_device) from [<c041f46c>] (__driver_attach+0x84/0xb0)
r10:00000000 r9:c096d224 r8:00000000 r7:c0a50cf0 r6:c0a6c504 r5:eb251a44
r4:eb251a10 r3:00000000
[<c041f3e8>] (__driver_attach) from [<c041da08>] (bus_for_each_dev+0x88/0x98)
r7:c0a50cf0 r6:c041f3e8 r5:c0a6c504 r4:00000000
[<c041d980>] (bus_for_each_dev) from [<c041f5bc>] (driver_attach+0x20/0x28)
r6:00000000 r5:eaa55f80 r4:c0a6c504
[<c041f59c>] (driver_attach) from [<c041e190>] (bus_add_driver+0x170/0x1e0)
[<c041e020>] (bus_add_driver) from [<c0420068>] (driver_register+0xa8/0xe8)
r7:c095883c r6:000000cb r5:ffffe000 r4:c0a6c504
[<c041ffc0>] (driver_register) from [<c04214b0>] (__platform_driver_register+0x38/0x4c)
r5:ffffe000 r4:c0935328
[<c0421478>] (__platform_driver_register) from [<c0935340>] (rcar_vin_driver_init+0x18/0x20)
[<c0935328>] (rcar_vin_driver_init) from [<c0900ecc>] (do_one_initcall+0x12c/0x154)
[<c0900da0>] (do_one_initcall) from [<c0901080>] (kernel_init_freeable+0x18c/0x1d0)
r8:c0a8a700 r7:c095883c r6:000000cb r5:c0a8a700 r4:00000007
[<c0900ef4>] (kernel_init_freeable) from [<c06eac64>] (kernel_init+0x10/0x110)
r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c06eac54 r4:00000000
[<c06eac54>] (kernel_init) from [<c0106db8>] (ret_from_fork+0x14/0x3c)
r5:c06eac54 r4:000000002. It then proceeds to OOPS.
Unable to handle kernel NULL pointer dereference at virtual address 0000000c
pgd = c0004000
[0000000c] *pgd=00000000
Internal error: Oops: 5 [#1] SMP ARM
CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.13.0-rc4-00632-gfae12f9c98a8c567 #7
Hardware name: Generic R8A7791 (Flattened Device Tree)
task: eb09b840 task.stack: eb09c000
PC is at rvin_v4l2_probe+0x38/0x1ec
LR is at rvin_digital_notify_complete+0x10c/0x11c
pc : [<c054594c>] lr : [<c0543614>] psr: a0000013
sp : eb09dcf8 ip : eb09dd20 fp : eb09dd1c
r10: 00000000 r9 : eaa56bd8 r8 : 00002006
r7 : eaa56810 r6 : c0a1e6dc r5 : 00000000 r4 : eaa56810
r3 : 00000000 r2 : 00000001 r1 : eaa57ec0 r0 : eaa56810
Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none
Control: 10c5387d Table: 4000406a DAC: 00000051
Process swapper/0 (pid: 1, stack limit = 0xeb09c210)
Stack: (0xeb09dcf8 to 0xeb09e000)
dce0: ea9e2868 eb1284c0
dd00: eaa56bd8 00000000 eb1284c0 eaa56810 eb09dd74 eb09dd20 c0543614 c0545920
dd20: 00000001 00000001 0000100a 00000001 00000000 00000000 00000000 00000000
dd40: 00000000 00000000 00000000 00000000 c051c17c eaa56bd8 c0543508 ea9e2868
dd60: eb1284c0 c0a5ff2c eb09dd94 eb09dd78 c0525164 c0543514 eaa56bd8 c0a5ff18
dd80: ea9e2868 eb3cda50 eb09ddbc eb09dd98 c0525288 c0525088 eaa56810 00000000
dda0: eb251a00 eb251a10 00000000 eaa56bd8 eb09dde4 eb09ddc0 c05433f0 c0525178
ddc0: c05432ec eb251a10 c0a6c504 00000000 c0a6c504 00000000 eb09de04 eb09dde8
dde0: c0420a3c c05432f8 eb251a10 c0ac72c8 c0ac72d4 00000000 eb09de34 eb09de08
de00: c041f320 c04209f0 00000000 eb251a10 eb251a44 c0a6c504 c0a50cf0 00000000
de20: c096d224 00000000 eb09de54 eb09de38 c041f46c c041f11c 00000000 c0a6c504
de40: c041f3e8 c0a50cf0 eb09de7c eb09de58 c041da08 c041f3f4 eb0eff58 eb2259b4
de60: eb0eff6c c0a6c504 eaa55f80 00000000 eb09de8c eb09de80 c041f5bc c041d98c
de80: eb09deb4 eb09de90 c041e190 c041f5a8 c0890798 eb09dea0 c0a6c504 ffffe000
dea0: 000000cb c095883c eb09decc eb09deb8 c0420068 c041e02c c0935328 ffffe000
dec0: eb09dedc eb09ded0 c04214b0 c041ffcc eb09deec eb09dee0 c0935340 c0421484
dee0: eb09df5c eb09def0 c0900ecc c0935334 00000000 c08b0334 eb09df00 eb09df08
df00: c013baa8 c09006a4 c010bf8c c08b0348 000000ca c08b0348 00000006 00000006
df20: 000000cb c08af36c ebfffca1 ebfffca4 c0a8a700 00000007 c0a8a700 00000007
df40: c0a8a700 000000cb c095883c c0a8a700 eb09df94 eb09df60 c0901080 c0900dac
df60: 00000006 00000006 00000000 c0900698 00000000 c06eac54 00000000 00000000
df80: 00000000 00000000 eb09dfac eb09df98 c06eac64 c0900f00 00000000 c06eac54
dfa0: 00000000 eb09dfb0 c0106db8 c06eac60 00000000 00000000 00000000 00000000
dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
dfe0: 00000000 00000000 00000000 00000000 00000013 00000000 420113b0 60d05413
Backtrace:
[<c0545914>] (rvin_v4l2_probe) from [<c0543614>] (rvin_digital_notify_complete+0x10c/0x11c)
r7:eaa56810 r6:eb1284c0 r5:00000000 r4:eaa56bd8
[<c0543508>] (rvin_digital_notify_complete) from [<c0525164>]
(v4l2_async_match_notify+0xe8/0xf0)
r8:c0a5ff2c r7:eb1284c0 r6:ea9e2868 r5:c0543508 r4:eaa56bd8
[<c052507c>] (v4l2_async_match_notify) from [<c0525288>] (v4l2_async_notifier_register+0x11c/0x150)
r7:eb3cda50 r6:ea9e2868 r5:c0a5ff18 r4:eaa56bd8
[<c052516c>] (v4l2_async_notifier_register) from [<c05433f0>] (rcar_vin_probe+0x104/0x178)
r9:eaa56bd8 r8:00000000 r7:eb251a10 r6:eb251a00 r5:00000000 r4:eaa56810
[<c05432ec>] (rcar_vin_probe) from [<c0420a3c>]
(platform_drv_probe+0x58/0xa4)
r9:00000000 r8:c0a6c504 r7:00000000 r6:c0a6c504 r5:eb251a10 r4:c05432ec
[<c04209e4>] (platform_drv_probe) from [<c041f320>] (driver_probe_device+0x210/0x2d8)
r7:00000000 r6:c0ac72d4 r5:c0ac72c8 r4:eb251a10
[<c041f110>] (driver_probe_device) from [<c041f46c>] (__driver_attach+0x84/0xb0)
r10:00000000 r9:c096d224 r8:00000000 r7:c0a50cf0 r6:c0a6c504 r5:eb251a44
r4:eb251a10 r3:00000000
[<c041f3e8>] (__driver_attach) from [<c041da08>] (bus_for_each_dev+0x88/0x98)
r7:c0a50cf0 r6:c041f3e8 r5:c0a6c504 r4:00000000
[<c041d980>] (bus_for_each_dev) from [<c041f5bc>] (driver_attach+0x20/0x28)
r6:00000000 r5:eaa55f80 r4:c0a6c504
[<c041f59c>] (driver_attach) from [<c041e190>] (bus_add_driver+0x170/0x1e0)
[<c041e020>] (bus_add_driver) from [<c0420068>] (driver_register+0xa8/0xe8)
r7:c095883c r6:000000cb r5:ffffe000 r4:c0a6c504
[<c041ffc0>] (driver_register) from [<c04214b0>] (__platform_driver_register+0x38/0x4c)
r5:ffffe000 r4:c0935328
[<c0421478>] (__platform_driver_register) from [<c0935340>] (rcar_vin_driver_init+0x18/0x20)
[<c0935328>] (rcar_vin_driver_init) from [<c0900ecc>] (do_one_initcall+0x12c/0x154)
[<c0900da0>] (do_one_initcall) from [<c0901080>] (kernel_init_freeable+0x18c/0x1d0)
r8:c0a8a700 r7:c095883c r6:000000cb r5:c0a8a700 r4:00000007
[<c0900ef4>] (kernel_init_freeable) from [<c06eac64>] (kernel_init+0x10/0x110)
r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c06eac54 r4:00000000
[<c06eac54>] (kernel_init) from [<c0106db8>] (ret_from_fork+0x14/0x3c)
r5:c06eac54 r4:00000000
Code: 03e05012 e5803368 0a00000a e5963068 (e593300c)
---[ end trace 82aa2a1c6173a5f6 ]---Oddly enough setting CONFIG_OF_DYNAMIC=n or applying the patch '[PATCH v2] device property: preserve usecount for node passed to of_fwnode_graph_get_port_parent()' fixes _both_ issues. It obviously would fix the 'Bad of_node_put() on ...' messages that it also fixes the OOPS is strange, so I did some digging.
The problem is introduced when rcar-vin in its complete callback calls v4l2_device_register_subdev_nodes(). Before the call vin->digital->subdev pointer is correct but after the call the vin->digital->subdev pointer is changed to a for me random value. And this is what is causing the OOPS in rvin_v4l2_probe() once it tries to operate on the subdevice using v4l2_subdev_call() using this bad pointer.
I tried to track down the issue but I can't understand what is causing it, but I managed to narrow it down. The callchain is:
- rvin_digital_notify_complete
- pr_dbg("sd: %p\n", vin->digital->subdev); # prints good pointer
- v4l2_device_register_subdev_nodes()
- __video_register_device()
- cdev_alloc() # Here the pointer gets corrupted
- pr_dbg("sd: %p\n", vin->digital->subdev); # prints bad pointer
I can't figure out why cdev_alloc() would corrupt it. I can even corrupt the pointer by calling cdev_alloc() directly from the rcar-vin driver itself. I added to following to the top of the complete callback before v4l2_device_register_subdev_nodes() is called.
pr_err("digital: %p sd: %p\n", vin->digital, vin->digital->subdev);
cdev_alloc();
pr_err("digital: %p sd: %p\n", vin->digital, vin->digital->subdev);And the result is:
[ 2.865306] digital: eb1284c0 sd: ea953068 [ 2.869414] digital: eb1284c0 sd: c0a1e6dc
If I set CONFIG_OF_DYNAMIC=n or apply the patch above the result is OK,
[ 1.961142] digital: ea8f8cc0 sd: ea8bac50 [ 1.965240] digital: ea8f8cc0 sd: ea8bac50
I can capture without issues so this patch in it self is good I think. So please add
However I would like the issue that is revealed by this patch to be sorted out before this patch is picked up as it causes problems with CONFIG_OF_DYNAMIC=y which is enabled by using the shmobile_defconfig.
Quoted 358 lines · Sakari Ailus
Instead of using a custom driver implementation, use
v4l2_async_notifier_parse_fwnode_endpoints()to parse the fwnode endpoints of the device.Signed-off-by Sakari Ailus <[email protected]>Acked-by Hans Verkuil <[email protected]>--- drivers/media/platform/rcar-vin/rcar-core.c | 107 +++++++++------------------- drivers/media/platform/rcar-vin/rcar-dma.c | 10 +-- drivers/media/platform/rcar-vin/rcar-v4l2.c | 14 ++-- drivers/media/platform/rcar-vin/rcar-vin.h | 4 +- 4 files changed, 46 insertions(+), 89 deletions(-)drivers/media/platform/rcar-vin/rcar-core.c +32
-75@@ -21,6 +21,7 @@#include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <media/v4l2-async.h> #include <media/v4l2-fwnode.h> #include "rcar-vin.h" @@ -77,14 +78,14 @@ static int rvin_digital_notify_complete(struct v4l2_async_notifier *notifier)int ret;/* Verify subdevices mbus format */ -if (!rvin_mbus_supported (&vin->digital)) { +if (!rvin_mbus_supported (vin->digital)) {vin_err (vin,"Unsupported media bus format for %s\n" , - vin->digital.subdev->name); + vin->digital->subdev->name);return -EINVAL ; }vin_dbg (vin,"Found media bus format for %s: %d\n" , - vin->digital.subdev->name, vin->digital.code); + vin->digital->subdev->name, vin->digital->code); ret =v4l2_device_register_subdev_nodes (&vin->v4l2_dev);if (ret <0 ) {@@ -103,7 +104,7 @@ static void rvin_digital_notify_unbind(struct v4l2_async_notifier *notifier,vin_dbg (vin,"unbind digital subdev %s\n" , subdev->name);rvin_v4l2_remove (vin); - vin->digital.subdev =NULL ; + vin->digital->subdev =NULL ; } static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier,@@ -120,117 +121,71 @@ static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier, ret =rvin_find_pad (subdev,MEDIA_PAD_FL_SOURCE );if (ret <0 )return ret; - vin->digital.source_pad = ret; + vin->digital->source_pad = ret; ret =rvin_find_pad (subdev,MEDIA_PAD_FL_SINK ); - vin->digital.sink_pad = ret <0 ?0 : ret; + vin->digital->sink_pad = ret <0 ?0 : ret; - vin->digital.subdev = subdev; + vin->digital->subdev = subdev;vin_dbg (vin,"bound subdev %s source pad: %u sink pad: %u\n" , - subdev->name, vin->digital.source_pad, - vin->digital.sink_pad); + subdev->name, vin->digital->source_pad, + vin->digital->sink_pad);return 0 ; } -static int rvin_digitial_parse_v4l2 (struct rvin_dev *vin, -struct device_node *ep, -struct v4l2_mbus_config *mbus_cfg) +static int rvin_digital_parse_v4l2 (struct device *dev, +struct v4l2_fwnode_endpoint *vep, +struct v4l2_async_subdev *asd) { -struct v4l2_fwnode_endpoint v4l2_ep; -int ret; +struct rvin_dev *vin =dev_get_drvdata (dev); +struct rvin_graph_entity *rvge = + container_of(asd, struct rvin_graph_entity, asd); - ret =v4l2_fwnode_endpoint_parse (of_fwnode_handle (ep), &v4l2_ep); -if (ret) { -vin_err (vin,"Could not parse v4l2 endpoint\n" ); -return -EINVAL ; - } +if (vep->base.port || vep->base.id) +return -ENOTCONN ; - mbus_cfg->type = v4l2_ep.bus_type; + rvge->mbus_cfg.type = vep->bus_type; -switch (mbus_cfg->type) { +switch (rvge->mbus_cfg.type) {case V4L2_MBUS_PARALLEL :vin_dbg (vin,"Found PARALLEL media bus\n" ); - mbus_cfg->flags = v4l2_ep.bus.parallel.flags; + rvge->mbus_cfg.flags = vep->bus.parallel.flags;break ;case V4L2_MBUS_BT656 :vin_dbg (vin,"Found BT656 media bus\n" ); - mbus_cfg->flags =0 ; + rvge->mbus_cfg.flags =0 ;break ;default :vin_err (vin,"Unknown media bus type\n" );return -EINVAL ; } -return 0 ; -} - -static int rvin_digital_graph_parse (struct rvin_dev *vin) -{ -struct device_node *ep, *np; -int ret; - - vin->digital.asd.match.fwnode.fwnode =NULL ; - vin->digital.subdev =NULL ; - -/* -* Port 0 id 0 is local digital input, try to get it. -* Not all instances can or will have this, that is OK -*/ - ep =of_graph_get_endpoint_by_regs (vin->dev->of_node,0 ,0 ); -if (!ep) -return 0 ; - - np =of_graph_get_remote_port_parent (ep); -if (!np) { -vin_err (vin,"No remote parent for digital input\n" ); -of_node_put (ep); -return -EINVAL ; - } -of_node_put (np); - - ret =rvin_digitial_parse_v4l2 (vin, ep, &vin->digital.mbus_cfg); -of_node_put (ep); -if (ret) -return ret; - - vin->digital.asd.match.fwnode.fwnode =of_fwnode_handle (np); - vin->digital.asd.match_type =V4L2_ASYNC_MATCH_FWNODE ; + vin->digital = rvge;return 0 ; }static int rvin_digital_graph_init (struct rvin_dev *vin) { -struct v4l2_async_subdev **subdevs =NULL ;int ret; - ret =rvin_digital_graph_parse (vin); + ret =v4l2_async_notifier_parse_fwnode_endpoints ( + vin->dev, &vin->notifier, +sizeof (struct rvin_graph_entity ), rvin_digital_parse_v4l2);if (ret)return ret; -if (!vin->digital.asd.match.fwnode.fwnode) { -vin_dbg (vin,"No digital subdevice found\n" ); +if (!vin->digital)return -ENODEV ; - } - -/* Register the subdevices notifier. */ - subdevs =devm_kzalloc (vin->dev,sizeof (*subdevs),GFP_KERNEL ); -if (subdevs ==NULL ) -return -ENOMEM ; - - subdevs[0 ] = &vin->digital.asd;vin_dbg (vin,"Found digital subdevice %pOF\n" , -to_of_node (subdevs[0 ]->match.fwnode.fwnode)); +to_of_node (vin->digital->asd.match.fwnode.fwnode)); - vin->notifier.num_subdevs =1 ; - vin->notifier.subdevs = subdevs; vin->notifier.bound = rvin_digital_notify_bound; vin->notifier.unbind = rvin_digital_notify_unbind; vin->notifier.complete = rvin_digital_notify_complete; - ret =v4l2_async_notifier_register (&vin->v4l2_dev, &vin->notifier);if (ret <0 ) {vin_err (vin,"Notifier registration failed\n" );@@ -290,6 +245,8 @@ static int rcar_vin_probe(struct platform_device *pdev)if (ret)return ret; +platform_set_drvdata (pdev, vin); + ret =rvin_digital_graph_init (vin);if (ret <0 ) goto error;@@ -297,11 +254,10 @@ static int rcar_vin_probe(struct platform_device *pdev)pm_suspend_ignore_children (&pdev->dev, true);pm_runtime_enable (&pdev->dev); -platform_set_drvdata (pdev, vin); -return 0 ; error:rvin_dma_remove (vin); +v4l2_async_notifier_cleanup (&vin->notifier);return ret; }@@ -313,6 +269,7 @@ static int rcar_vin_remove(struct platform_device *pdev)pm_runtime_disable (&pdev->dev);v4l2_async_notifier_unregister (&vin->notifier); +v4l2_async_notifier_cleanup (&vin->notifier);rvin_dma_remove (vin);drivers/media/platform/rcar-vin/rcar-dma.c +5
-5@@ -183,7 +183,7 @@ static int rvin_setup(struct rvin_dev *vin)/* * Input interface */ -switch (vin->digital.code) { +switch (vin->digital->code) {case MEDIA_BUS_FMT_YUYV8_1X16 :/* BT.601/BT.1358 16bit YCbCr422 */ vnmc |=VNMC_INF_YUV16 ;@@ -191,7 +191,7 @@ static int rvin_setup(struct rvin_dev *vin)break ;case MEDIA_BUS_FMT_UYVY8_2X8 :/* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */ - vnmc |= vin->digital.mbus_cfg.type ==V4L2_MBUS_BT656 ? + vnmc |= vin->digital->mbus_cfg.type ==V4L2_MBUS_BT656 ?VNMC_INF_YUV8_BT656 :VNMC_INF_YUV8_BT601 ; input_is_yuv = true;break ;@@ -200,7 +200,7 @@ static int rvin_setup(struct rvin_dev *vin)break ;case MEDIA_BUS_FMT_UYVY10_2X10 :/* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */ - vnmc |= vin->digital.mbus_cfg.type ==V4L2_MBUS_BT656 ? + vnmc |= vin->digital->mbus_cfg.type ==V4L2_MBUS_BT656 ?VNMC_INF_YUV10_BT656 :VNMC_INF_YUV10_BT601 ; input_is_yuv = true;break ;@@ -212,11 +212,11 @@ static int rvin_setup(struct rvin_dev *vin) dmr2 =VNDMR2_FTEV |VNDMR2_VLV (1 );/* Hsync Signal Polarity Select */ -if (!(vin->digital.mbus_cfg.flags &V4L2_MBUS_HSYNC_ACTIVE_LOW )) +if (!(vin->digital->mbus_cfg.flags &V4L2_MBUS_HSYNC_ACTIVE_LOW )) dmr2 |=VNDMR2_HPS ;/* Vsync Signal Polarity Select */ -if (!(vin->digital.mbus_cfg.flags &V4L2_MBUS_VSYNC_ACTIVE_LOW )) +if (!(vin->digital->mbus_cfg.flags &V4L2_MBUS_VSYNC_ACTIVE_LOW )) dmr2 |=VNDMR2_VPS ;/* drivers/media/platform/rcar-vin/rcar-v4l2.c +7
-7@@ -111,7 +111,7 @@ static int rvin_reset_format(struct rvin_dev *vin)struct v4l2_mbus_framefmt *mf = &fmt.format;int ret; - fmt.pad = vin->digital.source_pad; + fmt.pad = vin->digital->source_pad; ret =v4l2_subdev_call (vin_to_source (vin), pad, get_fmt,NULL , &fmt);if (ret)@@ -172,13 +172,13 @@ static int __rvin_try_format_source(struct rvin_dev *vin, sd =vin_to_source (vin); -v4l2_fill_mbus_format (&format.format, pix, vin->digital.code); +v4l2_fill_mbus_format (&format.format, pix, vin->digital->code); pad_cfg =v4l2_subdev_alloc_pad_config (sd);if (pad_cfg ==NULL )return -ENOMEM ; - format.pad = vin->digital.source_pad; + format.pad = vin->digital->source_pad; field = pix->field;@@ -555,7 +555,7 @@ static int rvin_enum_dv_timings(struct file *file, void *priv_fh,if (timings->pad)return -EINVAL ; - timings->pad = vin->digital.sink_pad; + timings->pad = vin->digital->sink_pad; ret =v4l2_subdev_call (sd, pad, enum_dv_timings, timings);@@ -607,7 +607,7 @@ static int rvin_dv_timings_cap(struct file *file, void *priv_fh,if (cap->pad)return -EINVAL ; - cap->pad = vin->digital.sink_pad; + cap->pad = vin->digital->sink_pad; ret =v4l2_subdev_call (sd, pad, dv_timings_cap, cap);@@ -625,7 +625,7 @@ static int rvin_g_edid(struct file *file, void *fh, struct v4l2_edid *edid)if (edid->pad)return -EINVAL ; - edid->pad = vin->digital.sink_pad; + edid->pad = vin->digital->sink_pad; ret =v4l2_subdev_call (sd, pad, get_edid, edid);@@ -643,7 +643,7 @@ static int rvin_s_edid(struct file *file, void *fh, struct v4l2_edid *edid)if (edid->pad)return -EINVAL ; - edid->pad = vin->digital.sink_pad; + edid->pad = vin->digital->sink_pad; ret =v4l2_subdev_call (sd, pad, set_edid, edid);drivers/media/platform/rcar-vin/rcar-vin.h +2
-2@@ -126,7 +126,7 @@ struct rvin_dev {struct v4l2_device v4l2_dev;struct v4l2_ctrl_handler ctrl_handler;struct v4l2_async_notifier notifier; -struct rvin_graph_entity digital; +struct rvin_graph_entity *digital;struct mutex lock;struct vb2_queue queue;@@ -145,7 +145,7 @@ struct rvin_dev {struct v4l2_rect compose; }; -#define vin_to_source (vin) vin->digital.subdev +#define vin_to_source (vin) ((vin)->digital->subdev)/* Debug */ #define vin_dbg(d, fmt, arg...) dev_dbg(d->dev, fmt, ##arg)Signature · 1 line
2.11.0
Signature · 2 lines
Regards, Niklas Söderlund
A message that is not in the archive (sent off-list or not yet received): 20170930131709.GP17182-ofJ5d6taAgIKcZgyrm77+z0dHWC0CY5B@public.gmane.org
Re: [PATCH v14 07/28] rcar-vin: Use generic parser for parsing fwnode endpoints
Hi Niklas,
Quoted 9 lines · Niklas Söderlund
Hi Sakari,
Thanks for your patch, I like it. Unfortunately it causes issues :-(
I picked the first 7 patches of this series on top of media-next and it produce problems when tested on Koelsch with
CONFIG_OF_DYNAMIC=y.1. It print's 'OF: ERROR: Bad
of_node_put()on /video@e6ef0000/port' messages during boot.
Do you have your own patch to fix fwnode_graph_get_port_parent() applied? I noticed it doesn't seem to be in Rob's tree; let's continue in the other thread.
<URL:https://www.mail-archive.com/[email protected]/msg117450.html>
Quoted 91 lines
OF: ERROR: Bad of_node_put() on /video@e6ef0000/port CPU: 1 PID: 1 Comm: swapper/0 Not tainted 4.13.0-rc4-00632-gfae12f9c98a8c567 #7 Hardware name: Generic R8A7791 (Flattened Device Tree) Backtrace: [<c010b16c>] (dump_backtrace) from [<c010b3b8>] (show_stack+0x18/0x1c) r7:00000001 r6:60000013 r5:00000000 r4:c0a7c88c [<c010b3a0>] (show_stack) from [<c06d9034>] (dump_stack+0x84/0xa0) [<c06d8fb0>] (dump_stack) from [<c05814ac>] (of_node_release+0x2c/0x94) r7:00000001 r6:c0a6fc4c r5:eb1284c0 r4:eb7c7a00 [<c0581480>] (of_node_release) from [<c06dcd3c>] (kobject_put+0xbc/0xdc) r7:00000001 r6:c0a6fc4c r5:eb1284c0 r4:eb7c7a00 [<c06dcc80>] (kobject_put) from [<c0580d48>] (of_node_put+0x1c/0x20) r6:eb7c7af8 r5:eb7c79e0 r4:eb7c7798 [<c0580d2c>] (of_node_put) from [<c057fc18>] (of_fwnode_put+0x38/0x44) [<c057fbe0>] (of_fwnode_put) from [<c04244a8>] (fwnode_handle_put+0x30/0x34) [<c0424478>] (fwnode_handle_put) from [<c0424714>] (fwnode_graph_get_port_parent+0x44/0x4c) [<c04246d0>] (fwnode_graph_get_port_parent) from [<c0514820>] (__v4l2_async_notifier_parse_fwnode_endpoints+0x1dc/0x2d8) r5:eaa56bd8 r4:00000000 [<c0514644>] (__v4l2_async_notifier_parse_fwnode_endpoints) from [<c0514a9c>] (v4l2_async_notifier_parse_fwnode_endpoints+0x20/0x28) r10:00000000 r9:eaa56bd8 r8:c0a6c504 r7:eb251a10 r6:eb251a00 r5:00000000 r4:eaa56810 [<c0514a7c>] (v4l2_async_notifier_parse_fwnode_endpoints) from [<c05433b8>] (rcar_vin_probe+0xcc/0x178) [<c05432ec>] (rcar_vin_probe) from [<c0420a3c>] (platform_drv_probe+0x58/0xa4) r9:00000000 r8:c0a6c504 r7:00000000 r6:c0a6c504 r5:eb251a10 r4:c05432ec [<c04209e4>] (platform_drv_probe) from [<c041f320>] (driver_probe_device+0x210/0x2d8) r7:00000000 r6:c0ac72d4 r5:c0ac72c8 r4:eb251a10 [<c041f110>] (driver_probe_device) from [<c041f46c>] (__driver_attach+0x84/0xb0) r10:00000000 r9:c096d224 r8:00000000 r7:c0a50cf0 r6:c0a6c504 r5:eb251a44 r4:eb251a10 r3:00000000 [<c041f3e8>] (__driver_attach) from [<c041da08>] (bus_for_each_dev+0x88/0x98) r7:c0a50cf0 r6:c041f3e8 r5:c0a6c504 r4:00000000 [<c041d980>] (bus_for_each_dev) from [<c041f5bc>] (driver_attach+0x20/0x28) r6:00000000 r5:eaa55f80 r4:c0a6c504 [<c041f59c>] (driver_attach) from [<c041e190>] (bus_add_driver+0x170/0x1e0) [<c041e020>] (bus_add_driver) from [<c0420068>] (driver_register+0xa8/0xe8) r7:c095883c r6:000000cb r5:ffffe000 r4:c0a6c504 [<c041ffc0>] (driver_register) from [<c04214b0>] (__platform_driver_register+0x38/0x4c) r5:ffffe000 r4:c0935328 [<c0421478>] (__platform_driver_register) from [<c0935340>] (rcar_vin_driver_init+0x18/0x20) [<c0935328>] (rcar_vin_driver_init) from [<c0900ecc>] (do_one_initcall+0x12c/0x154) [<c0900da0>] (do_one_initcall) from [<c0901080>] (kernel_init_freeable+0x18c/0x1d0) r8:c0a8a700 r7:c095883c r6:000000cb r5:c0a8a700 r4:00000007 [<c0900ef4>] (kernel_init_freeable) from [<c06eac64>] (kernel_init+0x10/0x110) r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c06eac54 r4:00000000 [<c06eac54>] (kernel_init) from [<c0106db8>] (ret_from_fork+0x14/0x3c) r5:c06eac54 r4:000000002. It then proceeds to OOPS.
Unable to handle kernel NULL pointer dereference at virtual address 0000000c pgd = c0004000 [0000000c] *pgd=00000000 Internal error: Oops: 5 [#1] SMP ARM CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.13.0-rc4-00632-gfae12f9c98a8c567 #7 Hardware name: Generic R8A7791 (Flattened Device Tree) task: eb09b840 task.stack: eb09c000 PC is at rvin_v4l2_probe+0x38/0x1ec LR is at rvin_digital_notify_complete+0x10c/0x11c pc : [<c054594c>] lr : [<c0543614>] psr: a0000013 sp : eb09dcf8 ip : eb09dd20 fp : eb09dd1c r10: 00000000 r9 : eaa56bd8 r8 : 00002006 r7 : eaa56810 r6 : c0a1e6dc r5 : 00000000 r4 : eaa56810 r3 : 00000000 r2 : 00000001 r1 : eaa57ec0 r0 : eaa56810 Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none Control: 10c5387d Table: 4000406a DAC: 00000051 Process swapper/0 (pid: 1, stack limit = 0xeb09c210) Stack: (0xeb09dcf8 to 0xeb09e000) dce0: ea9e2868 eb1284c0 dd00: eaa56bd8 00000000 eb1284c0 eaa56810 eb09dd74 eb09dd20 c0543614 c0545920 dd20: 00000001 00000001 0000100a 00000001 00000000 00000000 00000000 00000000 dd40: 00000000 00000000 00000000 00000000 c051c17c eaa56bd8 c0543508 ea9e2868 dd60: eb1284c0 c0a5ff2c eb09dd94 eb09dd78 c0525164 c0543514 eaa56bd8 c0a5ff18 dd80: ea9e2868 eb3cda50 eb09ddbc eb09dd98 c0525288 c0525088 eaa56810 00000000 dda0: eb251a00 eb251a10 00000000 eaa56bd8 eb09dde4 eb09ddc0 c05433f0 c0525178 ddc0: c05432ec eb251a10 c0a6c504 00000000 c0a6c504 00000000 eb09de04 eb09dde8 dde0: c0420a3c c05432f8 eb251a10 c0ac72c8 c0ac72d4 00000000 eb09de34 eb09de08 de00: c041f320 c04209f0 00000000 eb251a10 eb251a44 c0a6c504 c0a50cf0 00000000 de20: c096d224 00000000 eb09de54 eb09de38 c041f46c c041f11c 00000000 c0a6c504 de40: c041f3e8 c0a50cf0 eb09de7c eb09de58 c041da08 c041f3f4 eb0eff58 eb2259b4 de60: eb0eff6c c0a6c504 eaa55f80 00000000 eb09de8c eb09de80 c041f5bc c041d98c de80: eb09deb4 eb09de90 c041e190 c041f5a8 c0890798 eb09dea0 c0a6c504 ffffe000 dea0: 000000cb c095883c eb09decc eb09deb8 c0420068 c041e02c c0935328 ffffe000 dec0: eb09dedc eb09ded0 c04214b0 c041ffcc eb09deec eb09dee0 c0935340 c0421484 dee0: eb09df5c eb09def0 c0900ecc c0935334 00000000 c08b0334 eb09df00 eb09df08 df00: c013baa8 c09006a4 c010bf8c c08b0348 000000ca c08b0348 00000006 00000006 df20: 000000cb c08af36c ebfffca1 ebfffca4 c0a8a700 00000007 c0a8a700 00000007 df40: c0a8a700 000000cb c095883c c0a8a700 eb09df94 eb09df60 c0901080 c0900dac df60: 00000006 00000006 00000000 c0900698 00000000 c06eac54 00000000 00000000 df80: 00000000 00000000 eb09dfac eb09df98 c06eac64 c0900f00 00000000 c06eac54 dfa0: 00000000 eb09dfb0 c0106db8 c06eac60 00000000 00000000 00000000 00000000
Quoted 8 lines
dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
dfe0: 00000000 00000000 00000000 00000000 00000013 00000000 420113b0 60d05413
Backtrace:
[<c0545914>] (rvin_v4l2_probe) from [<c0543614>] (rvin_digital_notify_complete+0x10c/0x11c)
r7:eaa56810 r6:eb1284c0 r5:00000000 r4:eaa56bd8
[<c0543508>] (rvin_digital_notify_complete) from [<c0525164>]
(v4l2_async_match_notify+0xe8/0xf0)
r8:c0a5ff2c r7:eb1284c0 r6:ea9e2868 r5:c0543508 r4:eaa56bd8Could fixing the other issue fix this one as well?
I'll see how the rest works at my end with CONFIG_OF_DYNAMIC enabled.
Quoted 445 lines
[<c052507c>] (v4l2_async_match_notify) from [<c0525288>] (v4l2_async_notifier_register+0x11c/0x150) r7:eb3cda50 r6:ea9e2868 r5:c0a5ff18 r4:eaa56bd8 [<c052516c>] (v4l2_async_notifier_register) from [<c05433f0>] (rcar_vin_probe+0x104/0x178) r9:eaa56bd8 r8:00000000 r7:eb251a10 r6:eb251a00 r5:00000000 r4:eaa56810 [<c05432ec>] (rcar_vin_probe) from [<c0420a3c>] (platform_drv_probe+0x58/0xa4) r9:00000000 r8:c0a6c504 r7:00000000 r6:c0a6c504 r5:eb251a10 r4:c05432ec [<c04209e4>] (platform_drv_probe) from [<c041f320>] (driver_probe_device+0x210/0x2d8) r7:00000000 r6:c0ac72d4 r5:c0ac72c8 r4:eb251a10 [<c041f110>] (driver_probe_device) from [<c041f46c>] (__driver_attach+0x84/0xb0) r10:00000000 r9:c096d224 r8:00000000 r7:c0a50cf0 r6:c0a6c504 r5:eb251a44 r4:eb251a10 r3:00000000 [<c041f3e8>] (__driver_attach) from [<c041da08>] (bus_for_each_dev+0x88/0x98) r7:c0a50cf0 r6:c041f3e8 r5:c0a6c504 r4:00000000 [<c041d980>] (bus_for_each_dev) from [<c041f5bc>] (driver_attach+0x20/0x28) r6:00000000 r5:eaa55f80 r4:c0a6c504 [<c041f59c>] (driver_attach) from [<c041e190>] (bus_add_driver+0x170/0x1e0) [<c041e020>] (bus_add_driver) from [<c0420068>] (driver_register+0xa8/0xe8) r7:c095883c r6:000000cb r5:ffffe000 r4:c0a6c504 [<c041ffc0>] (driver_register) from [<c04214b0>] (__platform_driver_register+0x38/0x4c) r5:ffffe000 r4:c0935328 [<c0421478>] (__platform_driver_register) from [<c0935340>] (rcar_vin_driver_init+0x18/0x20) [<c0935328>] (rcar_vin_driver_init) from [<c0900ecc>] (do_one_initcall+0x12c/0x154) [<c0900da0>] (do_one_initcall) from [<c0901080>] (kernel_init_freeable+0x18c/0x1d0) r8:c0a8a700 r7:c095883c r6:000000cb r5:c0a8a700 r4:00000007 [<c0900ef4>] (kernel_init_freeable) from [<c06eac64>] (kernel_init+0x10/0x110) r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c06eac54 r4:00000000 [<c06eac54>] (kernel_init) from [<c0106db8>] (ret_from_fork+0x14/0x3c) r5:c06eac54 r4:00000000 Code: 03e05012 e5803368 0a00000a e5963068 (e593300c) ---[ end trace 82aa2a1c6173a5f6 ]---Oddly enough setting
CONFIG_OF_DYNAMIC=nor applying the patch '[PATCH v2] device property: preserve usecount for node passed toof_fwnode_graph_get_port_parent()' fixes _both_ issues. It obviously would fix the 'Badof_node_put()on ...' messages that it also fixes the OOPS is strange, so I did some digging.The problem is introduced when rcar-vin in its complete callback calls
v4l2_device_register_subdev_nodes(). Before the callvin->digital->subdevpointer is correct but after the call thevin->digital->subdevpointer is changed to a for me random value. And this is what is causing the OOPS inrvin_v4l2_probe()once it tries to operate on the subdevice usingv4l2_subdev_call()using this bad pointer.I tried to track down the issue but I can't understand what is causing it, but I managed to narrow it down. The callchain is:
-
rvin_digital_notify_complete
-pr_dbg("sd: %p\n", vin->digital->subdev); # prints good pointer
-v4l2_device_register_subdev_nodes()
-__video_register_device()
-cdev_alloc()# Here the pointer gets corrupted
-pr_dbg("sd: %p\n", vin->digital->subdev); # prints bad pointerI can't figure out why
cdev_alloc()would corrupt it. I can even corrupt the pointer by callingcdev_alloc()directly from the rcar-vin driver itself. I added to following to the top of the complete callback beforev4l2_device_register_subdev_nodes()is called.pr_err("digital: %p sd: %p\n", vin->digital, vin->digital->subdev); cdev_alloc(); pr_err("digital: %p sd: %p\n", vin->digital, vin->digital->subdev);And the result is:
[ 2.865306] digital: eb1284c0 sd: ea953068 [ 2.869414] digital: eb1284c0 sd: c0a1e6dcIf I set
CONFIG_OF_DYNAMIC=nor apply the patch above the result is OK,[ 1.961142] digital: ea8f8cc0 sd: ea8bac50 [ 1.965240] digital: ea8f8cc0 sd: ea8bac50I can capture without issues so this patch in it self is good I think. So please add
Acked-by Niklas Söderlund <[email protected]>However I would like the issue that is revealed by this patch to be sorted out before this patch is picked up as it causes problems with
CONFIG_OF_DYNAMIC=ywhich is enabled by using theshmobile_defconfig.Quoted 358 lines · Sakari Ailus
Instead of using a custom driver implementation, use
v4l2_async_notifier_parse_fwnode_endpoints()to parse the fwnode endpoints of the device.Acked-by Hans Verkuil <[email protected]>--- drivers/media/platform/rcar-vin/rcar-core.c | 107 +++++++++------------------- drivers/media/platform/rcar-vin/rcar-dma.c | 10 +-- drivers/media/platform/rcar-vin/rcar-v4l2.c | 14 ++-- drivers/media/platform/rcar-vin/rcar-vin.h | 4 +- 4 files changed, 46 insertions(+), 89 deletions(-)drivers/media/platform/rcar-vin/rcar-core.c +32
-75@@ -21,6 +21,7 @@#include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <media/v4l2-async.h> #include <media/v4l2-fwnode.h> #include "rcar-vin.h" @@ -77,14 +78,14 @@ static int rvin_digital_notify_complete(struct v4l2_async_notifier *notifier)int ret;/* Verify subdevices mbus format */ -if (!rvin_mbus_supported (&vin->digital)) { +if (!rvin_mbus_supported (vin->digital)) {vin_err (vin,"Unsupported media bus format for %s\n" , - vin->digital.subdev->name); + vin->digital->subdev->name);return -EINVAL ; }vin_dbg (vin,"Found media bus format for %s: %d\n" , - vin->digital.subdev->name, vin->digital.code); + vin->digital->subdev->name, vin->digital->code); ret =v4l2_device_register_subdev_nodes (&vin->v4l2_dev);if (ret <0 ) {@@ -103,7 +104,7 @@ static void rvin_digital_notify_unbind(struct v4l2_async_notifier *notifier,vin_dbg (vin,"unbind digital subdev %s\n" , subdev->name);rvin_v4l2_remove (vin); - vin->digital.subdev =NULL ; + vin->digital->subdev =NULL ; } static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier,@@ -120,117 +121,71 @@ static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier, ret =rvin_find_pad (subdev,MEDIA_PAD_FL_SOURCE );if (ret <0 )return ret; - vin->digital.source_pad = ret; + vin->digital->source_pad = ret; ret =rvin_find_pad (subdev,MEDIA_PAD_FL_SINK ); - vin->digital.sink_pad = ret <0 ?0 : ret; + vin->digital->sink_pad = ret <0 ?0 : ret; - vin->digital.subdev = subdev; + vin->digital->subdev = subdev;vin_dbg (vin,"bound subdev %s source pad: %u sink pad: %u\n" , - subdev->name, vin->digital.source_pad, - vin->digital.sink_pad); + subdev->name, vin->digital->source_pad, + vin->digital->sink_pad);return 0 ; } -static int rvin_digitial_parse_v4l2 (struct rvin_dev *vin, -struct device_node *ep, -struct v4l2_mbus_config *mbus_cfg) +static int rvin_digital_parse_v4l2 (struct device *dev, +struct v4l2_fwnode_endpoint *vep, +struct v4l2_async_subdev *asd) { -struct v4l2_fwnode_endpoint v4l2_ep; -int ret; +struct rvin_dev *vin =dev_get_drvdata (dev); +struct rvin_graph_entity *rvge = + container_of(asd, struct rvin_graph_entity, asd); - ret =v4l2_fwnode_endpoint_parse (of_fwnode_handle (ep), &v4l2_ep); -if (ret) { -vin_err (vin,"Could not parse v4l2 endpoint\n" ); -return -EINVAL ; - } +if (vep->base.port || vep->base.id) +return -ENOTCONN ; - mbus_cfg->type = v4l2_ep.bus_type; + rvge->mbus_cfg.type = vep->bus_type; -switch (mbus_cfg->type) { +switch (rvge->mbus_cfg.type) {case V4L2_MBUS_PARALLEL :vin_dbg (vin,"Found PARALLEL media bus\n" ); - mbus_cfg->flags = v4l2_ep.bus.parallel.flags; + rvge->mbus_cfg.flags = vep->bus.parallel.flags;break ;case V4L2_MBUS_BT656 :vin_dbg (vin,"Found BT656 media bus\n" ); - mbus_cfg->flags =0 ; + rvge->mbus_cfg.flags =0 ;break ;default :vin_err (vin,"Unknown media bus type\n" );return -EINVAL ; } -return 0 ; -} - -static int rvin_digital_graph_parse (struct rvin_dev *vin) -{ -struct device_node *ep, *np; -int ret; - - vin->digital.asd.match.fwnode.fwnode =NULL ; - vin->digital.subdev =NULL ; - -/* -* Port 0 id 0 is local digital input, try to get it. -* Not all instances can or will have this, that is OK -*/ - ep =of_graph_get_endpoint_by_regs (vin->dev->of_node,0 ,0 ); -if (!ep) -return 0 ; - - np =of_graph_get_remote_port_parent (ep); -if (!np) { -vin_err (vin,"No remote parent for digital input\n" ); -of_node_put (ep); -return -EINVAL ; - } -of_node_put (np); - - ret =rvin_digitial_parse_v4l2 (vin, ep, &vin->digital.mbus_cfg); -of_node_put (ep); -if (ret) -return ret; - - vin->digital.asd.match.fwnode.fwnode =of_fwnode_handle (np); - vin->digital.asd.match_type =V4L2_ASYNC_MATCH_FWNODE ; + vin->digital = rvge;return 0 ; }static int rvin_digital_graph_init (struct rvin_dev *vin) { -struct v4l2_async_subdev **subdevs =NULL ;int ret; - ret =rvin_digital_graph_parse (vin); + ret =v4l2_async_notifier_parse_fwnode_endpoints ( + vin->dev, &vin->notifier, +sizeof (struct rvin_graph_entity ), rvin_digital_parse_v4l2);if (ret)return ret; -if (!vin->digital.asd.match.fwnode.fwnode) { -vin_dbg (vin,"No digital subdevice found\n" ); +if (!vin->digital)return -ENODEV ; - } - -/* Register the subdevices notifier. */ - subdevs =devm_kzalloc (vin->dev,sizeof (*subdevs),GFP_KERNEL ); -if (subdevs ==NULL ) -return -ENOMEM ; - - subdevs[0 ] = &vin->digital.asd;vin_dbg (vin,"Found digital subdevice %pOF\n" , -to_of_node (subdevs[0 ]->match.fwnode.fwnode)); +to_of_node (vin->digital->asd.match.fwnode.fwnode)); - vin->notifier.num_subdevs =1 ; - vin->notifier.subdevs = subdevs; vin->notifier.bound = rvin_digital_notify_bound; vin->notifier.unbind = rvin_digital_notify_unbind; vin->notifier.complete = rvin_digital_notify_complete; - ret =v4l2_async_notifier_register (&vin->v4l2_dev, &vin->notifier);if (ret <0 ) {vin_err (vin,"Notifier registration failed\n" );@@ -290,6 +245,8 @@ static int rcar_vin_probe(struct platform_device *pdev)if (ret)return ret; +platform_set_drvdata (pdev, vin); + ret =rvin_digital_graph_init (vin);if (ret <0 ) goto error;@@ -297,11 +254,10 @@ static int rcar_vin_probe(struct platform_device *pdev)pm_suspend_ignore_children (&pdev->dev, true);pm_runtime_enable (&pdev->dev); -platform_set_drvdata (pdev, vin); -return 0 ; error:rvin_dma_remove (vin); +v4l2_async_notifier_cleanup (&vin->notifier);return ret; }@@ -313,6 +269,7 @@ static int rcar_vin_remove(struct platform_device *pdev)pm_runtime_disable (&pdev->dev);v4l2_async_notifier_unregister (&vin->notifier); +v4l2_async_notifier_cleanup (&vin->notifier);rvin_dma_remove (vin);drivers/media/platform/rcar-vin/rcar-dma.c +5
-5@@ -183,7 +183,7 @@ static int rvin_setup(struct rvin_dev *vin)/* * Input interface */ -switch (vin->digital.code) { +switch (vin->digital->code) {case MEDIA_BUS_FMT_YUYV8_1X16 :/* BT.601/BT.1358 16bit YCbCr422 */ vnmc |=VNMC_INF_YUV16 ;@@ -191,7 +191,7 @@ static int rvin_setup(struct rvin_dev *vin)break ;case MEDIA_BUS_FMT_UYVY8_2X8 :/* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */ - vnmc |= vin->digital.mbus_cfg.type ==V4L2_MBUS_BT656 ? + vnmc |= vin->digital->mbus_cfg.type ==V4L2_MBUS_BT656 ?VNMC_INF_YUV8_BT656 :VNMC_INF_YUV8_BT601 ; input_is_yuv = true;break ;@@ -200,7 +200,7 @@ static int rvin_setup(struct rvin_dev *vin)break ;case MEDIA_BUS_FMT_UYVY10_2X10 :/* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */ - vnmc |= vin->digital.mbus_cfg.type ==V4L2_MBUS_BT656 ? + vnmc |= vin->digital->mbus_cfg.type ==V4L2_MBUS_BT656 ?VNMC_INF_YUV10_BT656 :VNMC_INF_YUV10_BT601 ; input_is_yuv = true;break ;@@ -212,11 +212,11 @@ static int rvin_setup(struct rvin_dev *vin) dmr2 =VNDMR2_FTEV |VNDMR2_VLV (1 );/* Hsync Signal Polarity Select */ -if (!(vin->digital.mbus_cfg.flags &V4L2_MBUS_HSYNC_ACTIVE_LOW )) +if (!(vin->digital->mbus_cfg.flags &V4L2_MBUS_HSYNC_ACTIVE_LOW )) dmr2 |=VNDMR2_HPS ;/* Vsync Signal Polarity Select */ -if (!(vin->digital.mbus_cfg.flags &V4L2_MBUS_VSYNC_ACTIVE_LOW )) +if (!(vin->digital->mbus_cfg.flags &V4L2_MBUS_VSYNC_ACTIVE_LOW )) dmr2 |=VNDMR2_VPS ;/* drivers/media/platform/rcar-vin/rcar-v4l2.c +7
-7@@ -111,7 +111,7 @@ static int rvin_reset_format(struct rvin_dev *vin)struct v4l2_mbus_framefmt *mf = &fmt.format;int ret; - fmt.pad = vin->digital.source_pad; + fmt.pad = vin->digital->source_pad; ret =v4l2_subdev_call (vin_to_source (vin), pad, get_fmt,NULL , &fmt);if (ret)@@ -172,13 +172,13 @@ static int __rvin_try_format_source(struct rvin_dev *vin, sd =vin_to_source (vin); -v4l2_fill_mbus_format (&format.format, pix, vin->digital.code); +v4l2_fill_mbus_format (&format.format, pix, vin->digital->code); pad_cfg =v4l2_subdev_alloc_pad_config (sd);if (pad_cfg ==NULL )return -ENOMEM ; - format.pad = vin->digital.source_pad; + format.pad = vin->digital->source_pad; field = pix->field;@@ -555,7 +555,7 @@ static int rvin_enum_dv_timings(struct file *file, void *priv_fh,if (timings->pad)return -EINVAL ; - timings->pad = vin->digital.sink_pad; + timings->pad = vin->digital->sink_pad; ret =v4l2_subdev_call (sd, pad, enum_dv_timings, timings);@@ -607,7 +607,7 @@ static int rvin_dv_timings_cap(struct file *file, void *priv_fh,if (cap->pad)return -EINVAL ; - cap->pad = vin->digital.sink_pad; + cap->pad = vin->digital->sink_pad; ret =v4l2_subdev_call (sd, pad, dv_timings_cap, cap);@@ -625,7 +625,7 @@ static int rvin_g_edid(struct file *file, void *fh, struct v4l2_edid *edid)if (edid->pad)return -EINVAL ; - edid->pad = vin->digital.sink_pad; + edid->pad = vin->digital->sink_pad; ret =v4l2_subdev_call (sd, pad, get_edid, edid);@@ -643,7 +643,7 @@ static int rvin_s_edid(struct file *file, void *fh, struct v4l2_edid *edid)if (edid->pad)return -EINVAL ; - edid->pad = vin->digital.sink_pad; + edid->pad = vin->digital->sink_pad; ret =v4l2_subdev_call (sd, pad, set_edid, edid);drivers/media/platform/rcar-vin/rcar-vin.h +2
-2@@ -126,7 +126,7 @@ struct rvin_dev {struct v4l2_device v4l2_dev;struct v4l2_ctrl_handler ctrl_handler;struct v4l2_async_notifier notifier; -struct rvin_graph_entity digital; +struct rvin_graph_entity *digital;struct mutex lock;struct vb2_queue queue;@@ -145,7 +145,7 @@ struct rvin_dev {struct v4l2_rect compose; }; -#define vin_to_source (vin) vin->digital.subdev +#define vin_to_source (vin) ((vin)->digital->subdev)/* Debug */ #define vin_dbg(d, fmt, arg...) dev_dbg(d->dev, fmt, ##arg)Signature · 1 line
2.11.0
Signature · 8 lines
Regards, Sakari Ailus sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected] -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): 3f940721-f190-4662-cfda-d99a0d97bf08-VuQAYsv1563Yd54FQh9/[email protected]
Re: [PATCH v14 07/28] rcar-vin: Use generic parser for parsing fwnode endpoints
Hi Sakari,
Quoted 10 lines · Sakari Ailus
Hi Niklas,
Quoted 7 lines · Niklas Söderlund
Hi Sakari,
Thanks for your patch, I like it. Unfortunately it causes issues :-(
I picked the first 7 patches of this series on top of media-next and it produce problems when tested on Koelsch with
CONFIG_OF_DYNAMIC=y.
Quoted 8 lines
Quoted 2 lines
1. It print's 'OF: ERROR: Bad
of_node_put()on /video@e6ef0000/port' messages during boot.Do you have your own patch to fix
fwnode_graph_get_port_parent()applied? I noticed it doesn't seem to be in Rob's tree; let's continue in the other thread.<URL:https://www.mail-archive.com/[email protected]/msg117450.html>
To produce this issue the fix is not applied. But as I try to describe at the end of my email applying it fixes both issues. So I think this patch is correct (and that is why I Acked it) but my concern is that if it's picked up before the fwnode_graph_get_port_parent() issue is sorted out there will be problems for rcar-vin, and if possible I would like to avoid that.
Quoted 5 lines
Quoted 5 lines
OF: ERROR: Bad of_node_put() on /video@e6ef0000/port CPU: 1 PID: 1 Comm: swapper/0 Not tainted 4.13.0-rc4-00632-gfae12f9c98a8c567 #7 Hardware name: Generic R8A7791 (Flattened Device Tree)
[snip]
Quoted 4 lines
Could fixing the other issue fix this one as well?
I'll see how the rest works at my end with
CONFIG_OF_DYNAMICenabled.
Yes, as I try to describe bellow, applying the fix for fwnode_graph_get_port_parent() solves both issues :-)
What is troublesome for me is that I don't understand why cdev_alloc() would change/corrupt the subdevice pointer if CONFIG_OF_DYNAMIC=y or the fix is _not_ applied.
Quoted 453 lines
Quoted 446 lines
[<c052507c>] (v4l2_async_match_notify) from [<c0525288>] (v4l2_async_notifier_register+0x11c/0x150) r7:eb3cda50 r6:ea9e2868 r5:c0a5ff18 r4:eaa56bd8 [<c052516c>] (v4l2_async_notifier_register) from [<c05433f0>] (rcar_vin_probe+0x104/0x178) r9:eaa56bd8 r8:00000000 r7:eb251a10 r6:eb251a00 r5:00000000 r4:eaa56810 [<c05432ec>] (rcar_vin_probe) from [<c0420a3c>] (platform_drv_probe+0x58/0xa4) r9:00000000 r8:c0a6c504 r7:00000000 r6:c0a6c504 r5:eb251a10 r4:c05432ec [<c04209e4>] (platform_drv_probe) from [<c041f320>] (driver_probe_device+0x210/0x2d8) r7:00000000 r6:c0ac72d4 r5:c0ac72c8 r4:eb251a10 [<c041f110>] (driver_probe_device) from [<c041f46c>] (__driver_attach+0x84/0xb0) r10:00000000 r9:c096d224 r8:00000000 r7:c0a50cf0 r6:c0a6c504 r5:eb251a44 r4:eb251a10 r3:00000000 [<c041f3e8>] (__driver_attach) from [<c041da08>] (bus_for_each_dev+0x88/0x98) r7:c0a50cf0 r6:c041f3e8 r5:c0a6c504 r4:00000000 [<c041d980>] (bus_for_each_dev) from [<c041f5bc>] (driver_attach+0x20/0x28) r6:00000000 r5:eaa55f80 r4:c0a6c504 [<c041f59c>] (driver_attach) from [<c041e190>] (bus_add_driver+0x170/0x1e0) [<c041e020>] (bus_add_driver) from [<c0420068>] (driver_register+0xa8/0xe8) r7:c095883c r6:000000cb r5:ffffe000 r4:c0a6c504 [<c041ffc0>] (driver_register) from [<c04214b0>] (__platform_driver_register+0x38/0x4c) r5:ffffe000 r4:c0935328 [<c0421478>] (__platform_driver_register) from [<c0935340>] (rcar_vin_driver_init+0x18/0x20) [<c0935328>] (rcar_vin_driver_init) from [<c0900ecc>] (do_one_initcall+0x12c/0x154) [<c0900da0>] (do_one_initcall) from [<c0901080>] (kernel_init_freeable+0x18c/0x1d0) r8:c0a8a700 r7:c095883c r6:000000cb r5:c0a8a700 r4:00000007 [<c0900ef4>] (kernel_init_freeable) from [<c06eac64>] (kernel_init+0x10/0x110) r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c06eac54 r4:00000000 [<c06eac54>] (kernel_init) from [<c0106db8>] (ret_from_fork+0x14/0x3c) r5:c06eac54 r4:00000000 Code: 03e05012 e5803368 0a00000a e5963068 (e593300c) ---[ end trace 82aa2a1c6173a5f6 ]---Oddly enough setting
CONFIG_OF_DYNAMIC=nor applying the patch '[PATCH v2] device property: preserve usecount for node passed toof_fwnode_graph_get_port_parent()' fixes _both_ issues. It obviously would fix the 'Badof_node_put()on ...' messages that it also fixes the OOPS is strange, so I did some digging.The problem is introduced when rcar-vin in its complete callback calls
v4l2_device_register_subdev_nodes(). Before the callvin->digital->subdevpointer is correct but after the call thevin->digital->subdevpointer is changed to a for me random value. And this is what is causing the OOPS inrvin_v4l2_probe()once it tries to operate on the subdevice usingv4l2_subdev_call()using this bad pointer.I tried to track down the issue but I can't understand what is causing it, but I managed to narrow it down. The callchain is:
-
rvin_digital_notify_complete
-pr_dbg("sd: %p\n", vin->digital->subdev); # prints good pointer
-v4l2_device_register_subdev_nodes()
-__video_register_device()
-cdev_alloc()# Here the pointer gets corrupted
-pr_dbg("sd: %p\n", vin->digital->subdev); # prints bad pointerI can't figure out why
cdev_alloc()would corrupt it. I can even corrupt the pointer by callingcdev_alloc()directly from the rcar-vin driver itself. I added to following to the top of the complete callback beforev4l2_device_register_subdev_nodes()is called.pr_err("digital: %p sd: %p\n", vin->digital, vin->digital->subdev); cdev_alloc(); pr_err("digital: %p sd: %p\n", vin->digital, vin->digital->subdev);And the result is:
[ 2.865306] digital: eb1284c0 sd: ea953068 [ 2.869414] digital: eb1284c0 sd: c0a1e6dcIf I set
CONFIG_OF_DYNAMIC=nor apply the patch above the result is OK,[ 1.961142] digital: ea8f8cc0 sd: ea8bac50 [ 1.965240] digital: ea8f8cc0 sd: ea8bac50I can capture without issues so this patch in it self is good I think. So please add
Acked-by Niklas Söderlund <[email protected]>However I would like the issue that is revealed by this patch to be sorted out before this patch is picked up as it causes problems with
CONFIG_OF_DYNAMIC=ywhich is enabled by using theshmobile_defconfig.Quoted 358 lines · Sakari Ailus
Instead of using a custom driver implementation, use
v4l2_async_notifier_parse_fwnode_endpoints()to parse the fwnode endpoints of the device.Acked-by Hans Verkuil <[email protected]>--- drivers/media/platform/rcar-vin/rcar-core.c | 107 +++++++++------------------- drivers/media/platform/rcar-vin/rcar-dma.c | 10 +-- drivers/media/platform/rcar-vin/rcar-v4l2.c | 14 ++-- drivers/media/platform/rcar-vin/rcar-vin.h | 4 +- 4 files changed, 46 insertions(+), 89 deletions(-)drivers/media/platform/rcar-vin/rcar-core.c +32
-75@@ -21,6 +21,7 @@#include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <media/v4l2-async.h> #include <media/v4l2-fwnode.h> #include "rcar-vin.h" @@ -77,14 +78,14 @@ static int rvin_digital_notify_complete(struct v4l2_async_notifier *notifier)int ret;/* Verify subdevices mbus format */ -if (!rvin_mbus_supported (&vin->digital)) { +if (!rvin_mbus_supported (vin->digital)) {vin_err (vin,"Unsupported media bus format for %s\n" , - vin->digital.subdev->name); + vin->digital->subdev->name);return -EINVAL ; }vin_dbg (vin,"Found media bus format for %s: %d\n" , - vin->digital.subdev->name, vin->digital.code); + vin->digital->subdev->name, vin->digital->code); ret =v4l2_device_register_subdev_nodes (&vin->v4l2_dev);if (ret <0 ) {@@ -103,7 +104,7 @@ static void rvin_digital_notify_unbind(struct v4l2_async_notifier *notifier,vin_dbg (vin,"unbind digital subdev %s\n" , subdev->name);rvin_v4l2_remove (vin); - vin->digital.subdev =NULL ; + vin->digital->subdev =NULL ; } static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier,@@ -120,117 +121,71 @@ static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier, ret =rvin_find_pad (subdev,MEDIA_PAD_FL_SOURCE );if (ret <0 )return ret; - vin->digital.source_pad = ret; + vin->digital->source_pad = ret; ret =rvin_find_pad (subdev,MEDIA_PAD_FL_SINK ); - vin->digital.sink_pad = ret <0 ?0 : ret; + vin->digital->sink_pad = ret <0 ?0 : ret; - vin->digital.subdev = subdev; + vin->digital->subdev = subdev;vin_dbg (vin,"bound subdev %s source pad: %u sink pad: %u\n" , - subdev->name, vin->digital.source_pad, - vin->digital.sink_pad); + subdev->name, vin->digital->source_pad, + vin->digital->sink_pad);return 0 ; } -static int rvin_digitial_parse_v4l2 (struct rvin_dev *vin, -struct device_node *ep, -struct v4l2_mbus_config *mbus_cfg) +static int rvin_digital_parse_v4l2 (struct device *dev, +struct v4l2_fwnode_endpoint *vep, +struct v4l2_async_subdev *asd) { -struct v4l2_fwnode_endpoint v4l2_ep; -int ret; +struct rvin_dev *vin =dev_get_drvdata (dev); +struct rvin_graph_entity *rvge = + container_of(asd, struct rvin_graph_entity, asd); - ret =v4l2_fwnode_endpoint_parse (of_fwnode_handle (ep), &v4l2_ep); -if (ret) { -vin_err (vin,"Could not parse v4l2 endpoint\n" ); -return -EINVAL ; - } +if (vep->base.port || vep->base.id) +return -ENOTCONN ; - mbus_cfg->type = v4l2_ep.bus_type; + rvge->mbus_cfg.type = vep->bus_type; -switch (mbus_cfg->type) { +switch (rvge->mbus_cfg.type) {case V4L2_MBUS_PARALLEL :vin_dbg (vin,"Found PARALLEL media bus\n" ); - mbus_cfg->flags = v4l2_ep.bus.parallel.flags; + rvge->mbus_cfg.flags = vep->bus.parallel.flags;break ;case V4L2_MBUS_BT656 :vin_dbg (vin,"Found BT656 media bus\n" ); - mbus_cfg->flags =0 ; + rvge->mbus_cfg.flags =0 ;break ;default :vin_err (vin,"Unknown media bus type\n" );return -EINVAL ; } -return 0 ; -} - -static int rvin_digital_graph_parse (struct rvin_dev *vin) -{ -struct device_node *ep, *np; -int ret; - - vin->digital.asd.match.fwnode.fwnode =NULL ; - vin->digital.subdev =NULL ; - -/* -* Port 0 id 0 is local digital input, try to get it. -* Not all instances can or will have this, that is OK -*/ - ep =of_graph_get_endpoint_by_regs (vin->dev->of_node,0 ,0 ); -if (!ep) -return 0 ; - - np =of_graph_get_remote_port_parent (ep); -if (!np) { -vin_err (vin,"No remote parent for digital input\n" ); -of_node_put (ep); -return -EINVAL ; - } -of_node_put (np); - - ret =rvin_digitial_parse_v4l2 (vin, ep, &vin->digital.mbus_cfg); -of_node_put (ep); -if (ret) -return ret; - - vin->digital.asd.match.fwnode.fwnode =of_fwnode_handle (np); - vin->digital.asd.match_type =V4L2_ASYNC_MATCH_FWNODE ; + vin->digital = rvge;return 0 ; }static int rvin_digital_graph_init (struct rvin_dev *vin) { -struct v4l2_async_subdev **subdevs =NULL ;int ret; - ret =rvin_digital_graph_parse (vin); + ret =v4l2_async_notifier_parse_fwnode_endpoints ( + vin->dev, &vin->notifier, +sizeof (struct rvin_graph_entity ), rvin_digital_parse_v4l2);if (ret)return ret; -if (!vin->digital.asd.match.fwnode.fwnode) { -vin_dbg (vin,"No digital subdevice found\n" ); +if (!vin->digital)return -ENODEV ; - } - -/* Register the subdevices notifier. */ - subdevs =devm_kzalloc (vin->dev,sizeof (*subdevs),GFP_KERNEL ); -if (subdevs ==NULL ) -return -ENOMEM ; - - subdevs[0 ] = &vin->digital.asd;vin_dbg (vin,"Found digital subdevice %pOF\n" , -to_of_node (subdevs[0 ]->match.fwnode.fwnode)); +to_of_node (vin->digital->asd.match.fwnode.fwnode)); - vin->notifier.num_subdevs =1 ; - vin->notifier.subdevs = subdevs; vin->notifier.bound = rvin_digital_notify_bound; vin->notifier.unbind = rvin_digital_notify_unbind; vin->notifier.complete = rvin_digital_notify_complete; - ret =v4l2_async_notifier_register (&vin->v4l2_dev, &vin->notifier);if (ret <0 ) {vin_err (vin,"Notifier registration failed\n" );@@ -290,6 +245,8 @@ static int rcar_vin_probe(struct platform_device *pdev)if (ret)return ret; +platform_set_drvdata (pdev, vin); + ret =rvin_digital_graph_init (vin);if (ret <0 ) goto error;@@ -297,11 +254,10 @@ static int rcar_vin_probe(struct platform_device *pdev)pm_suspend_ignore_children (&pdev->dev, true);pm_runtime_enable (&pdev->dev); -platform_set_drvdata (pdev, vin); -return 0 ; error:rvin_dma_remove (vin); +v4l2_async_notifier_cleanup (&vin->notifier);return ret; }@@ -313,6 +269,7 @@ static int rcar_vin_remove(struct platform_device *pdev)pm_runtime_disable (&pdev->dev);v4l2_async_notifier_unregister (&vin->notifier); +v4l2_async_notifier_cleanup (&vin->notifier);rvin_dma_remove (vin);drivers/media/platform/rcar-vin/rcar-dma.c +5
-5@@ -183,7 +183,7 @@ static int rvin_setup(struct rvin_dev *vin)/* * Input interface */ -switch (vin->digital.code) { +switch (vin->digital->code) {case MEDIA_BUS_FMT_YUYV8_1X16 :/* BT.601/BT.1358 16bit YCbCr422 */ vnmc |=VNMC_INF_YUV16 ;@@ -191,7 +191,7 @@ static int rvin_setup(struct rvin_dev *vin)break ;case MEDIA_BUS_FMT_UYVY8_2X8 :/* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */ - vnmc |= vin->digital.mbus_cfg.type ==V4L2_MBUS_BT656 ? + vnmc |= vin->digital->mbus_cfg.type ==V4L2_MBUS_BT656 ?VNMC_INF_YUV8_BT656 :VNMC_INF_YUV8_BT601 ; input_is_yuv = true;break ;@@ -200,7 +200,7 @@ static int rvin_setup(struct rvin_dev *vin)break ;case MEDIA_BUS_FMT_UYVY10_2X10 :/* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */ - vnmc |= vin->digital.mbus_cfg.type ==V4L2_MBUS_BT656 ? + vnmc |= vin->digital->mbus_cfg.type ==V4L2_MBUS_BT656 ?VNMC_INF_YUV10_BT656 :VNMC_INF_YUV10_BT601 ; input_is_yuv = true;break ;@@ -212,11 +212,11 @@ static int rvin_setup(struct rvin_dev *vin) dmr2 =VNDMR2_FTEV |VNDMR2_VLV (1 );/* Hsync Signal Polarity Select */ -if (!(vin->digital.mbus_cfg.flags &V4L2_MBUS_HSYNC_ACTIVE_LOW )) +if (!(vin->digital->mbus_cfg.flags &V4L2_MBUS_HSYNC_ACTIVE_LOW )) dmr2 |=VNDMR2_HPS ;/* Vsync Signal Polarity Select */ -if (!(vin->digital.mbus_cfg.flags &V4L2_MBUS_VSYNC_ACTIVE_LOW )) +if (!(vin->digital->mbus_cfg.flags &V4L2_MBUS_VSYNC_ACTIVE_LOW )) dmr2 |=VNDMR2_VPS ;/* drivers/media/platform/rcar-vin/rcar-v4l2.c +7
-7@@ -111,7 +111,7 @@ static int rvin_reset_format(struct rvin_dev *vin)struct v4l2_mbus_framefmt *mf = &fmt.format;int ret; - fmt.pad = vin->digital.source_pad; + fmt.pad = vin->digital->source_pad; ret =v4l2_subdev_call (vin_to_source (vin), pad, get_fmt,NULL , &fmt);if (ret)@@ -172,13 +172,13 @@ static int __rvin_try_format_source(struct rvin_dev *vin, sd =vin_to_source (vin); -v4l2_fill_mbus_format (&format.format, pix, vin->digital.code); +v4l2_fill_mbus_format (&format.format, pix, vin->digital->code); pad_cfg =v4l2_subdev_alloc_pad_config (sd);if (pad_cfg ==NULL )return -ENOMEM ; - format.pad = vin->digital.source_pad; + format.pad = vin->digital->source_pad; field = pix->field;@@ -555,7 +555,7 @@ static int rvin_enum_dv_timings(struct file *file, void *priv_fh,if (timings->pad)return -EINVAL ; - timings->pad = vin->digital.sink_pad; + timings->pad = vin->digital->sink_pad; ret =v4l2_subdev_call (sd, pad, enum_dv_timings, timings);@@ -607,7 +607,7 @@ static int rvin_dv_timings_cap(struct file *file, void *priv_fh,if (cap->pad)return -EINVAL ; - cap->pad = vin->digital.sink_pad; + cap->pad = vin->digital->sink_pad; ret =v4l2_subdev_call (sd, pad, dv_timings_cap, cap);@@ -625,7 +625,7 @@ static int rvin_g_edid(struct file *file, void *fh, struct v4l2_edid *edid)if (edid->pad)return -EINVAL ; - edid->pad = vin->digital.sink_pad; + edid->pad = vin->digital->sink_pad; ret =v4l2_subdev_call (sd, pad, get_edid, edid);@@ -643,7 +643,7 @@ static int rvin_s_edid(struct file *file, void *fh, struct v4l2_edid *edid)if (edid->pad)return -EINVAL ; - edid->pad = vin->digital.sink_pad; + edid->pad = vin->digital->sink_pad; ret =v4l2_subdev_call (sd, pad, set_edid, edid);drivers/media/platform/rcar-vin/rcar-vin.h +2
-2@@ -126,7 +126,7 @@ struct rvin_dev {struct v4l2_device v4l2_dev;struct v4l2_ctrl_handler ctrl_handler;struct v4l2_async_notifier notifier; -struct rvin_graph_entity digital; +struct rvin_graph_entity *digital;struct mutex lock;struct vb2_queue queue;@@ -145,7 +145,7 @@ struct rvin_dev {struct v4l2_rect compose; }; -#define vin_to_source (vin) vin->digital.subdev +#define vin_to_source (vin) ((vin)->digital->subdev)/* Debug */ #define vin_dbg(d, fmt, arg...) dev_dbg(d->dev, fmt, ##arg)Signature · 1 line
2.11.0Signature · 4 lines
Regards, Sakari Ailus sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected]
Signature · 6 lines
Regards, Niklas Söderlund -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): 20171002121422.GQ17182-ofJ5d6taAgIKcZgyrm77+z0dHWC0CY5B@public.gmane.org
Re: [PATCH v14 07/28] rcar-vin: Use generic parser for parsing fwnode endpoints
Hejssan,
Quoted 20 lines · Niklas Söderlund
Hi Sakari,
Quoted 17 lines · Sakari Ailus
Hi Niklas,
Quoted 9 lines · Niklas Söderlund
Hi Sakari,
Thanks for your patch, I like it. Unfortunately it causes issues :-(
I picked the first 7 patches of this series on top of media-next and it produce problems when tested on Koelsch with
CONFIG_OF_DYNAMIC=y.1. It print's 'OF: ERROR: Bad
of_node_put()on /video@e6ef0000/port' messages during boot.Do you have your own patch to fix
fwnode_graph_get_port_parent()applied? I noticed it doesn't seem to be in Rob's tree; let's continue in the other thread.
Quoted 8 lines
Quoted 1 line
<URL:https://www.mail-archive.com/[email protected]/msg117450.html>
To produce this issue the fix is not applied. But as I try to describe at the end of my email applying it fixes both issues. So I think this patch is correct (and that is why I Acked it) but my concern is that if it's picked up before the
fwnode_graph_get_port_parent()issue is sorted out there will be problems for rcar-vin, and if possible I would like to avoid that.
Oops. I missed that between the oops log and the patch. X-)
Well, good to hear that this isn't an actual bug in this set. I'll try to be careful in sending pull requests. :-) The same issue would be present in any other driver using the new convenience functions.
Signature · 8 lines
Kind regards, Sakari Ailus sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected] -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v14 8/28 omap3isp: Fix check for our own sub-devices
In reply to a message not in the archiveWe only want to link sub-devices that were bound to the async notifier the isp driver registered but there may be other sub-devices in the v4l2_device as well. Check for the correct async notifier.
--- drivers/media/platform/omap3isp/isp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/platform/omap3isp/isp.c +1 -1
@@ -2155,7 +2155,7 @@ static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async)return ret;list_for_each_entry (sd, &v4l2_dev->subdevs, list) { -if (!sd->asd) +if (sd->notifier != &isp->notifier)continue ; ret = isp_link_entity(isp, &sd->entity,
Signature · 6 lines
2.11.0 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v14 9/28 omap3isp: Print the name of the entity where no source pads could be found
In reply to a message not in the archiveIf no source pads are found in an entity, print the name of the entity.
--- drivers/media/platform/omap3isp/isp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/media/platform/omap3isp/isp.c +2 -2
@@ -1669,8 +1669,8 @@ static int isp_link_entity(break ; }if (i == entity->num_pads) { -dev_err (isp->dev,"%s: no source pad in external entity\n" , - __func__); +dev_err (isp->dev,"%s: no source pad in external entity %s\n" , + __func__, entity->name);return -EINVAL ; }
Signature · 6 lines
2.11.0 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v14 10/28 v4l: async: Move async subdev notifier operations to a separate structure
In reply to a message not in the archiveFrom: Laurent Pinchart <laurent.pinchart-ryLnwIuWjnjg/[email protected]>
The async subdev notifier .bound(), .unbind() and .complete() operations are function pointers stored directly in the v4l2_async_subdev structure. As the structure isn't immutable, this creates a potential security risk as the function pointers are mutable.
To fix this, move the function pointers to a new v4l2_async_subdev_operations structure that can be made const in drivers.
--- drivers/media/platform/am437x/am437x-vpfe.c | 8 +++++-- drivers/media/platform/atmel/atmel-isc.c | 10 ++++++--- drivers/media/platform/atmel/atmel-isi.c | 10 ++++++--- drivers/media/platform/davinci/vpif_capture.c | 8 +++++-- drivers/media/platform/davinci/vpif_display.c | 8 +++++-- drivers/media/platform/exynos4-is/media-dev.c | 8 +++++-- drivers/media/platform/omap3isp/isp.c | 6 +++++- drivers/media/platform/pxa_camera.c | 8 +++++-- drivers/media/platform/qcom/camss-8x16/camss.c | 8 +++++-- drivers/media/platform/rcar-vin/rcar-core.c | 10 ++++++--- drivers/media/platform/rcar_drif.c | 10 ++++++--- drivers/media/platform/soc_camera/soc_camera.c | 14 +++++++------ drivers/media/platform/stm32/stm32-dcmi.c | 10 ++++++--- drivers/media/platform/ti-vpe/cal.c | 8 +++++-- drivers/media/platform/xilinx/xilinx-vipp.c | 8 +++++-- drivers/media/v4l2-core/v4l2-async.c | 20 +++++++++--------- drivers/staging/media/imx/imx-media-dev.c | 8 +++++-- include/media/v4l2-async.h | 29 +++++++++++++++++--------- 18 files changed, 131 insertions(+), 60 deletions(-)
drivers/media/platform/am437x/am437x-vpfe.c +6 -2
@@ -2417,6 +2417,11 @@ static int vpfe_async_complete(struct v4l2_async_notifier *notifier)return vpfe_probe_complete (vpfe); } +static const struct v4l2_async_notifier_operations vpfe_async_ops = { + .bound = vpfe_async_bound, + .complete = vpfe_async_complete, +}; +static struct vpfe_config *vpfe_get_pdata (struct platform_device *pdev) {
@@ -2590,8 +2595,7 @@ static int vpfe_probe(struct platform_device *pdev) vpfe->notifier.subdevs = vpfe->cfg->asd; vpfe->notifier.num_subdevs =ARRAY_SIZE (vpfe->cfg->asd); - vpfe->notifier.bound = vpfe_async_bound; - vpfe->notifier.complete = vpfe_async_complete; + vpfe->notifier.ops = &vpfe_async_ops; ret =v4l2_async_notifier_register (&vpfe->v4l2_dev, &vpfe->notifier);if (ret) {
drivers/media/platform/atmel/atmel-isc.c +7 -3
@@ -1639,6 +1639,12 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)return 0 ; } +static const struct v4l2_async_notifier_operations isc_async_ops = { + .bound = isc_async_bound, + .unbind = isc_async_unbind, + .complete = isc_async_complete, +}; +static void isc_subdev_cleanup (struct isc_device *isc) {struct isc_subdev_entity *subdev_entity;
@@ -1851,9 +1857,7 @@ static int atmel_isc_probe(struct platform_device *pdev)list_for_each_entry (subdev_entity, &isc->subdev_entities, list) { subdev_entity->notifier.subdevs = &subdev_entity->asd; subdev_entity->notifier.num_subdevs =1 ; - subdev_entity->notifier.bound = isc_async_bound; - subdev_entity->notifier.unbind = isc_async_unbind; - subdev_entity->notifier.complete = isc_async_complete; + subdev_entity->notifier.ops = &isc_async_ops; ret =v4l2_async_notifier_register (&isc->v4l2_dev, &subdev_entity->notifier);
drivers/media/platform/atmel/atmel-isi.c +7 -3
@@ -1105,6 +1105,12 @@ static int isi_graph_notify_bound(struct v4l2_async_notifier *notifier,return 0 ; } +static const struct v4l2_async_notifier_operations isi_graph_notify_ops = { + .bound = isi_graph_notify_bound, + .unbind = isi_graph_notify_unbind, + .complete = isi_graph_notify_complete, +}; +static int isi_graph_parse (struct atmel_isi *isi,struct device_node *node) {struct device_node *ep =NULL ;
@@ -1152,9 +1158,7 @@ static int isi_graph_init(struct atmel_isi *isi) isi->notifier.subdevs = subdevs; isi->notifier.num_subdevs =1 ; - isi->notifier.bound = isi_graph_notify_bound; - isi->notifier.unbind = isi_graph_notify_unbind; - isi->notifier.complete = isi_graph_notify_complete; + isi->notifier.ops = &isi_graph_notify_ops; ret =v4l2_async_notifier_register (&isi->v4l2_dev, &isi->notifier);if (ret <0 ) {
drivers/media/platform/davinci/vpif_capture.c +6 -2
@@ -1500,6 +1500,11 @@ static int vpif_async_complete(struct v4l2_async_notifier *notifier)return vpif_probe_complete (); } +static const struct v4l2_async_notifier_operations vpif_async_ops = { + .bound = vpif_async_bound, + .complete = vpif_async_complete, +}; +static struct vpif_capture_config *vpif_capture_get_pdata (struct platform_device *pdev) {
@@ -1691,8 +1696,7 @@ static __init int vpif_probe(struct platform_device *pdev) }else { vpif_obj.notifier.subdevs = vpif_obj.config->asd; vpif_obj.notifier.num_subdevs = vpif_obj.config->asd_sizes[0 ]; - vpif_obj.notifier.bound = vpif_async_bound; - vpif_obj.notifier.complete = vpif_async_complete; + vpif_obj.notifier.ops = &vpif_async_ops; err =v4l2_async_notifier_register (&vpif_obj.v4l2_dev, &vpif_obj.notifier);if (err) {
drivers/media/platform/davinci/vpif_display.c +6 -2
@@ -1232,6 +1232,11 @@ static int vpif_async_complete(struct v4l2_async_notifier *notifier)return vpif_probe_complete (); } +static const struct v4l2_async_notifier_operations vpif_async_ops = { + .bound = vpif_async_bound, + .complete = vpif_async_complete, +}; +/* * vpif_probe: This function creates device entries by register itself to the * V4L2 driver and initializes fields of each channel objects
@@ -1313,8 +1318,7 @@ static __init int vpif_probe(struct platform_device *pdev) }else { vpif_obj.notifier.subdevs = vpif_obj.config->asd; vpif_obj.notifier.num_subdevs = vpif_obj.config->asd_sizes[0 ]; - vpif_obj.notifier.bound = vpif_async_bound; - vpif_obj.notifier.complete = vpif_async_complete; + vpif_obj.notifier.ops = &vpif_async_ops; err =v4l2_async_notifier_register (&vpif_obj.v4l2_dev, &vpif_obj.notifier);if (err) {
drivers/media/platform/exynos4-is/media-dev.c +6 -2
@@ -1405,6 +1405,11 @@ static int subdev_notifier_complete(struct v4l2_async_notifier *notifier)return media_device_register (&fmd->media_dev); } +static const struct v4l2_async_notifier_operations subdev_notifier_ops = { + .bound = subdev_notifier_bound, + .complete = subdev_notifier_complete, +}; +static int fimc_md_probe (struct platform_device *pdev) {struct device *dev = &pdev->dev;
@@ -1479,8 +1484,7 @@ static int fimc_md_probe(struct platform_device *pdev)if (fmd->num_sensors >0 ) { fmd->subdev_notifier.subdevs = fmd->async_subdevs; fmd->subdev_notifier.num_subdevs = fmd->num_sensors; - fmd->subdev_notifier.bound = subdev_notifier_bound; - fmd->subdev_notifier.complete = subdev_notifier_complete; + fmd->subdev_notifier.ops = &subdev_notifier_ops; fmd->num_sensors =0 ; ret = v4l2_async_notifier_register(&fmd->v4l2_dev,
drivers/media/platform/omap3isp/isp.c +5 -1
@@ -2171,6 +2171,10 @@ static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async)return media_device_register (&isp->media_dev); } +static const struct v4l2_async_notifier_operations isp_subdev_notifier_ops = { + .complete = isp_subdev_notifier_complete, +}; +/* * isp_probe - Probe ISP platform device * @pdev: Pointer to ISP platform device
@@ -2341,7 +2345,7 @@ static int isp_probe(struct platform_device *pdev)if (ret <0 ) goto error_register_entities; - isp->notifier.complete = isp_subdev_notifier_complete; + isp->notifier.ops = &isp_subdev_notifier_ops; ret =v4l2_async_notifier_register (&isp->v4l2_dev, &isp->notifier);if (ret)
drivers/media/platform/pxa_camera.c +6 -2
@@ -2221,6 +2221,11 @@ static void pxa_camera_sensor_unbind(struct v4l2_async_notifier *notifier,mutex_unlock (&pcdev->mlock); } +static const struct v4l2_async_notifier_operations pxa_camera_sensor_ops = { + .bound = pxa_camera_sensor_bound, + .unbind = pxa_camera_sensor_unbind, +}; +/* * Driver probe, remove, suspend and resume operations */
@@ -2489,8 +2494,7 @@ static int pxa_camera_probe(struct platform_device *pdev) pcdev->asds[0 ] = &pcdev->asd; pcdev->notifier.subdevs = pcdev->asds; pcdev->notifier.num_subdevs =1 ; - pcdev->notifier.bound = pxa_camera_sensor_bound; - pcdev->notifier.unbind = pxa_camera_sensor_unbind; + pcdev->notifier.ops = &pxa_camera_sensor_ops;if (!of_have_populated_dt ()) pcdev->asd.match_type =V4L2_ASYNC_MATCH_I2C ;
drivers/media/platform/qcom/camss-8x16/camss.c +6 -2
@@ -601,6 +601,11 @@ static int camss_subdev_notifier_complete(struct v4l2_async_notifier *async)return media_device_register (&camss->media_dev); } +static const struct v4l2_async_notifier_operations camss_subdev_notifier_ops = { + .bound = camss_subdev_notifier_bound, + .complete = camss_subdev_notifier_complete, +}; +static const struct media_device_ops camss_media_ops = { .link_notify = v4l2_pipeline_link_notify, };
@@ -655,8 +660,7 @@ static int camss_probe(struct platform_device *pdev) goto err_register_entities;if (camss->notifier.num_subdevs) { - camss->notifier.bound = camss_subdev_notifier_bound; - camss->notifier.complete = camss_subdev_notifier_complete; + camss->notifier.ops = &camss_subdev_notifier_ops; ret =v4l2_async_notifier_register (&camss->v4l2_dev, &camss->notifier);
drivers/media/platform/rcar-vin/rcar-core.c +7 -3
@@ -134,6 +134,12 @@ static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier,return 0 ; } +static const struct v4l2_async_notifier_operations rvin_digital_notify_ops = { + .bound = rvin_digital_notify_bound, + .unbind = rvin_digital_notify_unbind, + .complete = rvin_digital_notify_complete, +}; + static int rvin_digital_parse_v4l2(struct device *dev, struct v4l2_fwnode_endpoint *vep,
@@ -183,9 +189,7 @@ static int rvin_digital_graph_init(struct rvin_dev *vin)vin_dbg (vin,"Found digital subdevice %pOF\n" ,to_of_node (vin->digital->asd.match.fwnode.fwnode)); - vin->notifier.bound = rvin_digital_notify_bound; - vin->notifier.unbind = rvin_digital_notify_unbind; - vin->notifier.complete = rvin_digital_notify_complete; + vin->notifier.ops = &rvin_digital_notify_ops; ret =v4l2_async_notifier_register (&vin->v4l2_dev, &vin->notifier);if (ret <0 ) {vin_err (vin,"Notifier registration failed\n" );
drivers/media/platform/rcar_drif.c +7 -3
@@ -1185,6 +1185,12 @@ static int rcar_drif_notify_complete(struct v4l2_async_notifier *notifier)return ret; } +static const struct v4l2_async_notifier_operations rcar_drif_notify_ops = { + .bound = rcar_drif_notify_bound, + .unbind = rcar_drif_notify_unbind, + .complete = rcar_drif_notify_complete, +}; +/* Read endpoint properties */ static void rcar_drif_get_ep_properties (struct rcar_drif_sdr *sdr,struct fwnode_handle *fwnode)
@@ -1347,9 +1353,7 @@ static int rcar_drif_sdr_probe(struct rcar_drif_sdr *sdr)if (ret) goto error; - sdr->notifier.bound = rcar_drif_notify_bound; - sdr->notifier.unbind = rcar_drif_notify_unbind; - sdr->notifier.complete = rcar_drif_notify_complete; + sdr->notifier.ops = &rcar_drif_notify_ops;/* Register notifier */ ret =v4l2_async_notifier_register (&sdr->v4l2_dev, &sdr->notifier);
drivers/media/platform/soc_camera/soc_camera.c +8 -6
@@ -1391,6 +1391,12 @@ static int soc_camera_async_complete(struct v4l2_async_notifier *notifier)return 0 ; } +static const struct v4l2_async_notifier_operations soc_camera_async_ops = { + .bound = soc_camera_async_bound, + .unbind = soc_camera_async_unbind, + .complete = soc_camera_async_complete, +}; +static int scan_async_group (struct soc_camera_host *ici,struct v4l2_async_subdev **asd,unsigned int size) {
@@ -1437,9 +1443,7 @@ static int scan_async_group(struct soc_camera_host *ici, sasc->notifier.subdevs = asd; sasc->notifier.num_subdevs = size; - sasc->notifier.bound = soc_camera_async_bound; - sasc->notifier.unbind = soc_camera_async_unbind; - sasc->notifier.complete = soc_camera_async_complete; + sasc->notifier.ops = &soc_camera_async_ops; icd->sasc = sasc; icd->parent = ici->v4l2_dev.dev;
@@ -1537,9 +1541,7 @@ static int soc_of_bind(struct soc_camera_host *ici, sasc->notifier.subdevs = &info->subdev; sasc->notifier.num_subdevs =1 ; - sasc->notifier.bound = soc_camera_async_bound; - sasc->notifier.unbind = soc_camera_async_unbind; - sasc->notifier.complete = soc_camera_async_complete; + sasc->notifier.ops = &soc_camera_async_ops; icd->sasc = sasc; icd->parent = ici->v4l2_dev.dev;
drivers/media/platform/stm32/stm32-dcmi.c +7 -3
@@ -1495,6 +1495,12 @@ static int dcmi_graph_notify_bound(struct v4l2_async_notifier *notifier,return 0 ; } +static const struct v4l2_async_notifier_operations dcmi_graph_notify_ops = { + .bound = dcmi_graph_notify_bound, + .unbind = dcmi_graph_notify_unbind, + .complete = dcmi_graph_notify_complete, +}; +static int dcmi_graph_parse (struct stm32_dcmi *dcmi,struct device_node *node) {struct device_node *ep =NULL ;
@@ -1542,9 +1548,7 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi) dcmi->notifier.subdevs = subdevs; dcmi->notifier.num_subdevs =1 ; - dcmi->notifier.bound = dcmi_graph_notify_bound; - dcmi->notifier.unbind = dcmi_graph_notify_unbind; - dcmi->notifier.complete = dcmi_graph_notify_complete; + dcmi->notifier.ops = &dcmi_graph_notify_ops; ret =v4l2_async_notifier_register (&dcmi->v4l2_dev, &dcmi->notifier);if (ret <0 ) {
drivers/media/platform/ti-vpe/cal.c +6 -2
@@ -1522,6 +1522,11 @@ static int cal_async_complete(struct v4l2_async_notifier *notifier)return 0 ; } +static const struct v4l2_async_notifier_operations cal_async_ops = { + .bound = cal_async_bound, + .complete = cal_async_complete, +}; +static int cal_complete_ctx (struct cal_ctx *ctx) {struct video_device *vfd;
@@ -1736,8 +1741,7 @@ static int of_cal_create_instance(struct cal_ctx *ctx, int inst) ctx->asd_list[0 ] = asd; ctx->notifier.subdevs = ctx->asd_list; ctx->notifier.num_subdevs =1 ; - ctx->notifier.bound = cal_async_bound; - ctx->notifier.complete = cal_async_complete; + ctx->notifier.ops = &cal_async_ops; ret =v4l2_async_notifier_register (&ctx->v4l2_dev, &ctx->notifier);if (ret) {
drivers/media/platform/xilinx/xilinx-vipp.c +6 -2
@@ -351,6 +351,11 @@ static int xvip_graph_notify_bound(struct v4l2_async_notifier *notifier,return -EINVAL ; } +static const struct v4l2_async_notifier_operations xvip_graph_notify_ops = { + .bound = xvip_graph_notify_bound, + .complete = xvip_graph_notify_complete, +}; +static int xvip_graph_parse_one (struct xvip_composite_device *xdev,struct device_node *node) {
@@ -548,8 +553,7 @@ static int xvip_graph_init(struct xvip_composite_device *xdev) xdev->notifier.subdevs = subdevs; xdev->notifier.num_subdevs = num_subdevs; - xdev->notifier.bound = xvip_graph_notify_bound; - xdev->notifier.complete = xvip_graph_notify_complete; + xdev->notifier.ops = &xvip_graph_notify_ops; ret =v4l2_async_notifier_register (&xdev->v4l2_dev, &xdev->notifier);if (ret <0 ) {
drivers/media/v4l2-core/v4l2-async.c +10 -10
@@ -102,16 +102,16 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier, {int ret; -if (notifier->bound) { - ret = notifier->bound (notifier, sd, asd); +if (notifier->ops->bound) { + ret = notifier->ops->bound (notifier, sd, asd);if (ret <0 )return ret; } ret =v4l2_device_register_subdev (notifier->v4l2_dev, sd);if (ret <0 ) { -if (notifier->unbind) - notifier->unbind (notifier, sd, asd); +if (notifier->ops->unbind) + notifier->ops->unbind (notifier, sd, asd);return ret; }
@@ -123,8 +123,8 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,/* Move from the global subdevice list to notifier's done */ list_move (&sd->async_list, ¬ifier->done); -if (list_empty (¬ifier->waiting) && notifier->complete) -return notifier->complete (notifier); +if (list_empty (¬ifier->waiting) && notifier->ops->complete) +return notifier->ops->complete (notifier);return 0 ; }
@@ -210,8 +210,8 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)list_for_each_entry_safe (sd, tmp, ¬ifier->done, async_list) {v4l2_async_cleanup (sd); -if (notifier->unbind) - notifier->unbind (notifier, sd, sd->asd); +if (notifier->ops->unbind) + notifier->ops->unbind (notifier, sd, sd->asd);list_move (&sd->async_list, &subdev_list); }
@@ -302,8 +302,8 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)v4l2_async_cleanup (sd); -if (notifier->unbind) - notifier->unbind (notifier, sd, sd->asd); +if (notifier->ops->unbind) + notifier->ops->unbind (notifier, sd, sd->asd);mutex_unlock (&list_lock); }
drivers/staging/media/imx/imx-media-dev.c +6 -2
@@ -440,6 +440,11 @@ static int imx_media_probe_complete(struct v4l2_async_notifier *notifier)return media_device_register (&imxmd->md); } +static const struct v4l2_async_notifier_operations imx_media_subdev_ops = { + .bound = imx_media_subdev_bound, + .complete = imx_media_probe_complete, +}; +/* * adds controls to a video device from an entity subdevice. * Continues upstream from the entity's sink pads.
@@ -608,8 +613,7 @@ static int imx_media_probe(struct platform_device *pdev)/* prepare the async subdev notifier and register it */ imxmd->subdev_notifier.subdevs = imxmd->async_ptrs; - imxmd->subdev_notifier.bound = imx_media_subdev_bound; - imxmd->subdev_notifier.complete = imx_media_probe_complete; + imxmd->subdev_notifier.ops = &imx_media_subdev_ops; ret =v4l2_async_notifier_register (&imxmd->v4l2_dev, &imxmd->subdev_notifier);if (ret) {
include/media/v4l2-async.h +19 -10
@@ -18,6 +18,7 @@ struct device;struct device_node ;struct v4l2_device ;struct v4l2_subdev ; +struct v4l2_async_notifier ;/* A random max subdevice number, used to allocate an array on stack */ #define V4L2_MAX_SUBDEVS 128U
@@ -79,8 +80,25 @@ struct v4l2_async_subdev { };/** +* struct v4l2_async_notifier_operations - Asynchronous V4L2 notifier operations +* @bound: a subdevice driver has successfully probed one of the subdevices +* @complete: all subdevices have been probed successfully +* @unbind: a subdevice is leaving +*/ +struct v4l2_async_notifier_operations { +int (*bound)(struct v4l2_async_notifier *notifier, +struct v4l2_subdev *subdev, +struct v4l2_async_subdev *asd); +int (*complete)(struct v4l2_async_notifier *notifier); +void (*unbind)(struct v4l2_async_notifier *notifier, +struct v4l2_subdev *subdev, +struct v4l2_async_subdev *asd); +}; + +/** * struct v4l2_async_notifier - v4l2_device notifier data * +* @ops: notifier operations * @num_subdevs: number of subdevices used in the subdevs array * @max_subdevs: number of subdevices allocated in the subdevs array * @subdevs: array of pointers to subdevice descriptors
@@ -88,11 +106,9 @@ struct v4l2_async_subdev {* @waiting: list of struct v4l2_async_subdev, waiting for their drivers * @done: list of struct v4l2_subdev, already probed * @list: member in a global list of notifiers -* @bound: a subdevice driver has successfully probed one of subdevices -* @complete: all subdevices have been probed successfully -* @unbind: a subdevice is leaving */ struct v4l2_async_notifier { +const struct v4l2_async_notifier_operations *ops;unsigned int num_subdevs;unsigned int max_subdevs;struct v4l2_async_subdev **subdevs;
@@ -100,13 +116,6 @@ struct v4l2_async_notifier {struct list_head waiting;struct list_head done;struct list_head list; -int (*bound)(struct v4l2_async_notifier *notifier, -struct v4l2_subdev *subdev, -struct v4l2_async_subdev *asd); -int (*complete)(struct v4l2_async_notifier *notifier); -void (*unbind)(struct v4l2_async_notifier *notifier, -struct v4l2_subdev *subdev, -struct v4l2_async_subdev *asd); };/**
Signature · 6 lines
2.11.0 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v14 11/28 v4l: async: Introduce helpers for calling async ops callbacks
In reply to a message not in the archiveAdd three helper functions to call async operations callbacks. Besides simplifying callbacks, this allows async notifiers to have no ops set, i.e. it can be left NULL.
--- drivers/media/v4l2-core/v4l2-async.c | 49 ++++++++++++++++++++++++++---------- include/media/v4l2-async.h | 1 + 2 files changed, 37 insertions(+), 13 deletions(-)
drivers/media/v4l2-core/v4l2-async.c +36 -13
@@ -25,6 +25,34 @@#include <media/v4l2-fwnode.h> #include <media/v4l2-subdev.h> +static int v4l2_async_notifier_call_bound (struct v4l2_async_notifier *n, +struct v4l2_subdev *subdev, +struct v4l2_async_subdev *asd) +{ +if (!n->ops || !n->ops->bound) +return 0 ; + +return n->ops->bound (n, subdev, asd); +} + +static void v4l2_async_notifier_call_unbind (struct v4l2_async_notifier *n, +struct v4l2_subdev *subdev, +struct v4l2_async_subdev *asd) +{ +if (!n->ops || !n->ops->unbind) +return ; + + n->ops->unbind (n, subdev, asd); +} + +static int v4l2_async_notifier_call_complete (struct v4l2_async_notifier *n) +{ +if (!n->ops || !n->ops->complete) +return 0 ; + +return n->ops->complete (n); +} +static bool match_i2c (struct v4l2_subdev *sd,struct v4l2_async_subdev *asd) {#if IS_ENABLED (CONFIG_I2C )
@@ -102,16 +130,13 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier, {int ret; -if (notifier->ops->bound) { - ret = notifier->ops->bound (notifier, sd, asd); -if (ret <0 ) -return ret; - } + ret =v4l2_async_notifier_call_bound (notifier, sd, asd); +if (ret <0 ) +return ret; ret =v4l2_device_register_subdev (notifier->v4l2_dev, sd);if (ret <0 ) { -if (notifier->ops->unbind) - notifier->ops->unbind (notifier, sd, asd); +v4l2_async_notifier_call_unbind (notifier, sd, asd);return ret; }
@@ -123,8 +148,8 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,/* Move from the global subdevice list to notifier's done */ list_move (&sd->async_list, ¬ifier->done); -if (list_empty (¬ifier->waiting) && notifier->ops->complete) -return notifier->ops->complete (notifier); +if (list_empty (¬ifier->waiting)) +return v4l2_async_notifier_call_complete (notifier);return 0 ; }
@@ -210,8 +235,7 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)list_for_each_entry_safe (sd, tmp, ¬ifier->done, async_list) {v4l2_async_cleanup (sd); -if (notifier->ops->unbind) - notifier->ops->unbind (notifier, sd, sd->asd); +v4l2_async_notifier_call_unbind (notifier, sd, sd->asd);list_move (&sd->async_list, &subdev_list); }
@@ -302,8 +326,7 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)v4l2_async_cleanup (sd); -if (notifier->ops->unbind) - notifier->ops->unbind (notifier, sd, sd->asd); +v4l2_async_notifier_call_unbind (notifier, sd, sd->asd);mutex_unlock (&list_lock); }
include/media/v4l2-async.h +1 -0
@@ -164,4 +164,5 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd);* @sd: pointer to &struct v4l2_subdev */ void v4l2_async_unregister_subdev (struct v4l2_subdev *sd); +#endif
Signature · 6 lines
2.11.0 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v14 12/28 v4l: async: Register sub-devices before calling bound callback
In reply to a message not in the archiveRegister the sub-device before calling the notifier's bound callback. Doing this the other way around is problematic as the struct v4l2_device has not assigned for the sub-device yet and may be required by the bound callback.
--- drivers/media/v4l2-core/v4l2-async.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/media/v4l2-core/v4l2-async.c +3 -3
@@ -130,13 +130,13 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier, {int ret; - ret =v4l2_async_notifier_call_bound (notifier, sd, asd); + ret =v4l2_device_register_subdev (notifier->v4l2_dev, sd);if (ret <0 )return ret; - ret =v4l2_device_register_subdev (notifier->v4l2_dev, sd); + ret =v4l2_async_notifier_call_bound (notifier, sd, asd);if (ret <0 ) { -v4l2_async_notifier_call_unbind (notifier, sd, asd); +v4l2_device_unregister_subdev (sd);return ret; }
Signature · 6 lines
2.11.0 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v14 13/28 v4l: async: Allow async notifier register call succeed with no subdevs
In reply to a message not in the archiveThe information on how many async sub-devices would be bindable to a notifier is typically dependent on information from platform firmware and it's not driver's business to be aware of that.
Many V4L2 main drivers are perfectly usable (and useful) without async sub-devices and so if there aren't any around, just proceed call the notifier's complete callback immediately without registering the notifier itself.
If a driver needs to check whether there are async sub-devices available, it can be done by inspecting the notifier's num_subdevs field which tells the number of async sub-devices.
--- drivers/media/v4l2-core/v4l2-async.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
drivers/media/v4l2-core/v4l2-async.c +10 -2
@@ -170,14 +170,22 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,struct v4l2_async_subdev *asd;int i; -if (!v4l2_dev || !notifier->num_subdevs || - notifier->num_subdevs >V4L2_MAX_SUBDEVS ) +if (!v4l2_dev || notifier->num_subdevs >V4L2_MAX_SUBDEVS )return -EINVAL ; notifier->v4l2_dev = v4l2_dev;INIT_LIST_HEAD (¬ifier->waiting);INIT_LIST_HEAD (¬ifier->done); +if (!notifier->num_subdevs) { +int ret; + + ret =v4l2_async_notifier_call_complete (notifier); + notifier->v4l2_dev =NULL ; + +return ret; + } +for (i =0 ; i < notifier->num_subdevs; i++) { asd = notifier->subdevs[i];
Signature · 6 lines
2.11.0 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v14 16/28 v4l: async: Ensure only unique fwnodes are registered to notifiers
In reply to a message not in the archiveWhile registering a notifier, check that each newly added fwnode is unique, and return an error if it is not. Also check that a newly added notifier does not have the same fwnodes twice.
--- drivers/media/v4l2-core/v4l2-async.c | 88 ++++++++++++++++++++++++++++++++---- 1 file changed, 79 insertions(+), 9 deletions(-)
drivers/media/v4l2-core/v4l2-async.c +79 -9
@@ -307,8 +307,71 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd) sd->dev =NULL ; } +/* See if an fwnode can be found in a notifier's lists. */ +static bool __v4l2_async_notifier_fwnode_has_async_subdev ( +struct v4l2_async_notifier *notifier,struct fwnode_handle *fwnode) +{ +struct v4l2_async_subdev *asd; +struct v4l2_subdev *sd; + +list_for_each_entry (asd, ¬ifier->waiting, list) { +if (asd->match_type !=V4L2_ASYNC_MATCH_FWNODE ) +continue ; + +if (asd->match.fwnode.fwnode == fwnode) +return true; + } + +list_for_each_entry (sd, ¬ifier->done, async_list) { +if (WARN_ON (!sd->asd)) +continue ; + +if (sd->asd->match_type !=V4L2_ASYNC_MATCH_FWNODE ) +continue ; + +if (sd->asd->match.fwnode.fwnode == fwnode) +return true; + } + +return false; +} + +/* +* Find out whether an async sub-device was set up for an fwnode already or +* whether it exists in a given notifier before @this_index. +*/ +static bool v4l2_async_notifier_fwnode_has_async_subdev ( +struct v4l2_async_notifier *notifier,struct fwnode_handle *fwnode, +unsigned int this_index) +{ +unsigned int j; + +lockdep_assert_held (&list_lock); + +/* Check that an fwnode is not being added more than once. */ +for (j =0 ; j < this_index; j++) { +struct v4l2_async_subdev *asd = notifier->subdevs[this_index]; +struct v4l2_async_subdev *other_asd = notifier->subdevs[j]; + +if (other_asd->match_type ==V4L2_ASYNC_MATCH_FWNODE && + asd->match.fwnode.fwnode == + other_asd->match.fwnode.fwnode) +return true; + } + +/* Check than an fwnode did not exist in other notifiers. */ +list_for_each_entry (notifier, ¬ifier_list, list) +if (__v4l2_async_notifier_fwnode_has_async_subdev ( + notifier, fwnode)) +return true; + +return false; +} +static int __v4l2_async_notifier_register (struct v4l2_async_notifier *notifier) { +struct device *dev = + notifier->v4l2_dev ? notifier->v4l2_dev->dev :NULL ;struct v4l2_async_subdev *asd;int ret;int i;
@@ -319,6 +382,8 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)INIT_LIST_HEAD (¬ifier->waiting);INIT_LIST_HEAD (¬ifier->done); +mutex_lock (&list_lock); +for (i =0 ; i < notifier->num_subdevs; i++) { asd = notifier->subdevs[i];
@@ -326,30 +391,35 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)case V4L2_ASYNC_MATCH_CUSTOM :case V4L2_ASYNC_MATCH_DEVNAME :case V4L2_ASYNC_MATCH_I2C : +break ;case V4L2_ASYNC_MATCH_FWNODE : +if (v4l2_async_notifier_fwnode_has_async_subdev ( + notifier, asd->match.fwnode.fwnode, i)) { +dev_err (dev, +"fwnode has already been registered or in notifier's subdev list\n" ); + ret = -EEXIST ; + goto out_unlock; + }break ;default : -dev_err (notifier->v4l2_dev ? notifier->v4l2_dev->dev :NULL , -"Invalid match type %u on %p\n" , +dev_err (dev,"Invalid match type %u on %p\n" , asd->match_type, asd); -return -EINVAL ; + ret = -EINVAL ; + goto out_unlock; }list_add_tail (&asd->list, ¬ifier->waiting); } -mutex_lock (&list_lock); - ret =v4l2_async_notifier_try_all_subdevs (notifier); -if (ret) { -mutex_unlock (&list_lock); -return ret; - } +if (ret) + goto out_unlock; ret =v4l2_async_notifier_try_complete (notifier);/* Keep also completed notifiers on the list */ list_add (¬ifier->list, ¬ifier_list); +out_unlock:mutex_unlock (&list_lock);return ret;
Signature · 6 lines
2.11.0 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v14 16/28] v4l: async: Ensure only unique fwnodes are registered to notifiers
Quoted 5 lines · Sakari Ailus
While registering a notifier, check that each newly added fwnode is unique, and return an error if it is not. Also check that a newly added notifier does not have the same fwnodes twice.
Signed-off-by Sakari Ailus <[email protected]>
Quoted 135 lines
--- drivers/media/v4l2-core/v4l2-async.c | 88 ++++++++++++++++++++++++++++++++---- 1 file changed, 79 insertions(+), 9 deletions(-)drivers/media/v4l2-core/v4l2-async.c +79
-9@@ -307,8 +307,71 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd) sd->dev =NULL ; } +/* See if an fwnode can be found in a notifier's lists. */ +static bool __v4l2_async_notifier_fwnode_has_async_subdev ( +struct v4l2_async_notifier *notifier,struct fwnode_handle *fwnode) +{ +struct v4l2_async_subdev *asd; +struct v4l2_subdev *sd; + +list_for_each_entry (asd, ¬ifier->waiting, list) { +if (asd->match_type !=V4L2_ASYNC_MATCH_FWNODE ) +continue ; + +if (asd->match.fwnode.fwnode == fwnode) +return true; + } + +list_for_each_entry (sd, ¬ifier->done, async_list) { +if (WARN_ON (!sd->asd)) +continue ; + +if (sd->asd->match_type !=V4L2_ASYNC_MATCH_FWNODE ) +continue ; + +if (sd->asd->match.fwnode.fwnode == fwnode) +return true; + } + +return false; +} + +/* +* Find out whether an async sub-device was set up for an fwnode already or +* whether it exists in a given notifier before @this_index. +*/ +static bool v4l2_async_notifier_fwnode_has_async_subdev ( +struct v4l2_async_notifier *notifier,struct fwnode_handle *fwnode, +unsigned int this_index) +{ +unsigned int j; + +lockdep_assert_held (&list_lock); + +/* Check that an fwnode is not being added more than once. */ +for (j =0 ; j < this_index; j++) { +struct v4l2_async_subdev *asd = notifier->subdevs[this_index]; +struct v4l2_async_subdev *other_asd = notifier->subdevs[j]; + +if (other_asd->match_type ==V4L2_ASYNC_MATCH_FWNODE && + asd->match.fwnode.fwnode == + other_asd->match.fwnode.fwnode) +return true; + } + +/* Check than an fwnode did not exist in other notifiers. */ +list_for_each_entry (notifier, ¬ifier_list, list) +if (__v4l2_async_notifier_fwnode_has_async_subdev ( + notifier, fwnode)) +return true; + +return false; +} +static int __v4l2_async_notifier_register (struct v4l2_async_notifier *notifier) { +struct device *dev = + notifier->v4l2_dev ? notifier->v4l2_dev->dev :NULL ;struct v4l2_async_subdev *asd;int ret;int i;@@ -319,6 +382,8 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)INIT_LIST_HEAD (¬ifier->waiting);INIT_LIST_HEAD (¬ifier->done); +mutex_lock (&list_lock); +for (i =0 ; i < notifier->num_subdevs; i++) { asd = notifier->subdevs[i];@@ -326,30 +391,35 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)case V4L2_ASYNC_MATCH_CUSTOM :case V4L2_ASYNC_MATCH_DEVNAME :case V4L2_ASYNC_MATCH_I2C : +break ;case V4L2_ASYNC_MATCH_FWNODE : +if (v4l2_async_notifier_fwnode_has_async_subdev ( + notifier, asd->match.fwnode.fwnode, i)) { +dev_err (dev, +"fwnode has already been registered or in notifier's subdev list\n" ); + ret = -EEXIST ; + goto out_unlock; + }break ;default : -dev_err (notifier->v4l2_dev ? notifier->v4l2_dev->dev :NULL , -"Invalid match type %u on %p\n" , +dev_err (dev,"Invalid match type %u on %p\n" , asd->match_type, asd); -return -EINVAL ; + ret = -EINVAL ; + goto out_unlock; }list_add_tail (&asd->list, ¬ifier->waiting); } -mutex_lock (&list_lock); - ret =v4l2_async_notifier_try_all_subdevs (notifier); -if (ret) { -mutex_unlock (&list_lock); -return ret; - } +if (ret) + goto out_unlock; ret =v4l2_async_notifier_try_complete (notifier);/* Keep also completed notifiers on the list */ list_add (¬ifier->list, ¬ifier_list); +out_unlock:mutex_unlock (&list_lock);return ret;
PATCH v14 18/28 dt: bindings: Add lens-focus binding for image sensors
In reply to a message not in the archiveThe lens-focus property contains a phandle to the lens voice coil driver that is associated to the sensor; typically both are contained in the same camera module.
--- Documentation/devicetree/bindings/media/video-interfaces.txt | 2 ++ 1 file changed, 2 insertions(+)
Documentation/devicetree/bindings/media/video-interfaces.txt +2 -0
@@ -74,6 +74,8 @@ Optional properties - flash-leds: An array of phandles, each referring to a flash LED, a sub-node of the LED driver device node. +- lens-focus: A phandle to the node of the focus lens controller. + Optional endpoint properties ----------------------------
Signature · 6 lines
2.11.0 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v14 22/28 v4l: async: Add a convenience function for registering sensors
In reply to a message not in the archiveAdd a convenience function for parsing firmware for information on related devices using v4l2_async_notifier_parse_fwnode_sensor_common() registering the notifier and finally the async sub-device itself.
This should be useful for sensor drivers that do not have device specific requirements related to firmware information parsing or the async framework.
--- drivers/media/v4l2-core/v4l2-async.c | 5 +++++ drivers/media/v4l2-core/v4l2-fwnode.c | 41 +++++++++++++++++++++++++++++++++++ include/media/v4l2-async.h | 22 +++++++++++++++++++ include/media/v4l2-subdev.h | 3 +++ 4 files changed, 71 insertions(+)
drivers/media/v4l2-core/v4l2-async.c +5 -0
@@ -580,6 +580,11 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd) {struct v4l2_async_notifier *notifier = sd->notifier; +if (sd->subdev_notifier) +v4l2_async_notifier_unregister (sd->subdev_notifier); +v4l2_async_notifier_cleanup (sd->subdev_notifier); +kfree (sd->subdev_notifier); +if (!sd->asd) {if (!list_empty (&sd->async_list))v4l2_async_cleanup (sd);
drivers/media/v4l2-core/v4l2-fwnode.c +41 -0
53 lines not on this page · raw message
include/media/v4l2-async.h +22 -0
@@ -173,6 +173,28 @@ void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier);int v4l2_async_register_subdev (struct v4l2_subdev *sd);/** +* v4l2_async_register_subdev_sensor_common - registers a sensor sub-device to +* the asynchronous sub-device +* framework and parse set up common +* sensor related devices +* +* @sd: pointer to struct &v4l2_subdev +* +* This function is just like v4l2_async_register_subdev() with the exception +* that calling it will also parse firmware interfaces for remote references +* using v4l2_async_notifier_parse_fwnode_sensor_common() and registers the +* async sub-devices. The sub-device is similarly unregistered by calling +* v4l2_async_unregister_subdev(). +* +* While registered, the subdev module is marked as in-use. +* +* An error is returned if the module is no longer loaded on any attempts +* to register it. +*/ +int __must_check v4l2_async_register_subdev_sensor_common ( +struct v4l2_subdev *sd); + +/** * v4l2_async_unregister_subdev - unregisters a sub-device to the asynchronous * subdevice framework *
include/media/v4l2-subdev.h +3 -0
@@ -793,6 +793,8 @@ struct v4l2_subdev_platform_data {* list. * @asd: Pointer to respective &struct v4l2_async_subdev. * @notifier: Pointer to the managing notifier. +* @subdev_notifier: A sub-device notifier implicitly registered for the sub- +* device using v4l2_device_register_sensor_subdev(). * @pdata: common part of subdevice platform data * * Each instance of a subdev driver should create this struct, either
@@ -823,6 +825,7 @@ struct v4l2_subdev {struct list_head async_list;struct v4l2_async_subdev *asd;struct v4l2_async_notifier *notifier; +struct v4l2_async_notifier *subdev_notifier;struct v4l2_subdev_platform_data *pdata; };
Signature · 6 lines
2.11.0 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): 20170925222540.371-23-sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected]
Hans Verkuil
Acked-byRe: [PATCH v14 22/28] v4l: async: Add a convenience function for registering sensors
Quoted 9 lines · Sakari Ailus
Add a convenience function for parsing firmware for information on related devices using
v4l2_async_notifier_parse_fwnode_sensor_common()registering the notifier and finally the async sub-device itself.This should be useful for sensor drivers that do not have device specific requirements related to firmware information parsing or the async framework.
Nice, makes sense.
Regards,
Hans
Quoted 130 lines
--- drivers/media/v4l2-core/v4l2-async.c | 5 +++++ drivers/media/v4l2-core/v4l2-fwnode.c | 41 +++++++++++++++++++++++++++++++++++ include/media/v4l2-async.h | 22 +++++++++++++++++++ include/media/v4l2-subdev.h | 3 +++ 4 files changed, 71 insertions(+)drivers/media/v4l2-core/v4l2-async.c +5
-0@@ -580,6 +580,11 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd) {struct v4l2_async_notifier *notifier = sd->notifier; +if (sd->subdev_notifier) +v4l2_async_notifier_unregister (sd->subdev_notifier); +v4l2_async_notifier_cleanup (sd->subdev_notifier); +kfree (sd->subdev_notifier); +if (!sd->asd) {if (!list_empty (&sd->async_list))v4l2_async_cleanup (sd);drivers/media/v4l2-core/v4l2-fwnode.c +41
-0@@ -29,6 +29,7 @@#include <media/v4l2-async.h> #include <media/v4l2-fwnode.h> +#include <media/v4l2-subdev.h> enum v4l2_fwnode_bus_type {V4L2_FWNODE_BUS_TYPE_GUESS =0 ,@@ -814,6 +815,46 @@ int v4l2_async_notifier_parse_fwnode_sensor_common( }EXPORT_SYMBOL_GPL (v4l2_async_notifier_parse_fwnode_sensor_common); +int v4l2_async_register_subdev_sensor_common (struct v4l2_subdev *sd) +{ +struct v4l2_async_notifier *notifier; +int ret; + +if (WARN_ON (!sd->dev)) +return -ENODEV ; + + notifier =kzalloc (sizeof (*notifier),GFP_KERNEL ); +if (!notifier) +return -ENOMEM ; + + ret =v4l2_async_notifier_parse_fwnode_sensor_common (sd->dev, + notifier); +if (ret <0 ) + goto out_cleanup; + + ret =v4l2_async_subdev_notifier_register (sd, notifier); +if (ret <0 ) + goto out_cleanup; + + ret =v4l2_async_register_subdev (sd); +if (ret <0 ) + goto out_unregister; + + sd->subdev_notifier = notifier; + +return 0 ; + +out_unregister: +v4l2_async_notifier_unregister (notifier); + +out_cleanup: +v4l2_async_notifier_cleanup (notifier); +kfree (notifier); + +return ret; +} +EXPORT_SYMBOL_GPL (v4l2_async_register_subdev_sensor_common); +MODULE_LICENSE ("GPL" );MODULE_AUTHOR ("Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected]>" );MODULE_AUTHOR ("Sylwester Nawrocki <[email protected]>" );include/media/v4l2-async.h +22
-0@@ -173,6 +173,28 @@ void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier);int v4l2_async_register_subdev (struct v4l2_subdev *sd);/** +* v4l2_async_register_subdev_sensor_common - registers a sensor sub-device to +* the asynchronous sub-device +* framework and parse set up common +* sensor related devices +* +* @sd: pointer to struct &v4l2_subdev +* +* This function is just like v4l2_async_register_subdev() with the exception +* that calling it will also parse firmware interfaces for remote references +* using v4l2_async_notifier_parse_fwnode_sensor_common() and registers the +* async sub-devices. The sub-device is similarly unregistered by calling +* v4l2_async_unregister_subdev(). +* +* While registered, the subdev module is marked as in-use. +* +* An error is returned if the module is no longer loaded on any attempts +* to register it. +*/ +int __must_check v4l2_async_register_subdev_sensor_common ( +struct v4l2_subdev *sd); + +/** * v4l2_async_unregister_subdev - unregisters a sub-device to the asynchronous * subdevice framework * include/media/v4l2-subdev.h +2
-0@@ -793,6 +793,8 @@ struct v4l2_subdev_platform_data {* list. * @asd: Pointer to respective &struct v4l2_async_subdev. * @notifier: Pointer to the managing notifier. +* @subdev_notifier: A sub-device notifier implicitly registered for the sub- +* device using v4l2_device_register_sensor_subdev(). * @pdata: common part of subdevice platform data * * Each instance of a subdev driver should create this struct, either
include/media/v4l2-subdev.h struct v4l2_subdev { · line 831
Quoted 7 lines
include/media/v4l2-subdev.h +1
-0@@ -823,6 +825,7 @@ struct v4l2_subdev {struct list_head async_list;struct v4l2_async_subdev *asd;struct v4l2_async_notifier *notifier; +struct v4l2_async_notifier *subdev_notifier;struct v4l2_subdev_platform_data *pdata; };
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v14 24/28 smiapp: Add support for flash and lens devices
In reply to a message not in the archiveParse async sub-devices related to the sensor by switching the async sub-device registration function.
These types devices aren't directly related to the sensor, but are nevertheless handled by the smiapp driver due to the relationship of these component to the main part of the camera module --- the sensor.
This does not yet address providing the user space with information on how to associate the sensor or lens devices but the kernel now has the necessary information to do that.
--- drivers/media/i2c/smiapp/smiapp-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/i2c/smiapp/smiapp-core.c +1 -1
@@ -3092,7 +3092,7 @@ static int smiapp_probe(struct i2c_client *client,if (rval <0 ) goto out_media_entity_cleanup; - rval =v4l2_async_register_subdev (&sensor->src->sd); + rval =v4l2_async_register_subdev_sensor_common (&sensor->src->sd);if (rval <0 ) goto out_media_entity_cleanup;
Signature · 6 lines
2.11.0 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): 20170925222540.371-26-sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected]
Hans Verkuil
Acked-byRe: [PATCH v14 24/28] smiapp: Add support for flash and lens devices
Quoted 7 lines · Sakari Ailus
Parse async sub-devices related to the sensor by switching the async sub-device registration function.
These types devices aren't directly related to the sensor, but are nevertheless handled by the smiapp driver due to the relationship of these component to the main part of the camera module --- the sensor.
Quoted 5 lines
This does not yet address providing the user space with information on how to associate the sensor or lens devices but the kernel now has the necessary information to do that.
Quoted 10 lines
--- drivers/media/i2c/smiapp/smiapp-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/media/i2c/smiapp/smiapp-core.c +0
-0
drivers/media/i2c/smiapp/smiapp-core.c static int smiapp_probe(struct i2c_client *client, · line 3098
Quoted 8 lines
drivers/media/i2c/smiapp/smiapp-core.c +1
-1@@ -3092,7 +3092,7 @@ static int smiapp_probe(struct i2c_client *client,if (rval <0 ) goto out_media_entity_cleanup; - rval =v4l2_async_register_subdev (&sensor->src->sd); + rval =v4l2_async_register_subdev_sensor_common (&sensor->src->sd);if (rval <0 ) goto out_media_entity_cleanup;
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v14 26/28 ov5670: Add support for flash and lens devices
In reply to a message not in the archiveParse async sub-devices related to the sensor by switching the async sub-device registration function.
--- drivers/media/i2c/ov5670.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/i2c/ov5670.c +1 -1
@@ -2514,7 +2514,7 @@ static int ov5670_probe(struct i2c_client *client) }/* Async register for subdev */ - ret =v4l2_async_register_subdev (&ov5670->sd); + ret =v4l2_async_register_subdev_sensor_common (&ov5670->sd);if (ret <0 ) { err_msg ="v4l2_async_register_subdev() error" ; goto error_entity_cleanup;
Signature · 6 lines
2.11.0 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v14 26/28] ov5670: Add support for flash and lens devices
Quoted 4 lines · Sakari Ailus
Parse async sub-devices related to the sensor by switching the async sub-device registration function.
Signed-off-by Sakari Ailus <[email protected]>
Quoted 18 lines
--- drivers/media/i2c/ov5670.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/media/i2c/ov5670.c +1
-1@@ -2514,7 +2514,7 @@ static int ov5670_probe(struct i2c_client *client) }/* Async register for subdev */ - ret =v4l2_async_register_subdev (&ov5670->sd); + ret =v4l2_async_register_subdev_sensor_common (&ov5670->sd);if (ret <0 ) { err_msg ="v4l2_async_register_subdev() error" ; goto error_entity_cleanup;
PATCH v14 28/28 arm: dts: omap3: N9/N950: Add flash references to the camera
In reply to a message not in the archiveAdd flash and indicator LED phandles to the sensor node.
--- arch/arm/boot/dts/omap3-n9.dts | 1 + arch/arm/boot/dts/omap3-n950-n9.dtsi | 4 ++-- arch/arm/boot/dts/omap3-n950.dts | 1 + 3 files changed, 4 insertions(+), 2 deletions(-)
arch/arm/boot/dts/omap3-n9.dts +1 -0
@@ -26,6 +26,7 @@ clocks = <&isp 0>; clock-frequency = <9600000>; nokia,nvm-size = <(16 * 64)>; + flash-leds = <&as3645a_flash &as3645a_indicator>; port { smia_1_1: endpoint { link-frequencies = /bits/ 64 <199200000 210000000 499200000>;
arch/arm/boot/dts/omap3-n950-n9.dtsi +2 -2
@@ -271,14 +271,14 @@ #size-cells = <0>; reg = <0x30>; compatible = "ams,as3645a"; - flash@0 { + as3645a_flash: flash@0 { reg = <0x0>; flash-timeout-us = <150000>; flash-max-microamp = <320000>; led-max-microamp = <60000>; ams,input-max-microamp = <1750000>; }; - indicator@1 { + as3645a_indicator: indicator@1 { reg = <0x1>; led-max-microamp = <10000>; };
arch/arm/boot/dts/omap3-n950.dts +1 -0
@@ -60,6 +60,7 @@ clocks = <&isp 0>; clock-frequency = <9600000>; nokia,nvm-size = <(16 * 64)>; + flash-leds = <&as3645a_flash &as3645a_indicator>; port { smia_1_1: endpoint { link-frequencies = /bits/ 64 <210000000 333600000 398400000>;
Signature · 6 lines
2.11.0 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Sakari Ailus
maintainerPATCH v14 2/28 v4l: async: Remove re-probing support
In reply to Sakari AilusRemove V4L2 async re-probing support. The re-probing support has been there to support cases where the sub-devices require resources provided by the main driver's hardware to function, such as clocks.
Reprobing has allowed unbinding and again binding the main driver without explicilty unbinding the sub-device drivers. This is certainly not a common need, and the responsibility will be the user's going forward.
An alternative could have been to introduce notifier specific locks. Considering the complexity of the re-probing and that it isn't really a solution to a problem but a workaround, remove re-probing instead.
--- drivers/media/v4l2-core/v4l2-async.c | 54 +----------------------------------- 1 file changed, 1 insertion(+), 53 deletions(-)
drivers/media/v4l2-core/v4l2-async.c +1 -53
@@ -198,78 +198,26 @@ EXPORT_SYMBOL(v4l2_async_notifier_register);void v4l2_async_notifier_unregister (struct v4l2_async_notifier *notifier) {struct v4l2_subdev *sd, *tmp; -unsigned int notif_n_subdev = notifier->num_subdevs; -unsigned int n_subdev =min (notif_n_subdev,V4L2_MAX_SUBDEVS ); -struct device **dev; -int i =0 ;if (!notifier->v4l2_dev)return ; - dev =kvmalloc_array (n_subdev,sizeof (*dev),GFP_KERNEL ); -if (!dev) { -dev_err (notifier->v4l2_dev->dev, -"Failed to allocate device cache!\n" ); - } -mutex_lock (&list_lock);list_del (¬ifier->list);list_for_each_entry_safe (sd, tmp, ¬ifier->done, async_list) { -struct device *d; - - d =get_device (sd->dev); -v4l2_async_cleanup (sd); -/* If we handled USB devices, we'd have to lock the parent too */ -device_release_driver (d); -if (notifier->unbind) notifier->unbind (notifier, sd, sd->asd); -/* -* Store device at the device cache, in order to call -* put_device() on the final step -*/ -if (dev) - dev[i++] = d; -else -put_device (d); +list_move (&sd->async_list, &subdev_list); }mutex_unlock (&list_lock); -/* -* Call device_attach() to reprobe devices -* -* NOTE: If dev allocation fails, i is 0, and the whole loop won't be -* executed. -*/ -while (i--) { -struct device *d = dev[i]; - -if (d &&device_attach (d) <0 ) { -const char *name ="(none)" ; -int lock =device_trylock (d); - -if (lock && d->driver) - name = d->driver->name; -dev_err (d,"Failed to re-probe to %s\n" , name); -if (lock) -device_unlock (d); - } -put_device (d); - } -kvfree (dev); - notifier->v4l2_dev =NULL ; - -/* -* Don't care about the waiting list, it is initialised and populated -* upon notifier registration. -*/ }EXPORT_SYMBOL (v4l2_async_notifier_unregister);
Signature · 1 line
2.11.0
Sakari Ailus
maintainerPATCH v14 3/28 v4l: async: Use more intuitive names for internal functions
In reply to Sakari AilusRename internal functions to make the names of the functions better describe what they do.
Old name New name
v4l2_async_test_notify v4l2_async_match_notify
v4l2_async_belongs v4l2_async_find_match
--- drivers/media/v4l2-core/v4l2-async.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-)
drivers/media/v4l2-core/v4l2-async.c +10 -9
@@ -60,8 +60,8 @@ static LIST_HEAD(subdev_list);static LIST_HEAD (notifier_list);static DEFINE_MUTEX (list_lock); -static struct v4l2_async_subdev *v4l2_async_belongs (struct v4l2_async_notifier *notifier, -struct v4l2_subdev *sd) +static struct v4l2_async_subdev *v4l2_async_find_match ( +struct v4l2_async_notifier *notifier,struct v4l2_subdev *sd) {bool (*match)(struct v4l2_subdev *,struct v4l2_async_subdev *);struct v4l2_async_subdev *asd;
@@ -95,9 +95,9 @@ static struct v4l2_async_subdev *v4l2_async_belongs(struct v4l2_async_notifier *return NULL ; } -static int v4l2_async_test_notify (struct v4l2_async_notifier *notifier, -struct v4l2_subdev *sd, -struct v4l2_async_subdev *asd) +static int v4l2_async_match_notify (struct v4l2_async_notifier *notifier, +struct v4l2_subdev *sd, +struct v4l2_async_subdev *asd) {int ret;
@@ -175,11 +175,11 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,list_for_each_entry_safe (sd, tmp, &subdev_list, async_list) {int ret; - asd =v4l2_async_belongs (notifier, sd); + asd =v4l2_async_find_match (notifier, sd);if (!asd)continue ; - ret =v4l2_async_test_notify (notifier, sd, asd); + ret =v4l2_async_match_notify (notifier, sd, asd);if (ret <0 ) {mutex_unlock (&list_lock);return ret;
@@ -238,9 +238,10 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)INIT_LIST_HEAD (&sd->async_list);list_for_each_entry (notifier, ¬ifier_list, list) { -struct v4l2_async_subdev *asd =v4l2_async_belongs (notifier, sd); +struct v4l2_async_subdev *asd =v4l2_async_find_match (notifier, + sd);if (asd) { -int ret =v4l2_async_test_notify (notifier, sd, asd); +int ret =v4l2_async_match_notify (notifier, sd, asd);mutex_unlock (&list_lock);return ret; }
Signature · 1 line
2.11.0
Sakari Ailus
maintainerPATCH v14 4/28 v4l: async: Add V4L2 async documentation to the documentation build
In reply to Sakari AilusThe V4L2 async wasn't part of the documentation build. Fix this.
--- Documentation/media/kapi/v4l2-async.rst | 3 +++ Documentation/media/kapi/v4l2-core.rst | 1 + 2 files changed, 4 insertions(+) create mode 100644 Documentation/media/kapi/v4l2-async.rst
Documentation/media/kapi/v4l2-async.rst new file +3 -0
@@ -0,0 +1,3 @@ +V4L2 async kAPI +^^^^^^^^^^^^^^^ +.. kernel-doc:: include/media/v4l2-async.h
Documentation/media/kapi/v4l2-core.rst +1 -0
@@ -19,6 +19,7 @@ Video4Linux devices v4l2-mc v4l2-mediabus v4l2-mem2mem + v4l2-async v4l2-fwnode v4l2-rect v4l2-tuner
Signature · 1 line
2.11.0
Sakari Ailus
maintainerPATCH v14 5/28 v4l: fwnode: Support generic parsing of graph endpoints in a device
In reply to Sakari AilusAdd two functions for parsing devices graph endpoints:v4l2_async_notifier_parse_fwnode_endpoints and v4l2_async_notifier_parse_fwnode_endpoints_by_port. The former iterates over all endpoints whereas the latter only iterates over the endpoints in a given port.
The former is mostly useful for existing drivers that currently implement the iteration over all the endpoints themselves whereas the latter is especially intended for devices with both sinks and sources: async sub-devices for external devices connected to the device's sources will have already been set up, or they are part of the master device.
--- drivers/media/v4l2-core/v4l2-async.c | 30 ++++++ drivers/media/v4l2-core/v4l2-fwnode.c | 196 ++++++++++++++++++++++++++++++++++ include/media/v4l2-async.h | 24 ++++- include/media/v4l2-fwnode.h | 118 ++++++++++++++++++++ 4 files changed, 366 insertions(+), 2 deletions(-)
drivers/media/v4l2-core/v4l2-async.c +30 -0
@@ -22,6 +22,7 @@#include <media/v4l2-async.h> #include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> #include <media/v4l2-subdev.h> static bool match_i2c (struct v4l2_subdev *sd,struct v4l2_async_subdev *asd)
@@ -221,6 +222,35 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) }EXPORT_SYMBOL (v4l2_async_notifier_unregister); +void v4l2_async_notifier_cleanup (struct v4l2_async_notifier *notifier) +{ +unsigned int i; + +if (!notifier->max_subdevs) +return ; + +for (i =0 ; i < notifier->num_subdevs; i++) { +struct v4l2_async_subdev *asd = notifier->subdevs[i]; + +switch (asd->match_type) { +case V4L2_ASYNC_MATCH_FWNODE : +fwnode_handle_put (asd->match.fwnode.fwnode); +break ; +default : +WARN_ON_ONCE (true); + } + +kfree (asd); + } + + notifier->max_subdevs =0 ; + notifier->num_subdevs =0 ; + +kvfree (notifier->subdevs); + notifier->subdevs =NULL ; +} +EXPORT_SYMBOL_GPL (v4l2_async_notifier_cleanup); +int v4l2_async_register_subdev (struct v4l2_subdev *sd) {struct v4l2_async_notifier *notifier;
drivers/media/v4l2-core/v4l2-fwnode.c +196 -0
214 lines not on this page · raw message
include/media/v4l2-async.h +22 -2
@@ -18,7 +18,6 @@ struct device;struct device_node ;struct v4l2_device ;struct v4l2_subdev ; -struct v4l2_async_notifier ;/* A random max subdevice number, used to allocate an array on stack */ #define V4L2_MAX_SUBDEVS 128U
@@ -50,6 +49,10 @@ enum v4l2_async_match_type {* @match: union of per-bus type matching data sets * @list: used to link struct v4l2_async_subdev objects, waiting to be * probed, to a notifier->waiting list +* +* When this struct is used as a member in a driver specific struct, +* the driver specific struct shall contain the &struct +* v4l2_async_subdev as its first member. */ struct v4l2_async_subdev {enum v4l2_async_match_type match_type;
@@ -78,7 +81,8 @@ struct v4l2_async_subdev {/** * struct v4l2_async_notifier - v4l2_device notifier data * -* @num_subdevs: number of subdevices +* @num_subdevs: number of subdevices used in the subdevs array +* @max_subdevs: number of subdevices allocated in the subdevs array * @subdevs: array of pointers to subdevice descriptors * @v4l2_dev: pointer to struct v4l2_device * @waiting: list of struct v4l2_async_subdev, waiting for their drivers
@@ -90,6 +94,7 @@ struct v4l2_async_subdev {*/ struct v4l2_async_notifier {unsigned int num_subdevs; +unsigned int max_subdevs;struct v4l2_async_subdev **subdevs;struct v4l2_device *v4l2_dev;struct list_head waiting;
@@ -121,6 +126,21 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,void v4l2_async_notifier_unregister (struct v4l2_async_notifier *notifier);/** +* v4l2_async_notifier_cleanup - clean up notifier resources +* @notifier: the notifier the resources of which are to be cleaned up +* +* Release memory resources related to a notifier, including the async +* sub-devices allocated for the purposes of the notifier but not the notifier +* itself. The user is responsible for calling this function to clean up the +* notifier after calling @v4l2_async_notifier_parse_fwnode_endpoints. +* +* There is no harm from calling v4l2_async_notifier_cleanup in other +* cases as long as its memory has been zeroed after it has been +* allocated. +*/ +void v4l2_async_notifier_cleanup (struct v4l2_async_notifier *notifier); + +/** * v4l2_async_register_subdev - registers a sub-device to the asynchronous * subdevice framework *
include/media/v4l2-fwnode.h +118 -0
128 lines not on this page · raw message
Signature · 1 line
2.11.0
A message that is not in the archive (sent off-list or not yet received): 20170925222540.371-6-sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected]
Hans Verkuil
Acked-byRe: [PATCH v14 05/28] v4l: fwnode: Support generic parsing of graph endpoints in a device
Quoted 6 lines · Sakari Ailus
Add two functions for parsing devices graph endpoints:
v4l2_async_notifier_parse_fwnode_endpointsandv4l2_async_notifier_parse_fwnode_endpoints_by_port. The former iterates over all endpoints whereas the latter only iterates over the endpoints in a given port.
Quoted 7 lines
The former is mostly useful for existing drivers that currently implement the iteration over all the endpoints themselves whereas the latter is especially intended for devices with both sinks and sources: async sub-devices for external devices connected to the device's sources will have already been set up, or they are part of the master device.
I have two small comments below. After fixing that you can add my:
Regards,
Hans
Quoted 29 lines
--- drivers/media/v4l2-core/v4l2-async.c | 30 ++++++ drivers/media/v4l2-core/v4l2-fwnode.c | 196 ++++++++++++++++++++++++++++++++++ include/media/v4l2-async.h | 24 ++++- include/media/v4l2-fwnode.h | 118 ++++++++++++++++++++ 4 files changed, 366 insertions(+), 2 deletions(-)drivers/media/v4l2-core/v4l2-async.c +7
-0@@ -22,6 +22,7 @@#include <media/v4l2-async.h> #include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> #include <media/v4l2-subdev.h> static bool match_i2c (struct v4l2_subdev *sd,struct v4l2_async_subdev *asd)@@ -221,6 +222,35 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) }EXPORT_SYMBOL (v4l2_async_notifier_unregister); +void v4l2_async_notifier_cleanup (struct v4l2_async_notifier *notifier) +{ +unsigned int i; + +if (!notifier->max_subdevs) +return ;
drivers/media/v4l2-core/v4l2-async.c void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) · line 240
Quoted 10 lines
drivers/media/v4l2-core/v4l2-async.c +10
-0+ +for (i =0 ; i < notifier->num_subdevs; i++) { +struct v4l2_async_subdev *asd = notifier->subdevs[i]; + +switch (asd->match_type) { +case V4L2_ASYNC_MATCH_FWNODE : +fwnode_handle_put (asd->match.fwnode.fwnode); +break ; +default : +WARN_ON_ONCE (true);
Missing break.
Quoted 121 lines
drivers/media/v4l2-core/v4l2-async.c +13
-0+ } + +kfree (asd); + } + + notifier->max_subdevs =0 ; + notifier->num_subdevs =0 ; + +kvfree (notifier->subdevs); + notifier->subdevs =NULL ; +} +EXPORT_SYMBOL_GPL (v4l2_async_notifier_cleanup); +int v4l2_async_register_subdev (struct v4l2_subdev *sd) {struct v4l2_async_notifier *notifier;drivers/media/v4l2-core/v4l2-fwnode.c +83
-0@@ -19,6 +19,7 @@*/ #include <linux/acpi.h> #include <linux/kernel.h> +#include <linux/mm.h> #include <linux/module.h> #include <linux/of.h> #include <linux/property.h> @@ -26,6 +27,7 @@#include <linux/string.h> #include <linux/types.h> +#include <media/v4l2-async.h> #include <media/v4l2-fwnode.h> enum v4l2_fwnode_bus_type {@@ -313,6 +315,200 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) }EXPORT_SYMBOL_GPL (v4l2_fwnode_put_link); +static int v4l2_async_notifier_realloc (struct v4l2_async_notifier *notifier, +unsigned int max_subdevs) +{ +struct v4l2_async_subdev **subdevs; + +if (max_subdevs <= notifier->max_subdevs) +return 0 ; + + subdevs =kvmalloc_array ( + max_subdevs,sizeof (*notifier->subdevs), +GFP_KERNEL | __GFP_ZERO); +if (!subdevs) +return -ENOMEM ; + +if (notifier->subdevs) { +memcpy (subdevs, notifier->subdevs, +sizeof (*subdevs) * notifier->num_subdevs); + +kvfree (notifier->subdevs); + } + + notifier->subdevs = subdevs; + notifier->max_subdevs = max_subdevs; + +return 0 ; +} + +static int v4l2_async_notifier_fwnode_parse_endpoint ( +struct device *dev,struct v4l2_async_notifier *notifier, +struct fwnode_handle *endpoint,unsigned int asd_struct_size, +int (*parse_endpoint)(struct device *dev, +struct v4l2_fwnode_endpoint *vep, +struct v4l2_async_subdev *asd)) +{ +struct v4l2_async_subdev *asd; +struct v4l2_fwnode_endpoint *vep; +int ret =0 ; + + asd =kzalloc (asd_struct_size,GFP_KERNEL ); +if (!asd) +return -ENOMEM ; + + asd->match_type =V4L2_ASYNC_MATCH_FWNODE ; + asd->match.fwnode.fwnode = +fwnode_graph_get_remote_port_parent (endpoint); +if (!asd->match.fwnode.fwnode) { +dev_warn (dev,"bad remote port parent\n" ); + ret = -EINVAL ; + goto out_err; + } + + vep =v4l2_fwnode_endpoint_alloc_parse (endpoint); +if (IS_ERR (vep)) { + ret =PTR_ERR (vep); +dev_warn (dev,"unable to parse V4L2 fwnode endpoint (%d)\n" , + ret); + goto out_err; + } + + ret = parse_endpoint ?parse_endpoint (dev, vep, asd) :0 ; +if (ret == -ENOTCONN ) +dev_dbg (dev,"ignoring port@%u/endpoint@%u\n" , vep->base.port, + vep->base.id); +else if (ret <0 ) +dev_warn (dev, +"driver could not parse port@%u/endpoint@%u (%d)\n" , + vep->base.port, vep->base.id, ret); +v4l2_fwnode_endpoint_free (vep); +if (ret <0 ) + goto out_err; + + notifier->subdevs[notifier->num_subdevs] = asd; + notifier->num_subdevs++; + +return 0 ; + +out_err: +fwnode_handle_put (asd->match.fwnode.fwnode); +kfree (asd); + +return ret == -ENOTCONN ?0 : ret;
drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 408
Quoted 10 lines
drivers/media/v4l2-core/v4l2-fwnode.c +10
-0+} + +static int __v4l2_async_notifier_parse_fwnode_endpoints ( +struct device *dev,struct v4l2_async_notifier *notifier, +size_t asd_struct_size,unsigned int port,bool has_port, +int (*parse_endpoint)(struct device *dev, +struct v4l2_fwnode_endpoint *vep, +struct v4l2_async_subdev *asd)) +{ +struct fwnode_handle *fwnode =NULL ;
You can drop the = NULL since the for-loop initializes it anyway.
Quoted 294 lines
drivers/media/v4l2-core/v4l2-fwnode.c +103
-0+unsigned int max_subdevs = notifier->max_subdevs; +int ret; + +if (WARN_ON (asd_struct_size <sizeof (struct v4l2_async_subdev ))) +return -EINVAL ; + +for (fwnode =NULL ; (fwnode =fwnode_graph_get_next_endpoint ( +dev_fwnode (dev), fwnode)); ) { +struct fwnode_handle *dev_fwnode; +bool is_available; + + dev_fwnode =fwnode_graph_get_port_parent (fwnode); + is_available =fwnode_device_is_available (dev_fwnode); +fwnode_handle_put (dev_fwnode); +if (!is_available) +continue ; + +if (has_port) { +struct fwnode_endpoint ep; + + ret =fwnode_graph_parse_endpoint (fwnode, &ep); +if (ret) { +fwnode_handle_put (fwnode); +return ret; + } + +if (ep.port != port) +continue ; + } + max_subdevs++; + } + +/* No subdevs to add? Return here. */ +if (max_subdevs == notifier->max_subdevs) +return 0 ; + + ret =v4l2_async_notifier_realloc (notifier, max_subdevs); +if (ret) +return ret; + +for (fwnode =NULL ; (fwnode =fwnode_graph_get_next_endpoint ( +dev_fwnode (dev), fwnode)); ) { +struct fwnode_handle *dev_fwnode; +bool is_available; + + dev_fwnode =fwnode_graph_get_port_parent (fwnode); + is_available =fwnode_device_is_available (dev_fwnode); +fwnode_handle_put (dev_fwnode); + +if (!fwnode_device_is_available (dev_fwnode)) +continue ; + +if (WARN_ON (notifier->num_subdevs >= notifier->max_subdevs)) { + ret = -EINVAL ; +break ; + } + +if (has_port) { +struct fwnode_endpoint ep; + + ret =fwnode_graph_parse_endpoint (fwnode, &ep); +if (ret) +break ; + +if (ep.port != port) +continue ; + } + + ret =v4l2_async_notifier_fwnode_parse_endpoint ( + dev, notifier, fwnode, asd_struct_size, parse_endpoint); +if (ret <0 ) +break ; + } + +fwnode_handle_put (fwnode); + +return ret; +} + +int v4l2_async_notifier_parse_fwnode_endpoints ( +struct device *dev,struct v4l2_async_notifier *notifier, +size_t asd_struct_size, +int (*parse_endpoint)(struct device *dev, +struct v4l2_fwnode_endpoint *vep, +struct v4l2_async_subdev *asd)) +{ +return __v4l2_async_notifier_parse_fwnode_endpoints ( + dev, notifier, asd_struct_size,0 , false, parse_endpoint); +} +EXPORT_SYMBOL_GPL (v4l2_async_notifier_parse_fwnode_endpoints); + +int v4l2_async_notifier_parse_fwnode_endpoints_by_port ( +struct device *dev,struct v4l2_async_notifier *notifier, +size_t asd_struct_size,unsigned int port, +int (*parse_endpoint)(struct device *dev, +struct v4l2_fwnode_endpoint *vep, +struct v4l2_async_subdev *asd)) +{ +return __v4l2_async_notifier_parse_fwnode_endpoints ( + dev, notifier, asd_struct_size, port, true, parse_endpoint); +} +EXPORT_SYMBOL_GPL (v4l2_async_notifier_parse_fwnode_endpoints_by_port); +MODULE_LICENSE ("GPL" );MODULE_AUTHOR ("Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected]>" );MODULE_AUTHOR ("Sylwester Nawrocki <[email protected]>" );include/media/v4l2-async.h +22
-2@@ -18,7 +18,6 @@ struct device;struct device_node ;struct v4l2_device ;struct v4l2_subdev ; -struct v4l2_async_notifier ;/* A random max subdevice number, used to allocate an array on stack */ #define V4L2_MAX_SUBDEVS 128U@@ -50,6 +49,10 @@ enum v4l2_async_match_type {* @match: union of per-bus type matching data sets * @list: used to link struct v4l2_async_subdev objects, waiting to be * probed, to a notifier->waiting list +* +* When this struct is used as a member in a driver specific struct, +* the driver specific struct shall contain the &struct +* v4l2_async_subdev as its first member. */ struct v4l2_async_subdev {enum v4l2_async_match_type match_type;@@ -78,7 +81,8 @@ struct v4l2_async_subdev {/** * struct v4l2_async_notifier - v4l2_device notifier data * -* @num_subdevs: number of subdevices +* @num_subdevs: number of subdevices used in the subdevs array +* @max_subdevs: number of subdevices allocated in the subdevs array * @subdevs: array of pointers to subdevice descriptors * @v4l2_dev: pointer to struct v4l2_device * @waiting: list of struct v4l2_async_subdev, waiting for their drivers @@ -90,6 +94,7 @@ struct v4l2_async_subdev {*/ struct v4l2_async_notifier {unsigned int num_subdevs; +unsigned int max_subdevs;struct v4l2_async_subdev **subdevs;struct v4l2_device *v4l2_dev;struct list_head waiting;@@ -121,6 +126,21 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,void v4l2_async_notifier_unregister (struct v4l2_async_notifier *notifier);/** +* v4l2_async_notifier_cleanup - clean up notifier resources +* @notifier: the notifier the resources of which are to be cleaned up +* +* Release memory resources related to a notifier, including the async +* sub-devices allocated for the purposes of the notifier but not the notifier +* itself. The user is responsible for calling this function to clean up the +* notifier after calling @v4l2_async_notifier_parse_fwnode_endpoints. +* +* There is no harm from calling v4l2_async_notifier_cleanup in other +* cases as long as its memory has been zeroed after it has been +* allocated. +*/ +void v4l2_async_notifier_cleanup (struct v4l2_async_notifier *notifier); + +/** * v4l2_async_register_subdev - registers a sub-device to the asynchronous * subdevice framework * include/media/v4l2-fwnode.h +109
-0@@ -25,6 +25,8 @@#include <media/v4l2-mediabus.h> struct fwnode_handle ; +struct v4l2_async_notifier ; +struct v4l2_async_subdev ;#define V4L2_FWNODE_CSI2_MAX_DATA_LANES 4@@ -201,4 +203,120 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,*/ void v4l2_fwnode_put_link (struct v4l2_fwnode_link *link); +/** +* v4l2_async_notifier_parse_fwnode_endpoints - Parse V4L2 fwnode endpoints in a +* device node +* @dev: the device the endpoints of which are to be parsed +* @notifier: notifier for @dev +* @asd_struct_size: size of the driver's async sub-device struct, including +* sizeof(struct v4l2_async_subdev). The &struct +* v4l2_async_subdev shall be the first member of +* the driver's async sub-device struct, i.e. both +* begin at the same memory address. +* @parse_endpoint: Driver's callback function called on each V4L2 fwnode +* endpoint. Optional. +* Return: %0 on success +* %-ENOTCONN if the endpoint is to be skipped but this +* should not be considered as an error +* %-EINVAL if the endpoint configuration is invalid +* +* Parse the fwnode endpoints of the @dev device and populate the async sub- +* devices array of the notifier. The @parse_endpoint callback function is +* called for each endpoint with the corresponding async sub-device pointer to +* let the caller initialize the driver-specific part of the async sub-device +* structure. +* +* The notifier memory shall be zeroed before this function is called on the +* notifier. +* +* This function may not be called on a registered notifier and may be called on +* a notifier only once. +* +* Do not change the notifier's subdevs array, take references to the subdevs +* array itself or change the notifier's num_subdevs field. This is because this +* function allocates and reallocates the subdevs array based on parsing +* endpoints. +* +* The &struct v4l2_fwnode_endpoint passed to the callback function +* @parse_endpoint is released once the function is finished. If there is a need +* to retain that configuration, the user needs to allocate memory for it. +* +* Any notifier populated using this function must be released with a call to +* v4l2_async_notifier_cleanup() after it has been unregistered and the async +* sub-devices are no longer in use, even if the function returned an error. +* +* Return: %0 on success, including when no async sub-devices are found +* %-ENOMEM if memory allocation failed +* %-EINVAL if graph or endpoint parsing failed +* Other error codes as returned by @parse_endpoint +*/ +int v4l2_async_notifier_parse_fwnode_endpoints ( +struct device *dev,struct v4l2_async_notifier *notifier, +size_t asd_struct_size, +int (*parse_endpoint)(struct device *dev, +struct v4l2_fwnode_endpoint *vep, +struct v4l2_async_subdev *asd)); + +/** +* v4l2_async_notifier_parse_fwnode_endpoints_by_port - Parse V4L2 fwnode +* endpoints of a port in a +* device node +* @dev: the device the endpoints of which are to be parsed +* @notifier: notifier for @dev +* @asd_struct_size: size of the driver's async sub-device struct, including +* sizeof(struct v4l2_async_subdev). The &struct +* v4l2_async_subdev shall be the first member of +* the driver's async sub-device struct, i.e. both +* begin at the same memory address. +* @port: port number where endpoints are to be parsed +* @parse_endpoint: Driver's callback function called on each V4L2 fwnode +* endpoint. Optional. +* Return: %0 on success +* %-ENOTCONN if the endpoint is to be skipped but this +* should not be considered as an error +* %-EINVAL if the endpoint configuration is invalid +* +* This function is just like v4l2_async_notifier_parse_fwnode_endpoints() with +* the exception that it only parses endpoints in a given port. This is useful +* on devices that have both sinks and sources: the async sub-devices connected +* to sources have already been configured by another driver (on capture +* devices). In this case the driver must know which ports to parse. +* +* Parse the fwnode endpoints of the @dev device on a given @port and populate +* the async sub-devices array of the notifier. The @parse_endpoint callback +* function is called for each endpoint with the corresponding async sub-device +* pointer to let the caller initialize the driver-specific part of the async +* sub-device structure. +* +* The notifier memory shall be zeroed before this function is called on the +* notifier the first time. +* +* This function may not be called on a registered notifier and may be called on +* a notifier only once per port. +* +* Do not change the notifier's subdevs array, take references to the subdevs +* array itself or change the notifier's num_subdevs field. This is because this +* function allocates and reallocates the subdevs array based on parsing +* endpoints. +* +* The &struct v4l2_fwnode_endpoint passed to the callback function +* @parse_endpoint is released once the function is finished. If there is a need +* to retain that configuration, the user needs to allocate memory for it. +* +* Any notifier populated using this function must be released with a call to +* v4l2_async_notifier_cleanup() after it has been unregistered and the async +* sub-devices are no longer in use, even if the function returned an error. +* +* Return: %0 on success, including when no async sub-devices are found +* %-ENOMEM if memory allocation failed +* %-EINVAL if graph or endpoint parsing failed
include/media/v4l2-fwnode.h int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode, · line 322
Quoted 10 lines
include/media/v4l2-fwnode.h +9
-0+* Other error codes as returned by @parse_endpoint +*/ +int v4l2_async_notifier_parse_fwnode_endpoints_by_port ( +struct device *dev,struct v4l2_async_notifier *notifier, +size_t asd_struct_size,unsigned int port, +int (*parse_endpoint)(struct device *dev, +struct v4l2_fwnode_endpoint *vep, +struct v4l2_async_subdev *asd)); +#endif /* _V4L2_FWNODE_H */
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Sakari Ailus
maintainerRe: [PATCH v14 05/28] v4l: fwnode: Support generic parsing of graph endpoints in a device
Quoted 13 lines · Hans Verkuil
Quoted 12 lines · Sakari Ailus
Add two functions for parsing devices graph endpoints:
v4l2_async_notifier_parse_fwnode_endpointsandv4l2_async_notifier_parse_fwnode_endpoints_by_port. The former iterates over all endpoints whereas the latter only iterates over the endpoints in a given port.The former is mostly useful for existing drivers that currently implement the iteration over all the endpoints themselves whereas the latter is especially intended for devices with both sinks and sources: async sub-devices for external devices connected to the device's sources will have already been set up, or they are part of the master device.
Quoted 5 lines
Quoted 1 line
Signed-off-by Sakari Ailus <[email protected]>I have two small comments below. After fixing that you can add my:
Acked-by Hans Verkuil <[email protected]>
Thanks; fixed the issues below.
Quoted 486 lines
Regards,
Hans
Quoted 29 lines
--- drivers/media/v4l2-core/v4l2-async.c | 30 ++++++ drivers/media/v4l2-core/v4l2-fwnode.c | 196 ++++++++++++++++++++++++++++++++++ include/media/v4l2-async.h | 24 ++++- include/media/v4l2-fwnode.h | 118 ++++++++++++++++++++ 4 files changed, 366 insertions(+), 2 deletions(-)drivers/media/v4l2-core/v4l2-async.c +7
-0@@ -22,6 +22,7 @@#include <media/v4l2-async.h> #include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> #include <media/v4l2-subdev.h> static bool match_i2c (struct v4l2_subdev *sd,struct v4l2_async_subdev *asd)@@ -221,6 +222,35 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) }EXPORT_SYMBOL (v4l2_async_notifier_unregister); +void v4l2_async_notifier_cleanup (struct v4l2_async_notifier *notifier) +{ +unsigned int i; + +if (!notifier->max_subdevs) +return ;drivers/media/v4l2-core/v4l2-async.c void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) · line 240
Quoted 10 lines
drivers/media/v4l2-core/v4l2-async.c +10
-0+ +for (i =0 ; i < notifier->num_subdevs; i++) { +struct v4l2_async_subdev *asd = notifier->subdevs[i]; + +switch (asd->match_type) { +case V4L2_ASYNC_MATCH_FWNODE : +fwnode_handle_put (asd->match.fwnode.fwnode); +break ; +default : +WARN_ON_ONCE (true);Missing break.
Quoted 121 lines
drivers/media/v4l2-core/v4l2-async.c +13
-0+ } + +kfree (asd); + } + + notifier->max_subdevs =0 ; + notifier->num_subdevs =0 ; + +kvfree (notifier->subdevs); + notifier->subdevs =NULL ; +} +EXPORT_SYMBOL_GPL (v4l2_async_notifier_cleanup); +int v4l2_async_register_subdev (struct v4l2_subdev *sd) {struct v4l2_async_notifier *notifier;drivers/media/v4l2-core/v4l2-fwnode.c +83
-0@@ -19,6 +19,7 @@*/ #include <linux/acpi.h> #include <linux/kernel.h> +#include <linux/mm.h> #include <linux/module.h> #include <linux/of.h> #include <linux/property.h> @@ -26,6 +27,7 @@#include <linux/string.h> #include <linux/types.h> +#include <media/v4l2-async.h> #include <media/v4l2-fwnode.h> enum v4l2_fwnode_bus_type {@@ -313,6 +315,200 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) }EXPORT_SYMBOL_GPL (v4l2_fwnode_put_link); +static int v4l2_async_notifier_realloc (struct v4l2_async_notifier *notifier, +unsigned int max_subdevs) +{ +struct v4l2_async_subdev **subdevs; + +if (max_subdevs <= notifier->max_subdevs) +return 0 ; + + subdevs =kvmalloc_array ( + max_subdevs,sizeof (*notifier->subdevs), +GFP_KERNEL | __GFP_ZERO); +if (!subdevs) +return -ENOMEM ; + +if (notifier->subdevs) { +memcpy (subdevs, notifier->subdevs, +sizeof (*subdevs) * notifier->num_subdevs); + +kvfree (notifier->subdevs); + } + + notifier->subdevs = subdevs; + notifier->max_subdevs = max_subdevs; + +return 0 ; +} + +static int v4l2_async_notifier_fwnode_parse_endpoint ( +struct device *dev,struct v4l2_async_notifier *notifier, +struct fwnode_handle *endpoint,unsigned int asd_struct_size, +int (*parse_endpoint)(struct device *dev, +struct v4l2_fwnode_endpoint *vep, +struct v4l2_async_subdev *asd)) +{ +struct v4l2_async_subdev *asd; +struct v4l2_fwnode_endpoint *vep; +int ret =0 ; + + asd =kzalloc (asd_struct_size,GFP_KERNEL ); +if (!asd) +return -ENOMEM ; + + asd->match_type =V4L2_ASYNC_MATCH_FWNODE ; + asd->match.fwnode.fwnode = +fwnode_graph_get_remote_port_parent (endpoint); +if (!asd->match.fwnode.fwnode) { +dev_warn (dev,"bad remote port parent\n" ); + ret = -EINVAL ; + goto out_err; + } + + vep =v4l2_fwnode_endpoint_alloc_parse (endpoint); +if (IS_ERR (vep)) { + ret =PTR_ERR (vep); +dev_warn (dev,"unable to parse V4L2 fwnode endpoint (%d)\n" , + ret); + goto out_err; + } + + ret = parse_endpoint ?parse_endpoint (dev, vep, asd) :0 ; +if (ret == -ENOTCONN ) +dev_dbg (dev,"ignoring port@%u/endpoint@%u\n" , vep->base.port, + vep->base.id); +else if (ret <0 ) +dev_warn (dev, +"driver could not parse port@%u/endpoint@%u (%d)\n" , + vep->base.port, vep->base.id, ret); +v4l2_fwnode_endpoint_free (vep); +if (ret <0 ) + goto out_err; + + notifier->subdevs[notifier->num_subdevs] = asd; + notifier->num_subdevs++; + +return 0 ; + +out_err: +fwnode_handle_put (asd->match.fwnode.fwnode); +kfree (asd); + +return ret == -ENOTCONN ?0 : ret;drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 408
Quoted 10 lines
drivers/media/v4l2-core/v4l2-fwnode.c +10
-0+} + +static int __v4l2_async_notifier_parse_fwnode_endpoints ( +struct device *dev,struct v4l2_async_notifier *notifier, +size_t asd_struct_size,unsigned int port,bool has_port, +int (*parse_endpoint)(struct device *dev, +struct v4l2_fwnode_endpoint *vep, +struct v4l2_async_subdev *asd)) +{ +struct fwnode_handle *fwnode =NULL ;You can drop the = NULL since the for-loop initializes it anyway.
Quoted 304 lines
drivers/media/v4l2-core/v4l2-fwnode.c +103
-0+unsigned int max_subdevs = notifier->max_subdevs; +int ret; + +if (WARN_ON (asd_struct_size <sizeof (struct v4l2_async_subdev ))) +return -EINVAL ; + +for (fwnode =NULL ; (fwnode =fwnode_graph_get_next_endpoint ( +dev_fwnode (dev), fwnode)); ) { +struct fwnode_handle *dev_fwnode; +bool is_available; + + dev_fwnode =fwnode_graph_get_port_parent (fwnode); + is_available =fwnode_device_is_available (dev_fwnode); +fwnode_handle_put (dev_fwnode); +if (!is_available) +continue ; + +if (has_port) { +struct fwnode_endpoint ep; + + ret =fwnode_graph_parse_endpoint (fwnode, &ep); +if (ret) { +fwnode_handle_put (fwnode); +return ret; + } + +if (ep.port != port) +continue ; + } + max_subdevs++; + } + +/* No subdevs to add? Return here. */ +if (max_subdevs == notifier->max_subdevs) +return 0 ; + + ret =v4l2_async_notifier_realloc (notifier, max_subdevs); +if (ret) +return ret; + +for (fwnode =NULL ; (fwnode =fwnode_graph_get_next_endpoint ( +dev_fwnode (dev), fwnode)); ) { +struct fwnode_handle *dev_fwnode; +bool is_available; + + dev_fwnode =fwnode_graph_get_port_parent (fwnode); + is_available =fwnode_device_is_available (dev_fwnode); +fwnode_handle_put (dev_fwnode); + +if (!fwnode_device_is_available (dev_fwnode)) +continue ; + +if (WARN_ON (notifier->num_subdevs >= notifier->max_subdevs)) { + ret = -EINVAL ; +break ; + } + +if (has_port) { +struct fwnode_endpoint ep; + + ret =fwnode_graph_parse_endpoint (fwnode, &ep); +if (ret) +break ; + +if (ep.port != port) +continue ; + } + + ret =v4l2_async_notifier_fwnode_parse_endpoint ( + dev, notifier, fwnode, asd_struct_size, parse_endpoint); +if (ret <0 ) +break ; + } + +fwnode_handle_put (fwnode); + +return ret; +} + +int v4l2_async_notifier_parse_fwnode_endpoints ( +struct device *dev,struct v4l2_async_notifier *notifier, +size_t asd_struct_size, +int (*parse_endpoint)(struct device *dev, +struct v4l2_fwnode_endpoint *vep, +struct v4l2_async_subdev *asd)) +{ +return __v4l2_async_notifier_parse_fwnode_endpoints ( + dev, notifier, asd_struct_size,0 , false, parse_endpoint); +} +EXPORT_SYMBOL_GPL (v4l2_async_notifier_parse_fwnode_endpoints); + +int v4l2_async_notifier_parse_fwnode_endpoints_by_port ( +struct device *dev,struct v4l2_async_notifier *notifier, +size_t asd_struct_size,unsigned int port, +int (*parse_endpoint)(struct device *dev, +struct v4l2_fwnode_endpoint *vep, +struct v4l2_async_subdev *asd)) +{ +return __v4l2_async_notifier_parse_fwnode_endpoints ( + dev, notifier, asd_struct_size, port, true, parse_endpoint); +} +EXPORT_SYMBOL_GPL (v4l2_async_notifier_parse_fwnode_endpoints_by_port); +MODULE_LICENSE ("GPL" );MODULE_AUTHOR ("Sakari Ailus <[email protected]>" );MODULE_AUTHOR ("Sylwester Nawrocki <[email protected]>" );include/media/v4l2-async.h +22
-2@@ -18,7 +18,6 @@ struct device;struct device_node ;struct v4l2_device ;struct v4l2_subdev ; -struct v4l2_async_notifier ;/* A random max subdevice number, used to allocate an array on stack */ #define V4L2_MAX_SUBDEVS 128U@@ -50,6 +49,10 @@ enum v4l2_async_match_type {* @match: union of per-bus type matching data sets * @list: used to link struct v4l2_async_subdev objects, waiting to be * probed, to a notifier->waiting list +* +* When this struct is used as a member in a driver specific struct, +* the driver specific struct shall contain the &struct +* v4l2_async_subdev as its first member. */ struct v4l2_async_subdev {enum v4l2_async_match_type match_type;@@ -78,7 +81,8 @@ struct v4l2_async_subdev {/** * struct v4l2_async_notifier - v4l2_device notifier data * -* @num_subdevs: number of subdevices +* @num_subdevs: number of subdevices used in the subdevs array +* @max_subdevs: number of subdevices allocated in the subdevs array * @subdevs: array of pointers to subdevice descriptors * @v4l2_dev: pointer to struct v4l2_device * @waiting: list of struct v4l2_async_subdev, waiting for their drivers @@ -90,6 +94,7 @@ struct v4l2_async_subdev {*/ struct v4l2_async_notifier {unsigned int num_subdevs; +unsigned int max_subdevs;struct v4l2_async_subdev **subdevs;struct v4l2_device *v4l2_dev;struct list_head waiting;@@ -121,6 +126,21 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,void v4l2_async_notifier_unregister (struct v4l2_async_notifier *notifier);/** +* v4l2_async_notifier_cleanup - clean up notifier resources +* @notifier: the notifier the resources of which are to be cleaned up +* +* Release memory resources related to a notifier, including the async +* sub-devices allocated for the purposes of the notifier but not the notifier +* itself. The user is responsible for calling this function to clean up the +* notifier after calling @v4l2_async_notifier_parse_fwnode_endpoints. +* +* There is no harm from calling v4l2_async_notifier_cleanup in other +* cases as long as its memory has been zeroed after it has been +* allocated. +*/ +void v4l2_async_notifier_cleanup (struct v4l2_async_notifier *notifier); + +/** * v4l2_async_register_subdev - registers a sub-device to the asynchronous * subdevice framework * include/media/v4l2-fwnode.h +118
-0@@ -25,6 +25,8 @@#include <media/v4l2-mediabus.h> struct fwnode_handle ; +struct v4l2_async_notifier ; +struct v4l2_async_subdev ;#define V4L2_FWNODE_CSI2_MAX_DATA_LANES 4@@ -201,4 +203,120 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,*/ void v4l2_fwnode_put_link (struct v4l2_fwnode_link *link); +/** +* v4l2_async_notifier_parse_fwnode_endpoints - Parse V4L2 fwnode endpoints in a +* device node +* @dev: the device the endpoints of which are to be parsed +* @notifier: notifier for @dev +* @asd_struct_size: size of the driver's async sub-device struct, including +* sizeof(struct v4l2_async_subdev). The &struct +* v4l2_async_subdev shall be the first member of +* the driver's async sub-device struct, i.e. both +* begin at the same memory address. +* @parse_endpoint: Driver's callback function called on each V4L2 fwnode +* endpoint. Optional. +* Return: %0 on success +* %-ENOTCONN if the endpoint is to be skipped but this +* should not be considered as an error +* %-EINVAL if the endpoint configuration is invalid +* +* Parse the fwnode endpoints of the @dev device and populate the async sub- +* devices array of the notifier. The @parse_endpoint callback function is +* called for each endpoint with the corresponding async sub-device pointer to +* let the caller initialize the driver-specific part of the async sub-device +* structure. +* +* The notifier memory shall be zeroed before this function is called on the +* notifier. +* +* This function may not be called on a registered notifier and may be called on +* a notifier only once. +* +* Do not change the notifier's subdevs array, take references to the subdevs +* array itself or change the notifier's num_subdevs field. This is because this +* function allocates and reallocates the subdevs array based on parsing +* endpoints. +* +* The &struct v4l2_fwnode_endpoint passed to the callback function +* @parse_endpoint is released once the function is finished. If there is a need +* to retain that configuration, the user needs to allocate memory for it. +* +* Any notifier populated using this function must be released with a call to +* v4l2_async_notifier_cleanup() after it has been unregistered and the async +* sub-devices are no longer in use, even if the function returned an error. +* +* Return: %0 on success, including when no async sub-devices are found +* %-ENOMEM if memory allocation failed +* %-EINVAL if graph or endpoint parsing failed +* Other error codes as returned by @parse_endpoint +*/ +int v4l2_async_notifier_parse_fwnode_endpoints ( +struct device *dev,struct v4l2_async_notifier *notifier, +size_t asd_struct_size, +int (*parse_endpoint)(struct device *dev, +struct v4l2_fwnode_endpoint *vep, +struct v4l2_async_subdev *asd)); + +/** +* v4l2_async_notifier_parse_fwnode_endpoints_by_port - Parse V4L2 fwnode +* endpoints of a port in a +* device node +* @dev: the device the endpoints of which are to be parsed +* @notifier: notifier for @dev +* @asd_struct_size: size of the driver's async sub-device struct, including +* sizeof(struct v4l2_async_subdev). The &struct +* v4l2_async_subdev shall be the first member of +* the driver's async sub-device struct, i.e. both +* begin at the same memory address. +* @port: port number where endpoints are to be parsed +* @parse_endpoint: Driver's callback function called on each V4L2 fwnode +* endpoint. Optional. +* Return: %0 on success +* %-ENOTCONN if the endpoint is to be skipped but this +* should not be considered as an error +* %-EINVAL if the endpoint configuration is invalid +* +* This function is just like v4l2_async_notifier_parse_fwnode_endpoints() with +* the exception that it only parses endpoints in a given port. This is useful +* on devices that have both sinks and sources: the async sub-devices connected +* to sources have already been configured by another driver (on capture +* devices). In this case the driver must know which ports to parse. +* +* Parse the fwnode endpoints of the @dev device on a given @port and populate +* the async sub-devices array of the notifier. The @parse_endpoint callback +* function is called for each endpoint with the corresponding async sub-device +* pointer to let the caller initialize the driver-specific part of the async +* sub-device structure. +* +* The notifier memory shall be zeroed before this function is called on the +* notifier the first time. +* +* This function may not be called on a registered notifier and may be called on +* a notifier only once per port. +* +* Do not change the notifier's subdevs array, take references to the subdevs +* array itself or change the notifier's num_subdevs field. This is because this +* function allocates and reallocates the subdevs array based on parsing +* endpoints. +* +* The &struct v4l2_fwnode_endpoint passed to the callback function +* @parse_endpoint is released once the function is finished. If there is a need +* to retain that configuration, the user needs to allocate memory for it. +* +* Any notifier populated using this function must be released with a call to +* v4l2_async_notifier_cleanup() after it has been unregistered and the async +* sub-devices are no longer in use, even if the function returned an error. +* +* Return: %0 on success, including when no async sub-devices are found +* %-ENOMEM if memory allocation failed +* %-EINVAL if graph or endpoint parsing failed +* Other error codes as returned by @parse_endpoint +*/ +int v4l2_async_notifier_parse_fwnode_endpoints_by_port ( +struct device *dev,struct v4l2_async_notifier *notifier, +size_t asd_struct_size,unsigned int port, +int (*parse_endpoint)(struct device *dev, +struct v4l2_fwnode_endpoint *vep, +struct v4l2_async_subdev *asd)); +#endif /* _V4L2_FWNODE_H */
Signature · 2 lines
Sakari Ailus [email protected]
Sakari Ailus
maintainerPATCH v14 6/28 omap3isp: Use generic parser for parsing fwnode endpoints
In reply to Sakari AilusInstead of using a custom driver implementation, use v4l2_async_notifier_parse_fwnode_endpoints() to parse the fwnode endpoints of the device.
--- drivers/media/platform/omap3isp/isp.c | 121 +++++++++++----------------------- drivers/media/platform/omap3isp/isp.h | 5 +- 2 files changed, 40 insertions(+), 86 deletions(-)
drivers/media/platform/omap3isp/isp.c +39 -82
@@ -2001,6 +2001,7 @@ static int isp_remove(struct platform_device *pdev)__omap3isp_put (isp, false);media_entity_enum_cleanup (&isp->crashed); +v4l2_async_notifier_cleanup (&isp->notifier);return 0 ; }
@@ -2011,44 +2012,41 @@ enum isp_of_phy { ISP_OF_PHY_CSIPHY2, }; -static int isp_fwnode_parse (struct device *dev,struct fwnode_handle *fwnode, -struct isp_async_subdev *isd) +static int isp_fwnode_parse (struct device *dev, +struct v4l2_fwnode_endpoint *vep, +struct v4l2_async_subdev *asd) { +struct isp_async_subdev *isd = + container_of(asd, struct isp_async_subdev, asd);struct isp_bus_cfg *buscfg = &isd->bus; -struct v4l2_fwnode_endpoint vep; -unsigned int i; -int ret;bool csi1 = false; - - ret =v4l2_fwnode_endpoint_parse (fwnode, &vep); -if (ret) -return ret; +unsigned int i;dev_dbg (dev,"parsing endpoint %pOF, interface %u\n" , -to_of_node (fwnode), vep.base.port); +to_of_node (vep->base.local_fwnode), vep->base.port); -switch (vep.base.port) { +switch (vep->base.port) {case ISP_OF_PHY_PARALLEL : buscfg->interface =ISP_INTERFACE_PARALLEL ; buscfg->bus.parallel.data_lane_shift = - vep.bus.parallel.data_shift; + vep->bus.parallel.data_shift; buscfg->bus.parallel.clk_pol = - !!(vep.bus.parallel.flags + !!(vep->bus.parallel.flags &V4L2_MBUS_PCLK_SAMPLE_FALLING ); buscfg->bus.parallel.hs_pol = - !!(vep.bus.parallel.flags &V4L2_MBUS_VSYNC_ACTIVE_LOW ); + !!(vep->bus.parallel.flags &V4L2_MBUS_VSYNC_ACTIVE_LOW ); buscfg->bus.parallel.vs_pol = - !!(vep.bus.parallel.flags &V4L2_MBUS_HSYNC_ACTIVE_LOW ); + !!(vep->bus.parallel.flags &V4L2_MBUS_HSYNC_ACTIVE_LOW ); buscfg->bus.parallel.fld_pol = - !!(vep.bus.parallel.flags &V4L2_MBUS_FIELD_EVEN_LOW ); + !!(vep->bus.parallel.flags &V4L2_MBUS_FIELD_EVEN_LOW ); buscfg->bus.parallel.data_pol = - !!(vep.bus.parallel.flags &V4L2_MBUS_DATA_ACTIVE_LOW ); - buscfg->bus.parallel.bt656 = vep.bus_type ==V4L2_MBUS_BT656 ; + !!(vep->bus.parallel.flags &V4L2_MBUS_DATA_ACTIVE_LOW ); + buscfg->bus.parallel.bt656 = vep->bus_type ==V4L2_MBUS_BT656 ;break ;case ISP_OF_PHY_CSIPHY1 :case ISP_OF_PHY_CSIPHY2 : -switch (vep.bus_type) { +switch (vep->bus_type) {case V4L2_MBUS_CCP2 :case V4L2_MBUS_CSI1 :dev_dbg (dev,"CSI-1/CCP-2 configuration\n" );
@@ -2060,11 +2058,11 @@ static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwnode,break ;default :dev_err (dev,"unsupported bus type %u\n" , - vep.bus_type); + vep->bus_type);return -EINVAL ; } -switch (vep.base.port) { +switch (vep->base.port) {case ISP_OF_PHY_CSIPHY1 :if (csi1) buscfg->interface =ISP_INTERFACE_CCP2B_PHY1 ;
@@ -2080,47 +2078,47 @@ static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwnode, }if (csi1) { buscfg->bus.ccp2.lanecfg.clk.pos = - vep.bus.mipi_csi1.clock_lane; + vep->bus.mipi_csi1.clock_lane; buscfg->bus.ccp2.lanecfg.clk.pol = - vep.bus.mipi_csi1.lane_polarity[0 ]; + vep->bus.mipi_csi1.lane_polarity[0 ];dev_dbg (dev,"clock lane polarity %u, pos %u\n" , buscfg->bus.ccp2.lanecfg.clk.pol, buscfg->bus.ccp2.lanecfg.clk.pos); buscfg->bus.ccp2.lanecfg.data[0 ].pos = - vep.bus.mipi_csi1.data_lane; + vep->bus.mipi_csi1.data_lane; buscfg->bus.ccp2.lanecfg.data[0 ].pol = - vep.bus.mipi_csi1.lane_polarity[1 ]; + vep->bus.mipi_csi1.lane_polarity[1 ];dev_dbg (dev,"data lane polarity %u, pos %u\n" , buscfg->bus.ccp2.lanecfg.data[0 ].pol, buscfg->bus.ccp2.lanecfg.data[0 ].pos); buscfg->bus.ccp2.strobe_clk_pol = - vep.bus.mipi_csi1.clock_inv; - buscfg->bus.ccp2.phy_layer = vep.bus.mipi_csi1.strobe; + vep->bus.mipi_csi1.clock_inv; + buscfg->bus.ccp2.phy_layer = vep->bus.mipi_csi1.strobe; buscfg->bus.ccp2.ccp2_mode = - vep.bus_type ==V4L2_MBUS_CCP2 ; + vep->bus_type ==V4L2_MBUS_CCP2 ; buscfg->bus.ccp2.vp_clk_pol =1 ; buscfg->bus.ccp2.crc =1 ; }else { buscfg->bus.csi2.lanecfg.clk.pos = - vep.bus.mipi_csi2.clock_lane; + vep->bus.mipi_csi2.clock_lane; buscfg->bus.csi2.lanecfg.clk.pol = - vep.bus.mipi_csi2.lane_polarities[0 ]; + vep->bus.mipi_csi2.lane_polarities[0 ];dev_dbg (dev,"clock lane polarity %u, pos %u\n" , buscfg->bus.csi2.lanecfg.clk.pol, buscfg->bus.csi2.lanecfg.clk.pos); buscfg->bus.csi2.num_data_lanes = - vep.bus.mipi_csi2.num_data_lanes; + vep->bus.mipi_csi2.num_data_lanes;for (i =0 ; i < buscfg->bus.csi2.num_data_lanes; i++) { buscfg->bus.csi2.lanecfg.data[i].pos = - vep.bus.mipi_csi2.data_lanes[i]; + vep->bus.mipi_csi2.data_lanes[i]; buscfg->bus.csi2.lanecfg.data[i].pol = - vep.bus.mipi_csi2.lane_polarities[i +1 ]; + vep->bus.mipi_csi2.lane_polarities[i +1 ]; dev_dbg(dev, "data lane %u polarity %u, pos %u\n", i, buscfg->bus.csi2.lanecfg.data[i].pol,
@@ -2137,57 +2135,13 @@ static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwnode,default :dev_warn (dev,"%pOF: invalid interface %u\n" , -to_of_node (fwnode), vep.base.port); +to_of_node (vep->base.local_fwnode), vep->base.port);return -EINVAL ; }return 0 ; } -static int isp_fwnodes_parse (struct device *dev, -struct v4l2_async_notifier *notifier) -{ -struct fwnode_handle *fwnode =NULL ; - - notifier->subdevs =devm_kcalloc ( - dev,ISP_MAX_SUBDEVS ,sizeof (*notifier->subdevs),GFP_KERNEL ); -if (!notifier->subdevs) -return -ENOMEM ; - -while (notifier->num_subdevs <ISP_MAX_SUBDEVS && - (fwnode =fwnode_graph_get_next_endpoint ( -of_fwnode_handle (dev->of_node), fwnode))) { -struct isp_async_subdev *isd; - - isd =devm_kzalloc (dev,sizeof (*isd),GFP_KERNEL ); -if (!isd) - goto error; - -if (isp_fwnode_parse (dev, fwnode, isd)) { -devm_kfree (dev, isd); -continue ; - } - - notifier->subdevs[notifier->num_subdevs] = &isd->asd; - - isd->asd.match.fwnode.fwnode = -fwnode_graph_get_remote_port_parent (fwnode); -if (!isd->asd.match.fwnode.fwnode) { -dev_warn (dev,"bad remote port parent\n" ); - goto error; - } - - isd->asd.match_type =V4L2_ASYNC_MATCH_FWNODE ; - notifier->num_subdevs++; - } - -return notifier->num_subdevs; - -error: -fwnode_handle_put (fwnode); -return -EINVAL ; -} -static int isp_subdev_notifier_complete (struct v4l2_async_notifier *async) { struct isp_device *isp = container_of(async, struct isp_device,
@@ -2256,15 +2210,17 @@ static int isp_probe(struct platform_device *pdev)if (ret)return ret; - ret =isp_fwnodes_parse (&pdev->dev, &isp->notifier); -if (ret <0 ) -return ret; - isp->autoidle = autoidle;mutex_init (&isp->isp_mutex);spin_lock_init (&isp->stat_lock); + ret =v4l2_async_notifier_parse_fwnode_endpoints ( + &pdev->dev, &isp->notifier,sizeof (struct isp_async_subdev ), + isp_fwnode_parse); +if (ret <0 ) + goto error; + isp->dev = &pdev->dev; isp->ref_count =0 ;
@@ -2406,6 +2362,7 @@ static int isp_probe(struct platform_device *pdev)isp_xclk_cleanup (isp);__omap3isp_put (isp, false); error: +v4l2_async_notifier_cleanup (&isp->notifier);mutex_destroy (&isp->isp_mutex);return ret;
drivers/media/platform/omap3isp/isp.h +1 -4
@@ -220,14 +220,11 @@ struct isp_device {unsigned int sbl_resources;unsigned int subclk_resources; - -#define ISP_MAX_SUBDEVS 8 -struct v4l2_subdev *subdevs[ISP_MAX_SUBDEVS ]; };struct isp_async_subdev { -struct isp_bus_cfg bus;struct v4l2_async_subdev asd; +struct isp_bus_cfg bus; };#define v4l2_subdev_to_bus_cfg (sd) \
Signature · 1 line
2.11.0
Sakari Ailus
maintainerPATCH v14 14/28 v4l: async: Prepare for async sub-device notifiers
In reply to Sakari AilusRefactor the V4L2 async framework a little in preparation for async sub-device notifiers.
--- drivers/media/v4l2-core/v4l2-async.c | 66 +++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 19 deletions(-)
drivers/media/v4l2-core/v4l2-async.c +47 -19
@@ -125,12 +125,13 @@ static struct v4l2_async_subdev *v4l2_async_find_match( }static int v4l2_async_match_notify (struct v4l2_async_notifier *notifier, +struct v4l2_device *v4l2_dev,struct v4l2_subdev *sd,struct v4l2_async_subdev *asd) {int ret; - ret =v4l2_device_register_subdev (notifier->v4l2_dev, sd); + ret =v4l2_device_register_subdev (v4l2_dev, sd);if (ret <0 )return ret;
@@ -154,6 +155,31 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,return 0 ; } +/* Test all async sub-devices in a notifier for a match. */ +static int v4l2_async_notifier_try_all_subdevs ( +struct v4l2_async_notifier *notifier) +{ +struct v4l2_device *v4l2_dev = notifier->v4l2_dev; +struct v4l2_subdev *sd, *tmp; + +list_for_each_entry_safe (sd, tmp, &subdev_list, async_list) { +struct v4l2_async_subdev *asd; +int ret; + + asd =v4l2_async_find_match (notifier, sd); +if (!asd) +continue ; + + ret =v4l2_async_match_notify (notifier, v4l2_dev, sd, asd); +if (ret <0 ) { +mutex_unlock (&list_lock); +return ret; + } + } + +return 0 ; +} +static void v4l2_async_cleanup (struct v4l2_subdev *sd) {v4l2_device_unregister_subdev (sd);
@@ -163,17 +189,15 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd) sd->dev =NULL ; } -int v4l2_async_notifier_register (struct v4l2_device *v4l2_dev, -struct v4l2_async_notifier *notifier) +static int __v4l2_async_notifier_register (struct v4l2_async_notifier *notifier) { -struct v4l2_subdev *sd, *tmp;struct v4l2_async_subdev *asd; +int ret;int i; -if (!v4l2_dev || notifier->num_subdevs >V4L2_MAX_SUBDEVS ) +if (notifier->num_subdevs >V4L2_MAX_SUBDEVS )return -EINVAL ; - notifier->v4l2_dev = v4l2_dev;INIT_LIST_HEAD (¬ifier->waiting);INIT_LIST_HEAD (¬ifier->done);
@@ -206,18 +230,10 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,mutex_lock (&list_lock); -list_for_each_entry_safe (sd, tmp, &subdev_list, async_list) { -int ret; - - asd =v4l2_async_find_match (notifier, sd); -if (!asd) -continue ; - - ret =v4l2_async_match_notify (notifier, sd, asd); -if (ret <0 ) { -mutex_unlock (&list_lock); -return ret; - } + ret =v4l2_async_notifier_try_all_subdevs (notifier); +if (ret) { +mutex_unlock (&list_lock); +return ret; }/* Keep also completed notifiers on the list */
@@ -227,6 +243,17 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,return 0 ; } + +int v4l2_async_notifier_register (struct v4l2_device *v4l2_dev, +struct v4l2_async_notifier *notifier) +{ +if (WARN_ON (!v4l2_dev)) +return -EINVAL ; + + notifier->v4l2_dev = v4l2_dev; + +return __v4l2_async_notifier_register (notifier); +}EXPORT_SYMBOL (v4l2_async_notifier_register);void v4l2_async_notifier_unregister (struct v4l2_async_notifier *notifier)
@@ -303,7 +330,8 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)struct v4l2_async_subdev *asd =v4l2_async_find_match (notifier, sd);if (asd) { -int ret =v4l2_async_match_notify (notifier, sd, asd); +int ret =v4l2_async_match_notify ( + notifier, notifier->v4l2_dev, sd, asd);mutex_unlock (&list_lock);return ret; }
Signature · 1 line
2.11.0
A message that is not in the archive (sent off-list or not yet received): 20170925222540.371-15-sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected]
Hans Verkuil
Acked-byRe: [PATCH v14 14/28] v4l: async: Prepare for async sub-device notifiers
Quoted 2 lines · Sakari Ailus
Refactor the V4L2 async framework a little in preparation for async sub-device notifiers.
Perhaps extend this a bit to also state the reason for these changes?
Quoted 2 lines
Anyway,
Quoted 119 lines
--- drivers/media/v4l2-core/v4l2-async.c | 66 +++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 19 deletions(-)drivers/media/v4l2-core/v4l2-async.c +45
-18@@ -125,12 +125,13 @@ static struct v4l2_async_subdev *v4l2_async_find_match( }static int v4l2_async_match_notify (struct v4l2_async_notifier *notifier, +struct v4l2_device *v4l2_dev,struct v4l2_subdev *sd,struct v4l2_async_subdev *asd) {int ret; - ret =v4l2_device_register_subdev (notifier->v4l2_dev, sd); + ret =v4l2_device_register_subdev (v4l2_dev, sd);if (ret <0 )return ret;@@ -154,6 +155,31 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,return 0 ; } +/* Test all async sub-devices in a notifier for a match. */ +static int v4l2_async_notifier_try_all_subdevs ( +struct v4l2_async_notifier *notifier) +{ +struct v4l2_device *v4l2_dev = notifier->v4l2_dev; +struct v4l2_subdev *sd, *tmp; + +list_for_each_entry_safe (sd, tmp, &subdev_list, async_list) { +struct v4l2_async_subdev *asd; +int ret; + + asd =v4l2_async_find_match (notifier, sd); +if (!asd) +continue ; + + ret =v4l2_async_match_notify (notifier, v4l2_dev, sd, asd); +if (ret <0 ) { +mutex_unlock (&list_lock); +return ret; + } + } + +return 0 ; +} +static void v4l2_async_cleanup (struct v4l2_subdev *sd) {v4l2_device_unregister_subdev (sd);@@ -163,17 +189,15 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd) sd->dev =NULL ; } -int v4l2_async_notifier_register (struct v4l2_device *v4l2_dev, -struct v4l2_async_notifier *notifier) +static int __v4l2_async_notifier_register (struct v4l2_async_notifier *notifier) { -struct v4l2_subdev *sd, *tmp;struct v4l2_async_subdev *asd; +int ret;int i; -if (!v4l2_dev || notifier->num_subdevs >V4L2_MAX_SUBDEVS ) +if (notifier->num_subdevs >V4L2_MAX_SUBDEVS )return -EINVAL ; - notifier->v4l2_dev = v4l2_dev;INIT_LIST_HEAD (¬ifier->waiting);INIT_LIST_HEAD (¬ifier->done);@@ -206,18 +230,10 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,mutex_lock (&list_lock); -list_for_each_entry_safe (sd, tmp, &subdev_list, async_list) { -int ret; - - asd =v4l2_async_find_match (notifier, sd); -if (!asd) -continue ; - - ret =v4l2_async_match_notify (notifier, sd, asd); -if (ret <0 ) { -mutex_unlock (&list_lock); -return ret; - } + ret =v4l2_async_notifier_try_all_subdevs (notifier); +if (ret) { +mutex_unlock (&list_lock); +return ret; }/* Keep also completed notifiers on the list */ @@ -227,6 +243,17 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,return 0 ; } + +int v4l2_async_notifier_register (struct v4l2_device *v4l2_dev, +struct v4l2_async_notifier *notifier) +{ +if (WARN_ON (!v4l2_dev)) +return -EINVAL ; + + notifier->v4l2_dev = v4l2_dev; + +return __v4l2_async_notifier_register (notifier); +}EXPORT_SYMBOL (v4l2_async_notifier_register);void v4l2_async_notifier_unregister (struct v4l2_async_notifier *notifier)
drivers/media/v4l2-core/v4l2-async.c int v4l2_async_register_subdev(struct v4l2_subdev *sd) · line 337
Quoted 9 lines
drivers/media/v4l2-core/v4l2-async.c +2
-1@@ -303,7 +330,8 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)struct v4l2_async_subdev *asd =v4l2_async_find_match (notifier, sd);if (asd) { -int ret =v4l2_async_match_notify (notifier, sd, asd); +int ret =v4l2_async_match_notify ( + notifier, notifier->v4l2_dev, sd, asd);mutex_unlock (&list_lock);return ret; }
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): ba80e242-a3c2-39af-01cd-6aa54649fb93-qWit8jRvyhVmR6Xm/[email protected]
Re: [PATCH v14 14/28] v4l: async: Prepare for async sub-device notifiers
Hi Hans,
Quoted 5 lines · Hans Verkuil
Quoted 2 lines · Sakari Ailus
Refactor the V4L2 async framework a little in preparation for async sub-device notifiers.
Perhaps extend this a bit to also state the reason for these changes?
Well, the true reason is that Laurent felt the following patch was doing too much, but most of the changes in it are actually tightly interconnected.
How about adding:
This avoids making some structural changes in the patch actually implementing sub-device notifiers, making that patch easier to review.
Quoted 7 lines
Quoted 3 lines
Anyway,
Acked-by Hans Verkuil <[email protected]>
Thanks!
Quoted 130 lines
Quoted 129 lines
--- drivers/media/v4l2-core/v4l2-async.c | 66 +++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 19 deletions(-)drivers/media/v4l2-core/v4l2-async.c +47
-19@@ -125,12 +125,13 @@ static struct v4l2_async_subdev *v4l2_async_find_match( }static int v4l2_async_match_notify (struct v4l2_async_notifier *notifier, +struct v4l2_device *v4l2_dev,struct v4l2_subdev *sd,struct v4l2_async_subdev *asd) {int ret; - ret =v4l2_device_register_subdev (notifier->v4l2_dev, sd); + ret =v4l2_device_register_subdev (v4l2_dev, sd);if (ret <0 )return ret;@@ -154,6 +155,31 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,return 0 ; } +/* Test all async sub-devices in a notifier for a match. */ +static int v4l2_async_notifier_try_all_subdevs ( +struct v4l2_async_notifier *notifier) +{ +struct v4l2_device *v4l2_dev = notifier->v4l2_dev; +struct v4l2_subdev *sd, *tmp; + +list_for_each_entry_safe (sd, tmp, &subdev_list, async_list) { +struct v4l2_async_subdev *asd; +int ret; + + asd =v4l2_async_find_match (notifier, sd); +if (!asd) +continue ; + + ret =v4l2_async_match_notify (notifier, v4l2_dev, sd, asd); +if (ret <0 ) { +mutex_unlock (&list_lock); +return ret; + } + } + +return 0 ; +} +static void v4l2_async_cleanup (struct v4l2_subdev *sd) {v4l2_device_unregister_subdev (sd);@@ -163,17 +189,15 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd) sd->dev =NULL ; } -int v4l2_async_notifier_register (struct v4l2_device *v4l2_dev, -struct v4l2_async_notifier *notifier) +static int __v4l2_async_notifier_register (struct v4l2_async_notifier *notifier) { -struct v4l2_subdev *sd, *tmp;struct v4l2_async_subdev *asd; +int ret;int i; -if (!v4l2_dev || notifier->num_subdevs >V4L2_MAX_SUBDEVS ) +if (notifier->num_subdevs >V4L2_MAX_SUBDEVS )return -EINVAL ; - notifier->v4l2_dev = v4l2_dev;INIT_LIST_HEAD (¬ifier->waiting);INIT_LIST_HEAD (¬ifier->done);@@ -206,18 +230,10 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,mutex_lock (&list_lock); -list_for_each_entry_safe (sd, tmp, &subdev_list, async_list) { -int ret; - - asd =v4l2_async_find_match (notifier, sd); -if (!asd) -continue ; - - ret =v4l2_async_match_notify (notifier, sd, asd); -if (ret <0 ) { -mutex_unlock (&list_lock); -return ret; - } + ret =v4l2_async_notifier_try_all_subdevs (notifier); +if (ret) { +mutex_unlock (&list_lock); +return ret; }/* Keep also completed notifiers on the list */ @@ -227,6 +243,17 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,return 0 ; } + +int v4l2_async_notifier_register (struct v4l2_device *v4l2_dev, +struct v4l2_async_notifier *notifier) +{ +if (WARN_ON (!v4l2_dev)) +return -EINVAL ; + + notifier->v4l2_dev = v4l2_dev; + +return __v4l2_async_notifier_register (notifier); +}EXPORT_SYMBOL (v4l2_async_notifier_register);void v4l2_async_notifier_unregister (struct v4l2_async_notifier *notifier)@@ -303,7 +330,8 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)struct v4l2_async_subdev *asd =v4l2_async_find_match (notifier, sd);if (asd) { -int ret =v4l2_async_match_notify (notifier, sd, asd); +int ret =v4l2_async_match_notify ( + notifier, notifier->v4l2_dev, sd, asd);mutex_unlock (&list_lock);return ret; }
Signature · 6 lines
Sakari Ailus sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected] -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v14 14/28] v4l: async: Prepare for async sub-device notifiers
Quoted 9 lines · Sakari Ailus
Hi Hans,
Quoted 5 lines · Hans Verkuil
Quoted 2 lines · Sakari Ailus
Refactor the V4L2 async framework a little in preparation for async sub-device notifiers.
Perhaps extend this a bit to also state the reason for these changes?
Quoted 8 lines
Well, the true reason is that Laurent felt the following patch was doing too much, but most of the changes in it are actually tightly interconnected.
How about adding:
This avoids making some structural changes in the patch actually implementing sub-device notifiers, making that patch easier to review.
That will do.
I preferred the original version, that way I could see WHY things were done, even though the patch was larger.
Regards,
Hans
Quoted 142 lines
Quoted 8 lines
Quoted 4 lines
Signed-off-by Sakari Ailus <[email protected]>Anyway,
Acked-by Hans Verkuil <[email protected]>Thanks!
Quoted 130 lines
Quoted 129 lines
--- drivers/media/v4l2-core/v4l2-async.c | 66 +++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 19 deletions(-)drivers/media/v4l2-core/v4l2-async.c +47
-19@@ -125,12 +125,13 @@ static struct v4l2_async_subdev *v4l2_async_find_match( }static int v4l2_async_match_notify (struct v4l2_async_notifier *notifier, +struct v4l2_device *v4l2_dev,struct v4l2_subdev *sd,struct v4l2_async_subdev *asd) {int ret; - ret =v4l2_device_register_subdev (notifier->v4l2_dev, sd); + ret =v4l2_device_register_subdev (v4l2_dev, sd);if (ret <0 )return ret;@@ -154,6 +155,31 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,return 0 ; } +/* Test all async sub-devices in a notifier for a match. */ +static int v4l2_async_notifier_try_all_subdevs ( +struct v4l2_async_notifier *notifier) +{ +struct v4l2_device *v4l2_dev = notifier->v4l2_dev; +struct v4l2_subdev *sd, *tmp; + +list_for_each_entry_safe (sd, tmp, &subdev_list, async_list) { +struct v4l2_async_subdev *asd; +int ret; + + asd =v4l2_async_find_match (notifier, sd); +if (!asd) +continue ; + + ret =v4l2_async_match_notify (notifier, v4l2_dev, sd, asd); +if (ret <0 ) { +mutex_unlock (&list_lock); +return ret; + } + } + +return 0 ; +} +static void v4l2_async_cleanup (struct v4l2_subdev *sd) {v4l2_device_unregister_subdev (sd);@@ -163,17 +189,15 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd) sd->dev =NULL ; } -int v4l2_async_notifier_register (struct v4l2_device *v4l2_dev, -struct v4l2_async_notifier *notifier) +static int __v4l2_async_notifier_register (struct v4l2_async_notifier *notifier) { -struct v4l2_subdev *sd, *tmp;struct v4l2_async_subdev *asd; +int ret;int i; -if (!v4l2_dev || notifier->num_subdevs >V4L2_MAX_SUBDEVS ) +if (notifier->num_subdevs >V4L2_MAX_SUBDEVS )return -EINVAL ; - notifier->v4l2_dev = v4l2_dev;INIT_LIST_HEAD (¬ifier->waiting);INIT_LIST_HEAD (¬ifier->done);@@ -206,18 +230,10 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,mutex_lock (&list_lock); -list_for_each_entry_safe (sd, tmp, &subdev_list, async_list) { -int ret; - - asd =v4l2_async_find_match (notifier, sd); -if (!asd) -continue ; - - ret =v4l2_async_match_notify (notifier, sd, asd); -if (ret <0 ) { -mutex_unlock (&list_lock); -return ret; - } + ret =v4l2_async_notifier_try_all_subdevs (notifier); +if (ret) { +mutex_unlock (&list_lock); +return ret; }/* Keep also completed notifiers on the list */ @@ -227,6 +243,17 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,return 0 ; } + +int v4l2_async_notifier_register (struct v4l2_device *v4l2_dev, +struct v4l2_async_notifier *notifier) +{ +if (WARN_ON (!v4l2_dev)) +return -EINVAL ; + + notifier->v4l2_dev = v4l2_dev; + +return __v4l2_async_notifier_register (notifier); +}EXPORT_SYMBOL (v4l2_async_notifier_register);void v4l2_async_notifier_unregister (struct v4l2_async_notifier *notifier)@@ -303,7 +330,8 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)struct v4l2_async_subdev *asd =v4l2_async_find_match (notifier, sd);if (asd) { -int ret =v4l2_async_match_notify (notifier, sd, asd); +int ret =v4l2_async_match_notify ( + notifier, notifier->v4l2_dev, sd, asd);mutex_unlock (&list_lock);return ret; }
Sakari Ailus
maintainerPATCH v14 15/28 v4l: async: Allow binding notifiers to sub-devices
In reply to Sakari AilusRegistering a notifier has required the knowledge of struct v4l2_device for the reason that sub-devices generally are registered to the v4l2_device (as well as the media device, also available through v4l2_device).
This information is not available for sub-device drivers at probe time.
What this patch does is that it allows registering notifiers without having v4l2_device around. Instead the sub-device pointer is stored in the notifier. Once the sub-device of the driver that registered the notifier is registered, the notifier will gain the knowledge of the v4l2_device, and the binding of async sub-devices from the sub-device driver's notifier may proceed.
The root notifier's complete callback is only called when all sub-device notifiers are completed.
--- drivers/media/v4l2-core/v4l2-async.c | 218 +++++++++++++++++++++++++++++------ include/media/v4l2-async.h | 16 ++- 2 files changed, 199 insertions(+), 35 deletions(-)
drivers/media/v4l2-core/v4l2-async.c +184 -34
@@ -124,11 +124,109 @@ static struct v4l2_async_subdev *v4l2_async_find_match(return NULL ; } +/* Find the sub-device notifier registered by a sub-device driver. */ +static struct v4l2_async_notifier *v4l2_async_find_subdev_notifier ( +struct v4l2_subdev *sd) +{ +struct v4l2_async_notifier *n; + +list_for_each_entry (n, ¬ifier_list, list) +if (n->sd == sd) +return n; + +return NULL ; +} + +/* Get v4l2_device related to the notifier if one can be found. */ +static struct v4l2_device *v4l2_async_notifier_find_v4l2_dev ( +struct v4l2_async_notifier *notifier) +{ +while (notifier->parent) + notifier = notifier->parent; + +return notifier->v4l2_dev; +} + +/* +* Return true if all child sub-device notifiers are complete, false otherwise. +*/ +static bool v4l2_async_notifier_can_complete ( +struct v4l2_async_notifier *notifier) +{ +struct v4l2_subdev *sd; + +if (!list_empty (¬ifier->waiting)) +return false; + +list_for_each_entry (sd, ¬ifier->done, async_list) { +struct v4l2_async_notifier *subdev_notifier = +v4l2_async_find_subdev_notifier (sd); + +if (subdev_notifier && + !v4l2_async_notifier_can_complete (subdev_notifier)) +return false; + } + +return true; +} + +/* Complete all notifiers. Call on the root notifier. */ +static int v4l2_async_notifier_complete ( +struct v4l2_async_notifier *notifier) +{ +struct v4l2_subdev *sd; + +list_for_each_entry (sd, ¬ifier->done, async_list) { +struct v4l2_async_notifier *subdev_notifier = +v4l2_async_find_subdev_notifier (sd); +int ret; + +if (!subdev_notifier) +continue ; + + ret =v4l2_async_notifier_complete (subdev_notifier); +if (ret) +return ret; + } + +return v4l2_async_notifier_call_complete (notifier); +} + +/* +* Complete notifiers if possible. This is done when all async sub-devices have +* been bound; v4l2_device is also available then. +*/ +static int v4l2_async_notifier_try_complete ( +struct v4l2_async_notifier *notifier) +{ +/* Quick check whether there are still more sub-devices here. */ +if (!list_empty (¬ifier->waiting)) +return 0 ; + +/* Check the entire notifier tree; find the root notifier first. */ +while (notifier->parent) + notifier = notifier->parent; + +/* This is root if it has v4l2_dev. */ +if (!notifier->v4l2_dev) +return 0 ; + +/* Is everything ready? */ +if (!v4l2_async_notifier_can_complete (notifier)) +return 0 ; + +return v4l2_async_notifier_complete (notifier); +} + +static int v4l2_async_notifier_try_all_subdevs ( +struct v4l2_async_notifier *notifier); +static int v4l2_async_match_notify (struct v4l2_async_notifier *notifier,struct v4l2_device *v4l2_dev,struct v4l2_subdev *sd,struct v4l2_async_subdev *asd) { +struct v4l2_async_notifier *subdev_notifier;int ret; ret =v4l2_device_register_subdev (v4l2_dev, sd);
@@ -149,8 +247,17 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,/* Move from the global subdevice list to notifier's done */ list_move (&sd->async_list, ¬ifier->done); -if (list_empty (¬ifier->waiting)) -return v4l2_async_notifier_call_complete (notifier); +/* +* See if the sub-device has a notifier. If it does, proceed +* with checking for its async sub-devices. +*/ + subdev_notifier =v4l2_async_find_subdev_notifier (sd); +if (subdev_notifier && !subdev_notifier->parent) { + subdev_notifier->parent = notifier; + ret =v4l2_async_notifier_try_all_subdevs (subdev_notifier); +if (ret) +return ret; + }return 0 ; }
@@ -159,10 +266,15 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,static int v4l2_async_notifier_try_all_subdevs (struct v4l2_async_notifier *notifier) { -struct v4l2_device *v4l2_dev = notifier->v4l2_dev; -struct v4l2_subdev *sd, *tmp; +struct v4l2_device *v4l2_dev = +v4l2_async_notifier_find_v4l2_dev (notifier); +struct v4l2_subdev *sd; -list_for_each_entry_safe (sd, tmp, &subdev_list, async_list) { +if (!v4l2_dev) +return 0 ; + +again: +list_for_each_entry (sd, &subdev_list, async_list) {struct v4l2_async_subdev *asd;int ret;
@@ -171,10 +283,16 @@ static int v4l2_async_notifier_try_all_subdevs(continue ; ret =v4l2_async_match_notify (notifier, v4l2_dev, sd, asd); -if (ret <0 ) { -mutex_unlock (&list_lock); +if (ret <0 )return ret; - } + +/* +* v4l2_async_match_notify() may lead to registering a +* new notifier and thus changing the async subdevs +* list. In order to proceed safely from here, restart +* parsing the list from the beginning. +*/ + goto again; }return 0 ;
@@ -201,15 +319,6 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)INIT_LIST_HEAD (¬ifier->waiting);INIT_LIST_HEAD (¬ifier->done); -if (!notifier->num_subdevs) { -int ret; - - ret =v4l2_async_notifier_call_complete (notifier); - notifier->v4l2_dev =NULL ; - -return ret; - } -for (i =0 ; i < notifier->num_subdevs; i++) { asd = notifier->subdevs[i];
@@ -236,18 +345,20 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)return ret; } + ret =v4l2_async_notifier_try_complete (notifier); +/* Keep also completed notifiers on the list */ list_add (¬ifier->list, ¬ifier_list);mutex_unlock (&list_lock); -return 0 ; +return ret; }int v4l2_async_notifier_register (struct v4l2_device *v4l2_dev,struct v4l2_async_notifier *notifier) { -if (WARN_ON (!v4l2_dev)) +if (WARN_ON (!v4l2_dev || notifier->sd))return -EINVAL ; notifier->v4l2_dev = v4l2_dev;
@@ -256,18 +367,31 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, }EXPORT_SYMBOL (v4l2_async_notifier_register); -void v4l2_async_notifier_unregister (struct v4l2_async_notifier *notifier) +int v4l2_async_subdev_notifier_register (struct v4l2_subdev *sd, +struct v4l2_async_notifier *notifier) { -struct v4l2_subdev *sd, *tmp; +if (WARN_ON (!sd || notifier->v4l2_dev)) +return -EINVAL ; -if (!notifier->v4l2_dev) -return ; + notifier->sd = sd; -mutex_lock (&list_lock); +return __v4l2_async_notifier_register (notifier); +} +EXPORT_SYMBOL (v4l2_async_subdev_notifier_register); -list_del (¬ifier->list); +/* Unbind all sub-devices in the notifier tree. */ +static void v4l2_async_notifier_unbind_all_subdevs ( +struct v4l2_async_notifier *notifier) +{ +struct v4l2_subdev *sd, *tmp;list_for_each_entry_safe (sd, tmp, ¬ifier->done, async_list) { +struct v4l2_async_notifier *subdev_notifier = +v4l2_async_find_subdev_notifier (sd); + +if (subdev_notifier) +v4l2_async_notifier_unbind_all_subdevs (subdev_notifier); +v4l2_async_cleanup (sd);v4l2_async_notifier_call_unbind (notifier, sd, sd->asd);
@@ -275,9 +399,24 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)list_move (&sd->async_list, &subdev_list); } -mutex_unlock (&list_lock); + notifier->parent =NULL ; +} +void v4l2_async_notifier_unregister (struct v4l2_async_notifier *notifier) +{ +if (!notifier->v4l2_dev && !notifier->sd) +return ; + +mutex_lock (&list_lock); + +v4l2_async_notifier_unbind_all_subdevs (notifier); + + notifier->sd =NULL ; notifier->v4l2_dev =NULL ; + +list_del (¬ifier->list); + +mutex_unlock (&list_lock); }EXPORT_SYMBOL (v4l2_async_notifier_unregister);
@@ -327,14 +466,25 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)INIT_LIST_HEAD (&sd->async_list);list_for_each_entry (notifier, ¬ifier_list, list) { -struct v4l2_async_subdev *asd =v4l2_async_find_match (notifier, - sd); -if (asd) { -int ret =v4l2_async_match_notify ( - notifier, notifier->v4l2_dev, sd, asd); -mutex_unlock (&list_lock); -return ret; - } +struct v4l2_device *v4l2_dev = +v4l2_async_notifier_find_v4l2_dev (notifier); +struct v4l2_async_subdev *asd; +int ret; + +if (!v4l2_dev) +continue ; + + asd =v4l2_async_find_match (notifier, sd); +if (!asd) +continue ; + + ret =v4l2_async_match_notify (notifier, v4l2_dev, sd, asd); + +if (!ret) + ret =v4l2_async_notifier_try_complete (notifier); + +mutex_unlock (&list_lock); +return ret; }/* None matched, wait for hot-plugging */
include/media/v4l2-async.h +15 -1
@@ -102,7 +102,9 @@ struct v4l2_async_notifier_operations {* @num_subdevs: number of subdevices used in the subdevs array * @max_subdevs: number of subdevices allocated in the subdevs array * @subdevs: array of pointers to subdevice descriptors -* @v4l2_dev: pointer to struct v4l2_device +* @v4l2_dev: v4l2_device of the root notifier, NULL otherwise +* @sd: sub-device that registered the notifier, NULL otherwise +* @parent: parent notifier * @waiting: list of struct v4l2_async_subdev, waiting for their drivers * @done: list of struct v4l2_subdev, already probed * @list: member in a global list of notifiers
@@ -113,6 +115,8 @@ struct v4l2_async_notifier {unsigned int max_subdevs;struct v4l2_async_subdev **subdevs;struct v4l2_device *v4l2_dev; +struct v4l2_subdev *sd; +struct v4l2_async_notifier *parent;struct list_head waiting;struct list_head done;struct list_head list;
@@ -128,6 +132,16 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, struct v4l2_async_notifier *notifier);/** +* v4l2_async_subdev_notifier_register - registers a subdevice asynchronous +* notifier for a sub-device +* +* @sd: pointer to &struct v4l2_subdev +* @notifier: pointer to &struct v4l2_async_notifier +*/ +int v4l2_async_subdev_notifier_register (struct v4l2_subdev *sd, +struct v4l2_async_notifier *notifier); + +/** * v4l2_async_notifier_unregister - unregisters a subdevice asynchronous notifier * * @notifier: pointer to &struct v4l2_async_notifier
Signature · 1 line
2.11.0
Re: [PATCH v14 15/28] v4l: async: Allow binding notifiers to sub-devices
Quoted 14 lines · Sakari Ailus
Registering a notifier has required the knowledge of struct
v4l2_devicefor the reason that sub-devices generally are registered to thev4l2_device(as well as the media device, also available throughv4l2_device).This information is not available for sub-device drivers at probe time.
What this patch does is that it allows registering notifiers without having
v4l2_devicearound. Instead the sub-device pointer is stored in the notifier. Once the sub-device of the driver that registered the notifier is registered, the notifier will gain the knowledge of thev4l2_device, and the binding of async sub-devices from the sub-device driver's notifier may proceed.
Quoted 4 lines
The root notifier's complete callback is only called when all sub-device notifiers are completed.
Signed-off-by Sakari Ailus <[email protected]>
Quoted 357 lines
--- drivers/media/v4l2-core/v4l2-async.c | 218 +++++++++++++++++++++++++++++------ include/media/v4l2-async.h | 16 ++- 2 files changed, 199 insertions(+), 35 deletions(-)drivers/media/v4l2-core/v4l2-async.c +184
-34@@ -124,11 +124,109 @@ static struct v4l2_async_subdev *v4l2_async_find_match(return NULL ; } +/* Find the sub-device notifier registered by a sub-device driver. */ +static struct v4l2_async_notifier *v4l2_async_find_subdev_notifier ( +struct v4l2_subdev *sd) +{ +struct v4l2_async_notifier *n; + +list_for_each_entry (n, ¬ifier_list, list) +if (n->sd == sd) +return n; + +return NULL ; +} + +/* Get v4l2_device related to the notifier if one can be found. */ +static struct v4l2_device *v4l2_async_notifier_find_v4l2_dev ( +struct v4l2_async_notifier *notifier) +{ +while (notifier->parent) + notifier = notifier->parent; + +return notifier->v4l2_dev; +} + +/* +* Return true if all child sub-device notifiers are complete, false otherwise. +*/ +static bool v4l2_async_notifier_can_complete ( +struct v4l2_async_notifier *notifier) +{ +struct v4l2_subdev *sd; + +if (!list_empty (¬ifier->waiting)) +return false; + +list_for_each_entry (sd, ¬ifier->done, async_list) { +struct v4l2_async_notifier *subdev_notifier = +v4l2_async_find_subdev_notifier (sd); + +if (subdev_notifier && + !v4l2_async_notifier_can_complete (subdev_notifier)) +return false; + } + +return true; +} + +/* Complete all notifiers. Call on the root notifier. */ +static int v4l2_async_notifier_complete ( +struct v4l2_async_notifier *notifier) +{ +struct v4l2_subdev *sd; + +list_for_each_entry (sd, ¬ifier->done, async_list) { +struct v4l2_async_notifier *subdev_notifier = +v4l2_async_find_subdev_notifier (sd); +int ret; + +if (!subdev_notifier) +continue ; + + ret =v4l2_async_notifier_complete (subdev_notifier); +if (ret) +return ret; + } + +return v4l2_async_notifier_call_complete (notifier); +} + +/* +* Complete notifiers if possible. This is done when all async sub-devices have +* been bound; v4l2_device is also available then. +*/ +static int v4l2_async_notifier_try_complete ( +struct v4l2_async_notifier *notifier) +{ +/* Quick check whether there are still more sub-devices here. */ +if (!list_empty (¬ifier->waiting)) +return 0 ; + +/* Check the entire notifier tree; find the root notifier first. */ +while (notifier->parent) + notifier = notifier->parent; + +/* This is root if it has v4l2_dev. */ +if (!notifier->v4l2_dev) +return 0 ; + +/* Is everything ready? */ +if (!v4l2_async_notifier_can_complete (notifier)) +return 0 ; + +return v4l2_async_notifier_complete (notifier); +} + +static int v4l2_async_notifier_try_all_subdevs ( +struct v4l2_async_notifier *notifier); +static int v4l2_async_match_notify (struct v4l2_async_notifier *notifier,struct v4l2_device *v4l2_dev,struct v4l2_subdev *sd,struct v4l2_async_subdev *asd) { +struct v4l2_async_notifier *subdev_notifier;int ret; ret =v4l2_device_register_subdev (v4l2_dev, sd);@@ -149,8 +247,17 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,/* Move from the global subdevice list to notifier's done */ list_move (&sd->async_list, ¬ifier->done); -if (list_empty (¬ifier->waiting)) -return v4l2_async_notifier_call_complete (notifier); +/* +* See if the sub-device has a notifier. If it does, proceed +* with checking for its async sub-devices. +*/ + subdev_notifier =v4l2_async_find_subdev_notifier (sd); +if (subdev_notifier && !subdev_notifier->parent) { + subdev_notifier->parent = notifier; + ret =v4l2_async_notifier_try_all_subdevs (subdev_notifier); +if (ret) +return ret; + }return 0 ; }@@ -159,10 +266,15 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,static int v4l2_async_notifier_try_all_subdevs (struct v4l2_async_notifier *notifier) { -struct v4l2_device *v4l2_dev = notifier->v4l2_dev; -struct v4l2_subdev *sd, *tmp; +struct v4l2_device *v4l2_dev = +v4l2_async_notifier_find_v4l2_dev (notifier); +struct v4l2_subdev *sd; -list_for_each_entry_safe (sd, tmp, &subdev_list, async_list) { +if (!v4l2_dev) +return 0 ; + +again: +list_for_each_entry (sd, &subdev_list, async_list) {struct v4l2_async_subdev *asd;int ret;@@ -171,10 +283,16 @@ static int v4l2_async_notifier_try_all_subdevs(continue ; ret =v4l2_async_match_notify (notifier, v4l2_dev, sd, asd); -if (ret <0 ) { -mutex_unlock (&list_lock); +if (ret <0 )return ret; - } + +/* +* v4l2_async_match_notify() may lead to registering a +* new notifier and thus changing the async subdevs +* list. In order to proceed safely from here, restart +* parsing the list from the beginning. +*/ + goto again; }return 0 ;@@ -201,15 +319,6 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)INIT_LIST_HEAD (¬ifier->waiting);INIT_LIST_HEAD (¬ifier->done); -if (!notifier->num_subdevs) { -int ret; - - ret =v4l2_async_notifier_call_complete (notifier); - notifier->v4l2_dev =NULL ; - -return ret; - } -for (i =0 ; i < notifier->num_subdevs; i++) { asd = notifier->subdevs[i];@@ -236,18 +345,20 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)return ret; } + ret =v4l2_async_notifier_try_complete (notifier); +/* Keep also completed notifiers on the list */ list_add (¬ifier->list, ¬ifier_list);mutex_unlock (&list_lock); -return 0 ; +return ret; }int v4l2_async_notifier_register (struct v4l2_device *v4l2_dev,struct v4l2_async_notifier *notifier) { -if (WARN_ON (!v4l2_dev)) +if (WARN_ON (!v4l2_dev || notifier->sd))return -EINVAL ; notifier->v4l2_dev = v4l2_dev;@@ -256,18 +367,31 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, }EXPORT_SYMBOL (v4l2_async_notifier_register); -void v4l2_async_notifier_unregister (struct v4l2_async_notifier *notifier) +int v4l2_async_subdev_notifier_register (struct v4l2_subdev *sd, +struct v4l2_async_notifier *notifier) { -struct v4l2_subdev *sd, *tmp; +if (WARN_ON (!sd || notifier->v4l2_dev)) +return -EINVAL ; -if (!notifier->v4l2_dev) -return ; + notifier->sd = sd; -mutex_lock (&list_lock); +return __v4l2_async_notifier_register (notifier); +} +EXPORT_SYMBOL (v4l2_async_subdev_notifier_register); -list_del (¬ifier->list); +/* Unbind all sub-devices in the notifier tree. */ +static void v4l2_async_notifier_unbind_all_subdevs ( +struct v4l2_async_notifier *notifier) +{ +struct v4l2_subdev *sd, *tmp;list_for_each_entry_safe (sd, tmp, ¬ifier->done, async_list) { +struct v4l2_async_notifier *subdev_notifier = +v4l2_async_find_subdev_notifier (sd); + +if (subdev_notifier) +v4l2_async_notifier_unbind_all_subdevs (subdev_notifier); +v4l2_async_cleanup (sd);v4l2_async_notifier_call_unbind (notifier, sd, sd->asd);@@ -275,9 +399,24 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)list_move (&sd->async_list, &subdev_list); } -mutex_unlock (&list_lock); + notifier->parent =NULL ; +} +void v4l2_async_notifier_unregister (struct v4l2_async_notifier *notifier) +{ +if (!notifier->v4l2_dev && !notifier->sd) +return ; + +mutex_lock (&list_lock); + +v4l2_async_notifier_unbind_all_subdevs (notifier); + + notifier->sd =NULL ; notifier->v4l2_dev =NULL ; + +list_del (¬ifier->list); + +mutex_unlock (&list_lock); }EXPORT_SYMBOL (v4l2_async_notifier_unregister);@@ -327,14 +466,25 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)INIT_LIST_HEAD (&sd->async_list);list_for_each_entry (notifier, ¬ifier_list, list) { -struct v4l2_async_subdev *asd =v4l2_async_find_match (notifier, - sd); -if (asd) { -int ret =v4l2_async_match_notify ( - notifier, notifier->v4l2_dev, sd, asd); -mutex_unlock (&list_lock); -return ret; - } +struct v4l2_device *v4l2_dev = +v4l2_async_notifier_find_v4l2_dev (notifier); +struct v4l2_async_subdev *asd; +int ret; + +if (!v4l2_dev) +continue ; + + asd =v4l2_async_find_match (notifier, sd); +if (!asd) +continue ; + + ret =v4l2_async_match_notify (notifier, v4l2_dev, sd, asd); + +if (!ret) + ret =v4l2_async_notifier_try_complete (notifier); + +mutex_unlock (&list_lock); +return ret; }/* None matched, wait for hot-plugging */ include/media/v4l2-async.h +15
-1@@ -102,7 +102,9 @@ struct v4l2_async_notifier_operations {* @num_subdevs: number of subdevices used in the subdevs array * @max_subdevs: number of subdevices allocated in the subdevs array * @subdevs: array of pointers to subdevice descriptors -* @v4l2_dev: pointer to struct v4l2_device +* @v4l2_dev: v4l2_device of the root notifier, NULL otherwise +* @sd: sub-device that registered the notifier, NULL otherwise +* @parent: parent notifier * @waiting: list of struct v4l2_async_subdev, waiting for their drivers * @done: list of struct v4l2_subdev, already probed * @list: member in a global list of notifiers @@ -113,6 +115,8 @@ struct v4l2_async_notifier {unsigned int max_subdevs;struct v4l2_async_subdev **subdevs;struct v4l2_device *v4l2_dev; +struct v4l2_subdev *sd; +struct v4l2_async_notifier *parent;struct list_head waiting;struct list_head done;struct list_head list;@@ -128,6 +132,16 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, struct v4l2_async_notifier *notifier);/** +* v4l2_async_subdev_notifier_register - registers a subdevice asynchronous +* notifier for a sub-device +* +* @sd: pointer to &struct v4l2_subdev +* @notifier: pointer to &struct v4l2_async_notifier +*/ +int v4l2_async_subdev_notifier_register (struct v4l2_subdev *sd, +struct v4l2_async_notifier *notifier); + +/** * v4l2_async_notifier_unregister - unregisters a subdevice asynchronous notifier * * @notifier: pointer to &struct v4l2_async_notifier
A message that is not in the archive (sent off-list or not yet received): 20170925222540.371-16-sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected]
Re: [PATCH v14 15/28] v4l: async: Allow binding notifiers to sub-devices
Quoted 14 lines · Sakari Ailus
Registering a notifier has required the knowledge of struct
v4l2_devicefor the reason that sub-devices generally are registered to thev4l2_device(as well as the media device, also available throughv4l2_device).This information is not available for sub-device drivers at probe time.
What this patch does is that it allows registering notifiers without having
v4l2_devicearound. Instead the sub-device pointer is stored in the notifier. Once the sub-device of the driver that registered the notifier is registered, the notifier will gain the knowledge of thev4l2_device, and the binding of async sub-devices from the sub-device driver's notifier may proceed.
Quoted 2 lines
The root notifier's complete callback is only called when all sub-device notifiers are completed.
This paragraph is actually no longer true. I changed it to:
The complete callbacks will be called only when the v4l2_device is available and no notifier has pending sub-devices to bind.
Signature · 6 lines
Sakari Ailus e-mail: [email protected] -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Sakari Ailus
maintainerPATCH v14 17/28 dt: bindings: Add a binding for flash LED devices associated to a sensor
In reply to Sakari AilusCamera flash drivers (and LEDs) are separate from the sensor devices in DT. In order to make an association between the two, provide the association information to the software.
--- Documentation/devicetree/bindings/media/video-interfaces.txt | 8 ++++++++ 1 file changed, 8 insertions(+)
Documentation/devicetree/bindings/media/video-interfaces.txt +8 -0
@@ -67,6 +67,14 @@ are required in a relevant parent node: identifier, should be 1. - #size-cells : should be zero. + +Optional properties +------------------- + +- flash-leds: An array of phandles, each referring to a flash LED, a sub-node + of the LED driver device node. + + Optional endpoint properties ----------------------------
Signature · 1 line
2.11.0
Sakari Ailus
maintainerPATCH v14 19/28 v4l: fwnode: Add a helper function for parsing generic references
In reply to Sakari AilusAdd function v4l2_fwnode_reference_parse() for parsing them as async sub-devices. This can be done on e.g. flash or lens async sub-devices that are not part of but are associated with a sensor.
--- drivers/media/v4l2-core/v4l2-fwnode.c | 69 +++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+)
drivers/media/v4l2-core/v4l2-fwnode.c +69 -0
@@ -509,6 +509,75 @@ int v4l2_async_notifier_parse_fwnode_endpoints_by_port( }EXPORT_SYMBOL_GPL (v4l2_async_notifier_parse_fwnode_endpoints_by_port); +/* +* v4l2_fwnode_reference_parse - parse references for async sub-devices +* @dev: the device node the properties of which are parsed for references +* @notifier: the async notifier where the async subdevs will be added +* @prop: the name of the property +* +* Return: 0 on success +* -ENOENT if no entries were found +* -ENOMEM if memory allocation failed +* -EINVAL if property parsing failed +*/ +static int v4l2_fwnode_reference_parse ( +struct device *dev,struct v4l2_async_notifier *notifier, +const char *prop) +{ +struct fwnode_reference_args args; +unsigned int index; +int ret; + +for (index =0 ; + !(ret =fwnode_property_get_reference_args ( +dev_fwnode (dev), prop,NULL ,0 , index, &args)); + index++) +fwnode_handle_put (args.fwnode); + +if (!index) +return -ENOENT ; + +/* +* Note that right now both -ENODATA and -ENOENT may signal +* out-of-bounds access. Return the error in cases other than that. +*/ +if (ret != -ENOENT && ret != -ENODATA ) +return ret; + + ret =v4l2_async_notifier_realloc (notifier, + notifier->num_subdevs + index); +if (ret) +return ret; + +for (index =0 ; !fwnode_property_get_reference_args ( +dev_fwnode (dev), prop,NULL ,0 , index, &args); + index++) { +struct v4l2_async_subdev *asd; + +if (WARN_ON (notifier->num_subdevs >= notifier->max_subdevs)) { + ret = -EINVAL ; + goto error; + } + + asd =kzalloc (sizeof (*asd),GFP_KERNEL ); +if (!asd) { + ret = -ENOMEM ; + goto error; + } + + notifier->subdevs[notifier->num_subdevs] = asd; + asd->match.fwnode.fwnode = args.fwnode; + asd->match_type =V4L2_ASYNC_MATCH_FWNODE ; + notifier->num_subdevs++; + } + +return 0 ; + +error: +fwnode_handle_put (args.fwnode); +return ret; +} +MODULE_LICENSE ("GPL" );MODULE_AUTHOR ("Sakari Ailus <[email protected]>" );MODULE_AUTHOR ("Sylwester Nawrocki <[email protected]>" );
Signature · 1 line
2.11.0
Sakari Ailus
maintainerPATCH v14 20/28 v4l: fwnode: Add a helper function to obtain device / integer references
In reply to Sakari Ailusv4l2_fwnode_reference_parse_int_prop() will find an fwnode such that under the device's own fwnode, it will follow child fwnodes with the given property-value pair and return the resulting fwnode.
--- drivers/media/v4l2-core/v4l2-fwnode.c | 201 ++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+)
drivers/media/v4l2-core/v4l2-fwnode.c +201 -0
@@ -578,6 +578,207 @@ static int v4l2_fwnode_reference_parse(return ret; } +/* +* v4l2_fwnode_reference_get_int_prop - parse a reference with integer +* arguments +* @dev: struct device pointer +* @notifier: notifier for @dev +* @prop: the name of the property +* @index: the index of the reference to get +* @props: the array of integer property names +* @nprops: the number of integer property names in @nprops +* +* Find fwnodes referred to by a property @prop, then under that +* iteratively, @nprops times, follow each child node which has a +* property in @props array at a given child index the value of which +* matches the integer argument at an index. +* +* For example, if this function was called with arguments and values +* @dev corresponding to device "SEN", @prop == "flash-leds", @index +* == 1, @props == { "led" }, @nprops == 1, with the ASL snippet below +* it would return the node marked with THISONE. The @dev argument in +* the ASL below. +* +* Device (LED) +* { +* Name (_DSD, Package () { +* ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), +* Package () { +* Package () { "led0", "LED0" }, +* Package () { "led1", "LED1" }, +* } +* }) +* Name (LED0, Package () { +* ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), +* Package () { +* Package () { "led", 0 }, +* } +* }) +* Name (LED1, Package () { +* // THISONE +* ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), +* Package () { +* Package () { "led", 1 }, +* } +* }) +* } +* +* Device (SEN) +* { +* Name (_DSD, Package () { +* ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), +* Package () { +* Package () { +* "flash-leds", +* Package () { ^LED, 0, ^LED, 1 }, +* } +* } +* }) +* } +* +* where +* +* LED LED driver device +* LED0 First LED +* LED1 Second LED +* SEN Camera sensor device (or another device the LED is +* related to) +* +* Return: 0 on success +* -ENOENT if no entries (or the property itself) were found +* -EINVAL if property parsing otherwise failed +* -ENOMEM if memory allocation failed +*/ +static struct fwnode_handle *v4l2_fwnode_reference_get_int_prop ( +struct fwnode_handle *fwnode,const char *prop,unsigned int index, +const char **props,unsigned int nprops) +{ +struct fwnode_reference_args fwnode_args; +unsigned int *args = fwnode_args.args; +struct fwnode_handle *child; +int ret; + +/* +* Obtain remote fwnode as well as the integer arguments. +* +* Note that right now both -ENODATA and -ENOENT may signal +* out-of-bounds access. Return -ENOENT in that case. +*/ + ret =fwnode_property_get_reference_args (fwnode, prop,NULL , nprops, + index, &fwnode_args); +if (ret) +return ERR_PTR (ret == -ENODATA ? -ENOENT : ret); + +/* +* Find a node in the tree under the referred fwnode corresponding the +* integer arguments. +*/ + fwnode = fwnode_args.fwnode; +while (nprops--) { +u32 val; + +/* Loop over all child nodes under fwnode. */ +fwnode_for_each_child_node (fwnode, child) { +if (fwnode_property_read_u32 (child, *props, &val)) +continue ; + +/* Found property, see if its value matches. */ +if (val == *args) +break ; + } + +fwnode_handle_put (fwnode); + +/* No property found; return an error here. */ +if (!child) { + fwnode =ERR_PTR (-ENOENT ); +break ; + } + + props++; + args++; + fwnode = child; + } + +return fwnode; +} + +/* +* v4l2_fwnode_reference_parse_int_props - parse references for async sub-devices +* @dev: struct device pointer +* @notifier: notifier for @dev +* @prop: the name of the property +* @props: the array of integer property names +* @nprops: the number of integer properties +* +* Use v4l2_fwnode_reference_get_int_prop to find fwnodes through reference in +* property @prop with integer arguments with child nodes matching in properties +* @props. Then, set up V4L2 async sub-devices for those fwnodes in the notifier +* accordingly. +* +* While it is technically possible to use this function on DT, it is only +* meaningful on ACPI. On Device tree you can refer to any node in the tree but +* on ACPI the references are limited to devices. +* +* Return: 0 on success +* -ENOENT if no entries (or the property itself) were found +* -EINVAL if property parsing otherwisefailed +* -ENOMEM if memory allocation failed +*/ +static int v4l2_fwnode_reference_parse_int_props ( +struct device *dev,struct v4l2_async_notifier *notifier, +const char *prop,const char **props,unsigned int nprops) +{ +struct fwnode_handle *fwnode; +unsigned int index; +int ret; + +for (index =0 ; !IS_ERR ((fwnode =v4l2_fwnode_reference_get_int_prop ( +dev_fwnode (dev), prop, index, props, + nprops))); index++) +fwnode_handle_put (fwnode); + +/* +* Note that right now both -ENODATA and -ENOENT may signal +* out-of-bounds access. Return the error in cases other than that. +*/ +if (PTR_ERR (fwnode) != -ENOENT &&PTR_ERR (fwnode) != -ENODATA ) +return PTR_ERR (fwnode); + + ret =v4l2_async_notifier_realloc (notifier, + notifier->num_subdevs + index); +if (ret) +return -ENOMEM ; + +for (index =0 ; !IS_ERR ((fwnode =v4l2_fwnode_reference_get_int_prop ( +dev_fwnode (dev), prop, index, props, + nprops))); index++) { +struct v4l2_async_subdev *asd; + +if (WARN_ON (notifier->num_subdevs >= notifier->max_subdevs)) { + ret = -EINVAL ; + goto error; + } + + asd =kzalloc (sizeof (struct v4l2_async_subdev ),GFP_KERNEL ); +if (!asd) { + ret = -ENOMEM ; + goto error; + } + + notifier->subdevs[notifier->num_subdevs] = asd; + asd->match.fwnode.fwnode = fwnode; + asd->match_type =V4L2_ASYNC_MATCH_FWNODE ; + notifier->num_subdevs++; + } + +return PTR_ERR (fwnode) == -ENOENT ?0 :PTR_ERR (fwnode); + +error: +fwnode_handle_put (fwnode); +return ret; +} +MODULE_LICENSE ("GPL" );MODULE_AUTHOR ("Sakari Ailus <[email protected]>" );MODULE_AUTHOR ("Sylwester Nawrocki <[email protected]>" );
Signature · 1 line
2.11.0
A message that is not in the archive (sent off-list or not yet received): 20170925222540.371-21-sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected]
Re: [PATCH v14 20/28] v4l: fwnode: Add a helper function to obtain device / integer references
Quoted 21 lines · Sakari Ailus
v4l2_fwnode_reference_parse_int_prop()will find an fwnode such that under the device's own fwnode, it will follow child fwnodes with the given property-value pair and return the resulting fwnode.--- drivers/media/v4l2-core/v4l2-fwnode.c | 201 ++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+)drivers/media/v4l2-core/v4l2-fwnode.c +4
-0@@ -578,6 +578,207 @@ static int v4l2_fwnode_reference_parse(return ret; } +/* +* v4l2_fwnode_reference_get_int_prop - parse a reference with integer +* arguments +* @dev: struct device pointer
drivers/media/v4l2-core/v4l2-fwnode.c static int v4l2_fwnode_reference_parse( · line 594
Quoted 10 lines
drivers/media/v4l2-core/v4l2-fwnode.c +10
-0+* @notifier: notifier for @dev +* @prop: the name of the property +* @index: the index of the reference to get +* @props: the array of integer property names +* @nprops: the number of integer property names in @nprops +* +* Find fwnodes referred to by a property @prop, then under that +* iteratively, @nprops times, follow each child node which has a +* property in @props array at a given child index the value of which +* matches the integer argument at an index.
"at an index". Still makes no sense to me. Which index?
drivers/media/v4l2-core/v4l2-fwnode.c static int v4l2_fwnode_reference_parse( · line 600
Quoted 6 lines
drivers/media/v4l2-core/v4l2-fwnode.c +6
-0+* +* For example, if this function was called with arguments and values +* @dev corresponding to device "SEN", @prop == "flash-leds", @index +* == 1, @props == { "led" }, @nprops == 1, with the ASL snippet below +* it would return the node marked with THISONE. The @dev argument in +* the ASL below.
I know I asked for this before, but can you change the example to one where nprops = 2? I think that will help understanding this.
Quoted 63 lines
drivers/media/v4l2-core/v4l2-fwnode.c +63
-0+* +* Device (LED) +* { +* Name (_DSD, Package () { +* ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), +* Package () { +* Package () { "led0", "LED0" }, +* Package () { "led1", "LED1" }, +* } +* }) +* Name (LED0, Package () { +* ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), +* Package () { +* Package () { "led", 0 }, +* } +* }) +* Name (LED1, Package () { +* // THISONE +* ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), +* Package () { +* Package () { "led", 1 }, +* } +* }) +* } +* +* Device (SEN) +* { +* Name (_DSD, Package () { +* ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), +* Package () { +* Package () { +* "flash-leds", +* Package () { ^LED, 0, ^LED, 1 }, +* } +* } +* }) +* } +* +* where +* +* LED LED driver device +* LED0 First LED +* LED1 Second LED +* SEN Camera sensor device (or another device the LED is +* related to) +* +* Return: 0 on success +* -ENOENT if no entries (or the property itself) were found +* -EINVAL if property parsing otherwise failed +* -ENOMEM if memory allocation failed +*/ +static struct fwnode_handle *v4l2_fwnode_reference_get_int_prop ( +struct fwnode_handle *fwnode,const char *prop,unsigned int index, +const char **props,unsigned int nprops) +{ +struct fwnode_reference_args fwnode_args; +unsigned int *args = fwnode_args.args; +struct fwnode_handle *child; +int ret; + +/* +* Obtain remote fwnode as well as the integer arguments. +*
drivers/media/v4l2-core/v4l2-fwnode.c static int v4l2_fwnode_reference_parse( · line 673
Quoted 10 lines
drivers/media/v4l2-core/v4l2-fwnode.c +10
-0+* Note that right now both -ENODATA and -ENOENT may signal +* out-of-bounds access. Return -ENOENT in that case. +*/ + ret =fwnode_property_get_reference_args (fwnode, prop,NULL , nprops, + index, &fwnode_args); +if (ret) +return ERR_PTR (ret == -ENODATA ? -ENOENT : ret); + +/* +* Find a node in the tree under the referred fwnode corresponding the
corresponding -> corresponding to
Quoted 102 lines
drivers/media/v4l2-core/v4l2-fwnode.c +101
-0+* integer arguments. +*/ + fwnode = fwnode_args.fwnode; +while (nprops--) { +u32 val; + +/* Loop over all child nodes under fwnode. */ +fwnode_for_each_child_node (fwnode, child) { +if (fwnode_property_read_u32 (child, *props, &val)) +continue ; + +/* Found property, see if its value matches. */ +if (val == *args) +break ; + } + +fwnode_handle_put (fwnode); + +/* No property found; return an error here. */ +if (!child) { + fwnode =ERR_PTR (-ENOENT ); +break ; + } + + props++; + args++; + fwnode = child; + } + +return fwnode; +} + +/* +* v4l2_fwnode_reference_parse_int_props - parse references for async sub-devices +* @dev: struct device pointer +* @notifier: notifier for @dev +* @prop: the name of the property +* @props: the array of integer property names +* @nprops: the number of integer properties +* +* Use v4l2_fwnode_reference_get_int_prop to find fwnodes through reference in +* property @prop with integer arguments with child nodes matching in properties +* @props. Then, set up V4L2 async sub-devices for those fwnodes in the notifier +* accordingly. +* +* While it is technically possible to use this function on DT, it is only +* meaningful on ACPI. On Device tree you can refer to any node in the tree but +* on ACPI the references are limited to devices. +* +* Return: 0 on success +* -ENOENT if no entries (or the property itself) were found +* -EINVAL if property parsing otherwisefailed +* -ENOMEM if memory allocation failed +*/ +static int v4l2_fwnode_reference_parse_int_props ( +struct device *dev,struct v4l2_async_notifier *notifier, +const char *prop,const char **props,unsigned int nprops) +{ +struct fwnode_handle *fwnode; +unsigned int index; +int ret; + +for (index =0 ; !IS_ERR ((fwnode =v4l2_fwnode_reference_get_int_prop ( +dev_fwnode (dev), prop, index, props, + nprops))); index++) +fwnode_handle_put (fwnode); + +/* +* Note that right now both -ENODATA and -ENOENT may signal +* out-of-bounds access. Return the error in cases other than that. +*/ +if (PTR_ERR (fwnode) != -ENOENT &&PTR_ERR (fwnode) != -ENODATA ) +return PTR_ERR (fwnode); + + ret =v4l2_async_notifier_realloc (notifier, + notifier->num_subdevs + index); +if (ret) +return -ENOMEM ; + +for (index =0 ; !IS_ERR ((fwnode =v4l2_fwnode_reference_get_int_prop ( +dev_fwnode (dev), prop, index, props, + nprops))); index++) { +struct v4l2_async_subdev *asd; + +if (WARN_ON (notifier->num_subdevs >= notifier->max_subdevs)) { + ret = -EINVAL ; + goto error; + } + + asd =kzalloc (sizeof (struct v4l2_async_subdev ),GFP_KERNEL ); +if (!asd) { + ret = -ENOMEM ; + goto error; + } + + notifier->subdevs[notifier->num_subdevs] = asd; + asd->match.fwnode.fwnode = fwnode; + asd->match_type =V4L2_ASYNC_MATCH_FWNODE ; + notifier->num_subdevs++; + } +
drivers/media/v4l2-core/v4l2-fwnode.c static int v4l2_fwnode_reference_parse(
Quoted 10 lines
drivers/media/v4l2-core/v4l2-fwnode.c +7
-0+return PTR_ERR (fwnode) == -ENOENT ?0 :PTR_ERR (fwnode); + +error: +fwnode_handle_put (fwnode); +return ret; +} +MODULE_LICENSE ("GPL" );MODULE_AUTHOR ("Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected]>" );MODULE_AUTHOR ("Sylwester Nawrocki <[email protected]>" );
Regards,
Hans
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): fbd2f71d-aa6d-08ef-1723-132864bde27b-qWit8jRvyhVmR6Xm/[email protected]
Re: [PATCH v14 20/28] v4l: fwnode: Add a helper function to obtain device / integer references
Hi Hans,
Thanks for the review.
Quoted 18 lines · Hans Verkuil
Quoted 17 lines · Sakari Ailus
v4l2_fwnode_reference_parse_int_prop()will find an fwnode such that under the device's own fwnode, it will follow child fwnodes with the given property-value pair and return the resulting fwnode.--- drivers/media/v4l2-core/v4l2-fwnode.c | 201 ++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+)drivers/media/v4l2-core/v4l2-fwnode.c +0
-0@@ -578,6 +578,207 @@ static int v4l2_fwnode_reference_parse(return ret; }
Quoted 16 lines
Quoted 4 lines
drivers/media/v4l2-core/v4l2-fwnode.c +4
-0+/* +* v4l2_fwnode_reference_get_int_prop - parse a reference with integer +* arguments +* @dev: struct device pointer drivers/media/v4l2-core/v4l2-fwnode.c static int v4l2_fwnode_reference_parse( · line 594
Quoted 10 lines
drivers/media/v4l2-core/v4l2-fwnode.c +10
-0+* @notifier: notifier for @dev +* @prop: the name of the property +* @index: the index of the reference to get +* @props: the array of integer property names +* @nprops: the number of integer property names in @nprops +* +* Find fwnodes referred to by a property @prop, then under that +* iteratively, @nprops times, follow each child node which has a +* property in @props array at a given child index the value of which +* matches the integer argument at an index. "at an index". Still makes no sense to me. Which index?
How about this:
First find an fwnode referred to by the reference at @index in @prop.
Then under that fwnode, @nprops times, for each property in @props, iteratively follow child nodes starting from fwnode such that they have the property in @props array at the index of the child node distance from the root node and the value of that property matching with the integer argument of the reference, at the same index.
Quoted 10 lines
drivers/media/v4l2-core/v4l2-fwnode.c static int v4l2_fwnode_reference_parse( · line 600
Quoted 7 lines
drivers/media/v4l2-core/v4l2-fwnode.c +6
-0+* +* For example, if this function was called with arguments and values +* @dev corresponding to device "SEN", @prop == "flash-leds", @index +* == 1, @props == { "led" }, @nprops == 1, with the ASL snippet below +* it would return the node marked with THISONE. The @dev argument in +* the ASL below. I know I asked for this before, but can you change the example to one where nprops = 2? I think that will help understanding this.
I could do that but then the example no longer corresponds to any actual case that exists at the moment. LED nodes will use a single integer argument and lens-focus nodes none.
Quoted 68 lines
Quoted 68 lines
drivers/media/v4l2-core/v4l2-fwnode.c +67
-0+* +* Device (LED) +* { +* Name (_DSD, Package () { +* ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), +* Package () { +* Package () { "led0", "LED0" }, +* Package () { "led1", "LED1" }, +* } +* }) +* Name (LED0, Package () { +* ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), +* Package () { +* Package () { "led", 0 }, +* } +* }) +* Name (LED1, Package () { +* // THISONE +* ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), +* Package () { +* Package () { "led", 1 }, +* } +* }) +* } +* +* Device (SEN) +* { +* Name (_DSD, Package () { +* ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), +* Package () { +* Package () { +* "flash-leds", +* Package () { ^LED, 0, ^LED, 1 }, +* } +* } +* }) +* } +* +* where +* +* LED LED driver device +* LED0 First LED +* LED1 Second LED +* SEN Camera sensor device (or another device the LED is +* related to) +* +* Return: 0 on success +* -ENOENT if no entries (or the property itself) were found +* -EINVAL if property parsing otherwise failed +* -ENOMEM if memory allocation failed +*/ +static struct fwnode_handle *v4l2_fwnode_reference_get_int_prop ( +struct fwnode_handle *fwnode,const char *prop,unsigned int index, +const char **props,unsigned int nprops) +{ +struct fwnode_reference_args fwnode_args; +unsigned int *args = fwnode_args.args; +struct fwnode_handle *child; +int ret; + +/* +* Obtain remote fwnode as well as the integer arguments. +* +* Note that right now both -ENODATA and -ENOENT may signal +* out-of-bounds access. Return -ENOENT in that case. +*/ + ret = fwnode_property_get_reference_args(fwnode, prop, NULL, nprops,
Quoted 8 lines
drivers/media/v4l2-core/v4l2-fwnode.c static int v4l2_fwnode_reference_parse( · line 673
Quoted 6 lines
drivers/media/v4l2-core/v4l2-fwnode.c +6
-0+ index, &fwnode_args); +if (ret) +return ERR_PTR (ret == -ENODATA ? -ENOENT : ret); + +/* +* Find a node in the tree under the referred fwnode corresponding the corresponding -> corresponding to
Fixed.
Quoted 117 lines
Quoted 103 lines
drivers/media/v4l2-core/v4l2-fwnode.c +101
-0+* integer arguments. +*/ + fwnode = fwnode_args.fwnode; +while (nprops--) { +u32 val; + +/* Loop over all child nodes under fwnode. */ +fwnode_for_each_child_node (fwnode, child) { +if (fwnode_property_read_u32 (child, *props, &val)) +continue ; + +/* Found property, see if its value matches. */ +if (val == *args) +break ; + } + +fwnode_handle_put (fwnode); + +/* No property found; return an error here. */ +if (!child) { + fwnode =ERR_PTR (-ENOENT ); +break ; + } + + props++; + args++; + fwnode = child; + } + +return fwnode; +} + +/* +* v4l2_fwnode_reference_parse_int_props - parse references for async sub-devices +* @dev: struct device pointer +* @notifier: notifier for @dev +* @prop: the name of the property +* @props: the array of integer property names +* @nprops: the number of integer properties +* +* Use v4l2_fwnode_reference_get_int_prop to find fwnodes through reference in +* property @prop with integer arguments with child nodes matching in properties +* @props. Then, set up V4L2 async sub-devices for those fwnodes in the notifier +* accordingly. +* +* While it is technically possible to use this function on DT, it is only +* meaningful on ACPI. On Device tree you can refer to any node in the tree but +* on ACPI the references are limited to devices. +* +* Return: 0 on success +* -ENOENT if no entries (or the property itself) were found +* -EINVAL if property parsing otherwisefailed +* -ENOMEM if memory allocation failed +*/ +static int v4l2_fwnode_reference_parse_int_props ( +struct device *dev,struct v4l2_async_notifier *notifier, +const char *prop,const char **props,unsigned int nprops) +{ +struct fwnode_handle *fwnode; +unsigned int index; +int ret; + +for (index =0 ; !IS_ERR ((fwnode =v4l2_fwnode_reference_get_int_prop ( +dev_fwnode (dev), prop, index, props, + nprops))); index++) +fwnode_handle_put (fwnode); + +/* +* Note that right now both -ENODATA and -ENOENT may signal +* out-of-bounds access. Return the error in cases other than that. +*/ +if (PTR_ERR (fwnode) != -ENOENT &&PTR_ERR (fwnode) != -ENODATA ) +return PTR_ERR (fwnode); + + ret =v4l2_async_notifier_realloc (notifier, + notifier->num_subdevs + index); +if (ret) +return -ENOMEM ; + +for (index =0 ; !IS_ERR ((fwnode =v4l2_fwnode_reference_get_int_prop ( +dev_fwnode (dev), prop, index, props, + nprops))); index++) { +struct v4l2_async_subdev *asd; + +if (WARN_ON (notifier->num_subdevs >= notifier->max_subdevs)) { + ret = -EINVAL ; + goto error; + } + + asd =kzalloc (sizeof (struct v4l2_async_subdev ),GFP_KERNEL ); +if (!asd) { + ret = -ENOMEM ; + goto error; + } + + notifier->subdevs[notifier->num_subdevs] = asd; + asd->match.fwnode.fwnode = fwnode; + asd->match_type =V4L2_ASYNC_MATCH_FWNODE ; + notifier->num_subdevs++; + } +drivers/media/v4l2-core/v4l2-fwnode.c static int v4l2_fwnode_reference_parse(
Quoted 10 lines
drivers/media/v4l2-core/v4l2-fwnode.c +7
-0+return PTR_ERR (fwnode) == -ENOENT ?0 :PTR_ERR (fwnode); + +error: +fwnode_handle_put (fwnode); +return ret; +} +MODULE_LICENSE ("GPL" );MODULE_AUTHOR ("Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected]>" );MODULE_AUTHOR ("Sylwester Nawrocki <[email protected]>" );Regards,
Hans
Signature · 6 lines
Sakari Ailus sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected] -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): 20170926113029.eh5i4sp6we6lvgow-z7MJbOB4PBP+e+fPlCVrcFDQ4js95KgL@public.gmane.org
Re: [PATCH v14 20/28] v4l: fwnode: Add a helper function to obtain device / integer references
Hi Sakari,
My reply here is also valid for v15.
Quoted 40 lines · Sakari Ailus
Hi Hans,
Thanks for the review.
Quoted 18 lines · Hans Verkuil
Quoted 17 lines · Sakari Ailus
v4l2_fwnode_reference_parse_int_prop()will find an fwnode such that under the device's own fwnode, it will follow child fwnodes with the given property-value pair and return the resulting fwnode.--- drivers/media/v4l2-core/v4l2-fwnode.c | 201 ++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+)drivers/media/v4l2-core/v4l2-fwnode.c +0
-0@@ -578,6 +578,207 @@ static int v4l2_fwnode_reference_parse(return ret; }Quoted 16 lines
Quoted 4 lines
drivers/media/v4l2-core/v4l2-fwnode.c +4
-0+/* +* v4l2_fwnode_reference_get_int_prop - parse a reference with integer +* arguments +* @dev: struct device pointer drivers/media/v4l2-core/v4l2-fwnode.c static int v4l2_fwnode_reference_parse( · line 594
Quoted 10 lines
drivers/media/v4l2-core/v4l2-fwnode.c +10
-0+* @notifier: notifier for @dev +* @prop: the name of the property +* @index: the index of the reference to get +* @props: the array of integer property names +* @nprops: the number of integer property names in @nprops +* +* Find fwnodes referred to by a property @prop, then under that +* iteratively, @nprops times, follow each child node which has a +* property in @props array at a given child index the value of which +* matches the integer argument at an index. "at an index". Still makes no sense to me. Which index?
Quoted 7 lines
How about this:
First find an fwnode referred to by the reference at @index in @prop.
Then under that fwnode, @nprops times, for each property in @props, iteratively follow child nodes starting from fwnode such that they have the property in @props array at the index of the child node distance from the
distance? You mean 'instance'?
Quoted 2 lines
root node and the value of that property matching with the integer argument of the reference, at the same index.
You've completely lost me. About halfway through this sentence my brain crashed :-)
Quoted 9 lines
Quoted 9 lines
Quoted 8 lines
drivers/media/v4l2-core/v4l2-fwnode.c +6
-0+* +* For example, if this function was called with arguments and values +* @dev corresponding to device "SEN", @prop == "flash-leds", @index +* == 1, @props == { "led" }, @nprops == 1, with the ASL snippet below +* it would return the node marked with THISONE. The @dev argument in +* the ASL below.
Quoted 6 lines
Quoted 2 lines
I know I asked for this before, but can you change the example to one where nprops = 2? I think that will help understanding this.
I could do that but then the example no longer corresponds to any actual case that exists at the moment. LED nodes will use a single integer argument and lens-focus nodes none.
So? The example is here to understand the code and it doesn't have to be related to actual hardware for a mainlined driver.
If you really don't want to do this here, then put the example in the commit log. I don't see any reason why you can't put it here, though.
I think that once I see an 'nprops = 2' example I can rephrase that brain-crash sentence for you...
BTW, where are the ACPI 'bindings' defined anyway? For DT they are in the bindings directory, but where does ACPI define such things? Just curious.
Regards,
Hans
Quoted 78 lines
Quoted 69 lines
Quoted 69 lines
drivers/media/v4l2-core/v4l2-fwnode.c +67
-0+* +* Device (LED) +* { +* Name (_DSD, Package () { +* ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), +* Package () { +* Package () { "led0", "LED0" }, +* Package () { "led1", "LED1" }, +* } +* }) +* Name (LED0, Package () { +* ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), +* Package () { +* Package () { "led", 0 }, +* } +* }) +* Name (LED1, Package () { +* // THISONE +* ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), +* Package () { +* Package () { "led", 1 }, +* } +* }) +* } +* +* Device (SEN) +* { +* Name (_DSD, Package () { +* ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), +* Package () { +* Package () { +* "flash-leds", +* Package () { ^LED, 0, ^LED, 1 }, +* } +* } +* }) +* } +* +* where +* +* LED LED driver device +* LED0 First LED +* LED1 Second LED +* SEN Camera sensor device (or another device the LED is +* related to) +* +* Return: 0 on success +* -ENOENT if no entries (or the property itself) were found +* -EINVAL if property parsing otherwise failed +* -ENOMEM if memory allocation failed +*/ +static struct fwnode_handle *v4l2_fwnode_reference_get_int_prop ( +struct fwnode_handle *fwnode,const char *prop,unsigned int index, +const char **props,unsigned int nprops) +{ +struct fwnode_reference_args fwnode_args; +unsigned int *args = fwnode_args.args; +struct fwnode_handle *child; +int ret; + +/* +* Obtain remote fwnode as well as the integer arguments. +* +* Note that right now both -ENODATA and -ENOENT may signal +* out-of-bounds access. Return -ENOENT in that case. +*/ + ret = fwnode_property_get_reference_args(fwnode, prop, NULL, nprops,Quoted 8 lines
drivers/media/v4l2-core/v4l2-fwnode.c static int v4l2_fwnode_reference_parse( · line 673
Quoted 6 lines
drivers/media/v4l2-core/v4l2-fwnode.c +6
-0+ index, &fwnode_args); +if (ret) +return ERR_PTR (ret == -ENODATA ? -ENOENT : ret); + +/* +* Find a node in the tree under the referred fwnode corresponding the corresponding -> corresponding to
Quoted 120 lines
Fixed.
Quoted 117 lines
Quoted 103 lines
drivers/media/v4l2-core/v4l2-fwnode.c +101
-0+* integer arguments. +*/ + fwnode = fwnode_args.fwnode; +while (nprops--) { +u32 val; + +/* Loop over all child nodes under fwnode. */ +fwnode_for_each_child_node (fwnode, child) { +if (fwnode_property_read_u32 (child, *props, &val)) +continue ; + +/* Found property, see if its value matches. */ +if (val == *args) +break ; + } + +fwnode_handle_put (fwnode); + +/* No property found; return an error here. */ +if (!child) { + fwnode =ERR_PTR (-ENOENT ); +break ; + } + + props++; + args++; + fwnode = child; + } + +return fwnode; +} + +/* +* v4l2_fwnode_reference_parse_int_props - parse references for async sub-devices +* @dev: struct device pointer +* @notifier: notifier for @dev +* @prop: the name of the property +* @props: the array of integer property names +* @nprops: the number of integer properties +* +* Use v4l2_fwnode_reference_get_int_prop to find fwnodes through reference in +* property @prop with integer arguments with child nodes matching in properties +* @props. Then, set up V4L2 async sub-devices for those fwnodes in the notifier +* accordingly. +* +* While it is technically possible to use this function on DT, it is only +* meaningful on ACPI. On Device tree you can refer to any node in the tree but +* on ACPI the references are limited to devices. +* +* Return: 0 on success +* -ENOENT if no entries (or the property itself) were found +* -EINVAL if property parsing otherwisefailed +* -ENOMEM if memory allocation failed +*/ +static int v4l2_fwnode_reference_parse_int_props ( +struct device *dev,struct v4l2_async_notifier *notifier, +const char *prop,const char **props,unsigned int nprops) +{ +struct fwnode_handle *fwnode; +unsigned int index; +int ret; + +for (index =0 ; !IS_ERR ((fwnode =v4l2_fwnode_reference_get_int_prop ( +dev_fwnode (dev), prop, index, props, + nprops))); index++) +fwnode_handle_put (fwnode); + +/* +* Note that right now both -ENODATA and -ENOENT may signal +* out-of-bounds access. Return the error in cases other than that. +*/ +if (PTR_ERR (fwnode) != -ENOENT &&PTR_ERR (fwnode) != -ENODATA ) +return PTR_ERR (fwnode); + + ret =v4l2_async_notifier_realloc (notifier, + notifier->num_subdevs + index); +if (ret) +return -ENOMEM ; + +for (index =0 ; !IS_ERR ((fwnode =v4l2_fwnode_reference_get_int_prop ( +dev_fwnode (dev), prop, index, props, + nprops))); index++) { +struct v4l2_async_subdev *asd; + +if (WARN_ON (notifier->num_subdevs >= notifier->max_subdevs)) { + ret = -EINVAL ; + goto error; + } + + asd =kzalloc (sizeof (struct v4l2_async_subdev ),GFP_KERNEL ); +if (!asd) { + ret = -ENOMEM ; + goto error; + } + + notifier->subdevs[notifier->num_subdevs] = asd; + asd->match.fwnode.fwnode = fwnode; + asd->match_type =V4L2_ASYNC_MATCH_FWNODE ; + notifier->num_subdevs++; + } +drivers/media/v4l2-core/v4l2-fwnode.c static int v4l2_fwnode_reference_parse(
Quoted 10 lines
drivers/media/v4l2-core/v4l2-fwnode.c +7
-0+return PTR_ERR (fwnode) == -ENOENT ?0 :PTR_ERR (fwnode); + +error: +fwnode_handle_put (fwnode); +return ret; +} +MODULE_LICENSE ("GPL" );MODULE_AUTHOR ("Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected]>" );MODULE_AUTHOR ("Sylwester Nawrocki <[email protected]>" );Regards,
Hans
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Sakari Ailus
maintainerRe: [PATCH v14 20/28] v4l: fwnode: Add a helper function to obtain device / integer references
Hi Hans,
Quoted 47 lines · Hans Verkuil
Hi Sakari,
My reply here is also valid for v15.
Quoted 42 lines · Sakari Ailus
Hi Hans,
Thanks for the review.
Quoted 18 lines · Hans Verkuil
Quoted 17 lines · Sakari Ailus
v4l2_fwnode_reference_parse_int_prop()will find an fwnode such that under the device's own fwnode, it will follow child fwnodes with the given property-value pair and return the resulting fwnode.Signed-off-by Sakari Ailus <[email protected]>--- drivers/media/v4l2-core/v4l2-fwnode.c | 201 ++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+)drivers/media/v4l2-core/v4l2-fwnode.c +0
-0@@ -578,6 +578,207 @@ static int v4l2_fwnode_reference_parse(return ret; }Quoted 16 lines
Quoted 4 lines
drivers/media/v4l2-core/v4l2-fwnode.c +4
-0+/* +* v4l2_fwnode_reference_get_int_prop - parse a reference with integer +* arguments +* @dev: struct device pointer drivers/media/v4l2-core/v4l2-fwnode.c static int v4l2_fwnode_reference_parse( · line 594
Quoted 10 lines
drivers/media/v4l2-core/v4l2-fwnode.c +10
-0+* @notifier: notifier for @dev +* @prop: the name of the property +* @index: the index of the reference to get +* @props: the array of integer property names +* @nprops: the number of integer property names in @nprops +* +* Find fwnodes referred to by a property @prop, then under that +* iteratively, @nprops times, follow each child node which has a +* property in @props array at a given child index the value of which +* matches the integer argument at an index. "at an index". Still makes no sense to me. Which index?
How about this:
Quoted 7 lines
Quoted 5 lines
First find an fwnode referred to by the reference at @index in @prop.
Then under that fwnode, @nprops times, for each property in @props, iteratively follow child nodes starting from fwnode such that they have the property in @props array at the index of the child node distance from the
distance? You mean 'instance'?
No. It's a tree structure: this is the distance between a node in the tree and the root node (i.e. device's fwnode).
Quoted 5 lines
Quoted 3 lines
root node and the value of that property matching with the integer argument of the reference, at the same index.
You've completely lost me. About halfway through this sentence my brain crashed :-)
:-D
Did keeping distance have any effect?
Quoted 13 lines
Quoted 13 lines
Quoted 12 lines
drivers/media/v4l2-core/v4l2-fwnode.c static int v4l2_fwnode_reference_parse( · line 600
Quoted 9 lines
drivers/media/v4l2-core/v4l2-fwnode.c +6
-0+* +* For example, if this function was called with arguments and values +* @dev corresponding to device "SEN", @prop == "flash-leds", @index +* == 1, @props == { "led" }, @nprops == 1, with the ASL snippet below +* it would return the node marked with THISONE. The @dev argument in +* the ASL below. I know I asked for this before, but can you change the example to one where nprops = 2? I think that will help understanding this.
Quoted 6 lines
Quoted 3 lines
I could do that but then the example no longer corresponds to any actual case that exists at the moment. LED nodes will use a single integer argument and lens-focus nodes none.
So? The example is here to understand the code and it doesn't have to be related to actual hardware for a mainlined driver.
This isn't about hardware, the definitions being parsed currently aren't specific to any single piece of hardware. I could add an example which does not exist, that's certainly possible. But I fail to see how it'd help while the contrary could well be the case.
Quoted 9 lines
If you really don't want to do this here, then put the example in the commit log. I don't see any reason why you can't put it here, though.
I think that once I see an 'nprops = 2' example I can rephrase that brain-crash sentence for you...
BTW, where are the ACPI 'bindings' defined anyway? For DT they are in the bindings directory, but where does ACPI define such things? Just curious.
As the fwnode interface can be used to access information in both ACPI and DT, there is an incentive to maintain the interfaces effectively the same. In other words where the interfaces are the same, there is no need to define bindings for ACPI as such. Where there are differences the bindings are defined in Documentation/acpi/dsd .
The so far only technical reason to that is related to the same is that ACPI can only refer to device nodes (i.e. nodes that correspond to struct devices), not sub-nodes under them.
Signature · 4 lines
Kind regards, Sakari Ailus e-mail: [email protected]
Re: [PATCH v14 20/28] v4l: fwnode: Add a helper function to obtain device / integer references
Quoted 62 lines · Sakari Ailus
Hi Hans,
Quoted 47 lines · Hans Verkuil
Hi Sakari,
My reply here is also valid for v15.
Quoted 42 lines · Sakari Ailus
Hi Hans,
Thanks for the review.
Quoted 18 lines · Hans Verkuil
Quoted 17 lines · Sakari Ailus
v4l2_fwnode_reference_parse_int_prop()will find an fwnode such that under the device's own fwnode, it will follow child fwnodes with the given property-value pair and return the resulting fwnode.Signed-off-by Sakari Ailus <[email protected]>--- drivers/media/v4l2-core/v4l2-fwnode.c | 201 ++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+)drivers/media/v4l2-core/v4l2-fwnode.c +0
-0@@ -578,6 +578,207 @@ static int v4l2_fwnode_reference_parse(return ret; }Quoted 16 lines
Quoted 4 lines
drivers/media/v4l2-core/v4l2-fwnode.c +4
-0+/* +* v4l2_fwnode_reference_get_int_prop - parse a reference with integer +* arguments +* @dev: struct device pointer drivers/media/v4l2-core/v4l2-fwnode.c static int v4l2_fwnode_reference_parse( · line 594
Quoted 10 lines
drivers/media/v4l2-core/v4l2-fwnode.c +10
-0+* @notifier: notifier for @dev +* @prop: the name of the property +* @index: the index of the reference to get +* @props: the array of integer property names +* @nprops: the number of integer property names in @nprops +* +* Find fwnodes referred to by a property @prop, then under that +* iteratively, @nprops times, follow each child node which has a +* property in @props array at a given child index the value of which +* matches the integer argument at an index. "at an index". Still makes no sense to me. Which index?
How about this:
Quoted 7 lines
Quoted 5 lines
First find an fwnode referred to by the reference at @index in @prop.
Then under that fwnode, @nprops times, for each property in @props, iteratively follow child nodes starting from fwnode such that they have the property in @props array at the index of the child node distance from the
distance? You mean 'instance'?
No. It's a tree structure: this is the distance between a node in the tree and the root node (i.e. device's fwnode).
Quoted 1 line
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
root node and the value of that property matching with the integer argument of the reference, at the same index.
You've completely lost me. About halfway through this sentence my brain crashed :-)
:-D
Did keeping distance have any effect?
No :-)
"the index of the child node distance from the root node": I have absolutely no idea how to interpret that.
Quoted 18 lines
Quoted 18 lines
Quoted 17 lines
Quoted 11 lines
drivers/media/v4l2-core/v4l2-fwnode.c static int v4l2_fwnode_reference_parse( · line 600
Quoted 10 lines
drivers/media/v4l2-core/v4l2-fwnode.c +6
-0+* +* For example, if this function was called with arguments and values +* @dev corresponding to device "SEN", @prop == "flash-leds", @index +* == 1, @props == { "led" }, @nprops == 1, with the ASL snippet below +* it would return the node marked with THISONE. The @dev argument in +* the ASL below. Quoted 2 lines
I know I asked for this before, but can you change the example to one where nprops = 2? I think that will help understanding this.
I could do that but then the example no longer corresponds to any actual case that exists at the moment. LED nodes will use a single integer argument and lens-focus nodes none.
Quoted 7 lines
Quoted 2 lines
So? The example is here to understand the code and it doesn't have to be related to actual hardware for a mainlined driver.
This isn't about hardware, the definitions being parsed currently aren't specific to any single piece of hardware. I could add an example which does not exist, that's certainly possible. But I fail to see how it'd help while the contrary could well be the case.
It helps to relate the code (and the comments for that matter) to what is in the ACPI. In fact, if you can make such an example, then I can see if I can come up with a better description.
Regards,
Hans
Quoted 21 lines
Quoted 10 lines
If you really don't want to do this here, then put the example in the commit log. I don't see any reason why you can't put it here, though.
I think that once I see an 'nprops = 2' example I can rephrase that brain-crash sentence for you...
BTW, where are the ACPI 'bindings' defined anyway? For DT they are in the bindings directory, but where does ACPI define such things? Just curious.
As the fwnode interface can be used to access information in both ACPI and DT, there is an incentive to maintain the interfaces effectively the same. In other words where the interfaces are the same, there is no need to define bindings for ACPI as such. Where there are differences the bindings are defined in
Documentation/acpi/dsd.The so far only technical reason to that is related to the same is that ACPI can only refer to device nodes (i.e. nodes that correspond to struct devices), not sub-nodes under them.
A message that is not in the archive (sent off-list or not yet received): d8a48273-7a19-0f83-4a4d-8058b7a59e0e-qWit8jRvyhVmR6Xm/[email protected]
Re: [PATCH v14 20/28] v4l: fwnode: Add a helper function to obtain device / integer references
Hi Hans,
Quoted 68 lines · Hans Verkuil
Quoted 67 lines · Sakari Ailus
Hi Hans,
Quoted 47 lines · Hans Verkuil
Hi Sakari,
My reply here is also valid for v15.
Quoted 42 lines · Sakari Ailus
Hi Hans,
Thanks for the review.
Quoted 18 lines · Hans Verkuil
Quoted 17 lines · Sakari Ailus
v4l2_fwnode_reference_parse_int_prop()will find an fwnode such that under the device's own fwnode, it will follow child fwnodes with the given property-value pair and return the resulting fwnode.--- drivers/media/v4l2-core/v4l2-fwnode.c | 201 ++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+)drivers/media/v4l2-core/v4l2-fwnode.c +0
-0@@ -578,6 +578,207 @@ static int v4l2_fwnode_reference_parse(return ret; }Quoted 16 lines
Quoted 4 lines
drivers/media/v4l2-core/v4l2-fwnode.c +4
-0+/* +* v4l2_fwnode_reference_get_int_prop - parse a reference with integer +* arguments +* @dev: struct device pointer drivers/media/v4l2-core/v4l2-fwnode.c static int v4l2_fwnode_reference_parse( · line 594
Quoted 10 lines
drivers/media/v4l2-core/v4l2-fwnode.c +10
-0+* @notifier: notifier for @dev +* @prop: the name of the property +* @index: the index of the reference to get +* @props: the array of integer property names +* @nprops: the number of integer property names in @nprops +* +* Find fwnodes referred to by a property @prop, then under that +* iteratively, @nprops times, follow each child node which has a +* property in @props array at a given child index the value of which +* matches the integer argument at an index. "at an index". Still makes no sense to me. Which index?
How about this:
Quoted 7 lines
Quoted 5 lines
First find an fwnode referred to by the reference at @index in @prop.
Then under that fwnode, @nprops times, for each property in @props, iteratively follow child nodes starting from fwnode such that they have the property in @props array at the index of the child node distance from the
distance? You mean 'instance'?
No. It's a tree structure: this is the distance between a node in the tree and the root node (i.e. device's fwnode).
Quoted 5 lines
Quoted 3 lines
root node and the value of that property matching with the integer argument of the reference, at the same index.
You've completely lost me. About halfway through this sentence my brain crashed :-)
Quoted 8 lines
Quoted 3 lines
:-D
Did keeping distance have any effect?
No :-)
"the index of the child node distance from the root node": I have absolutely no idea how to interpret that.
This index is referring to the properties array and its value is the same as the distance of the child node from the device's root node.
Quoted 22 lines
Quoted 22 lines
Quoted 21 lines
Quoted 12 lines
Quoted 12 lines
Quoted 11 lines
drivers/media/v4l2-core/v4l2-fwnode.c +6
-0+* +* For example, if this function was called with arguments and values +* @dev corresponding to device "SEN", @prop == "flash-leds", @index +* == 1, @props == { "led" }, @nprops == 1, with the ASL snippet below +* it would return the node marked with THISONE. The @dev argument in +* the ASL below. Quoted 6 lines
Quoted 2 lines
I know I asked for this before, but can you change the example to one where nprops = 2? I think that will help understanding this.
I could do that but then the example no longer corresponds to any actual case that exists at the moment. LED nodes will use a single integer argument and lens-focus nodes none.
So? The example is here to understand the code and it doesn't have to be related to actual hardware for a mainlined driver.
Quoted 8 lines
Quoted 4 lines
This isn't about hardware, the definitions being parsed currently aren't specific to any single piece of hardware. I could add an example which does not exist, that's certainly possible. But I fail to see how it'd help while the contrary could well be the case.
It helps to relate the code (and the comments for that matter) to what is in the ACPI. In fact, if you can make such an example, then I can see if I can come up with a better description.
Hmm. I thought about the example, and figured out the graph data structure could be parsed using this function as well. From Documentation/acpi/dsd/graph.txt:
Scope (\_SB.PCI0.I2C2)
{
Device (CAM0)
{
Name (_DSD, Package () {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () { "compatible", Package () { "nokia,smia" } },
},
ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
Package () {
Package () { "port0", "PRT0" },
}
})
Name (PRT0, Package() {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () { "port", 0 },
},
ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
Package () {
Package () { "endpoint0", "EP00" },
}
})
Name (EP00, Package() {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () { "endpoint", 0 },
Package () { "remote-endpoint", Package() { \_SB.PCI0.ISP, 4, 0 } },
}
})
}
}
Scope (\_SB.PCI0)
{
Device (ISP)
{
Name (_DSD, Package () {
ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
Package () {
Package () { "port4", "PRT4" },
}
})
Name (PRT4, Package() {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () { "port", 4 }, /* CSI-2 port number */
},
ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
Package () {
Package () { "endpoint0", "EP40" },
}
})
Name (EP40, Package() {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () { "endpoint", 0 },
Package () { "remote-endpoint", Package () { \_SB.PCI0.I2C2.CAM0, 0, 0 } },
}
})
}
}Quoted 1 line
From the EP40 node under ISP device, you could parse the graph remote
endpoint using v4l2_fwnode_reference_get_int_prop with these arguments (the argument dev changed to fwnode in an earlier version of the patch, I'll address that soon as well):
@fwnode: fwnode referring to EP40 under ISP.
@prop: "remote-endpoint"
@index: 0
@props: "port", "endpoint"
@nprops: 2
And you'd get back fwnode referring to EP00 under CAM0.
The same works the other way around: if you use EP00 under CAM0 as the fwnode, you'll get fwnode referring to EP40 under ISP.
If the remote-endpoint property would have additional references beyond the first one, then incrementing index could be used to obtain them. The graph bindings don't allow this though.
This function can be eventually moved to the ACPI framework, but doing that right now would probably one kernel release delay for the functionality.
Signature · 8 lines
Regards, Sakari Ailus sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected] -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Sakari Ailus
maintainerRe: [PATCH v14 20/28] v4l: fwnode: Add a helper function to obtain device / integer references
Quoted 175 lines · Sakari Ailus
Hi Hans,
Quoted 68 lines · Hans Verkuil
Quoted 67 lines · Sakari Ailus
Hi Hans,
Quoted 47 lines · Hans Verkuil
Hi Sakari,
My reply here is also valid for v15.
Quoted 42 lines · Sakari Ailus
Hi Hans,
Thanks for the review.
Quoted 18 lines · Hans Verkuil
Quoted 17 lines · Sakari Ailus
v4l2_fwnode_reference_parse_int_prop()will find an fwnode such that under the device's own fwnode, it will follow child fwnodes with the given property-value pair and return the resulting fwnode.Signed-off-by Sakari Ailus <[email protected]>--- drivers/media/v4l2-core/v4l2-fwnode.c | 201 ++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+)drivers/media/v4l2-core/v4l2-fwnode.c +0
-0@@ -578,6 +578,207 @@ static int v4l2_fwnode_reference_parse(return ret; }Quoted 16 lines
Quoted 4 lines
drivers/media/v4l2-core/v4l2-fwnode.c +4
-0+/* +* v4l2_fwnode_reference_get_int_prop - parse a reference with integer +* arguments +* @dev: struct device pointer drivers/media/v4l2-core/v4l2-fwnode.c static int v4l2_fwnode_reference_parse( · line 594
Quoted 10 lines
drivers/media/v4l2-core/v4l2-fwnode.c +10
-0+* @notifier: notifier for @dev +* @prop: the name of the property +* @index: the index of the reference to get +* @props: the array of integer property names +* @nprops: the number of integer property names in @nprops +* +* Find fwnodes referred to by a property @prop, then under that +* iteratively, @nprops times, follow each child node which has a +* property in @props array at a given child index the value of which +* matches the integer argument at an index. "at an index". Still makes no sense to me. Which index?
How about this:
Quoted 7 lines
Quoted 5 lines
First find an fwnode referred to by the reference at @index in @prop.
Then under that fwnode, @nprops times, for each property in @props, iteratively follow child nodes starting from fwnode such that they have the property in @props array at the index of the child node distance from the
distance? You mean 'instance'?
No. It's a tree structure: this is the distance between a node in the tree and the root node (i.e. device's fwnode).
Quoted 5 lines
Quoted 3 lines
root node and the value of that property matching with the integer argument of the reference, at the same index.
You've completely lost me. About halfway through this sentence my brain crashed :-)
Quoted 8 lines
Quoted 3 lines
:-D
Did keeping distance have any effect?
No :-)
"the index of the child node distance from the root node": I have absolutely no idea how to interpret that.
This index is referring to the properties array and its value is the same as the distance of the child node from the device's root node.
Quoted 22 lines
Quoted 22 lines
Quoted 21 lines
Quoted 12 lines
Quoted 12 lines
Quoted 11 lines
drivers/media/v4l2-core/v4l2-fwnode.c +6
-0+* +* For example, if this function was called with arguments and values +* @dev corresponding to device "SEN", @prop == "flash-leds", @index +* == 1, @props == { "led" }, @nprops == 1, with the ASL snippet below +* it would return the node marked with THISONE. The @dev argument in +* the ASL below. Quoted 6 lines
Quoted 2 lines
I know I asked for this before, but can you change the example to one where nprops = 2? I think that will help understanding this.
I could do that but then the example no longer corresponds to any actual case that exists at the moment. LED nodes will use a single integer argument and lens-focus nodes none.
So? The example is here to understand the code and it doesn't have to be related to actual hardware for a mainlined driver.
Quoted 8 lines
Quoted 4 lines
This isn't about hardware, the definitions being parsed currently aren't specific to any single piece of hardware. I could add an example which does not exist, that's certainly possible. But I fail to see how it'd help while the contrary could well be the case.
It helps to relate the code (and the comments for that matter) to what is in the ACPI. In fact, if you can make such an example, then I can see if I can come up with a better description.
Hmm. I thought about the example, and figured out the graph data structure could be parsed using this function as well. From
Documentation/acpi/dsd/graph.txt:Scope (\_SB.PCI0.I2C2) { Device (CAM0) { Name (_DSD, Package () { ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), Package () { Package () { "compatible", Package () { "nokia,smia" } }, }, ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), Package () { Package () { "port0", "PRT0" }, } }) Name (PRT0, Package() { ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), Package () { Package () { "port", 0 }, }, ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), Package () { Package () { "endpoint0", "EP00" }, } }) Name (EP00, Package() { ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), Package () { Package () { "endpoint", 0 }, Package () { "remote-endpoint", Package() { \_SB.PCI0.ISP, 4, 0 } }, } }) } } Scope (\_SB.PCI0) { Device (ISP) { Name (_DSD, Package () { ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), Package () { Package () { "port4", "PRT4" }, } }) Name (PRT4, Package() { ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), Package () { Package () { "port", 4 }, /* CSI-2 port number */ }, ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), Package () { Package () { "endpoint0", "EP40" }, } }) Name (EP40, Package() {
Quoted 8 lines
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () { "endpoint", 0 },
Package () { "remote-endpoint", Package () { \_SB.PCI0.I2C2.CAM0, 0, 0 } },
}
})
}
}If you did this with DT it'd look roughly like:
cam0 {
compatible = "nokia,smia";
port {
cam0_ep: endpoint {
remote-endpoint = <&isp_port4_ep>;
};
};
};isp {
ports {
port@4 {
reg = <4>;
isp_port4_ep: endpoint {
remote-endpoint = <&cam0_ep>;
};
};
};
};And in ACPI style, i.e. with explicit "port" and "endpoint" properties as well as integers to point the ports and endpoints:
cam: cam0 {
compatible = "nokia,smia";
port {
port = <0>;
cam0_ep: endpoint {
endpoint = <0>;
remote-endpoint = <&isp 4 0>;
};
};
};isp: isp {
ports {
port@4 {
port = <4>;
isp_port4_ep: endpoint {
endpoint = <0>;
remote-endpoint = <&cam 0 0>;
};
};
};
};Quoted 29 lines
From the EP40 node under ISP device, you could parse the graph remote endpoint using
v4l2_fwnode_reference_get_int_propwith these arguments (the argument dev changed to fwnode in an earlier version of the patch, I'll address that soon as well):@fwnode: fwnode referring to EP40 under ISP.
@prop: "remote-endpoint"
@index: 0
@props: "port", "endpoint"
@nprops: 2And you'd get back fwnode referring to EP00 under CAM0.
The same works the other way around: if you use EP00 under CAM0 as the fwnode, you'll get fwnode referring to EP40 under ISP.
If the remote-endpoint property would have additional references beyond the first one, then incrementing index could be used to obtain them. The graph bindings don't allow this though.
This function can be eventually moved to the ACPI framework, but doing that right now would probably one kernel release delay for the functionality.
Signature · 4 lines
Regards, Sakari Ailus [email protected]
Signature · 2 lines
Sakari Ailus e-mail: [email protected]
Sakari Ailus
maintainerPATCH v14 21/28 v4l: fwnode: Add convenience function for parsing common external refs
In reply to Sakari AilusAdd v4l2_fwnode_parse_reference_sensor_common for parsing common sensor properties that refer to adjacent devices such as flash or lens driver chips.
As this is an association only, there's little a regular driver needs to know about these devices as such.
--- drivers/media/v4l2-core/v4l2-fwnode.c | 35 +++++++++++++++++++++++++++++++++++ include/media/v4l2-async.h | 3 ++- include/media/v4l2-fwnode.h | 21 +++++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-)
drivers/media/v4l2-core/v4l2-fwnode.c +35 -0
@@ -779,6 +779,41 @@ static int v4l2_fwnode_reference_parse_int_props(return ret; } +int v4l2_async_notifier_parse_fwnode_sensor_common ( +struct device *dev,struct v4l2_async_notifier *notifier) +{ +static const char *led_props[] = {"led" }; +static const struct { +const char *name; +const char **props; +unsigned int nprops; + } props[] = { + {"flash-leds" , led_props,ARRAY_SIZE (led_props) }, + {"lens-focus" ,NULL ,0 }, + }; +unsigned int i; + +for (i =0 ; i <ARRAY_SIZE (props); i++) { +int ret; + +if (props[i].props &&is_acpi_node (dev_fwnode (dev))) + ret =v4l2_fwnode_reference_parse_int_props ( + dev, notifier, props[i].name, + props[i].props, props[i].nprops); +else + ret =v4l2_fwnode_reference_parse ( + dev, notifier, props[i].name); +if (ret && ret != -ENOENT ) { +dev_warn (dev,"parsing property \"%s\" failed (%d)\n" , + props[i].name, ret); +return ret; + } + } + +return 0 ; +} +EXPORT_SYMBOL_GPL (v4l2_async_notifier_parse_fwnode_sensor_common); +MODULE_LICENSE ("GPL" );MODULE_AUTHOR ("Sakari Ailus <[email protected]>" );MODULE_AUTHOR ("Sylwester Nawrocki <[email protected]>" );
include/media/v4l2-async.h +2 -1
@@ -155,7 +155,8 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier);* Release memory resources related to a notifier, including the async * sub-devices allocated for the purposes of the notifier but not the notifier * itself. The user is responsible for calling this function to clean up the -* notifier after calling @v4l2_async_notifier_parse_fwnode_endpoints. +* notifier after calling @v4l2_async_notifier_parse_fwnode_endpoints or +* @v4l2_fwnode_reference_parse_sensor_common. * * There is no harm from calling v4l2_async_notifier_cleanup in other * cases as long as its memory has been zeroed after it has been
include/media/v4l2-fwnode.h +21 -0
@@ -319,4 +319,25 @@ int v4l2_async_notifier_parse_fwnode_endpoints_by_port(struct v4l2_fwnode_endpoint *vep, struct v4l2_async_subdev *asd)); +/** +* v4l2_fwnode_reference_parse_sensor_common - parse common references on +* sensors for async sub-devices +* @dev: the device node the properties of which are parsed for references +* @notifier: the async notifier where the async subdevs will be added +* +* Parse common sensor properties for remote devices related to the +* sensor and set up async sub-devices for them. +* +* Any notifier populated using this function must be released with a call to +* v4l2_async_notifier_release() after it has been unregistered and the async +* sub-devices are no longer in use, even in the case the function returned an +* error. +* +* Return: 0 on success +* -ENOMEM if memory allocation failed +* -EINVAL if property parsing failed +*/ +int v4l2_async_notifier_parse_fwnode_sensor_common ( +struct device *dev,struct v4l2_async_notifier *notifier); +#endif /* _V4L2_FWNODE_H */
Signature · 1 line
2.11.0
Sakari Ailus
maintainerPATCH v14 22/28 v4l: fwnode: Add a convenience function for registering sensors
In reply to Sakari AilusAdd a convenience function for parsing firmware for information on related devices using v4l2_async_notifier_parse_fwnode_sensor_common() registering the notifier and finally the async sub-device itself.
This should be useful for sensor drivers that do not have device specific requirements related to firmware information parsing or the async framework.
--- drivers/media/v4l2-core/v4l2-async.c | 5 +++++ drivers/media/v4l2-core/v4l2-fwnode.c | 41 +++++++++++++++++++++++++++++++++++ include/media/v4l2-async.h | 22 +++++++++++++++++++ include/media/v4l2-subdev.h | 3 +++ 4 files changed, 71 insertions(+)
drivers/media/v4l2-core/v4l2-async.c +5 -0
@@ -570,6 +570,11 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd) {struct v4l2_async_notifier *notifier = sd->notifier; +if (sd->subdev_notifier) +v4l2_async_notifier_unregister (sd->subdev_notifier); +v4l2_async_notifier_cleanup (sd->subdev_notifier); +kfree (sd->subdev_notifier); +if (!sd->asd) {if (!list_empty (&sd->async_list))v4l2_async_cleanup (sd);
drivers/media/v4l2-core/v4l2-fwnode.c +41 -0
53 lines not on this page · raw message
include/media/v4l2-async.h +22 -0
@@ -173,6 +173,28 @@ void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier);int v4l2_async_register_subdev (struct v4l2_subdev *sd);/** +* v4l2_async_register_subdev_sensor_common - registers a sensor sub-device to +* the asynchronous sub-device +* framework and parse set up common +* sensor related devices +* +* @sd: pointer to struct &v4l2_subdev +* +* This function is just like v4l2_async_register_subdev() with the exception +* that calling it will also parse firmware interfaces for remote references +* using v4l2_async_notifier_parse_fwnode_sensor_common() and registers the +* async sub-devices. The sub-device is similarly unregistered by calling +* v4l2_async_unregister_subdev(). +* +* While registered, the subdev module is marked as in-use. +* +* An error is returned if the module is no longer loaded on any attempts +* to register it. +*/ +int __must_check v4l2_async_register_subdev_sensor_common ( +struct v4l2_subdev *sd); + +/** * v4l2_async_unregister_subdev - unregisters a sub-device to the asynchronous * subdevice framework *
include/media/v4l2-subdev.h +3 -0
@@ -793,6 +793,8 @@ struct v4l2_subdev_platform_data {* list. * @asd: Pointer to respective &struct v4l2_async_subdev. * @notifier: Pointer to the managing notifier. +* @subdev_notifier: A sub-device notifier implicitly registered for the sub- +* device using v4l2_device_register_sensor_subdev(). * @pdata: common part of subdevice platform data * * Each instance of a subdev driver should create this struct, either
@@ -823,6 +825,7 @@ struct v4l2_subdev {struct list_head async_list;struct v4l2_async_subdev *asd;struct v4l2_async_notifier *notifier; +struct v4l2_async_notifier *subdev_notifier;struct v4l2_subdev_platform_data *pdata; };
Signature · 1 line
2.11.0
Re: [PATCH v14 22/28] v4l: fwnode: Add a convenience function for registering sensors
Quoted 7 lines · Sakari Ailus
Add a convenience function for parsing firmware for information on related devices using
v4l2_async_notifier_parse_fwnode_sensor_common()registering the notifier and finally the async sub-device itself.This should be useful for sensor drivers that do not have device specific requirements related to firmware information parsing or the async framework.
I'm confused. This is a second patch 22/28 that appears to be identical to the previous one.
I'm ignoring this one, I assume something went wrong when you mailed this series.
Regards,
Hans
Quoted 139 lines
Signed-off-by Sakari Ailus <[email protected]>--- drivers/media/v4l2-core/v4l2-async.c | 5 +++++ drivers/media/v4l2-core/v4l2-fwnode.c | 41 +++++++++++++++++++++++++++++++++++ include/media/v4l2-async.h | 22 +++++++++++++++++++ include/media/v4l2-subdev.h | 3 +++ 4 files changed, 71 insertions(+)drivers/media/v4l2-core/v4l2-async.c +5
-0@@ -570,6 +570,11 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd) {struct v4l2_async_notifier *notifier = sd->notifier; +if (sd->subdev_notifier) +v4l2_async_notifier_unregister (sd->subdev_notifier); +v4l2_async_notifier_cleanup (sd->subdev_notifier); +kfree (sd->subdev_notifier); +if (!sd->asd) {if (!list_empty (&sd->async_list))v4l2_async_cleanup (sd);drivers/media/v4l2-core/v4l2-fwnode.c +41
-0@@ -29,6 +29,7 @@#include <media/v4l2-async.h> #include <media/v4l2-fwnode.h> +#include <media/v4l2-subdev.h> enum v4l2_fwnode_bus_type {V4L2_FWNODE_BUS_TYPE_GUESS =0 ,@@ -814,6 +815,46 @@ int v4l2_async_notifier_parse_fwnode_sensor_common( }EXPORT_SYMBOL_GPL (v4l2_async_notifier_parse_fwnode_sensor_common); +int v4l2_async_register_subdev_sensor_common (struct v4l2_subdev *sd) +{ +struct v4l2_async_notifier *notifier; +int ret; + +if (WARN_ON (!sd->dev)) +return -ENODEV ; + + notifier =kzalloc (sizeof (*notifier),GFP_KERNEL ); +if (!notifier) +return -ENOMEM ; + + ret =v4l2_async_notifier_parse_fwnode_sensor_common (sd->dev, + notifier); +if (ret <0 ) + goto out_cleanup; + + ret =v4l2_async_subdev_notifier_register (sd, notifier); +if (ret <0 ) + goto out_cleanup; + + ret =v4l2_async_register_subdev (sd); +if (ret <0 ) + goto out_unregister; + + sd->subdev_notifier = notifier; + +return 0 ; + +out_unregister: +v4l2_async_notifier_unregister (notifier); + +out_cleanup: +v4l2_async_notifier_cleanup (notifier); +kfree (notifier); + +return ret; +} +EXPORT_SYMBOL_GPL (v4l2_async_register_subdev_sensor_common); +MODULE_LICENSE ("GPL" );MODULE_AUTHOR ("Sakari Ailus <[email protected]>" );MODULE_AUTHOR ("Sylwester Nawrocki <[email protected]>" );include/media/v4l2-async.h +22
-0@@ -173,6 +173,28 @@ void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier);int v4l2_async_register_subdev (struct v4l2_subdev *sd);/** +* v4l2_async_register_subdev_sensor_common - registers a sensor sub-device to +* the asynchronous sub-device +* framework and parse set up common +* sensor related devices +* +* @sd: pointer to struct &v4l2_subdev +* +* This function is just like v4l2_async_register_subdev() with the exception +* that calling it will also parse firmware interfaces for remote references +* using v4l2_async_notifier_parse_fwnode_sensor_common() and registers the +* async sub-devices. The sub-device is similarly unregistered by calling +* v4l2_async_unregister_subdev(). +* +* While registered, the subdev module is marked as in-use. +* +* An error is returned if the module is no longer loaded on any attempts +* to register it. +*/ +int __must_check v4l2_async_register_subdev_sensor_common ( +struct v4l2_subdev *sd); + +/** * v4l2_async_unregister_subdev - unregisters a sub-device to the asynchronous * subdevice framework * include/media/v4l2-subdev.h +3
-0@@ -793,6 +793,8 @@ struct v4l2_subdev_platform_data {* list. * @asd: Pointer to respective &struct v4l2_async_subdev. * @notifier: Pointer to the managing notifier. +* @subdev_notifier: A sub-device notifier implicitly registered for the sub- +* device using v4l2_device_register_sensor_subdev(). * @pdata: common part of subdevice platform data * * Each instance of a subdev driver should create this struct, either @@ -823,6 +825,7 @@ struct v4l2_subdev {struct list_head async_list;struct v4l2_async_subdev *asd;struct v4l2_async_notifier *notifier; +struct v4l2_async_notifier *subdev_notifier;struct v4l2_subdev_platform_data *pdata; };
A message that is not in the archive (sent off-list or not yet received): ac50fc71-c528-a703-04bb-6abc1fc7c19a-qWit8jRvyhVmR6Xm/[email protected]
Re: [PATCH v14 22/28] v4l: fwnode: Add a convenience function for registering sensors
Quoted 5 lines · Hans Verkuil
Quoted 4 lines · Sakari Ailus
Add a convenience function for parsing firmware for information on related devices using
v4l2_async_notifier_parse_fwnode_sensor_common()registering the notifier and finally the async sub-device itself.
Quoted 8 lines
Quoted 3 lines
This should be useful for sensor drivers that do not have device specific requirements related to firmware information parsing or the async framework.
I'm confused. This is a second patch 22/28 that appears to be identical to the previous one.
I'm ignoring this one, I assume something went wrong when you mailed this series.
Yes. I changed the subject but accidentally used the same directory for the patches. The patch is the same.
The intended subject prefix is "v4l: fwnode".
Signature · 6 lines
Sakari Ailus sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected] -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Sakari Ailus
maintainerPATCH v14 23/28 dt: bindings: smiapp: Document lens-focus and flash-leds properties
In reply to Sakari AilusDocument optional lens-focus and flash-leds properties for the smiapp driver.
--- Documentation/devicetree/bindings/media/i2c/nokia,smia.txt | 2 ++ 1 file changed, 2 insertions(+)
Documentation/devicetree/bindings/media/i2c/nokia,smia.txt +2 -0
@@ -27,6 +27,8 @@ Optional properties - nokia,nvm-size: The size of the NVM, in bytes. If the size is not given, the NVM contents will not be read. - reset-gpios: XSHUTDOWN GPIO +- flash-leds: See ../video-interfaces.txt +- lens-focus: See ../video-interfaces.txt Endpoint node mandatory properties
Signature · 1 line
2.11.0
Sakari Ailus
maintainerPATCH v14 25/28 et8ek8: Add support for flash and lens devices
In reply to Sakari AilusParse async sub-devices related to the sensor by switching the async sub-device registration function.
--- drivers/media/i2c/et8ek8/et8ek8_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/i2c/et8ek8/et8ek8_driver.c +1 -1
@@ -1453,7 +1453,7 @@ static int et8ek8_probe(struct i2c_client *client, goto err_mutex; } - ret =v4l2_async_register_subdev (&sensor->subdev); + ret =v4l2_async_register_subdev_sensor_common (&sensor->subdev);if (ret <0 ) goto err_entity;
Signature · 1 line
2.11.0
Re: [PATCH v14 25/28] et8ek8: Add support for flash and lens devices
Quoted 4 lines · Sakari Ailus
Parse async sub-devices related to the sensor by switching the async sub-device registration function.
Signed-off-by Sakari Ailus <[email protected]>
Quoted 18 lines
--- drivers/media/i2c/et8ek8/et8ek8_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/media/i2c/et8ek8/et8ek8_driver.c +1
-1@@ -1453,7 +1453,7 @@ static int et8ek8_probe(struct i2c_client *client, goto err_mutex; } - ret =v4l2_async_register_subdev (&sensor->subdev); + ret =v4l2_async_register_subdev_sensor_common (&sensor->subdev);if (ret <0 ) goto err_entity;
Sakari Ailus
maintainerPATCH v14 27/28 ov13858: Add support for flash and lens devices
In reply to Sakari AilusParse async sub-devices related to the sensor by switching the async sub-device registration function.
--- drivers/media/i2c/ov13858.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/i2c/ov13858.c +1 -1
@@ -1746,7 +1746,7 @@ static int ov13858_probe(struct i2c_client *client, goto error_handler_free; } - ret =v4l2_async_register_subdev (&ov13858->sd); + ret =v4l2_async_register_subdev_sensor_common (&ov13858->sd);if (ret <0 ) goto error_media_entity;
Signature · 1 line
2.11.0
A message that is not in the archive (sent off-list or not yet received): 20170925222540.371-29-sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected]
Hans Verkuil
Acked-byRe: [PATCH v14 27/28] ov13858: Add support for flash and lens devices
Quoted 4 lines · Sakari Ailus
Parse async sub-devices related to the sensor by switching the async sub-device registration function.
Quoted 10 lines
--- drivers/media/i2c/ov13858.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/media/i2c/ov13858.c +0
-0
drivers/media/i2c/ov13858.c static int ov13858_probe(struct i2c_client *client, · line 1752
Quoted 8 lines
drivers/media/i2c/ov13858.c +1
-1@@ -1746,7 +1746,7 @@ static int ov13858_probe(struct i2c_client *client, goto error_handler_free; } - ret =v4l2_async_register_subdev (&ov13858->sd); + ret =v4l2_async_register_subdev_sensor_common (&ov13858->sd);if (ret <0 ) goto error_media_entity;
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html