rk3588 v4l2架构梳理

本文详细解析了在RK3588平台上V4L2异步注册过程,包括A部分的v4l2_async_notifier_parse_fwnode_endpoints_by_port函数,B部分的v4l2_async_subdev_notifier_register,以及C部分的v4l2_async_register_subdev。通过分析注册顺序和链表操作,阐述了如何匹配和管理subdev及asd节点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本篇文章仅为防止忘记v4l2 异步注册写的,个人觉的写的不够详细,仅供参考,

dts如下


// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
 * Copyright (c) 2022 Rockchip Electronics Co., Ltd.
 *
 */

/ {
	cam_ircut0: cam_ircut {
		status = "okay";
		compatible = "rockchip,ircut";
		ircut-open-gpios = <&gpio4 RK_PA0 GPIO_ACTIVE_HIGH>;
		ircut-close-gpios  = <&gpio4 RK_PA1 GPIO_ACTIVE_HIGH>;
		rockchip,camera-module-index = <0>;
		rockchip,camera-module-facing = "back";
	};

};

&csi2_dcphy0 {
	status = "okay";

	ports {
		#address-cells = <1>;
		#size-cells = <0>;
		port@0 {
			reg = <0>;
			#address-cells = <1>;
			#size-cells = <0>;

			mipidphy0_in_ucam0: endpoint@1 {
				reg = <1>;
				remote-endpoint = <&ov13855_out0>;
				data-lanes = <1 2 3 4>;
			};
		};
		port@1 {
			reg = <1>;
			#address-cells = <1>;
			#size-cells = <0>;

			csidcphy0_out: endpoint@0 {
				reg = <0>;
				remote-endpoint = <&mipi0_csi2_input>;
			};
		};
	};
};

&csi2_dphy0_hw {
	status = "okay";
};

&i2c4 {
	status = "okay";
	pinctrl-0 = <&i2c4m0_xfer>;
	
	dw9763: dw9763@c {
		compatible = "dongwoon,dw9763";
		status = "okay";
		reg = <0xc>;
		rockchip,camera-module-index = <0>;
		rockchip,vcm-start-current = <10>;
		rockchip,vcm-rated-current = <85>;
		//rockchip,vcm-step-mode = <5>;
		rockchip,camera-module-facing = "back";
		vdd-gpio = <&aw_gpio1 0 GPIO_ACTIVE_HIGH>;
		};


	ov13855: ov13855@10 {
		compatible = "ovti,ov13855";
		status = "okay";
		reg = <0x10>;
		clocks = <&cru CLK_MIPI_CAMARAOUT_M1>;
		clock-names = "xvclk";
		pinctrl-names = "default";
		pinctrl-0 = <&mipim0_camera1_clk>;
		power-domains = <&power RK3588_PD_VI>;
		reset-gpios = <&gpio1 RK_PB0 GPIO_ACTIVE_HIGH>;
		pwdn-gpios = <&gpio1 RK_PA4 GPIO_ACTIVE_HIGH>;
		//lf-gpios = <&aw_gpio1 0 GPIO_ACTIVE_HIGH>;
		//iovdd-gpios = <&aw_gpio1 1 GPIO_ACTIVE_HIGH>;
		vaf-gpios = <&aw_gpio1 2 GPIO_ACTIVE_HIGH>;
		avdd-gpios = <&aw_gpio1 3 GPIO_ACTIVE_HIGH>;
		dvdd-gpios = <&aw_gpio1 4 GPIO_ACTIVE_HIGH>;
		rockchip,camera-module-index = <0>;
		rockchip,camera-module-facing = "back";
		rockchip,camera-module-name = "CMK-OT2016-FV1";
		rockchip,camera-module-lens-name = "default";
		lens-focus = <&dw9763>;
		port {
			ov13855_out0: endpoint {
				remote-endpoint = <&mipidphy0_in_ucam0>;
				data-lanes = <1 2 3 4>;
			};
		};
	};
};

&mipi0_csi2 {
	status = "okay";

	ports {
		#address-cells = <1>;
		#size-cells = <0>;

		port@0 {
			reg = <0>;
			#address-cells = <1>;
			#size-cells = <0>;

			mipi0_csi2_input: endpoint@1 {
				reg = <1>;
				remote-endpoint = <&csidcphy0_out>;
			};
		};

		port@1 {
			reg = <1>;
			#address-cells = <1>;
			#size-cells = <0>;

			mipi0_csi2_output: endpoint@0 {
				reg = <0>;
				remote-endpoint = <&cif_mipi_in0>;
			};
		};
	};
};

&pinctrl {
	cam {
	/*
		mipidphy0_pwr: mipidphy0-pwr {
			rockchip,pins =
				<1 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>;
		};
	*/
	};
};

&rkcif {
	status = "okay";
};

&rkcif_mipi_lvds {
	status = "okay";

	port {
		cif_mipi_in0: endpoint {
			remote-endpoint = <&mipi0_csi2_output>;
		};
	};
};

&rkcif_mipi_lvds_sditf {
	status = "okay";

	port {
		mipi_lvds_sditf: endpoint {
			remote-endpoint = <&isp0_vir0>;
		};
	};
};

&rkcif_mmu {
	status = "okay";
};

&rkisp0 {
	status = "okay";
};

&isp0_mmu {
	status = "okay";
};

&rkisp0_vir0 {
	status = "okay";

	port {
		#address-cells = <1>;
		#size-cells = <0>;

		isp0_vir0: endpoint@0 {
			reg = <0>;
			remote-endpoint = <&mipi_lvds_sditf>;
		};
	};
};

kernel-5.10/driver/phy/rockchip/phy-rockchip-csi-dphy.c

rockchip_csi2_dphy_probe==>rockchip_csi2dphy_media_init


static int rockchip_csi2dphy_media_init(struct csi2_dphy *dphy)
{
	int ret;
	
	//media entity后面再分析
	dphy->pads[CSI2_DPHY_RX_PAD_SOURCE].flags =
		MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT;
	dphy->pads[CSI2_DPHY_RX_PAD_SINK].flags =
		MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
	dphy->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
	ret = media_entity_pads_init(&dphy->sd.entity,
				CSI2_DPHY_RX_PADS_NUM, dphy->pads);
	if (ret < 0)
		return ret;

	v4l2_async_notifier_init(&dphy->notifier);

	ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(      .................................A
		dphy->dev, &dphy->notifier,
		sizeof(struct sensor_async_subdev), 0,
		rockchip_csi2_dphy_fwnode_parse);
	if (ret < 0)
		return ret;

	dphy->sd.subdev_notifier = &dphy->notifier;
	dphy->notifier.ops = &rockchip_csi2_dphy_async_ops;
	ret = v4l2_async_subdev_notifier_register(&dphy->sd, &dphy->notifier); ....................................B
	if (ret) {
		dev_err(dphy->dev,
			"failed to register async notifier : %d\n", ret);
		v4l2_async_notifier_cleanup(&dphy->notifier);
		return ret;
	}

	return v4l2_async_register_subdev(&dphy->sd);	............................................C
}

A部分

先看A部分v4l2_async_notifier_parse_fwnode_endpoints_by_port


kernel-5.10\drivers\media\v4l2-core\v4l2-fwnode.c

int
v4l2_async_notifier_parse_fwnode_endpoints_by_port(struct device *dev,
						   struct v4l2_async_notifier *notifier,
						   size_t asd_struct_size,
						   unsigned int port,
						   parse_endpoint_func parse_endpoint)
{
	return __v4l2_async_notifier_parse_fwnode_ep(dev, notifier,
						     asd_struct_size,
						     port, true,
						     parse_endpoint);
}
EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints_by_port);


具体调用__v4l2_async_notifier_parse_fwnode_ep


static int
__v4l2_async_notifier_parse_fwnode_ep(struct device *dev,
				      struct v4l2_async_notifier *notifier,
				      size_t asd_struct_size,
				      unsigned int port,
				      bool has_port,
				      parse_endpoint_func parse_endpoint)
{
	struct fwnode_handle *fwnode;
	int ret = 0;

	if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
		return -EINVAL;

	fwnode_graph_for_each_endpoint(dev_fwnode(dev), fwnode) {
		struct fwnode_handle *dev_fwnode;
		bool is_available;

		/*fwnode_graph_get_port_parent具体调用
		*		struct fwnode_handle *
		*		fwnode_graph_get_port_parent(const struct fwnode_handle *endpoint)
		*		{
		*			struct fwnode_handle *port, *parent;
		*		
		*			port = fwnode_get_parent(endpoint);
		*			parent = fwnode_call_ptr_op(port, graph_get_port_parent);
		*		
		*			fwnode_handle_put(port);
		*		
		*			return parent;
		*		}
		*		EXPORT_SYMBOL_GPL(fwnode_graph_get_port_parent);
		*最后具体调用kernel-5.10\drivers\of\property.c中的函数
		*下面的fwnode_device_is_available也是调用property.c中的fwnode_device_is_available ===》fwnode_device_is_available,判断dts中的status是否为okay
		*/
		dev_fwnode = fwnode_graph_get_port_parent(fwnode);
		is_available = fwnode_device_is_available(dev_fwnode);
		printk("====>fwnode:%s,dev_fwnode:%s,is_available %d",fwnode->dev->of_node->full_name,dev_fwnode->dev->of_node->full_name,is_available);
		fwnode_handle_put(dev_fwnode);
		if (!is_available)
			continue;

		if (has_port) {
			struct fwnode_endpoint ep;

			ret = fwnode_graph_parse_endpoint(fwnode, &ep);
			if (ret)
				break;

			if (ep.port != port)
				continue;
		}

		ret = v4l2_async_notifier_fwnode_parse_endpoint(dev,
								notifier,
								fwnode,
								asd_struct_size,
								parse_endpoint);
		if (ret < 0)
			break;
	}

	fwnode_handle_put(fwnode);

	return ret;
}



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,
					  parse_endpoint_func parse_endpoint)
{
	struct v4l2_fwnode_endpoint vep = { .bus_type = 0 };
	struct v4l2_async_subdev *asd;
	int ret;

	asd = kzalloc(asd_struct_size, GFP_KERNEL);
	if (!asd)
		return -ENOMEM;

	asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
	asd->match.fwnode =
		fwnode_graph_get_remote_port_parent(endpoint);
	printk("====>asd->match.fwnode %s \n",asd->match.fwnode->dev->of_node->full_name);
	if (!asd->match.fwnode) {
		dev_dbg(dev, "no remote endpoint found\n");
		ret = -ENOTCONN;
		goto out_err;
	}

	ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &vep);
	if (ret) {
		dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n",
			 ret);
		goto out_err;
	}

	ret = parse_endpoint ? parse_endpoint(dev, &vep, asd) : 0;
	if (ret == -ENOTCONN)
		dev_dbg(dev, "ignoring port@%u/endpoint@%u\n", vep.base.port,
			vep.base.id);
	else if (ret < 0)
		dev_warn(dev,
			 "driver could not parse port@%u/endpoint@%u (%d)\n",
			 vep.base.port, vep.base.id, ret);
	v4l2_fwnode_endpoint_free(&vep);
	if (ret < 0)
		goto out_err;

	ret = v4l2_async_notifier_add_subdev(notifier, asd);
	if (ret < 0) {
		/* not an error if asd already exists */
		if (ret == -EEXIST)
			ret = 0;
		goto out_err;
	}

	return 0;

out_err:
	fwnode_handle_put(asd->match.fwnode);
	kfree(asd);

	return ret == -ENOTCONN ? 0 : ret;
}



这是subdev异步注册的其中一个关键步骤list_add_tail(&asd->asd_list, &notifier->asd_list);

注意asd->match.fwnode是endpoint的父节点,比如asd->match.fwnode mipi0-csi2@fdd10000,下次注册mipi0-csi2是会用当前的subdev与asd上的fwnode进行对比,如果是同意个节点则匹配上

这里贴一下打印的log,按注册顺序


====>dev : rkcif-mipi-lvds
[    8.185161][    T1] ====>dev_fwnode:rkcif-mipi-lvds
[    8.185181][    T1] ====>asd->match.fwnode mipi0-csi2@fdd10000
[    8.185189][    T1] ===== begin parsing endpoint /rkcif-mipi-lvds/port/endpoint
[    8.185195][    T1] fwnode video bus type not specified (0), mbus type not specified (0)
[    8.185206][    T1] ===== end parsing endpoint /rkcif-mipi-lvds/port/endpoint
[    8.185276][    T1] rkcif rkcif-mipi-lvds1: Adding to iommu group 16
[    8.185292][    T1] rkcif rkcif-mipi-lvds1: rkcif driver version: v00.01.0a
[    8.185335][    T1] rkcif rkcif-mipi-lvds1: attach to cif hw node
[    8.185341][    T1] rkcif rkcif-mipi-lvds1: rkcif wait line 0

[    8.185989][    T1] ====>dev : rkcif-mipi-lvds1
[    8.185996][    T1] ====>dev_fwnode:rkcif-mipi-lvds1
[    8.186017][    T1] ====>asd->match.fwnode mipi1-csi2@fdd20000
[    8.186023][    T1] ===== begin parsing endpoint /rkcif-mipi-lvds1/port/endpoint
[    8.186028][    T1] fwnode video bus type not specified (0), mbus type not specified (0)
[    8.186037][    T1] ===== end parsing endpoint /rkcif-mipi-lvds1/port/endpoint
[    8.186904][    T1] ====>dev : mipi0-csi2@fdd10000
[    8.186912][    T1] ====>dev_fwnode:mipi0-csi2@fdd10000
[    8.186918][    T1] ====>ep:0,ep->id:1
[    8.186923][    T1] ====>asd->match.fwnode csi2-dcphy0
[    8.186930][    T1] ===== begin parsing endpoint /mipi0-csi2@fdd10000/ports/port@0/endpoint@1
[    8.186936][    T1] fwnode video bus type not specified (0), mbus type not specified (0)
[    8.186946][    T1] ===== end parsing endpoint /mipi0-csi2@fdd10000/ports/port@0/endpoint@1
[    8.186952][    T1] ====>dev_fwnode:mipi0-csi2@fdd10000
[    8.186957][    T1] ====>ep:1,ep->id:0
[    8.186966][    T1] rkcif rkcif-mipi-lvds: Entity type for entity rockchip-mipi-csi2 was not initialized!
[    8.186972][    T1] rockchip-mipi-csi2: Async registered subdev
[    8.186979][    T1] rockchip-mipi-csi2: probe success, v4l2_dev:rkcif-mipi-lvds!
[    8.187065][    T1] ====>dev : mipi1-csi2@fdd20000
[    8.187070][    T1] ====>dev_fwnode:mipi1-csi2@fdd20000
[    8.187076][    T1] ====>ep:0,ep->id:1
[    8.187085][    T1] ====>asd->match.fwnode csi2-dcphy1
[    8.187091][    T1] ===== begin parsing endpoint /mipi1-csi2@fdd20000/ports/port@0/endpoint@1
[    8.187097][    T1] fwnode video bus type not specified (0), mbus type not specified (0)
[    8.187105][    T1] ===== end parsing endpoint /mipi1-csi2@fdd20000/ports/port@0/endpoint@1
[    8.187111][    T1] ====>dev_fwnode:mipi1-csi2@fdd20000
[    8.187116][    T1] ====>ep:1,ep->id:0
[    8.187122][    T1] rkcif rkcif-mipi-lvds1: Entity type for entity rockchip-mipi-csi2 was not initialized!
[    8.187128][    T1] rockchip-mipi-csi2: Async registered subdev
[    8.187135][    T1] rockchip-mipi-csi2: probe success, v4l2_dev:rkcif-mipi-lvds1!
[    8.187531][    T1] rkisp_hw fdcb0000.rkisp: Adding to iommu group 14
[    8.187687][    T1] rkisp_hw fdcb0000.rkisp: is_thunderboot: 0
[    8.187694][    T1] rkisp_hw fdcb0000.rkisp: max input:0x0@0fps
[    8.187700][    T1] rkisp_hw fdcb0000.rkisp: Missing rockchip,grf property
[    8.187773][    T1] rkisp_hw fdcb0000.rkisp: no find phandle sram
[    8.187877][    T1] rkisp_hw fdcc0000.rkisp: Adding to iommu group 15
[    8.188072][    T1] rkisp_hw fdcc0000.rkisp: is_thunderboot: 0
[    8.188078][    T1] rkisp_hw fdcc0000.rkisp: max input:0x0@0fps
[    8.188083][    T1] rkisp_hw fdcc0000.rkisp: Missing rockchip,grf property
[    8.188152][    T1] rkisp_hw fdcc0000.rkisp: no find phandle sram
[    8.188448][    T1] rkisp rkisp0-vir0: rkisp driver version: v01.09.00
[    8.188574][    T1] rkisp rkisp0-vir0: Entity type for entity rkisp-isp-subdev was not initialized!
[    8.189026][    T1] ====>dev : rkisp0-vir0
[    8.189032][    T1] ====>dev_fwnode:rkisp0-vir0
[    8.189039][    T1] ====>asd->match.fwnode rkcif-mipi-lvds-sditf
[    8.189045][    T1] ===== begin parsing endpoint /rkisp0-vir0/port/endpoint@0
[    8.189051][    T1] fwnode video bus type not specified (0), mbus type not specified (0)
[    8.189060][    T1] ===== end parsing endpoint /rkisp0-vir0/port/endpoint@0
[    8.189102][    T1] rkisp rkisp1-vir0: rkisp driver version: v01.09.00
[    8.189219][    T1] rkisp rkisp1-vir0: Entity type for entity rkisp-isp-subdev was not initialized!
[    8.189652][    T1] ====>dev : rkisp1-vir0
[    8.189658][    T1] ====>dev_fwnode:rkisp1-vir0
[    8.189663][    T1] ====>asd->match.fwnode rkcif-mipi-lvds1-sditf
[    8.189669][    T1] ===== begin parsing endpoint /rkisp1-vir0/port/endpoint@0
[    8.189675][    T1] fwnode video bus type not specified (0), mbus type not specified (0)
[    8.189684][    T1] ===== end parsing endpoint /rkisp1-vir0/port/endpoint@0


[    9.289965][    T1] ov13855 4-0010: driver version: 00.01.02
[    9.290169][    T1] ov13855 4-0010: could not get default pinstate
[    9.290181][    T1] ov13855 4-0010: could not get sleep pinstate
[    9.298546][    T1] ov13855 4-0010: Detected OV00d855 sensor, REVISION 0xb0
[    9.310223][  T217] vendor storage:20190527 ret = 0
[    9.327207][    T1] ov13855 5-0010: driver version: 00.01.02
[    9.327330][    T1] ov13855 5-0010: could not get default pinstate
[    9.327342][    T1] ov13855 5-0010: could not get sleep pinstate
[    9.336122][    T1] ov13855 5-0010: Detected OV00d855 sensor, REVISION 0xb0
[    9.369541][    T1] registered taskstats version 1

[    9.441305][    T9] ====>dev : csi2-dcphy0
[    9.441344][    T9] ====>dev_fwnode:csi2-dcphy0
[    9.441356][    T9] ====>ep:0,ep->id:1
[    9.441456][    T9] ====>asd->match.fwnode ov13855@10
[    9.441471][    T9] ===== begin parsing endpoint /csi2-dcphy0/ports/port@0/endpoint@1
[    9.441484][    T9] fwnode video bus type not specified (0), mbus type not specified (0)
[    9.441505][    T9] ===== end parsing endpoint /csi2-dcphy0/ports/port@0/endpoint@1
[    9.441523][    T9] ====>dev_fwnode:csi2-dcphy0
[    9.441533][    T9] ====>ep:1,ep->id:0
[    9.441574][    T9] rockchip-csi2-dphy csi2-dcphy0: dphy0 matches m00_b_ov13855 4-0010:bus type 5
[    9.441600][    T9] rockchip-csi2-dphy csi2-dcphy0: csi2_dphy_update_sensor_mbus fail to get dphy param, used default value
[    9.442858][    T9] rockchip-csi2-dphy csi2-dcphy0: csi2_dphy_update_sensor_mbus fail to get dphy param, used default value
[    9.442909][    T9] rkcif-mipi-lvds: Async subdev notifier completed
[    9.442922][    T9] rockchip-csi2-dphy csi2-dcphy0: csi2 dphy0 probe successfully!
[    9.442995][  T193] rockchip-csi2-dphy csi2-dcphy0: csi2_dphy_update_sensor_mbus fail to get dphy param, used default value
[    9.443171][    T9] ====>dev : csi2-dcphy1
[    9.443186][    T9] ====>dev_fwnode:csi2-dcphy1
[    9.443197][    T9] ====>ep:0,ep->id:1
[    9.443233][    T9] ====>asd->match.fwnode ov13855@10
[    9.443246][    T9] ===== begin parsing endpoint /csi2-dcphy1/ports/port@0/endpoint@1
[    9.443257][    T9] fwnode video bus type not specified (0), mbus type not specified (0)
[    9.443273][    T9] ===== end parsing endpoint /csi2-dcphy1/ports/port@0/endpoint@1
[    9.443464][  T193] rockchip-csi2-dphy csi2-dcphy0: csi2_dphy_update_sensor_mbus fail to get dphy param, used default value
[    9.443492][  T193] rockchip-csi2-dphy csi2-dcphy0: csi2_dphy_update_sensor_mbus fail to get dphy param, used default value
[    9.443523][  T193] rkisp0-vir0: Async subdev notifier completed
[    9.443626][    T9] ====>dev_fwnode:csi2-dcphy1
[    9.443642][    T9] ====>ep:1,ep->id:0
[    9.443668][    T9] rockchip-csi2-dphy csi2-dcphy1: dphy1 matches m01_f_ov13855 5-0010:bus type 5
[    9.443686][    T9] rockchip-csi2-dphy csi2-dcphy1: csi2_dphy_update_sensor_mbus fail to get dphy param, used default value
[    9.445319][    T9] rockchip-csi2-dphy csi2-dcphy1: csi2_dphy_update_sensor_mbus fail to get dphy param, used default value
[    9.445367][    T9] rkcif-mipi-lvds1: Async subdev notifier completed
[    9.445380][    T9] rockchip-csi2-dphy csi2-dcphy1: csi2 dphy1 probe successfully!
[    9.445446][  T194] rockchip-csi2-dphy csi2-dcphy1: csi2_dphy_update_sensor_mbus fail to get dphy param, used default value
[    9.446089][  T194] rockchip-csi2-dphy csi2-dcphy1: csi2_dphy_update_sensor_mbus fail to get dphy param, used default value
[    9.446113][  T194] rockchip-csi2-dphy csi2-dcphy1: csi2_dphy_update_sensor_mbus fail to get dphy param, used default value
[    9.446134][  T194] rkisp1-vir0: Async subdev notifier completed


总的来说这个函数就是找到endpoint的远程父节点,并将asd添加到notifier->asd_list上,此处也可参考v4l2_async_notifier_parse_fwnode_endpoints_by_port 分析

B部分

函数v4l2_async_subdev_notifier_register
->__v4l2_async_notifier_register


static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
{
	struct v4l2_async_subdev *asd;
	int ret, i = 0;

	INIT_LIST_HEAD(¬ifier->waiting);
	INIT_LIST_HEAD(¬ifier->done);

	mutex_lock(&list_lock);

	list_for_each_entry(asd, & notifier->asd_list, asd_list) {
		ret = v4l2_async_notifier_asd_valid(notifier, asd, i++);
		if (ret)
			goto err_unlock;

		list_add_tail(&asd->list, & notifier->waiting);
	}

	ret = v4l2_async_notifier_try_all_subdevs(notifier);
	if (ret < 0)
		goto err_unbind;

	ret = v4l2_async_notifier_try_complete(notifier);
	if (ret < 0)
		goto err_unbind;

	/* Keep also completed notifiers on the list */
	list_add(¬ifier->list, ¬ifier_list);

	mutex_unlock(&list_lock);

	return 0;

err_unbind:
	/*
	 * On failure, unbind all sub-devices registered through this notifier.
	 */
	v4l2_async_notifier_unbind_all_subdevs(notifier);

err_unlock:
	mutex_unlock(&list_lock);

	return ret;
}


遍历notifier->asd_list,将上面A部分注册的asd->list加入notifier->waiting

v4l2_async_notifier_try_all_subdevs函数需要v4l2_dev注册后才能完成,也就是再没有注册v4l2_dev前,所有的subdev都不会和asd匹配

C部分

函数v4l2_async_register_subdev初始化sd->async_list并加入subdev_list

sensor==》 mipi csi2_dcphy0==》mipi0_csi2==》rkcif_mipi_lvds – – – >rkcif_mipi_lvds_sditf ==> rkisp0_vir0

注册的顺序可参考上面的log

rkcif_mipi_lvds 注册完成后notifier_list链表上有1个notifier,是mipi0-csi2@fdd10000的

mipi0_csi2注册后,notifier_list链表上有1个notifier,是csi2-dcphy0,此时notifier_list上的mipi0-csi2@fdd10000的notifier已经和sd匹配,已经从队列中移除

按log顺序是,接着是ov13855 sensor注册,notifier_list链表上有2个notifier,分别是csi2-dcphy0和ov13855 sensor 上附带的af或flash的

csi2_dcphy0注册后,此时notifier_list上的csi2-dcphy0的notifier已经和sd匹配,已经从队列中移除,af或flash注册是的notifier_list清空

感觉我将的不够清楚的可以参考https://blog.csdn.net/ldl617/category_11006713.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

autho

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值