基于RV1126 Video分析-----mipi协议解析模块所代表的subdev子设备注册

工作:

															sensor

								LIST_HEAD(notifier_list)----+                    LIST_HEAD(subdev_list)----+	
				                                            |                                              |
				                                            |                                              |
				                                            | 挂载                                         | 挂载
		                                                    |                                              |
struct techpoint 		                                    |                                              |
	struct v4l2_async_notifier *subdev_notifier; -----------+                                              |
		struct v4l2_subdev *sd; ---------+                                                                 |
			                             | bind                                                            |
	struct v4l2_subdev subdev;-----------+  ---------------------------------------------------------------+
		const struct v4l2_subdev_ops *ops(init!!!)		   
		struct v4l2_device *v4l2_dev; (NULL)        

	struct i2c_client *client;
		struct device dev;					
			struct device_node	*of_node; // A  			如节点	tp2855_1@44 
				struct	device_node *child;  //Aa           如节点 		ports 	
			+-------struct fwnode_handle *fwnode; 
			|	+---struct	device_node *child; // Aa-1     如节点    		ucam_out0
			|	|			
			|   |
			|   |
			|   |									mipi_csi_dphy
			|   |
			|	|											LIST_HEAD(notifier_list)-----+         LIST_HEAD(subdev_list)-----+
			|	|																		 |                                    |
			|	|																		 |挂载                                |挂载
			|	|			struct mipidphy_priv                                         |                                    |
			|	|		+-------struct v4l2_async_notifier notifier; --------------------+                                    |
			|	|		|			const struct v4l2_async_notifier_operations *ops; (init!!!)                               |
			|	|		|	+-------struct list_head waiting;//等待通知链表 												  |
			|	|		|	|		struct v4l2_async_subdev **subdevs;//数组 												  |
			|	|		|	+-----------|//subdevs[n] 将远端目标节点封装为 v4l2_async_subdev 结构 保存在该数组                |
			|	|		|				|enum v4l2_async_match_type match_type = V4L2_ASYNC_MATCH_FWNODE                      |
			|	|		|				|union match                                                                          |
			+---|-------|--------------------struct fwnode_handle *fwnode;													  |
				|		|			struct v4l2_subdev *sd ------------+                                                      |
				|		|						    				   |                                                      |
				|		|		struct v4l2_subdev sd;-----------------+ -----------------------------------------------------+
				|		|			const struct v4l2_subdev_ops *ops	
				|		|			struct v4l2_device *v4l2_dev; (NULL)
				|		+------------struct v4l2_async_notifier *subdev_notifier;
				|					
				|				struct device *dev;
				|					struct device_node	*of_node; //A associated device tree node           如 节点 csi_dphy0                        
				|						struct	device_node *child;  //Aa                 第一个子节点      如 节点 	ports 				
				|							struct	device_node *child; // Aa-1           第一个子节点      如 节点 		port@0 
				|								struct	device_node *child; //Aa-1-1      第一个子节点      如 节点 			csi_dphy1_input: endpoint@1
				|------------------------------------remote-endpoint = <&ucam_out0> 设备树属性
								
												struct	device_node *sibling; // Aa-2     第二个子节点      如 节点 		port@1 
				+-----------------------------------struct fwnode_handle *fwnode; 
				|		+---------------------------struct	device_node *child; //Aa-2-1  第一个子节点      如 节点 			csi_dphy1_output: endpoint@0
				|		|								remote-endpoint = <&mipi_csi2_input> 设备树属性
				|		|
				|		|
				|		|
				|		|						
				|		|												
				|		|												mipi_csi   
				|		|																		LIST_HEAD(notifier_list)-----+       LIST_HEAD(subdev_list)----+
                |       |                                                                                                    |                                 |
				|		|																									 |                                 |
				|		|						struct csi2_dev                                                              |                                 |
				|		|							struct device *dev;== platform_device *pdev->dev                         |                                 |
				|		|				+-----------struct v4l2_async_notifier notifier;-------------------------------------+                                 |
				|		|				|				const struct v4l2_async_notifier_operations *ops; (init !!!!)                                          |
				|		|				|		+-------struct list_head waiting;//等待通知链表		                                                           |
				|		|				|		|		struct v4l2_async_subdev **subdevs;//subdevs数组                                                       |
				|		|				|		+-----------|//subdevs[n] 将远端目标节点封装为 v4l2_async_subdev 结构 保存在该数组                             |
				|		|				|					|enum v4l2_async_match_type match_type = V4L2_ASYNC_MATCH_FWNODE  设备树fwnode匹配方式             |
				|		|				|					|union match                                                                                       |
				+-------|---------------|-----------------------struct fwnode_handle *fwnode;                                                                  |
						|				|				struct v4l2_subdev *sd -----+                                                                          |
						|				|											|                                                                          |
						|				|											|                                                                          |
						|				|			struct v4l2_subdev	sd; --------+--------------------------------------------------------------------------+
						|				|				const struct v4l2_subdev_ops *ops;
						|				|				struct v4l2_device *v4l2_dev; (NULL)
						|				|				struct device *dev;== platform_device *pdev->dev
						|				+---------------struct v4l2_async_notifier	notifier;
						|								
						|							struct device *dev;
						|								(-->)struct device_node	*of_node; //A associated device tree node           如 节点 mipi_csi2                        
						|										struct	device_node *child;  //Aa                 第一个子节点      如 节点 	ports 				
						|											struct	device_node *child; // Aa-1           第一个子节点      如 节点 		port@0
						|												struct	device_node *child; //Aa-1-1      第一个子节点      如 节点 			endpoint@1
						+---------------------------------------------------remote-endpoint = <&csi_dphy0_output>; 设备树属性			

&mipi_csi2 {                                     
	status = "okay";                                
    
	ports {                                         
		#address-cells = <1>;                         
		#size-cells = <0>;                            
                                                 
		port@0 {                                      
			reg = <0>;                                  
			#address-cells = <1>;                       
			#size-cells = <0>;                          
                                                 
			mipi_csi2_input: endpoint@1 {               
				reg = <1>;                                
				remote-endpoint = <&csi_dphy0_output>;    
				data-lanes = <1 2 3 4>;                   
			};                                          
		};                                            
                                                                                     
		port@1 {                                      
			reg = <1>;                                  
			#address-cells = <1>;                       
			#size-cells = <0>;                          
                                                 
			mipi_csi2_output: endpoint@0 {              
				reg = <0>;                                
				remote-endpoint = <&cif_mipi_in>;         
				data-lanes = <1 2 3 4>;                   
			};                                          
		};                                            
	};                                            
};

kernel\drivers\media\platform\rockchip\cif\mipi-csi2.c

struct csi2_dev {
	struct device		*dev;
	struct v4l2_subdev	sd;
	struct media_pad	pad[CSI2_NUM_PADS];
	struct clk_bulk_data	*clks_bulk;
	int			clks_num;
	struct reset_control	*rsts_bulk;

	void __iomem		*base;
	struct v4l2_async_notifier	notifier;
	struct v4l2_fwnode_bus_mipi_csi2	bus;

	/* lock to protect all members below */
	struct mutex lock;

	struct v4l2_mbus_framefmt	format_mbus;
	struct v4l2_rect	crop;
	int			stream_count;
	struct v4l2_subdev	*src_sd;
	bool			sink_linked[CSI2_NUM_SRC_PADS];
	struct csi2_sensor	sensors[MAX_CSI2_SENSORS];
	const struct csi2_match_data	*match_data;
	int			num_sensors;
	atomic_t		frm_sync_seq;
	struct csi2_err_stats err_list[RK_CSI2_ERR_MAX];
};



static const struct
v4l2_async_notifier_operations csi2_async_ops = {
	.bound = csi2_notifier_bound,
	.unbind = csi2_notifier_unbind,
};



static const struct v4l2_subdev_core_ops csi2_core_ops = {
	.subscribe_event = rkcif_csi2_subscribe_event,
	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
};

static const struct v4l2_subdev_video_ops csi2_video_ops = {
	.g_mbus_config = csi2_g_mbus_config,
	.s_stream = csi2_s_stream,
};

static const struct v4l2_subdev_pad_ops csi2_pad_ops = {
	.get_fmt = csi2_get_set_fmt,
	.set_fmt = csi2_get_set_fmt,
	.get_selection = csi2_get_selection,
	.set_selection = csi2_set_selection,
};

static const struct v4l2_subdev_ops csi2_subdev_ops = {
	.core = &csi2_core_ops,
	.video = &csi2_video_ops,
	.pad = &csi2_pad_ops,
};

static const struct csi2_match_data rv1126_csi2_match_data = {
	.chip_id = CHIP_RV1126_CSI2,
	.num_pads = CSI2_NUM_PADS,//5
};

static const struct of_device_id csi2_dt_ids[] = {
	{
		.compatible = "rockchip,rk1808-mipi-csi2",
		.data = &rk1808_csi2_match_data,
	},
	{
		.compatible = "rockchip,rk3288-mipi-csi2",
		.data = &rk3288_csi2_match_data,
	},
	{
		.compatible = "rockchip,rk3568-mipi-csi2",
		.data = &rk3568_csi2_match_data,
	},
	{
		.compatible = "rockchip,rv1126-mipi-csi2",
		.data = &rv1126_csi2_match_data,
	},
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, csi2_dt_ids);


static const struct media_entity_operations csi2_entity_ops = {
	.link_setup = csi2_link_setup,
	.link_validate = v4l2_subdev_link_validate,
};



static int csi2_notifier(struct csi2_dev *csi2)
{
	struct v4l2_async_notifier *ntf = &csi2->notifier;
	int ret;
	
	/* 设备树解析
	
	 参数1 csi2_dev->device
	 参数2 csi2_dev->v4l2_async_notifier
	 参数3 size_t v4l2_async_subdev
	 参数4 0
	 参数5 函数指针 csi2_parse_endpoint
	
	*/
	
	/*
	解析 endpoint1 节点对应的远程端点(csi_dphy0的 子节点 port@1 ),并记录到 mipi_csi2->v4l2_async_notifier->subdevs[]数组
	
	
	工作
	1 		通过 mipi_csi2 节点 找到 最底层孙设备 mipi_csi2_input: endpoint@1 节点
			
			struct mipi_csi2
				struct device *dev;
				(-->)struct device_node	*of_node; //A associated device tree node           如 节点 mipi_csi2                        
						struct	device_node *child;  //Aa                 第一个子节点      如 节点 	ports 				
							struct	device_node *child; // Aa-1           第一个子节点      如 节点 		port@0
								struct	device_node *child; //Aa-1-1      第一个子节点      如 节点 			endpoint@1
								(<--)struct fwnode_handle fwnode;		
	


	 2 		通过 最底层孙设备 endpoint@1 节点 的 "remote-endpoint" 属性  找到 远程关联节点 csi_dphy0_output 的 父节点 port@1
	 
	 3 		将 远程关联节点 csi_dphy0_output 的 父节点 port@1 信息 组织成 struct v4l2_async_subdev 数据结构。作为子设备 添加到 struct mipi_csi2 中 。
				这样 就将 mipi_csi2 信息与 mipidphy 信息 关联了起来
				
		struct mipi_csi2
			struct device *dev;
			(-->)struct device_node	*of_node; //A associated device tree node           如 节点 mipi_csi2                        
					struct	device_node *child;  //Aa                 第一个子节点      如 节点 	ports 				
						struct	device_node *child; // Aa-1           第一个子节点      如 节点 		port@0
							struct	device_node *child; //Aa-1-1      第一个子节点      如 节点 			endpoint@1
							(<--)struct fwnode_handle fwnode;			

 			struct v4l2_async_notifier notifier;	
				struct v4l2_async_subdev **subdevs;//subdevs数组
					enum v4l2_async_match_type match_type = V4L2_ASYNC_MATCH_FWNODE  设备树fwnode匹配方式 
					union match
						struct fwnode_handle *fwnode;-----------------------------------------------------相连接的远程节点csi_dphy0_output 的 父节点 port@1 的 fwnode
						
	*/
	
	ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(csi2->dev,
								 &csi2->notifier,
								 sizeof(struct v4l2_async_subdev), 0,
								 csi2_parse_endpoint);
	if (ret < 0)
		return ret;

	if (!ntf->num_subdevs)
		return -ENODEV;	/* no endpoint */

	csi2->sd.subdev_notifier = &csi2->notifier;
	csi2->notifier.ops = &csi2_async_ops;
	
	
	/* 主要就是将异步通知notifier挂载到 全局notifier_list链表上 
	
		1 记录v4l2_subdev 到 异步通知notifier  notifier->sd = sd
		2 将异步通知notifier挂载到 全局notifier_list链表上 
		3 对于mipi-csi 驱动 还有 将 远端关联节点 挂载到  struct csi2_dev -> v4l2_async_notifier->waiting 等待链表上
		 
		v4l2_subdev
		v4l2_async_notifier
	*/
	ret = v4l2_async_subdev_notifier_register(&csi2->sd, &csi2->notifier);
	if (ret) {
		v4l2_err(&csi2->sd,
			 "failed to register async notifier : %d\n",
			 ret);
		v4l2_async_notifier_cleanup(&csi2->notifier);
		return ret;
	}

	
        /*
         * 这里会有v4l2_dev = NULL不执行
         * 只是将当前subdev挂载到 全局链表subdev_list上
         */

	ret = v4l2_async_register_subdev(&csi2->sd);

	return ret;
}
	


static int csi2_probe(struct platform_device *pdev)
{
	const struct of_device_id *match;
	struct device *dev = &pdev->dev;
	struct device_node *node = pdev->dev.of_node;
	struct csi2_dev *csi2 = NULL;
	struct resource *res;
	const struct csi2_match_data *data;
	int ret, irq;

	match = of_match_node(csi2_dt_ids, node);
	if (IS_ERR(match))
		return PTR_ERR(match);
	data = match->data;

	csi2 = devm_kzalloc(&pdev->dev, sizeof(*csi2), GFP_KERNEL);
	if (!csi2)
		return -ENOMEM;

	csi2->dev = &pdev->dev;
	csi2->match_data = data;

	/*
		初始化 csi2_dev->v4l2_subdev->ops
	*/
	v4l2_subdev_init(&csi2->sd, &csi2_subdev_ops);
	v4l2_set_subdevdata(&csi2->sd, &pdev->dev);
	csi2->sd.entity.ops = &csi2_entity_ops;
	csi2->sd.dev = &pdev->dev;
	csi2->sd.owner = THIS_MODULE;
	csi2->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
	ret = strscpy(csi2->sd.name, DEVICE_NAME, sizeof(csi2->sd.name));
	if (ret < 0)
		v4l2_err(&csi2->sd, "failed to copy name\n");
	platform_set_drvdata(pdev, &csi2->sd);
...
	mutex_init(&csi2->lock);
...
	
	
	/*
	参数 struct csi2_dev *csi2
	*/
	ret = csi2_notifier(csi2);
	if (ret)
		goto rmmutex;

...
}


static struct platform_driver csi2_driver = {
	.driver = {
		.name = DEVICE_NAME,
		.of_match_table = csi2_dt_ids,
	},
	.probe = csi2_probe,
	.remove = csi2_remove,
};

int __init rkcif_csi2_plat_drv_init(void)
{
	return platform_driver_register(&csi2_driver);
}

void __exit rkcif_csi2_plat_drv_exit(void)
{
	platform_driver_unregister(&csi2_driver);
}

kernel\drivers\media\v4l2-core\v4l2-async.c

int v4l2_async_register_subdev(struct v4l2_subdev *sd)
{
	struct v4l2_async_notifier *subdev_notifier;
	struct v4l2_async_notifier *notifier;
	int ret;

	if (!sd->fwnode && sd->dev)
		sd->fwnode = dev_fwnode(sd->dev);

	mutex_lock(&list_lock);

	INIT_LIST_HEAD(&sd->async_list);

...

	 /*
         * 没有匹配到相关的信息
         * 将当前subdev挂载到 全局链表subdev_list上
         */
		 
	list_add(&sd->async_list, &subdev_list);
...
	
	return ret;
}

你可能感兴趣的:(Video驱动,链表,数据结构)