Unified fwnode endpoint parser, async sub-device notifier support, N9 flash DTS
Subsystems (16)
Sakari Ailus
maintainerv8 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.
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 (20):
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
docs-rst: v4l: Include Qualcomm CAMSS in 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 binding notifiers to sub-devices
dt: bindings: Add a binding for flash devices associated to a sensor
dt: bindings: Add lens-focus binding for image sensors
v4l: fwnode: Add convenience function for parsing generic references
v4l: fwnode: Add convenience function for parsing common external refs
smiapp: Add support for flash and lens devices
dt: bindings: smiapp: Document lens-focus and flash properties
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 + Documentation/media/v4l-drivers/index.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/smiapp/smiapp-core.c | 18 +- drivers/media/i2c/smiapp/smiapp.h | 4 +- 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 | 127 +++----- 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 | 122 +++----- 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 | 326 ++++++++++++++------ drivers/media/v4l2-core/v4l2-fwnode.c | 327 ++++++++++++++++----- drivers/staging/media/imx/imx-media-dev.c | 8 +- include/media/v4l2-async.h | 68 ++++- include/media/v4l2-fwnode.h | 165 ++++++++++- 34 files changed, 934 insertions(+), 405 deletions(-) create mode 100644 Documentation/media/kapi/v4l2-async.rst
Signature · 1 line
2.11.0
A message that is not in the archive (sent off-list or not yet received): 20170905130553.1332-1-sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected]
PATCH v8 1/21 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 consequientally 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
A message that is not in the archive (sent off-list or not yet received): 20170905130553.1332-2-sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected]
Pavel Machek
Acked-byRe: [PATCH v8 01/21] v4l: fwnode: Move KernelDoc documentation to the header
Quoted 10 lines · Sakari Ailus
In V4L2 the practice is to have the KernelDoc documentation in the header and not in .c source code files. This consequientally makes the V4L2 fwnode function documentation part of the Media documentation build.
Also correct the link related function and argument naming in documentation.
Reviewed-by Niklas Söderlund <[email protected]>Acked-by Hans Verkuil <[email protected]>
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
PATCH v8 4/21 v4l: async: Add V4L2 async documentation to the documentation build
In reply to a message not in the archiveThe 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 · 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 v8 7/21 omap3isp: Use generic parser for parsing fwnode endpoints
In reply to a message not in the archiveInstead of using driver implementation, use v4l2_async_notifier_parse_fwnode_endpoints() to parse the fwnode endpoints of the device.
--- drivers/media/platform/omap3isp/isp.c | 115 +++++++++++----------------------- drivers/media/platform/omap3isp/isp.h | 5 +- 2 files changed, 37 insertions(+), 83 deletions(-)
drivers/media/platform/omap3isp/isp.c +36 -79
@@ -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_release (&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,7 +2210,9 @@ static int isp_probe(struct platform_device *pdev)if (ret)return ret; - ret =isp_fwnodes_parse (&pdev->dev, &isp->notifier); + ret =v4l2_async_notifier_parse_fwnode_endpoints ( + &pdev->dev, &isp->notifier,sizeof (struct isp_async_subdev ), + isp_fwnode_parse);if (ret <0 )return ret;
@@ -2407,6 +2363,7 @@ static int isp_probe(struct platform_device *pdev)__omap3isp_put (isp, false); error:mutex_destroy (&isp->isp_mutex); +v4l2_async_notifier_release (&isp->notifier);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 · 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): 20170905130553.1332-8-sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected]
Hans Verkuil
Acked-byRe: [PATCH v8 07/21] omap3isp: Use generic parser for parsing fwnode endpoints
Quoted 5 lines · Sakari Ailus
Instead of using driver implementation, use
v4l2_async_notifier_parse_fwnode_endpoints()to parse the fwnode endpoints of the device.
Regards,
Hans
Quoted 241 lines
--- drivers/media/platform/omap3isp/isp.c | 115 +++++++++++----------------------- drivers/media/platform/omap3isp/isp.h | 5 +- 2 files changed, 37 insertions(+), 83 deletions(-)drivers/media/platform/omap3isp/isp.c +36
-79@@ -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_release (&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,7 +2210,9 @@ static int isp_probe(struct platform_device *pdev)if (ret)return ret; - ret =isp_fwnodes_parse (&pdev->dev, &isp->notifier); + ret =v4l2_async_notifier_parse_fwnode_endpoints ( + &pdev->dev, &isp->notifier,sizeof (struct isp_async_subdev ), + isp_fwnode_parse);if (ret <0 )return ret;@@ -2407,6 +2363,7 @@ static int isp_probe(struct platform_device *pdev)__omap3isp_put (isp, false); error:mutex_destroy (&isp->isp_mutex); +v4l2_async_notifier_release (&isp->notifier);return ret; }drivers/media/platform/omap3isp/isp.h +0
-2@@ -220,14 +220,11 @@ struct isp_device {unsigned int sbl_resources;unsigned int subclk_resources; - -#define ISP_MAX_SUBDEVS 8
drivers/media/platform/omap3isp/isp.h struct isp_device { · line 230
Quoted 10 lines
drivers/media/platform/omap3isp/isp.h +1
-2-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) \
--
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 v8 8/21 rcar-vin: Use generic parser for parsing fwnode endpoints
In reply to a message not in the archiveInstead of using 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 | 112 +++++++++------------------- 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, 48 insertions(+), 92 deletions(-)
drivers/media/platform/rcar-vin/rcar-core.c +34 -78
@@ -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,70 @@ 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 -EPERM ; - 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" ); -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)); +if (vin->notifier.num_subdevs >0 ) +vin_dbg (vin,"Found digital subdevice %pOF\n" , +to_of_node ( + vin->notifier.subdevs[0 ]->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 +244,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 +253,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_release (&vin->notifier);return ret; }
@@ -313,6 +268,7 @@ static int rcar_vin_remove(struct platform_device *pdev)pm_runtime_disable (&pdev->dev);v4l2_async_notifier_unregister (&vin->notifier); +v4l2_async_notifier_release (&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
A message that is not in the archive (sent off-list or not yet received): 20170905130553.1332-9-sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected]
Hans Verkuil
Acked-byRe: [PATCH v8 08/21] rcar-vin: Use generic parser for parsing fwnode endpoints
Quoted 174 lines · Sakari Ailus
Instead of using 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 | 112 +++++++++------------------- 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, 48 insertions(+), 92 deletions(-)drivers/media/platform/rcar-vin/rcar-core.c +26
-67@@ -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,70 @@ 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 -EPERM ; - 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" ); -return -ENODEV ; - } - -/* Register the subdevices notifier. */ - subdevs =devm_kzalloc (vin->dev,sizeof (*subdevs),GFP_KERNEL ); -if (subdevs ==NULL )
drivers/media/platform/rcar-vin/rcar-core.c static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier, · line 183
Quoted 10 lines
drivers/media/platform/rcar-vin/rcar-core.c +4
-6-return -ENOMEM ; - - subdevs[0 ] = &vin->digital.asd; - -vin_dbg (vin,"Found digital subdevice %pOF\n" , -to_of_node (subdevs[0 ]->match.fwnode.fwnode)); +if (vin->notifier.num_subdevs >0 ) +vin_dbg (vin,"Found digital subdevice %pOF\n" , +to_of_node ( + vin->notifier.subdevs[0 ]->match.fwnode.fwnode));
As mentioned in my review of patch 6/21, this violates the documentation of the v4l2_async_notifier_parse_fwnode_endpoints function.
However, I think the problem is with the documentation and not with this code, so:
Regards,
Hans
Quoted 165 lines
drivers/media/platform/rcar-vin/rcar-core.c +4
-5- 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 +244,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 +253,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_release (&vin->notifier);return ret; }@@ -313,6 +268,7 @@ static int rcar_vin_remove(struct platform_device *pdev)pm_runtime_disable (&pdev->dev);v4l2_async_notifier_unregister (&vin->notifier); +v4l2_async_notifier_release (&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 +1
-1@@ -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;
drivers/media/platform/rcar-vin/rcar-vin.h struct rvin_dev { · line 151
Quoted 8 lines
drivers/media/platform/rcar-vin/rcar-vin.h +1
-1@@ -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)
--
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): a51aea1f-0a00-7a7b-8197-e0f5a0443a05-qWit8jRvyhVmR6Xm/[email protected]
Re: [PATCH v8 08/21] rcar-vin: Use generic parser for parsing fwnode endpoints
Hi Hans,
Quoted 35 lines · Hans Verkuil
Quoted 20 lines · Sakari Ailus
static int
rvin_digital_graph_init(struct rvin_dev *vin){(quoted diff) +3
-10- 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"); - return -ENODEV; - } - - /* Register the subdevices notifier. */ - subdevs = devm_kzalloc(vin->dev, sizeof(*subdevs), GFP_KERNEL); - if (subdevs == NULL)Review
Quoted 10 lines
(quoted diff) +4
-6- return -ENOMEM; - - subdevs[0] = &vin->digital.asd; - - vin_dbg(vin, "Found digital subdevice %pOF\n", - to_of_node(subdevs[0]->match.fwnode.fwnode)); + if (vin->notifier.num_subdevs > 0) + vin_dbg(vin, "Found digital subdevice %pOF\n", + to_of_node( + vin->notifier.subdevs[0]->match.fwnode.fwnode));As mentioned in my review of patch 6/21, this violates the documentation of the
v4l2_async_notifier_parse_fwnode_endpointsfunction.
Quoted 4 lines
However, I think the problem is with the documentation and not with this code, so:
Acked-by Hans Verkuil <[email protected]>
Thanks. I still don't like to encourage accessing the notifier fields directly from drivers, and in this case there isn't a need to either. The following changes work, too, and I'll use them in the next version:
drivers/media/platform/rcar-vin/rcar-core.c +2 -2
@@ -177,10 +177,10 @@ static int rvin_digital_graph_init(struct rvin_dev *vin)if (ret)return ret; -if (vin->notifier.num_subdevs >0 ) +if (vin->digital)vin_dbg (vin,"Found digital subdevice %pOF\n" ,to_of_node ( - vin->notifier.subdevs[0 ]->match.fwnode.fwnode)); + vin->digital->asd.match.fwnode.fwnode)); vin->notifier.bound = rvin_digital_notify_bound; vin->notifier.unbind = rvin_digital_notify_unbind;
I also changed EPERM still used in this version to ENOTCONN.
Signature · 8 lines
Regards, 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
PATCH v8 10/21 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
Re: [PATCH v8 10/21] omap3isp: Print the name of the entity where no source pads could be found
Quoted 3 lines · Sakari Ailus
If no source pads are found in an entity, print the name of the entity.
Signed-off-by Sakari Ailus <[email protected]>
Regards,
Hans
Quoted 20 lines
--- 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 ; }
PATCH v8 11/21 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,
@@ -182,9 +188,7 @@ static int rvin_digital_graph_init(struct rvin_dev *vin)to_of_node ( vin->notifier.subdevs[0]->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
@@ -107,16 +107,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; }
@@ -128,8 +128,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 ; }
@@ -215,8 +215,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); }mutex_unlock (&list_lock);
@@ -294,8 +294,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 v8 13/21 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
@@ -135,13 +135,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
A message that is not in the archive (sent off-list or not yet received): 20170905130553.1332-14-sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected]
Hans Verkuil
Acked-byRe: [PATCH v8 13/21] v4l: async: Register sub-devices before calling bound callback
Quoted 6 lines · Sakari Ailus
Register the sub-device before calling the notifier's bound callback. Doing this the other way around is problematic as the struct
v4l2_devicehas not assigned for the sub-device yet and may be required by the bound callback.
Regards,
Hans
Quoted 16 lines
--- drivers/media/v4l2-core/v4l2-async.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)drivers/media/v4l2-core/v4l2-async.c +1
-1@@ -135,13 +135,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 )
drivers/media/v4l2-core/v4l2-async.c static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier, · line 147
Quoted 10 lines
drivers/media/v4l2-core/v4l2-async.c +2
-2return 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; }
--
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 v8 14/21 v4l: async: Allow binding notifiers to sub-devices
In reply to a message not in the archiveRegistering 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 to 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 master notifier's complete callback is only called when all sub-device notifiers are completed.
--- drivers/media/v4l2-core/v4l2-async.c | 209 ++++++++++++++++++++++++++++++----- include/media/v4l2-async.h | 16 ++- 2 files changed, 194 insertions(+), 31 deletions(-)
drivers/media/v4l2-core/v4l2-async.c +179 -30
@@ -53,6 +53,10 @@ static int v4l2_async_notifier_call_complete(struct v4l2_async_notifier *n)return n->ops->complete (n); } +static int v4l2_async_match_notify (struct v4l2_async_notifier *notifier, +struct v4l2_subdev *sd, +struct v4l2_async_subdev *asd); +static bool match_i2c (struct v4l2_subdev *sd,struct v4l2_async_subdev *asd) {#if IS_ENABLED (CONFIG_I2C )
@@ -129,14 +133,119 @@ static struct v4l2_async_subdev *v4l2_async_find_match(return NULL ; } +/* Get the sub-device notifier registered by a sub-device driver. */ +static struct v4l2_async_notifier *v4l2_async_get_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 ; +} + +/* Return true if all sub-device notifiers are complete, false otherwise. */ +static bool v4l2_async_subdev_notifiers_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_get_subdev_notifier (sd); + +if (!subdev_notifier) +continue ; + +if (!v4l2_async_subdev_notifiers_complete (subdev_notifier)) +return false; + } + +return true; +} + +/* Get v4l2_device related to the notifier if one can be found. */ +static struct v4l2_device *v4l2_async_notifier_get_v4l2_dev ( +struct v4l2_async_notifier *notifier) +{ +while (notifier->master) + notifier = notifier->master; + +return notifier->v4l2_dev; +} + +/* 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_subdev *sd, *tmp; + +if (!v4l2_async_notifier_get_v4l2_dev (notifier)) +return 0 ; + +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, sd, asd); +if (ret <0 ) +return ret; + } + +return 0 ; +} + +/* Try completing a notifier. */ +static int v4l2_async_notifier_try_complete ( +struct v4l2_async_notifier *notifier) +{ +do { +int ret; + +/* Any local async sub-devices left? */ +if (!list_empty (¬ifier->waiting)) +return 0 ; + +/* +* Any sub-device notifiers waiting for async subdevs +* to be bound? +*/ +if (!v4l2_async_subdev_notifiers_complete (notifier)) +return 0 ; + +/* Proceed completing the notifier */ + ret =v4l2_async_notifier_call_complete (notifier); +if (ret <0 ) +return ret; + +/* +* Obtain notifier's master. If there is one, repeat +* the process, otherwise we're done here. +*/ + }while ((notifier = notifier->master)); + +return 0 ; +} +static int v4l2_async_match_notify (struct v4l2_async_notifier *notifier,struct v4l2_subdev *sd,struct v4l2_async_subdev *asd) { +struct v4l2_async_notifier *subdev_notifier;int ret; - ret =v4l2_device_register_subdev (notifier->v4l2_dev, sd); -if (ret <0 ) + ret =v4l2_device_register_subdev ( +v4l2_async_notifier_get_v4l2_dev (notifier), sd); +if (ret)return ret; ret =v4l2_async_notifier_call_bound (notifier, sd, asd);
@@ -153,10 +262,20 @@ 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_get_subdev_notifier (sd); +if (subdev_notifier && !subdev_notifier->master) { + subdev_notifier->master = notifier; + ret =v4l2_async_notifier_try_all_subdevs (subdev_notifier); +if (ret) +return ret; + } -return 0 ; +/* Try completing the notifier and its master(s). */ +return v4l2_async_notifier_try_complete (notifier); }static void v4l2_async_cleanup (struct v4l2_subdev *sd)
@@ -168,18 +287,17 @@ 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 || +if (!notifier->v4l2_dev == !notifier->sd || !notifier->num_subdevs || notifier->num_subdevs >V4L2_MAX_SUBDEVS )return -EINVAL ; - notifier->v4l2_dev = v4l2_dev; +INIT_LIST_HEAD (¬ifier->list);INIT_LIST_HEAD (¬ifier->waiting);INIT_LIST_HEAD (¬ifier->done);
@@ -203,18 +321,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 */
@@ -224,28 +334,67 @@ 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 (!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) +int v4l2_async_subdev_notifier_register (struct v4l2_subdev *sd, +struct v4l2_async_notifier *notifier) { -struct v4l2_subdev *sd, *tmp; +if (!sd) +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_get_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); + +list_del (&sd->async_list); +list_add (&sd->async_list, &subdev_list); } -mutex_unlock (&list_lock); + notifier->master =NULL ; +} + +void v4l2_async_notifier_unregister (struct v4l2_async_notifier *notifier) +{ +if (!notifier->v4l2_dev && !notifier->sd) +return ; - notifier->v4l2_dev =NULL ; +mutex_lock (&list_lock); + +v4l2_async_notifier_unbind_all_subdevs (notifier); + +list_del (¬ifier->list); + +mutex_unlock (&list_lock); }EXPORT_SYMBOL (v4l2_async_notifier_unregister);
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 master, for subdev notifiers NULL +* @sd: sub-device that registered the notifier, NULL otherwise +* @master: master notifier carrying @v4l2_dev * @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 *master;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 · 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): 20170905130553.1332-15-sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected]
Re: [PATCH v8 14/21] v4l: async: Allow binding notifiers to sub-devices
Quoted 9 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 to the
to -> in
Quoted 122 lines
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 master notifier's complete callback is only called when all sub-device notifiers are completed.
--- drivers/media/v4l2-core/v4l2-async.c | 209 ++++++++++++++++++++++++++++++----- include/media/v4l2-async.h | 16 ++- 2 files changed, 194 insertions(+), 31 deletions(-)drivers/media/v4l2-core/v4l2-async.c +93
-0@@ -53,6 +53,10 @@ static int v4l2_async_notifier_call_complete(struct v4l2_async_notifier *n)return n->ops->complete (n); } +static int v4l2_async_match_notify (struct v4l2_async_notifier *notifier, +struct v4l2_subdev *sd, +struct v4l2_async_subdev *asd); +static bool match_i2c (struct v4l2_subdev *sd,struct v4l2_async_subdev *asd) {#if IS_ENABLED (CONFIG_I2C )@@ -129,14 +133,119 @@ static struct v4l2_async_subdev *v4l2_async_find_match(return NULL ; } +/* Get the sub-device notifier registered by a sub-device driver. */ +static struct v4l2_async_notifier *v4l2_async_get_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 ; +} + +/* Return true if all sub-device notifiers are complete, false otherwise. */ +static bool v4l2_async_subdev_notifiers_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_get_subdev_notifier (sd); + +if (!subdev_notifier) +continue ; + +if (!v4l2_async_subdev_notifiers_complete (subdev_notifier)) +return false; + } + +return true; +} + +/* Get v4l2_device related to the notifier if one can be found. */ +static struct v4l2_device *v4l2_async_notifier_get_v4l2_dev ( +struct v4l2_async_notifier *notifier) +{ +while (notifier->master) + notifier = notifier->master; + +return notifier->v4l2_dev; +} + +/* 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_subdev *sd, *tmp; + +if (!v4l2_async_notifier_get_v4l2_dev (notifier)) +return 0 ; + +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, sd, asd); +if (ret <0 ) +return ret; + } + +return 0 ; +} + +/* Try completing a notifier. */ +static int v4l2_async_notifier_try_complete ( +struct v4l2_async_notifier *notifier) +{ + do { + int ret; + + /* Any local async sub-devices left? */ + if (!list_empty(¬ifier->waiting)) + return 0; + + /* + * Any sub-device notifiers waiting for async subdevs + * to be bound? + */ + if (!v4l2_async_subdev_notifiers_complete(notifier)) + return 0; +
drivers/media/v4l2-core/v4l2-async.c static struct v4l2_async_subdev *v4l2_async_find_match( · line 234
Quoted 10 lines
drivers/media/v4l2-core/v4l2-async.c +10
-0+/* Proceed completing the notifier */ + ret =v4l2_async_notifier_call_complete (notifier); +if (ret <0 ) +return ret; + +/* +* Obtain notifier's master. If there is one, repeat +* the process, otherwise we're done here. +*/ + }while ((notifier = notifier->master));
I'd change this to:
notifier = notifier->master; } while (notifier);
Quoted 48 lines
drivers/media/v4l2-core/v4l2-async.c +21
-6+ +return 0 ; +} +static int v4l2_async_match_notify (struct v4l2_async_notifier *notifier,struct v4l2_subdev *sd,struct v4l2_async_subdev *asd) { +struct v4l2_async_notifier *subdev_notifier;int ret; - ret =v4l2_device_register_subdev (notifier->v4l2_dev, sd); -if (ret <0 ) + ret =v4l2_device_register_subdev ( +v4l2_async_notifier_get_v4l2_dev (notifier), sd); +if (ret)return ret; ret =v4l2_async_notifier_call_bound (notifier, sd, asd);@@ -153,10 +262,20 @@ 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_get_subdev_notifier (sd); +if (subdev_notifier && !subdev_notifier->master) { + subdev_notifier->master = notifier; + ret =v4l2_async_notifier_try_all_subdevs (subdev_notifier); +if (ret) +return ret; + } -return 0 ; +/* Try completing the notifier and its master(s). */ +return v4l2_async_notifier_try_complete (notifier); }static void v4l2_async_cleanup (struct v4l2_subdev *sd)@@ -168,18 +287,17 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd) sd->dev =NULL ; } -int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
drivers/media/v4l2-core/v4l2-async.c static void v4l2_async_cleanup(struct v4l2_subdev *sd) · line 296
Quoted 10 lines
drivers/media/v4l2-core/v4l2-async.c +3
-3- 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 || + if (!notifier->v4l2_dev == !notifier->sd || !notifier->num_subdevs ||
With the changes suggested below this can be changed to:
if (!notifier->num_subdevs ||
However, I have a question about that: why would it be wrong to call this with no subdevs in the list?
It's perfectly valid to have no subdevs at all. There may be a fixed incoming video stream that is not controlled by a subdev. We have a case like that in fact.
Quoted 32 lines
drivers/media/v4l2-core/v4l2-async.c +5
-13notifier->num_subdevs > V4L2_MAX_SUBDEVS)return -EINVAL ; - notifier->v4l2_dev = v4l2_dev; +INIT_LIST_HEAD (¬ifier->list);INIT_LIST_HEAD (¬ifier->waiting);INIT_LIST_HEAD (¬ifier->done);@@ -203,18 +321,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 */
drivers/media/v4l2-core/v4l2-async.c int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, · line 341
Quoted 8 lines
drivers/media/v4l2-core/v4l2-async.c +5
-0@@ -224,28 +334,67 @@ 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 (!v4l2_dev)
I'd change this to:
if (!v4l2_dev || notifier->sd)
Quoted 4 lines
drivers/media/v4l2-core/v4l2-async.c +4
-0+return -EINVAL ; + + notifier->v4l2_dev = v4l2_dev; +
drivers/media/v4l2-core/v4l2-async.c int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, · line 353
Quoted 10 lines
drivers/media/v4l2-core/v4l2-async.c +5
-2+return __v4l2_async_notifier_register (notifier); +}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 (!sd)
and this to:
if (!sd || notifier->v4l2_dev)
Quoted 58 lines
drivers/media/v4l2-core/v4l2-async.c +33
-6+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_get_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); + +list_del (&sd->async_list); +list_add (&sd->async_list, &subdev_list); } -mutex_unlock (&list_lock); + notifier->master =NULL ; +} + +void v4l2_async_notifier_unregister (struct v4l2_async_notifier *notifier) +{ +if (!notifier->v4l2_dev && !notifier->sd) +return ; - notifier->v4l2_dev =NULL ; +mutex_lock (&list_lock); + +v4l2_async_notifier_unbind_all_subdevs (notifier); + +list_del (¬ifier->list); + +mutex_unlock (&list_lock); }EXPORT_SYMBOL (v4l2_async_notifier_unregister);include/media/v4l2-async.h +0
-0
include/media/v4l2-async.h struct v4l2_async_notifier_operations { · line 107
Quoted 7 lines
include/media/v4l2-async.h +3
-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 master, for subdev notifiers NULL +* @sd: sub-device that registered the notifier, NULL otherwise +* @master: master notifier carrying @v4l2_dev
I think this description is out of date. It is really the parent notifier, right? Should 'master' be renamed to 'parent'?
Same problem with the description of @v4l2_dev: it's the v4l2_device of the root/top-level notifier.
Quoted 20 lines
include/media/v4l2-async.h +5
-0* @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 *master;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 +*
include/media/v4l2-async.h int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, · line 147
Quoted 10 lines
include/media/v4l2-async.h +7
-0+* @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
This v8 is much better and is getting close.
Thanks!
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
Re: [PATCH v8 14/21] v4l: async: Allow binding notifiers to sub-devices
Hi Hans,
Quoted 6 lines · Hans Verkuil
Quoted 5 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).
Quoted 6 lines
Quoted 4 lines
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 to theto -> in
Fixed.
Quoted 136 lines
Quoted 123 lines
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 master notifier's complete callback is only called when all sub-device notifiers are completed.
Signed-off-by Sakari Ailus <[email protected]>--- drivers/media/v4l2-core/v4l2-async.c | 209 ++++++++++++++++++++++++++++++----- include/media/v4l2-async.h | 16 ++- 2 files changed, 194 insertions(+), 31 deletions(-)drivers/media/v4l2-core/v4l2-async.c +93
-0@@ -53,6 +53,10 @@ static int v4l2_async_notifier_call_complete(struct v4l2_async_notifier *n)return n->ops->complete (n); } +static int v4l2_async_match_notify (struct v4l2_async_notifier *notifier, +struct v4l2_subdev *sd, +struct v4l2_async_subdev *asd); +static bool match_i2c (struct v4l2_subdev *sd,struct v4l2_async_subdev *asd) {#if IS_ENABLED (CONFIG_I2C )@@ -129,14 +133,119 @@ static struct v4l2_async_subdev *v4l2_async_find_match(return NULL ; } +/* Get the sub-device notifier registered by a sub-device driver. */ +static struct v4l2_async_notifier *v4l2_async_get_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 ; +} + +/* Return true if all sub-device notifiers are complete, false otherwise. */ +static bool v4l2_async_subdev_notifiers_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_get_subdev_notifier (sd); + +if (!subdev_notifier) +continue ; + +if (!v4l2_async_subdev_notifiers_complete (subdev_notifier)) +return false; + } + +return true; +} + +/* Get v4l2_device related to the notifier if one can be found. */ +static struct v4l2_device *v4l2_async_notifier_get_v4l2_dev ( +struct v4l2_async_notifier *notifier) +{ +while (notifier->master) + notifier = notifier->master; + +return notifier->v4l2_dev; +} + +/* 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_subdev *sd, *tmp; + +if (!v4l2_async_notifier_get_v4l2_dev (notifier)) +return 0 ; + +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, sd, asd); +if (ret <0 ) +return ret; + } + +return 0 ; +} + +/* Try completing a notifier. */ +static int v4l2_async_notifier_try_complete ( +struct v4l2_async_notifier *notifier) +{ + do { + int ret; + + /* Any local async sub-devices left? */ + if (!list_empty(¬ifier->waiting)) + return 0; + + /* + * Any sub-device notifiers waiting for async subdevs + * to be bound? + */ + if (!v4l2_async_subdev_notifiers_complete(notifier)) + return 0; +drivers/media/v4l2-core/v4l2-async.c static struct v4l2_async_subdev *v4l2_async_find_match( · line 234
Quoted 10 lines
drivers/media/v4l2-core/v4l2-async.c +10
-0+/* Proceed completing the notifier */ + ret =v4l2_async_notifier_call_complete (notifier); +if (ret <0 ) +return ret; + +/* +* Obtain notifier's master. If there is one, repeat +* the process, otherwise we're done here. +*/ + }while ((notifier = notifier->master));I'd change this to:
Quoted 2 lines
notifier = notifier->master; } while (notifier);
I prefer the original for the same reason as in related case: the loop condition as well as obtaining the next entry is better separated from where the real work on the entries takes place.
Quoted 62 lines
Quoted 49 lines
drivers/media/v4l2-core/v4l2-async.c +21
-6+ +return 0 ; +} +static int v4l2_async_match_notify (struct v4l2_async_notifier *notifier,struct v4l2_subdev *sd,struct v4l2_async_subdev *asd) { +struct v4l2_async_notifier *subdev_notifier;int ret; - ret =v4l2_device_register_subdev (notifier->v4l2_dev, sd); -if (ret <0 ) + ret =v4l2_device_register_subdev ( +v4l2_async_notifier_get_v4l2_dev (notifier), sd); +if (ret)return ret; ret =v4l2_async_notifier_call_bound (notifier, sd, asd);@@ -153,10 +262,20 @@ 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_get_subdev_notifier (sd); +if (subdev_notifier && !subdev_notifier->master) { + subdev_notifier->master = notifier; + ret =v4l2_async_notifier_try_all_subdevs (subdev_notifier); +if (ret) +return ret; + } -return 0 ; +/* Try completing the notifier and its master(s). */ +return v4l2_async_notifier_try_complete (notifier); }static void v4l2_async_cleanup (struct v4l2_subdev *sd)@@ -168,18 +287,17 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd) sd->dev =NULL ; } -int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,drivers/media/v4l2-core/v4l2-async.c static void v4l2_async_cleanup(struct v4l2_subdev *sd) · line 296
Quoted 10 lines
drivers/media/v4l2-core/v4l2-async.c +3
-3- 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 || + if (!notifier->v4l2_dev == !notifier->sd || !notifier->num_subdevs ||With the changes suggested below this can be changed to:
Quoted 7 lines
if (!notifier->num_subdevs ||However, I have a question about that: why would it be wrong to call this with no subdevs in the list?
It's perfectly valid to have no subdevs at all. There may be a fixed incoming video stream that is not controlled by a subdev. We have a case like that in fact.
I added a separate patch for that earlier in the set.
Quoted 44 lines
Quoted 33 lines
drivers/media/v4l2-core/v4l2-async.c +5
-13notifier->num_subdevs > V4L2_MAX_SUBDEVS)return -EINVAL ; - notifier->v4l2_dev = v4l2_dev; +INIT_LIST_HEAD (¬ifier->list);INIT_LIST_HEAD (¬ifier->waiting);INIT_LIST_HEAD (¬ifier->done);@@ -203,18 +321,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 */ drivers/media/v4l2-core/v4l2-async.c int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, · line 341
Quoted 8 lines
drivers/media/v4l2-core/v4l2-async.c +5
-0@@ -224,28 +334,67 @@ 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 (!v4l2_dev)I'd change this to:
Quoted 1 line
if (!v4l2_dev || notifier->sd)
Done.
Quoted 18 lines
Quoted 5 lines
drivers/media/v4l2-core/v4l2-async.c +4
-0+return -EINVAL ; + + notifier->v4l2_dev = v4l2_dev; +drivers/media/v4l2-core/v4l2-async.c int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, · line 353
Quoted 10 lines
drivers/media/v4l2-core/v4l2-async.c +5
-2+return __v4l2_async_notifier_register (notifier); +}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 (!sd)and this to:
Quoted 1 line
if (!sd || notifier->v4l2_dev)
Done as well. And removed the interesting-looking check from __v4l2_async_subdev_notifier_register(). :-)
Quoted 54 lines
Quoted 54 lines
drivers/media/v4l2-core/v4l2-async.c +33
-6+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_get_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); + +list_del (&sd->async_list); +list_add (&sd->async_list, &subdev_list); } -mutex_unlock (&list_lock); + notifier->master =NULL ; +} + +void v4l2_async_notifier_unregister (struct v4l2_async_notifier *notifier) +{ +if (!notifier->v4l2_dev && !notifier->sd) +return ; - notifier->v4l2_dev =NULL ; +mutex_lock (&list_lock); + +v4l2_async_notifier_unbind_all_subdevs (notifier); + +list_del (¬ifier->list); + +mutex_unlock (&list_lock); }EXPORT_SYMBOL (v4l2_async_notifier_unregister);
Quoted 15 lines
include/media/v4l2-async.h struct v4l2_async_notifier_operations { · line 107
Quoted 12 lines
include/media/v4l2-async.h +3
-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 master, for subdev notifiers NULL +* @sd: sub-device that registered the notifier, NULL otherwise +* @master: master notifier carrying @v4l2_dev I think this description is out of date. It is really the parent notifier, right? Should 'master' be renamed to 'parent'?
You could view it as one, yes. What is known is that the notifier is related, and through which the v4l2_dev can be found. I'll rename it as "parent".
I'll use root in the commit message as well.
Quoted 3 lines
Same problem with the description of @v4l2_dev: it's the
v4l2_deviceof the root/top-level notifier.
"v4l2_device of the root notifier, NULL otherwise"?
Quoted 25 lines
Quoted 25 lines
include/media/v4l2-async.h +10
-0* @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 *master;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);
Quoted 8 lines
include/media/v4l2-async.h int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, · line 147
Quoted 6 lines
include/media/v4l2-async.h +2
-0+ +/** * v4l2_async_notifier_unregister - unregisters a subdevice asynchronous notifier * * @notifier: pointer to &struct v4l2_async_notifier This v8 is much better and is getting close.
Thanks!
Signature · 4 lines
Regards, Sakari Ailus e-mail: [email protected]
A message that is not in the archive (sent off-list or not yet received): 20170907083209.3xtaxwhrfmgrtpfz-S+BSfZ9RZZmRSg0ZkenSGLdO1Tsj/[email protected]
Re: [PATCH v8 14/21] v4l: async: Allow binding notifiers to sub-devices
Quoted 25 lines · Sakari Ailus
Hi Hans,
Quoted 17 lines · Hans Verkuil
include/media/v4l2-async.h struct v4l2_async_notifier_operations { · line 107
Quoted 12 lines · Sakari Ailus
include/media/v4l2-async.h +3
-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 master, for subdev notifiers NULL +* @sd: sub-device that registered the notifier, NULL otherwise +* @master: master notifier carrying @v4l2_dev I think this description is out of date. It is really the parent notifier, right? Should 'master' be renamed to 'parent'?
You could view it as one, yes. What is known is that the notifier is related, and through which the
v4l2_devcan be found. I'll rename it as "parent".
Quoted 7 lines
I'll use root in the commit message as well.
Quoted 3 lines
Same problem with the description of @v4l2_dev: it's the
v4l2_deviceof the root/top-level notifier."
v4l2_deviceof the root notifier, NULL otherwise"?
Ack.
Hans
Quoted 35 lines
Quoted 26 lines
Quoted 26 lines
include/media/v4l2-async.h +10
-0* @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 *master;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);Quoted 8 lines
include/media/v4l2-async.h int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, · line 147
Quoted 6 lines
include/media/v4l2-async.h +2
-0+ +/** * v4l2_async_notifier_unregister - unregisters a subdevice asynchronous notifier * * @notifier: pointer to &struct v4l2_async_notifier This v8 is much better and is getting close.
Quoted 2 lines
Thanks!
--
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 v8 15/21 dt: bindings: Add a binding for flash devices associated to a sensor
In reply to a message not in the archiveCamera 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: An array of phandles, each referring to a flash LED, a sub-node + of the LED driver device node. + + 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
Re: [PATCH v8 15/21] dt: bindings: Add a binding for flash devices associated to a sensor
Quoted 6 lines · Sakari Ailus
Camera 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.
Signed-off-by Sakari Ailus <[email protected]>Acked-by Rob Herring <[email protected]>
Regards,
Hans
Quoted 24 lines
--- 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: An array of phandles, each referring to a flash LED, a sub-node + of the LED driver device node. + + Optional endpoint properties ----------------------------
PATCH v8 17/21 v4l: fwnode: Add convenience function for parsing generic references
In reply to a message not in the archiveAdd function v4l2_fwnode_reference_count() for counting external references and 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.
struct v4l2_async_notifier.max_subdevs field is added to contain the maximum number of sub-devices in a notifier to reflect the memory allocated for the subdevs array.
--- drivers/media/v4l2-core/v4l2-fwnode.c | 85 +++++++++++++++++++++++++++++++++++ include/media/v4l2-fwnode.h | 28 ++++++++++++ 2 files changed, 113 insertions(+)
drivers/media/v4l2-core/v4l2-fwnode.c +85 -0
@@ -453,6 +453,91 @@ int v4l2_async_notifier_parse_fwnode_endpoints( }EXPORT_SYMBOL_GPL (v4l2_async_notifier_parse_fwnode_endpoints); +static void v4l2_fwnode_print_args (struct fwnode_reference_args *args) +{ +unsigned int i; + +for (i =0 ; i < args->nargs; i++) { +pr_cont (" %u" , args->args[i]); +if (i +1 < args->nargs) +pr_cont ("," ); + } +} + +int v4l2_fwnode_reference_parse ( +struct device *dev,struct v4l2_async_notifier *notifier, +const char *prop,const char *nargs_prop,unsigned int nargs, +size_t asd_struct_size, +int (*parse_single)(struct device *dev, +struct fwnode_reference_args *args, +struct v4l2_async_subdev *asd)) +{ +struct fwnode_reference_args args; +unsigned int index =0 ; +int ret = -ENOENT ; + +if (asd_struct_size <sizeof (struct v4l2_async_subdev )) +return -EINVAL ; + +for (; !fwnode_property_get_reference_args ( +dev_fwnode (dev), prop, nargs_prop, nargs, + index, &args); index++) +fwnode_handle_put (args.fwnode); + + ret =v4l2_async_notifier_realloc (notifier, + notifier->num_subdevs + index); +if (ret) +return -ENOMEM ; + +for (ret = -ENOENT , index =0 ; !fwnode_property_get_reference_args ( +dev_fwnode (dev), prop, nargs_prop, nargs, + index, &args); index++) { +struct v4l2_async_subdev *asd; + +if (WARN_ON (notifier->num_subdevs >= notifier->max_subdevs)) { + ret = -EINVAL ; + goto error; + } + + asd =kzalloc (asd_struct_size,GFP_KERNEL ); +if (!asd) { + ret = -ENOMEM ; + goto error; + } + + ret = parse_single ?parse_single (dev, &args, asd) :0 ; +if (ret <0 ) { +kfree (asd); +if (ret == -ENOTCONN ) +dev_dbg (dev, +"ignoring reference prop \"%s\", nargs_prop \"%s\", nargs %u, index %u" , + prop, nargs_prop, nargs, index); +else +dev_warn (dev, +"driver could not parse reference prop \"%s\", nargs_prop \"%s\", nargs %u, index %u" , + prop, nargs_prop, nargs, index); +v4l2_fwnode_print_args (&args); +pr_cont ("\n" ); +if (ret == -ENOTCONN ) +continue ; +else + 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; +} +EXPORT_SYMBOL_GPL (v4l2_fwnode_reference_parse); +MODULE_LICENSE ("GPL" );MODULE_AUTHOR ("Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected]>" );MODULE_AUTHOR ("Sylwester Nawrocki <[email protected]>" );
include/media/v4l2-fwnode.h +28 -0
@@ -254,4 +254,32 @@ int v4l2_async_notifier_parse_fwnode_endpoints(struct v4l2_fwnode_endpoint *vep, struct v4l2_async_subdev *asd)); +/** +* 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 +* @nargs_prop: the name of the property in the remote node that specifies the +* number of integer arguments (may be NULL, in that case nargs +* will be used). +* @nargs: the number of integer arguments after the reference +* @asd_struct_size: the size of the driver's async sub-device struct, including +* @struct v4l2_async_subdev +* @parse_single: driver's callback function for parsing a reference. Optional. +* Return: 0 on success +* %-ENOTCONN if the reference is to be skipped. This +* will not be considered as an error +* +* Return: 0 on success +* -ENOMEM if memory allocation failed +* -EINVAL if property parsing failed +*/ +int v4l2_fwnode_reference_parse ( +struct device *dev,struct v4l2_async_notifier *notifier, +const char *prop,const char *nargs_prop,unsigned int nargs, +size_t asd_struct_size, +int (*parse_single)(struct device *dev, +struct fwnode_reference_args *args, +struct v4l2_async_subdev *asd)); +#endif /* _V4L2_FWNODE_H */
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 v8 18/21 v4l: fwnode: Add convenience function for parsing common external refs
In reply to a message not in the archiveAdd 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 | 27 +++++++++++++++++++++++++++ include/media/v4l2-fwnode.h | 3 +++ 2 files changed, 30 insertions(+)
drivers/media/v4l2-core/v4l2-fwnode.c +27 -0
@@ -538,6 +538,33 @@ int v4l2_fwnode_reference_parse( }EXPORT_SYMBOL_GPL (v4l2_fwnode_reference_parse); +int v4l2_fwnode_reference_parse_sensor_common ( +struct device *dev,struct v4l2_async_notifier *notifier) +{ +static const struct { +char *name; +char *cells; +unsigned int nr_cells; + } props[] = { + {"flash" ,NULL ,0 }, + {"lens-focus" ,NULL ,0 }, + }; +unsigned int i; +int rval; + +for (i =0 ; i <ARRAY_SIZE (props); i++) { + rval =v4l2_fwnode_reference_parse ( + dev, notifier, props[i].name, props[i].cells, + props[i].nr_cells,sizeof (struct v4l2_async_subdev ), +NULL ); +if (rval <0 && rval != -ENOENT ) +return rval; + } + +return rval; +} +EXPORT_SYMBOL_GPL (v4l2_fwnode_reference_parse_sensor_common); +MODULE_LICENSE ("GPL" );MODULE_AUTHOR ("Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected]>" );MODULE_AUTHOR ("Sylwester Nawrocki <[email protected]>" );
include/media/v4l2-fwnode.h +3 -0
@@ -282,4 +282,7 @@ int v4l2_fwnode_reference_parse(struct fwnode_reference_args *args, struct v4l2_async_subdev *asd)); +int v4l2_fwnode_reference_parse_sensor_common ( +struct device *dev,struct v4l2_async_notifier *notifier); +#endif /* _V4L2_FWNODE_H */
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 v8 19/21 smiapp: Add support for flash and lens devices
In reply to a message not in the archiveParse async sub-devices by using v4l2_subdev_fwnode_reference_parse_sensor_common().
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 | 18 ++++++++++++++++-- drivers/media/i2c/smiapp/smiapp.h | 4 +++- 2 files changed, 19 insertions(+), 3 deletions(-)
drivers/media/i2c/smiapp/smiapp-core.c +16 -2
@@ -31,7 +31,7 @@#include <linux/regulator/consumer.h> #include <linux/slab.h> #include <linux/smiapp.h> -#include <linux/v4l2-mediabus.h> +#include <media/v4l2-async.h> #include <media/v4l2-fwnode.h> #include <media/v4l2-device.h>
@@ -2887,6 +2887,11 @@ static int smiapp_probe(struct i2c_client *client,v4l2_i2c_subdev_init (&sensor->src->sd, client, &smiapp_ops); sensor->src->sd.internal_ops = &smiapp_internal_src_ops; + rval =v4l2_fwnode_reference_parse_sensor_common ( + &client->dev, &sensor->notifier); +if (rval <0 && rval != -ENOENT ) +return rval; + sensor->vana =devm_regulator_get (&client->dev,"vana" );if (IS_ERR (sensor->vana)) {dev_err (&client->dev,"could not get regulator for vana\n" );
@@ -3092,9 +3097,14 @@ static int smiapp_probe(struct i2c_client *client,if (rval <0 ) goto out_media_entity_cleanup; + rval =v4l2_async_subdev_notifier_register (&sensor->src->sd, + &sensor->notifier); +if (rval) + goto out_media_entity_cleanup; + rval =v4l2_async_register_subdev (&sensor->src->sd);if (rval <0 ) - goto out_media_entity_cleanup; + goto out_unregister_async_notifier;pm_runtime_set_active (&client->dev);pm_runtime_get_noresume (&client->dev);
@@ -3105,6 +3115,9 @@ static int smiapp_probe(struct i2c_client *client,return 0 ; +out_unregister_async_notifier: +v4l2_async_notifier_unregister (&sensor->notifier); + out_media_entity_cleanup:media_entity_cleanup (&sensor->src->sd.entity);
@@ -3124,6 +3137,7 @@ static int smiapp_remove(struct i2c_client *client)unsigned int i;v4l2_async_unregister_subdev (subdev); +v4l2_async_notifier_unregister (&sensor->notifier);pm_runtime_disable (&client->dev);if (!pm_runtime_status_suspended (&client->dev))
drivers/media/i2c/smiapp/smiapp.h +3 -1
@@ -20,9 +20,10 @@#define __SMIAPP_PRIV_H_#include <linux/mutex.h> +#include <media/i2c/smiapp.h> +#include <media/v4l2-async.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-subdev.h> -#include <media/i2c/smiapp.h> #include "smiapp-pll.h" #include "smiapp-reg.h"
@@ -172,6 +173,7 @@ struct smiapp_subdev {* struct smiapp_sensor - Main device structure */ struct smiapp_sensor { +struct v4l2_async_notifier notifier;/* * "mutex" is used to serialise access to all fields here * except v4l2_ctrls at the end of the struct. "mutex" is also
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 v8 2/21 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, 54 deletions(-)
drivers/media/v4l2-core/v4l2-async.c +0 -54
@@ -203,78 +203,24 @@ 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); }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
Re: [PATCH v8 02/21] v4l: async: Remove re-probing support
Quoted 8 lines · Sakari Ailus
Remove 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.
Quoted 5 lines
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.
Signed-off-by Sakari Ailus <[email protected]>
Regards,
Hans
Quoted 88 lines
--- drivers/media/v4l2-core/v4l2-async.c | 54 ------------------------------------ 1 file changed, 54 deletions(-)drivers/media/v4l2-core/v4l2-async.c +0
-54@@ -203,78 +203,24 @@ 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); }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);
Sakari Ailus
maintainerPATCH v8 3/21 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
@@ -65,8 +65,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;
@@ -100,9 +100,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;
@@ -180,11 +180,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;
@@ -241,9 +241,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
Re: [PATCH v8 03/21] v4l: async: Use more intuitive names for internal functions
Quoted 8 lines · Sakari Ailus
Rename internal functions to make the names of the functions better describe what they do.
Old name New name
v4l2_async_test_notifyv4l2_async_match_notify
v4l2_async_belongsv4l2_async_find_matchSigned-off-by Sakari Ailus <[email protected]>
Regards,
Hans
Quoted 60 lines
--- drivers/media/v4l2-core/v4l2-async.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-)drivers/media/v4l2-core/v4l2-async.c +10
-9@@ -65,8 +65,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;@@ -100,9 +100,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;@@ -180,11 +180,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;@@ -241,9 +241,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; }
Re: [PATCH v8 03/21] v4l: async: Use more intuitive names for internal functions
In reply to Sakari AilusQuoted 8 lines · Sakari Ailus
Rename internal functions to make the names of the functions better describe what they do.
Old name New name
v4l2_async_test_notifyv4l2_async_match_notify
v4l2_async_belongsv4l2_async_find_matchSigned-off-by Sakari Ailus <[email protected]>
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Sakari Ailus
maintainerPATCH v8 5/21 docs-rst: v4l: Include Qualcomm CAMSS in documentation build
In reply to Sakari AilusQualcomm CAMSS was left out from documentation build. Fix this.
--- Documentation/media/v4l-drivers/index.rst | 1 + 1 file changed, 1 insertion(+)
Documentation/media/v4l-drivers/index.rst +1 -0
@@ -50,6 +50,7 @@ For more details see the file COPYING in the source distribution of Linux. philips pvrusb2 pxa_camera + qcom_camss radiotrack rcar-fdp1 saa7134
Signature · 1 line
2.11.0
Sakari Ailus
maintainerPATCH v8 6/21 v4l: fwnode: Support generic parsing of graph endpoints in a device
In reply to Sakari AilusThe current practice is that drivers iterate over their endpoints and parse each endpoint separately. This is very similar in a number of drivers, implement a generic function for the job. Driver specific matters can be taken into account in the driver specific callback.
--- drivers/media/v4l2-core/v4l2-async.c | 19 +++++ drivers/media/v4l2-core/v4l2-fwnode.c | 140 ++++++++++++++++++++++++++++++++++ include/media/v4l2-async.h | 24 +++++- include/media/v4l2-fwnode.h | 53 +++++++++++++ 4 files changed, 234 insertions(+), 2 deletions(-)
drivers/media/v4l2-core/v4l2-async.c +19 -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)
@@ -224,6 +225,24 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) }EXPORT_SYMBOL (v4l2_async_notifier_unregister); +void v4l2_async_notifier_release (struct v4l2_async_notifier *notifier) +{ +unsigned int i; + +if (!notifier->max_subdevs) +return ; + +for (i =0 ; i < notifier->num_subdevs; i++) +kfree (notifier->subdevs[i]); + + notifier->max_subdevs =0 ; + notifier->num_subdevs =0 ; + +kvfree (notifier->subdevs); + notifier->subdevs =NULL ; +} +EXPORT_SYMBOL_GPL (v4l2_async_notifier_release); +int v4l2_async_register_subdev (struct v4l2_subdev *sd) {struct v4l2_async_notifier *notifier;
drivers/media/v4l2-core/v4l2-fwnode.c +140 -0
158 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_release - release notifier resources +* @notifier: the notifier the resources of which are to be released +* +* Release memory resources related to a notifier, including the async +* sub-devices allocated for the purposes of the notifier. The user is +* responsible for releasing the notifier's resources after calling +* @v4l2_async_notifier_parse_fwnode_endpoints. +* +* There is no harm from calling v4l2_async_notifier_release in other +* cases as long as its memory has been zeroed after it has been +* allocated. +*/ +void v4l2_async_notifier_release (struct v4l2_async_notifier *notifier); + +/** * v4l2_async_register_subdev - registers a sub-device to the asynchronous * subdevice framework *
include/media/v4l2-fwnode.h +53 -0
63 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): 20170905130553.1332-7-sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected]
Re: [PATCH v8 06/21] v4l: fwnode: Support generic parsing of graph endpoints in a device
Quoted 131 lines · Sakari Ailus
The current practice is that drivers iterate over their endpoints and parse each endpoint separately. This is very similar in a number of drivers, implement a generic function for the job. Driver specific matters can be taken into account in the driver specific callback.
--- drivers/media/v4l2-core/v4l2-async.c | 19 +++++ drivers/media/v4l2-core/v4l2-fwnode.c | 140 ++++++++++++++++++++++++++++++++++ include/media/v4l2-async.h | 24 +++++- include/media/v4l2-fwnode.h | 53 +++++++++++++ 4 files changed, 234 insertions(+), 2 deletions(-)drivers/media/v4l2-core/v4l2-async.c +19
-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)@@ -224,6 +225,24 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) }EXPORT_SYMBOL (v4l2_async_notifier_unregister); +void v4l2_async_notifier_release (struct v4l2_async_notifier *notifier) +{ +unsigned int i; + +if (!notifier->max_subdevs) +return ; + +for (i =0 ; i < notifier->num_subdevs; i++) +kfree (notifier->subdevs[i]); + + notifier->max_subdevs =0 ; + notifier->num_subdevs =0 ; + +kvfree (notifier->subdevs); + notifier->subdevs =NULL ; +} +EXPORT_SYMBOL_GPL (v4l2_async_notifier_release); +int v4l2_async_register_subdev (struct v4l2_subdev *sd) {struct v4l2_async_notifier *notifier;drivers/media/v4l2-core/v4l2-fwnode.c +59
-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,144 @@ 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; +struct fwnode_endpoint ep; +int ret =0 ; + + asd =kzalloc (asd_struct_size,GFP_KERNEL ); +if (!asd) +return -ENOMEM ; + + 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; + } + +/* Ignore endpoints the parsing of which failed. */ + 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);
drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 384
Quoted 10 lines
drivers/media/v4l2-core/v4l2-fwnode.c +10
-0+ goto out_err; + } + + ep = vep->base; + + ret = parse_endpoint ?parse_endpoint (dev, vep, asd) :0 ; +v4l2_fwnode_endpoint_free (vep); +if (ret == -ENOTCONN ) { +dev_dbg (dev,"ignoring endpoint %u,%u\n" , ep.port, ep.id); +kfree (asd);
Shouldn't there be a call to fwnode_handle_put()?
drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 390
Quoted 6 lines
drivers/media/v4l2-core/v4l2-fwnode.c +6
-0+return 0 ; + }else if (ret <0 ) { +dev_warn (dev,"driver could not parse endpoint %u,%u (%d)\n" , + ep.port, ep.id, ret); + goto out_err; + }
I think this would be better and it avoids the need for the ep local variable:
ret = parse_endpoint ? parse_endpoint(dev, vep, asd) : 0; if (ret == -ENOTCONN) dev_dbg(dev, "ignoring endpoint %u,%u\n", vep->base.port, vep->base.id); else if (ret < 0) dev_warn(dev, "driver could not parse endpoint %u,%u (%d)\n", vep->base.port, vep->base.id, ret); v4l2_fwnode_endpoint_free(vep); if (ret < 0) goto out_err;
And the 'return ret;' below would become:
return ret == -ENOTCONN ? 0 : ret;
Quoted 16 lines
drivers/media/v4l2-core/v4l2-fwnode.c +16
-0+ + asd->match_type =V4L2_ASYNC_MATCH_FWNODE ; + notifier->subdevs[notifier->num_subdevs] = asd; + notifier->num_subdevs++; + +return 0 ; + +out_err: +fwnode_handle_put (asd->match.fwnode.fwnode); +kfree (asd); + +return ret; +} + +int v4l2_async_notifier_parse_fwnode_endpoints( + struct device *dev, struct v4l2_async_notifier *notifier,
drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 416
Quoted 10 lines
drivers/media/v4l2-core/v4l2-fwnode.c +10
-0+size_t asd_struct_size, + int (*parse_endpoint)(struct device *dev, +struct v4l2_fwnode_endpoint *vep, + struct v4l2_async_subdev *asd)) +{ + struct fwnode_handle *fwnode = NULL; +unsigned int max_subdevs = notifier->max_subdevs; +int ret; + +if (asd_struct_size <sizeof (struct v4l2_async_subdev ))
I think this can be a WARN_ON or a WARN_ON_ONCE. Up to you, though.
drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 423
Quoted 7 lines
drivers/media/v4l2-core/v4l2-fwnode.c +7
-0+return -EINVAL ; + +for (fwnode =NULL ; (fwnode =fwnode_graph_get_next_endpoint ( +dev_fwnode (dev), fwnode)); ) +if (fwnode_device_is_available ( +fwnode_graph_get_port_parent (fwnode))) + max_subdevs++;
I think I would prefer this as a simple for (;;):
for (;;) {
fwnode = fwnode_graph_get_next_endpoint(dev_fwnode(dev), fwnode));
if (fwnode == NULL)
break;
...
}Or alternatively as a do...while:
do {
fwnode = fwnode_graph_get_next_endpoint(dev_fwnode(dev), fwnode));
if (fwnode && fwnode_device_is_available(
fwnode_graph_get_port_parent(fwnode)))
max_subdevs++;
} while (fwnode);Both are IMHO a bit more readable. I leave it up to you, though.
drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 434
Quoted 11 lines
drivers/media/v4l2-core/v4l2-fwnode.c +11
-0+ +/* 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)); ) {
Same comment as above.
Quoted 124 lines
drivers/media/v4l2-core/v4l2-fwnode.c +21
-0+if (!fwnode_device_is_available ( +fwnode_graph_get_port_parent (fwnode))) +continue ; + +if (WARN_ON (notifier->num_subdevs >= notifier->max_subdevs)) { + ret = -EINVAL ; +break ; + } + + 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; +} +EXPORT_SYMBOL_GPL (v4l2_async_notifier_parse_fwnode_endpoints); +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_release - release notifier resources +* @notifier: the notifier the resources of which are to be released +* +* Release memory resources related to a notifier, including the async +* sub-devices allocated for the purposes of the notifier. The user is +* responsible for releasing the notifier's resources after calling +* @v4l2_async_notifier_parse_fwnode_endpoints. +* +* There is no harm from calling v4l2_async_notifier_release in other +* cases as long as its memory has been zeroed after it has been +* allocated. +*/ +void v4l2_async_notifier_release (struct v4l2_async_notifier *notifier); + +/** * v4l2_async_register_subdev - registers a sub-device to the asynchronous * subdevice framework * include/media/v4l2-fwnode.h +22
-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,55 @@ 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
include/media/v4l2-fwnode.h int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode, · line 235
Quoted 10 lines
include/media/v4l2-fwnode.h +10
-0+* 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. When using this function, the user may not access the +* notifier's subdevs array nor change notifier's num_subdevs field, these are +* reserved for the framework's internal use only.
The rvin_digital_graph_init() function accesses the subdevs array.
I still don't like this sentence, and I still think it should be dropped. Either that or completely rewritten.
Quoted 13 lines
include/media/v4l2-fwnode.h +12
-0+* +* 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_release() after it has been unregistered and the async +* sub-devices are no longer in use. +* +* 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 257
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 ( +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)); +#endif /* _V4L2_FWNODE_H */
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): dd3a2e55-8de0-c30e-04a7-cb26b519689c-qWit8jRvyhVmR6Xm/[email protected]
Re: [PATCH v8 06/21] v4l: fwnode: Support generic parsing of graph endpoints in a device
Hi Hans,
Quoted 136 lines · Hans Verkuil
Quoted 135 lines · Sakari Ailus
The current practice is that drivers iterate over their endpoints and parse each endpoint separately. This is very similar in a number of drivers, implement a generic function for the job. Driver specific matters can be taken into account in the driver specific callback.
--- drivers/media/v4l2-core/v4l2-async.c | 19 +++++ drivers/media/v4l2-core/v4l2-fwnode.c | 140 ++++++++++++++++++++++++++++++++++ include/media/v4l2-async.h | 24 +++++- include/media/v4l2-fwnode.h | 53 +++++++++++++ 4 files changed, 234 insertions(+), 2 deletions(-)drivers/media/v4l2-core/v4l2-async.c +19
-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)@@ -224,6 +225,24 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) }EXPORT_SYMBOL (v4l2_async_notifier_unregister); +void v4l2_async_notifier_release (struct v4l2_async_notifier *notifier) +{ +unsigned int i; + +if (!notifier->max_subdevs) +return ; + +for (i =0 ; i < notifier->num_subdevs; i++) +kfree (notifier->subdevs[i]); + + notifier->max_subdevs =0 ; + notifier->num_subdevs =0 ; + +kvfree (notifier->subdevs); + notifier->subdevs =NULL ; +} +EXPORT_SYMBOL_GPL (v4l2_async_notifier_release); +int v4l2_async_register_subdev (struct v4l2_subdev *sd) {struct v4l2_async_notifier *notifier;drivers/media/v4l2-core/v4l2-fwnode.c +63
-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,144 @@ 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; +struct fwnode_endpoint ep; +int ret =0 ; + + asd =kzalloc (asd_struct_size,GFP_KERNEL ); +if (!asd) +return -ENOMEM ; + + 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; + } + +/* Ignore endpoints the parsing of which failed. */ + 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; + } + + ep = vep->base;
Quoted 8 lines
drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 384
Quoted 6 lines
drivers/media/v4l2-core/v4l2-fwnode.c +6
-0+ + ret = parse_endpoint ?parse_endpoint (dev, vep, asd) :0 ; +v4l2_fwnode_endpoint_free (vep); +if (ret == -ENOTCONN ) { +dev_dbg (dev,"ignoring endpoint %u,%u\n" , ep.port, ep.id); +kfree (asd);Shouldn't there be a call to
fwnode_handle_put()?
Actually no. But your hunch is right in the sense that I think there are issues. The fwnode_endpoint (as of_endpoint) contains the fwnode which is referenced, but no reference is taken here. One couldn't be released either later on, as the fwnode field is const.
I guess this is almost fine as long as the fwnode field is used for pointer comparison and nothing else but you can never be sure what drivers actually do.
This actually should be addressed for both OF and fwnode but it's mostly independent of this patchset. Luckily there are not *that* many users of this. The V4L2 fwnode interface that allocates and releases endpoints makes this quite a bit easier actually.
Quoted 20 lines
drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 390
Quoted 7 lines
drivers/media/v4l2-core/v4l2-fwnode.c +6
-0+return 0 ; + }else if (ret <0 ) { +dev_warn (dev,"driver could not parse endpoint %u,%u (%d)\n" , + ep.port, ep.id, ret); + goto out_err; + }I think this would be better and it avoids the need for the ep local variable:
ret = parse_endpoint ? parse_endpoint(dev, vep, asd) : 0; if (ret == -ENOTCONN) dev_dbg(dev, "ignoring endpoint %u,%u\n", vep->base.port, vep->base.id); else if (ret < 0) dev_warn(dev, "driver could not parse endpoint %u,%u (%d)\n", vep->base.port, vep->base.id, ret); v4l2_fwnode_endpoint_free(vep); if (ret < 0) goto out_err;
Quoted 3 lines
And the 'return ret;' below would become:
return ret == -ENOTCONN ? 0 : ret;
Looks good to me, I'll use it.
Quoted 21 lines
Quoted 21 lines
drivers/media/v4l2-core/v4l2-fwnode.c +20
-0+ + asd->match_type =V4L2_ASYNC_MATCH_FWNODE ; + notifier->subdevs[notifier->num_subdevs] = asd; + notifier->num_subdevs++; + +return 0 ; + +out_err: +fwnode_handle_put (asd->match.fwnode.fwnode); +kfree (asd); + +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))
Quoted 8 lines
drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 416
Quoted 6 lines
drivers/media/v4l2-core/v4l2-fwnode.c +6
-0+{ +struct fwnode_handle *fwnode =NULL ; +unsigned int max_subdevs = notifier->max_subdevs; +int ret; + +if (asd_struct_size <sizeof (struct v4l2_async_subdev ))I think this can be a
WARN_ONor aWARN_ON_ONCE. Up to you, though.
It'd be a driver bug, so either seems appropriate. I'll use WARN_ON().
Quoted 11 lines
drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 423
Quoted 8 lines
drivers/media/v4l2-core/v4l2-fwnode.c +7
-0+return -EINVAL ; + +for (fwnode =NULL ; (fwnode =fwnode_graph_get_next_endpoint ( +dev_fwnode (dev), fwnode)); ) +if (fwnode_device_is_available ( +fwnode_graph_get_port_parent (fwnode))) + max_subdevs++;I think I would prefer this as a simple for (;;):
Quoted 1 line
for (;;) {I think for (;;) is misuse of the for loop. :-D
Quoted 17 lines
fwnode = fwnode_graph_get_next_endpoint(dev_fwnode(dev), fwnode)); if (fwnode == NULL) break; ... }Or alternatively as a do...while:
do { fwnode = fwnode_graph_get_next_endpoint(dev_fwnode(dev), fwnode)); if (fwnode && fwnode_device_is_available( fwnode_graph_get_port_parent(fwnode))) max_subdevs++; } while (fwnode);Both are IMHO a bit more readable. I leave it up to you, though.
Quoted 13 lines
drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 434
Quoted 11 lines
drivers/media/v4l2-core/v4l2-fwnode.c +11
-0+ +/* 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)); ) {Same comment as above.
What I like in the original code is that managing looping over all endpoints takes place directly in the for () statement and does not spill over to where the individual endpoints are being handled.
What would you think of adding a macro to do this? Say, we could write this as:
fwnode_graph_for_each_endpoint(dev_fwnode(dev), fwnode) {
...
}That'd have to go through linux-pm tree though, and we could change the code here later on.
Quoted 138 lines
Quoted 125 lines
drivers/media/v4l2-core/v4l2-fwnode.c +21
-0+if (!fwnode_device_is_available ( +fwnode_graph_get_port_parent (fwnode))) +continue ; + +if (WARN_ON (notifier->num_subdevs >= notifier->max_subdevs)) { + ret = -EINVAL ; +break ; + } + + 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; +} +EXPORT_SYMBOL_GPL (v4l2_async_notifier_parse_fwnode_endpoints); +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_release - release notifier resources +* @notifier: the notifier the resources of which are to be released +* +* Release memory resources related to a notifier, including the async +* sub-devices allocated for the purposes of the notifier. The user is +* responsible for releasing the notifier's resources after calling +* @v4l2_async_notifier_parse_fwnode_endpoints. +* +* There is no harm from calling v4l2_async_notifier_release in other +* cases as long as its memory has been zeroed after it has been +* allocated. +*/ +void v4l2_async_notifier_release (struct v4l2_async_notifier *notifier); + +/** * v4l2_async_register_subdev - registers a sub-device to the asynchronous * subdevice framework * include/media/v4l2-fwnode.h +22
-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,55 @@ 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 include/media/v4l2-fwnode.h int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode, · line 235
Quoted 10 lines
include/media/v4l2-fwnode.h +10
-0+* 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. When using this function, the user may not access the +* notifier's subdevs array nor change notifier's num_subdevs field, these are +* reserved for the framework's internal use only. The
rvin_digital_graph_init()function accesses the subdevs array.
Quoted 2 lines
I still don't like this sentence, and I still think it should be dropped. Either that or completely rewritten.
How about:
When using this function on a notifier, the user is not allowed to change the notifier's subdevs array, take references to the subdevs array itself nor change the notifier's num_subdevs field. This is because the function allocates and reallocates the subdevs array based on parsing endpoints.
Signature · 8 lines
Regards, 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
Re: [PATCH v8 06/21] v4l: fwnode: Support generic parsing of graph endpoints in a device
Quoted 153 lines · Sakari Ailus
Hi Hans,
Quoted 136 lines · Hans Verkuil
Quoted 135 lines · Sakari Ailus
The current practice is that drivers iterate over their endpoints and parse each endpoint separately. This is very similar in a number of drivers, implement a generic function for the job. Driver specific matters can be taken into account in the driver specific callback.
Signed-off-by Sakari Ailus <[email protected]>--- drivers/media/v4l2-core/v4l2-async.c | 19 +++++ drivers/media/v4l2-core/v4l2-fwnode.c | 140 ++++++++++++++++++++++++++++++++++ include/media/v4l2-async.h | 24 +++++- include/media/v4l2-fwnode.h | 53 +++++++++++++ 4 files changed, 234 insertions(+), 2 deletions(-)drivers/media/v4l2-core/v4l2-async.c +19
-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)@@ -224,6 +225,24 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) }EXPORT_SYMBOL (v4l2_async_notifier_unregister); +void v4l2_async_notifier_release (struct v4l2_async_notifier *notifier) +{ +unsigned int i; + +if (!notifier->max_subdevs) +return ; + +for (i =0 ; i < notifier->num_subdevs; i++) +kfree (notifier->subdevs[i]); + + notifier->max_subdevs =0 ; + notifier->num_subdevs =0 ; + +kvfree (notifier->subdevs); + notifier->subdevs =NULL ; +} +EXPORT_SYMBOL_GPL (v4l2_async_notifier_release); +int v4l2_async_register_subdev (struct v4l2_subdev *sd) {struct v4l2_async_notifier *notifier;drivers/media/v4l2-core/v4l2-fwnode.c +63
-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,144 @@ 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; +struct fwnode_endpoint ep; +int ret =0 ; + + asd =kzalloc (asd_struct_size,GFP_KERNEL ); +if (!asd) +return -ENOMEM ; + + 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; + } + +/* Ignore endpoints the parsing of which failed. */ + 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; + } + + ep = vep->base;Quoted 8 lines
drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 384
Quoted 6 lines
drivers/media/v4l2-core/v4l2-fwnode.c +6
-0+ + ret = parse_endpoint ?parse_endpoint (dev, vep, asd) :0 ; +v4l2_fwnode_endpoint_free (vep); +if (ret == -ENOTCONN ) { +dev_dbg (dev,"ignoring endpoint %u,%u\n" , ep.port, ep.id); +kfree (asd);Shouldn't there be a call to
fwnode_handle_put()?Actually no. But your hunch is right in the sense that I think there are issues. The
fwnode_endpoint(asof_endpoint) contains the fwnode which is referenced, but no reference is taken here. One couldn't be released either later on, as the fwnode field is const.
Quoted 8 lines
I guess this is almost fine as long as the fwnode field is used for pointer comparison and nothing else but you can never be sure what drivers actually do.
This actually should be addressed for both OF and fwnode but it's mostly independent of this patchset. Luckily there are not *that* many users of this. The V4L2 fwnode interface that allocates and releases endpoints makes this quite a bit easier actually.
I think a comment or two here would be helpful. If I tripped over this, so will others.
Quoted 28 lines
Quoted 21 lines
drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 390
Quoted 8 lines
drivers/media/v4l2-core/v4l2-fwnode.c +6
-0+return 0 ; + }else if (ret <0 ) { +dev_warn (dev,"driver could not parse endpoint %u,%u (%d)\n" , + ep.port, ep.id, ret); + goto out_err; + }I think this would be better and it avoids the need for the ep local variable:
ret = parse_endpoint ? parse_endpoint(dev, vep, asd) : 0; if (ret == -ENOTCONN) dev_dbg(dev, "ignoring endpoint %u,%u\n", vep->base.port, vep->base.id); else if (ret < 0) dev_warn(dev, "driver could not parse endpoint %u,%u (%d)\n", vep->base.port, vep->base.id, ret); v4l2_fwnode_endpoint_free(vep); if (ret < 0) goto out_err;Quoted 3 lines
And the 'return ret;' below would become:
return ret == -ENOTCONN ? 0 : ret;Looks good to me, I'll use it.
Quoted 1 line
Quoted 9 lines
Quoted 9 lines
drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 399
Quoted 9 lines
drivers/media/v4l2-core/v4l2-fwnode.c +9
-0+ + asd->match_type =V4L2_ASYNC_MATCH_FWNODE ; + notifier->subdevs[notifier->num_subdevs] = asd; + notifier->num_subdevs++; + +return 0 ; + +out_err: +fwnode_handle_put (asd->match.fwnode.fwnode);
Just a reminder: this put() should now check if ret != -ENOTCONN.
Quoted 75 lines
Quoted 11 lines
Quoted 11 lines
drivers/media/v4l2-core/v4l2-fwnode.c +11
-0+kfree (asd); + +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))Quoted 8 lines
drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 416
Quoted 6 lines
drivers/media/v4l2-core/v4l2-fwnode.c +6
-0+{ +struct fwnode_handle *fwnode =NULL ; +unsigned int max_subdevs = notifier->max_subdevs; +int ret; + +if (asd_struct_size <sizeof (struct v4l2_async_subdev ))I think this can be a
WARN_ONor aWARN_ON_ONCE. Up to you, though.It'd be a driver bug, so either seems appropriate. I'll use
WARN_ON().Quoted 11 lines
drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 423
Quoted 8 lines
drivers/media/v4l2-core/v4l2-fwnode.c +7
-0+return -EINVAL ; + +for (fwnode =NULL ; (fwnode =fwnode_graph_get_next_endpoint ( +dev_fwnode (dev), fwnode)); ) +if (fwnode_device_is_available ( +fwnode_graph_get_port_parent (fwnode))) + max_subdevs++;I think I would prefer this as a simple for (;;):
Quoted 1 line
for (;;) {I think for (;;) is misuse of the for loop. :-D
Quoted 17 lines
fwnode = fwnode_graph_get_next_endpoint(dev_fwnode(dev), fwnode)); if (fwnode == NULL) break; ... }Or alternatively as a do...while:
do { fwnode = fwnode_graph_get_next_endpoint(dev_fwnode(dev), fwnode)); if (fwnode && fwnode_device_is_available( fwnode_graph_get_port_parent(fwnode))) max_subdevs++; } while (fwnode);Both are IMHO a bit more readable. I leave it up to you, though.
Quoted 13 lines
drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 434
Quoted 11 lines
drivers/media/v4l2-core/v4l2-fwnode.c +11
-0+ +/* 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)); ) {Same comment as above.
What I like in the original code is that managing looping over all endpoints takes place directly in the for () statement and does not spill over to where the individual endpoints are being handled.
What would you think of adding a macro to do this? Say, we could write this as:
Quoted 6 lines
fwnode_graph_for_each_endpoint(dev_fwnode(dev), fwnode) { ... }That'd have to go through linux-pm tree though, and we could change the code here later on.
I think that's a good idea. Let's do that.
Quoted 142 lines
Quoted 139 lines
Quoted 126 lines
drivers/media/v4l2-core/v4l2-fwnode.c +21
-0+if (!fwnode_device_is_available ( +fwnode_graph_get_port_parent (fwnode))) +continue ; + +if (WARN_ON (notifier->num_subdevs >= notifier->max_subdevs)) { + ret = -EINVAL ; +break ; + } + + 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; +} +EXPORT_SYMBOL_GPL (v4l2_async_notifier_parse_fwnode_endpoints); +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_release - release notifier resources +* @notifier: the notifier the resources of which are to be released +* +* Release memory resources related to a notifier, including the async +* sub-devices allocated for the purposes of the notifier. The user is +* responsible for releasing the notifier's resources after calling +* @v4l2_async_notifier_parse_fwnode_endpoints. +* +* There is no harm from calling v4l2_async_notifier_release in other +* cases as long as its memory has been zeroed after it has been +* allocated. +*/ +void v4l2_async_notifier_release (struct v4l2_async_notifier *notifier); + +/** * v4l2_async_register_subdev - registers a sub-device to the asynchronous * subdevice framework * include/media/v4l2-fwnode.h +22
-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,55 @@ 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 include/media/v4l2-fwnode.h int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode, · line 235
Quoted 10 lines
include/media/v4l2-fwnode.h +10
-0+* 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. When using this function, the user may not access the +* notifier's subdevs array nor change notifier's num_subdevs field, these are +* reserved for the framework's internal use only. The
rvin_digital_graph_init()function accesses the subdevs array.Quoted 2 lines
I still don't like this sentence, and I still think it should be dropped. Either that or completely rewritten.
Quoted 7 lines
How about:
When using this function on a notifier, the user is not allowed to change the notifier's subdevs array, take references to the subdevs array itself nor change the notifier's
num_subdevsfield. This is because the function allocates and reallocates the subdevs array based on parsing endpoints.
How about this:
"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."
It's the "When using this function" part that really trips me up. It's odd phrasing.
Regards,
Hans
Re: [PATCH v8 06/21] v4l: fwnode: Support generic parsing of graph endpoints in a device
Hi Hans,
Quoted 158 lines · Hans Verkuil
Quoted 157 lines · Sakari Ailus
Hi Hans,
Quoted 136 lines · Hans Verkuil
Quoted 135 lines · Sakari Ailus
The current practice is that drivers iterate over their endpoints and parse each endpoint separately. This is very similar in a number of drivers, implement a generic function for the job. Driver specific matters can be taken into account in the driver specific callback.
Signed-off-by Sakari Ailus <[email protected]>--- drivers/media/v4l2-core/v4l2-async.c | 19 +++++ drivers/media/v4l2-core/v4l2-fwnode.c | 140 ++++++++++++++++++++++++++++++++++ include/media/v4l2-async.h | 24 +++++- include/media/v4l2-fwnode.h | 53 +++++++++++++ 4 files changed, 234 insertions(+), 2 deletions(-)drivers/media/v4l2-core/v4l2-async.c +19
-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)@@ -224,6 +225,24 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) }EXPORT_SYMBOL (v4l2_async_notifier_unregister); +void v4l2_async_notifier_release (struct v4l2_async_notifier *notifier) +{ +unsigned int i; + +if (!notifier->max_subdevs) +return ; + +for (i =0 ; i < notifier->num_subdevs; i++) +kfree (notifier->subdevs[i]); + + notifier->max_subdevs =0 ; + notifier->num_subdevs =0 ; + +kvfree (notifier->subdevs); + notifier->subdevs =NULL ; +} +EXPORT_SYMBOL_GPL (v4l2_async_notifier_release); +int v4l2_async_register_subdev (struct v4l2_subdev *sd) {struct v4l2_async_notifier *notifier;drivers/media/v4l2-core/v4l2-fwnode.c +63
-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,144 @@ 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; +struct fwnode_endpoint ep; +int ret =0 ; + + asd =kzalloc (asd_struct_size,GFP_KERNEL ); +if (!asd) +return -ENOMEM ; + + 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; + } + +/* Ignore endpoints the parsing of which failed. */ + 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; + } + + ep = vep->base;Quoted 8 lines
drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 384
Quoted 6 lines
drivers/media/v4l2-core/v4l2-fwnode.c +6
-0+ + ret = parse_endpoint ?parse_endpoint (dev, vep, asd) :0 ; +v4l2_fwnode_endpoint_free (vep); +if (ret == -ENOTCONN ) { +dev_dbg (dev,"ignoring endpoint %u,%u\n" , ep.port, ep.id); +kfree (asd);Shouldn't there be a call to
fwnode_handle_put()?Actually no. But your hunch is right in the sense that I think there are issues. The
fwnode_endpoint(asof_endpoint) contains the fwnode which is referenced, but no reference is taken here. One couldn't be released either later on, as the fwnode field is const.I guess this is almost fine as long as the fwnode field is used for pointer comparison and nothing else but you can never be sure what drivers actually do.
Quoted 7 lines
Quoted 4 lines
This actually should be addressed for both OF and fwnode but it's mostly independent of this patchset. Luckily there are not *that* many users of this. The V4L2 fwnode interface that allocates and releases endpoints makes this quite a bit easier actually.
I think a comment or two here would be helpful. If I tripped over this, so will others.
Reading the code again, I noticed I didn't read far enough the last time. While v4l2_fwnode_endpoint_alloc_parse() won't take a reference, fwnode_graph_get_remote_port_parent() does. That reference indeed isn't released right now.
It shouldn't be too hard to do that properly in v4l2_async_notifier_release(). I guess I'll do just that actually. By that time, there are no users left anymore.
Good catch.
Quoted 29 lines
Quoted 29 lines
Quoted 22 lines
drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 390
Quoted 9 lines
drivers/media/v4l2-core/v4l2-fwnode.c +6
-0+return 0 ; + }else if (ret <0 ) { +dev_warn (dev,"driver could not parse endpoint %u,%u (%d)\n" , + ep.port, ep.id, ret); + goto out_err; + }I think this would be better and it avoids the need for the ep local variable:
ret = parse_endpoint ? parse_endpoint(dev, vep, asd) : 0; if (ret == -ENOTCONN) dev_dbg(dev, "ignoring endpoint %u,%u\n", vep->base.port, vep->base.id); else if (ret < 0) dev_warn(dev, "driver could not parse endpoint %u,%u (%d)\n", vep->base.port, vep->base.id, ret); v4l2_fwnode_endpoint_free(vep); if (ret < 0) goto out_err;Quoted 3 lines
And the 'return ret;' below would become:
return ret == -ENOTCONN ? 0 : ret;Looks good to me, I'll use it.
Quoted 1 line
Quoted 11 lines
Quoted 9 lines
Quoted 9 lines
drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 399
Quoted 9 lines
drivers/media/v4l2-core/v4l2-fwnode.c +9
-0+ + asd->match_type =V4L2_ASYNC_MATCH_FWNODE ; + notifier->subdevs[notifier->num_subdevs] = asd; + notifier->num_subdevs++; + +return 0 ; + +out_err: +fwnode_handle_put (asd->match.fwnode.fwnode);Just a reminder: this
put()should now check if ret !=-ENOTCONN.
Should it? Even if ret == -ENOTCONN, the reference is there and needs to be released as the endpoint is not used (just as in the case of an error).
Quoted 76 lines
Quoted 76 lines
Quoted 12 lines
Quoted 12 lines
drivers/media/v4l2-core/v4l2-fwnode.c +11
-0+kfree (asd); + +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))Quoted 8 lines
drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 416
Quoted 6 lines
drivers/media/v4l2-core/v4l2-fwnode.c +6
-0+{ +struct fwnode_handle *fwnode =NULL ; +unsigned int max_subdevs = notifier->max_subdevs; +int ret; + +if (asd_struct_size <sizeof (struct v4l2_async_subdev ))I think this can be a
WARN_ONor aWARN_ON_ONCE. Up to you, though.It'd be a driver bug, so either seems appropriate. I'll use
WARN_ON().Quoted 11 lines
drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 423
Quoted 8 lines
drivers/media/v4l2-core/v4l2-fwnode.c +7
-0+return -EINVAL ; + +for (fwnode =NULL ; (fwnode =fwnode_graph_get_next_endpoint ( +dev_fwnode (dev), fwnode)); ) +if (fwnode_device_is_available ( +fwnode_graph_get_port_parent (fwnode))) + max_subdevs++;I think I would prefer this as a simple for (;;):
Quoted 1 line
for (;;) {I think for (;;) is misuse of the for loop. :-D
Quoted 17 lines
fwnode = fwnode_graph_get_next_endpoint(dev_fwnode(dev), fwnode)); if (fwnode == NULL) break; ... }Or alternatively as a do...while:
do { fwnode = fwnode_graph_get_next_endpoint(dev_fwnode(dev), fwnode)); if (fwnode && fwnode_device_is_available( fwnode_graph_get_port_parent(fwnode))) max_subdevs++; } while (fwnode);Both are IMHO a bit more readable. I leave it up to you, though.
Quoted 13 lines
drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 434
Quoted 11 lines
drivers/media/v4l2-core/v4l2-fwnode.c +11
-0+ +/* 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)); ) {Same comment as above.
What I like in the original code is that managing looping over all endpoints takes place directly in the for () statement and does not spill over to where the individual endpoints are being handled.
What would you think of adding a macro to do this? Say, we could write this as:
Quoted 8 lines
Quoted 6 lines
fwnode_graph_for_each_endpoint(dev_fwnode(dev), fwnode) { ... }That'd have to go through linux-pm tree though, and we could change the code here later on.
I think that's a good idea. Let's do that.
Ack. I'll submit a patch on that in the near future.
Quoted 151 lines
Quoted 143 lines
Quoted 140 lines
Quoted 127 lines
drivers/media/v4l2-core/v4l2-fwnode.c +21
-0+if (!fwnode_device_is_available ( +fwnode_graph_get_port_parent (fwnode))) +continue ; + +if (WARN_ON (notifier->num_subdevs >= notifier->max_subdevs)) { + ret = -EINVAL ; +break ; + } + + 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; +} +EXPORT_SYMBOL_GPL (v4l2_async_notifier_parse_fwnode_endpoints); +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_release - release notifier resources +* @notifier: the notifier the resources of which are to be released +* +* Release memory resources related to a notifier, including the async +* sub-devices allocated for the purposes of the notifier. The user is +* responsible for releasing the notifier's resources after calling +* @v4l2_async_notifier_parse_fwnode_endpoints. +* +* There is no harm from calling v4l2_async_notifier_release in other +* cases as long as its memory has been zeroed after it has been +* allocated. +*/ +void v4l2_async_notifier_release (struct v4l2_async_notifier *notifier); + +/** * v4l2_async_register_subdev - registers a sub-device to the asynchronous * subdevice framework * include/media/v4l2-fwnode.h +22
-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,55 @@ 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 include/media/v4l2-fwnode.h int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode, · line 235
Quoted 10 lines
include/media/v4l2-fwnode.h +10
-0+* 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. When using this function, the user may not access the +* notifier's subdevs array nor change notifier's num_subdevs field, these are +* reserved for the framework's internal use only. The
rvin_digital_graph_init()function accesses the subdevs array.Quoted 2 lines
I still don't like this sentence, and I still think it should be dropped. Either that or completely rewritten.
Quoted 7 lines
How about:
When using this function on a notifier, the user is not allowed to change the notifier's subdevs array, take references to the subdevs array itself nor change the notifier's
num_subdevsfield. This is because the function allocates and reallocates the subdevs array based on parsing endpoints.
Quoted 6 lines
How about this:
"Do not change the notifier's subdevs array, take references to the subdevs array itself or change the notifier's
num_subdevsfield. This is because this function allocates and reallocates the subdevs array based on parsing endpoints."
I'll use this in the next version.
Signature · 4 lines
Regards, Sakari Ailus e-mail: [email protected]
A message that is not in the archive (sent off-list or not yet received): 20170907095850.m7mlag3tofwbj2jc-S+BSfZ9RZZmRSg0ZkenSGLdO1Tsj/[email protected]
Re: [PATCH v8 06/21] v4l: fwnode: Support generic parsing of graph endpoints in a device
Quoted 221 lines · Sakari Ailus
Hi Hans,
Quoted 158 lines · Hans Verkuil
Quoted 157 lines · Sakari Ailus
Hi Hans,
Quoted 136 lines · Hans Verkuil
Quoted 135 lines · Sakari Ailus
The current practice is that drivers iterate over their endpoints and parse each endpoint separately. This is very similar in a number of drivers, implement a generic function for the job. Driver specific matters can be taken into account in the driver specific callback.
--- drivers/media/v4l2-core/v4l2-async.c | 19 +++++ drivers/media/v4l2-core/v4l2-fwnode.c | 140 ++++++++++++++++++++++++++++++++++ include/media/v4l2-async.h | 24 +++++- include/media/v4l2-fwnode.h | 53 +++++++++++++ 4 files changed, 234 insertions(+), 2 deletions(-)drivers/media/v4l2-core/v4l2-async.c +19
-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)@@ -224,6 +225,24 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) }EXPORT_SYMBOL (v4l2_async_notifier_unregister); +void v4l2_async_notifier_release (struct v4l2_async_notifier *notifier) +{ +unsigned int i; + +if (!notifier->max_subdevs) +return ; + +for (i =0 ; i < notifier->num_subdevs; i++) +kfree (notifier->subdevs[i]); + + notifier->max_subdevs =0 ; + notifier->num_subdevs =0 ; + +kvfree (notifier->subdevs); + notifier->subdevs =NULL ; +} +EXPORT_SYMBOL_GPL (v4l2_async_notifier_release); +int v4l2_async_register_subdev (struct v4l2_subdev *sd) {struct v4l2_async_notifier *notifier;drivers/media/v4l2-core/v4l2-fwnode.c +63
-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,144 @@ 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; +struct fwnode_endpoint ep; +int ret =0 ; + + asd =kzalloc (asd_struct_size,GFP_KERNEL ); +if (!asd) +return -ENOMEM ; + + 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; + } + +/* Ignore endpoints the parsing of which failed. */ + 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; + } + + ep = vep->base;Quoted 8 lines
drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 384
Quoted 6 lines
drivers/media/v4l2-core/v4l2-fwnode.c +6
-0+ + ret = parse_endpoint ?parse_endpoint (dev, vep, asd) :0 ; +v4l2_fwnode_endpoint_free (vep); +if (ret == -ENOTCONN ) { +dev_dbg (dev,"ignoring endpoint %u,%u\n" , ep.port, ep.id); +kfree (asd);Shouldn't there be a call to
fwnode_handle_put()?Actually no. But your hunch is right in the sense that I think there are issues. The
fwnode_endpoint(asof_endpoint) contains the fwnode which is referenced, but no reference is taken here. One couldn't be released either later on, as the fwnode field is const.I guess this is almost fine as long as the fwnode field is used for pointer comparison and nothing else but you can never be sure what drivers actually do.
Quoted 7 lines
Quoted 4 lines
This actually should be addressed for both OF and fwnode but it's mostly independent of this patchset. Luckily there are not *that* many users of this. The V4L2 fwnode interface that allocates and releases endpoints makes this quite a bit easier actually.
I think a comment or two here would be helpful. If I tripped over this, so will others.
Reading the code again, I noticed I didn't read far enough the last time. While
v4l2_fwnode_endpoint_alloc_parse()won't take a reference,fwnode_graph_get_remote_port_parent()does. That reference indeed isn't released right now.It shouldn't be too hard to do that properly in
v4l2_async_notifier_release(). I guess I'll do just that actually. By that time, there are no users left anymore.Good catch.
Quoted 29 lines
Quoted 29 lines
Quoted 22 lines
drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 390
Quoted 9 lines
drivers/media/v4l2-core/v4l2-fwnode.c +6
-0+return 0 ; + }else if (ret <0 ) { +dev_warn (dev,"driver could not parse endpoint %u,%u (%d)\n" , + ep.port, ep.id, ret); + goto out_err; + }I think this would be better and it avoids the need for the ep local variable:
ret = parse_endpoint ? parse_endpoint(dev, vep, asd) : 0; if (ret == -ENOTCONN) dev_dbg(dev, "ignoring endpoint %u,%u\n", vep->base.port, vep->base.id); else if (ret < 0) dev_warn(dev, "driver could not parse endpoint %u,%u (%d)\n", vep->base.port, vep->base.id, ret); v4l2_fwnode_endpoint_free(vep); if (ret < 0) goto out_err;Quoted 3 lines
And the 'return ret;' below would become:
return ret == -ENOTCONN ? 0 : ret;Looks good to me, I'll use it.
Quoted 1 line
Quoted 11 lines
Quoted 9 lines
Quoted 9 lines
drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 399
Quoted 9 lines
drivers/media/v4l2-core/v4l2-fwnode.c +9
-0+ + asd->match_type =V4L2_ASYNC_MATCH_FWNODE ; + notifier->subdevs[notifier->num_subdevs] = asd; + notifier->num_subdevs++; + +return 0 ; + +out_err: +fwnode_handle_put (asd->match.fwnode.fwnode);Just a reminder: this
put()should now check if ret !=-ENOTCONN.
Quoted 2 lines
Should it? Even if ret ==
-ENOTCONN, the reference is there and needs to be released as the endpoint is not used (just as in the case of an error).
Well, in the previous reply you mentioned that the put wasn't necessary, hence my comment. Since it is now needed again you can ignore this.
Regards,
Hans
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
drivers/media/v4l2-core/v4l2-fwnode.c void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · line 403
Quoted 6 lines
drivers/media/v4l2-core/v4l2-fwnode.c +4
-0+kfree (asd); + +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
Sakari Ailus
maintainerPATCH v8 9/21 omap3isp: Fix check for our own sub-devices
In reply to Sakari AilusWe 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 · 1 line
2.11.0
A message that is not in the archive (sent off-list or not yet received): 20170905130553.1332-10-sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected]
Hans Verkuil
Acked-byRe: [PATCH v8 09/21] omap3isp: Fix check for our own sub-devices
Quoted 5 lines · Sakari Ailus
We 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_deviceas well. Check for the correct async notifier.
Regards,
Hans
Quoted 10 lines
--- drivers/media/platform/omap3isp/isp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/media/platform/omap3isp/isp.c +0
-0
drivers/media/platform/omap3isp/isp.c static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async) · line 2161
Quoted 8 lines
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,
--
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 v8 12/21 v4l: async: Introduce helpers for calling async ops callbacks
In reply to Sakari AilusAdd 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 )
@@ -107,16 +135,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; }
@@ -128,8 +153,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 ; }
@@ -215,8 +240,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); }mutex_unlock (&list_lock);
@@ -294,8 +318,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 · 1 line
2.11.0
A message that is not in the archive (sent off-list or not yet received): 20170905130553.1332-13-sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected]
Hans Verkuil
Acked-byRe: [PATCH v8 12/21] v4l: async: Introduce helpers for calling async ops callbacks
Quoted 3 lines · Sakari Ailus
Add 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.
What is the use-case of that?
Anyway:
Regards,
Hans
Quoted 104 lines
--- 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 )@@ -107,16 +135,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; }@@ -128,8 +153,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 ; }@@ -215,8 +240,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); }mutex_unlock (&list_lock);@@ -294,8 +318,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 +0
-0
include/media/v4l2-async.h int v4l2_async_register_subdev(struct v4l2_subdev *sd); · line 168
Quoted 5 lines
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
--
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 v8 12/21] v4l: async: Introduce helpers for calling async ops callbacks
Quoted 6 lines · Hans Verkuil
Quoted 3 lines · Sakari Ailus
Add 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.
What is the use-case of that?
Going forward, the sub-notifiers that are just for binding associated devices (later in the patchset, 17th and 18th patches) there is no need for callbacks. This allows having no ops either.
Quoted 4 lines
Anyway:
Acked-by Hans Verkuil <[email protected]>
Thanks!
Signature · 2 lines
Sakari Ailus e-mail: [email protected]
Sakari Ailus
maintainerPATCH v8 16/21 dt: bindings: Add lens-focus binding for image sensors
In reply to Sakari AilusThe 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: 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 · 1 line
2.11.0
A message that is not in the archive (sent off-list or not yet received): 20170905130553.1332-17-sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected]
Hans Verkuil
Acked-byRe: [PATCH v8 16/21] dt: bindings: Add lens-focus binding for image sensors
Quoted 8 lines · Sakari Ailus
The 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.
Regards,
Hans
Quoted 10 lines
--- Documentation/devicetree/bindings/media/video-interfaces.txt | 2 ++ 1 file changed, 2 insertions(+)Documentation/devicetree/bindings/media/video-interfaces.txt +0
-0
Documentation/devicetree/bindings/media/video-interfaces.txt Optional properties · line 81
Quoted 8 lines
Documentation/devicetree/bindings/media/video-interfaces.txt +2
-0@@ -74,6 +74,8 @@ Optional properties - flash: 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 ----------------------------
--
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 v8 20/21 dt: bindings: smiapp: Document lens-focus and flash properties
In reply to Sakari AilusDocument optional lens-focus and flash 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: One or more phandles to refer to flash LEDs +- lens-focus: Phandle for lens focus Endpoint node mandatory properties
Signature · 1 line
2.11.0
Sakari Ailus
maintainerPATCH v8 21/21 arm: dts: omap3: N9/N950: Add flash references to the camera
In reply to Sakari AilusAdd 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 = <&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
@@ -269,13 +269,13 @@ as3645a@30 { reg = <0x30>; compatible = "ams,as3645a"; - flash { + as3645a_flash: flash { flash-timeout-us = <150000>; flash-max-microamp = <320000>; led-max-microamp = <60000>; peak-current-limit = <1750000>; }; - indicator { + as3645a_indicator: indicator { 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 = <&as3645a_flash &as3645a_indicator>; port { smia_1_1: endpoint { link-frequencies = /bits/ 64 <210000000 333600000 398400000>;
Signature · 1 line
2.11.0