基于RV1126 Video分析-----sensor模块所代表的subdev子设备注册

工作:

static LIST_HEAD(notifier_list); //异步通知链表
static LIST_HEAD(subdev_list);//v4l2_subdev 链表

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

&i2c1 {                                          
                                             
/delete-node/ ar0230@10;                        
/delete-node/ ov4689@36;                        
/delete-node/ os04a10@36;                       
                                            
tp2855_1: tp2855_1@44 {  
	
	compatible = "techpoint,tp2855";                        
	reg = <0x44>;  //i2c地址                     
	...
	port {                                        
		ucam_out0: endpoint {                       
			remote-endpoint = <&csi_dphy0_input>; //Sensor连接到mipi
			data-lanes = <1 2 3 4>;                   
		};                                          
	};   
}; 

tp2855_2: tp2855_2@45 {
	compatible = "techpoint,tp2855";
	reg = <0x45>; //i2c地址         
	...
	port {
		ucam_out1: endpoint {
			remote-endpoint = <&csi_dphy1_input>; //Sensor连接到mipi    csi_dphy1_input
			data-lanes = <1 2 3 4>; 
		};
	};
};

};

kernel\drivers\media\i2c\techpoint\techpoint_v4l2.c

static const struct v4l2_subdev_pad_ops techpoint_subdev_pad_ops = {
	.enum_mbus_code = techpoint_enum_mbus_code,
	.enum_frame_size = techpoint_enum_frame_sizes,
	.get_fmt = techpoint_get_fmt,
	.set_fmt = techpoint_set_fmt,
};

static const struct v4l2_subdev_video_ops techpoint_video_ops = {
	.s_stream = techpoint_stream,
	.g_mbus_config = techpoint_g_mbus_config,
	.g_frame_interval = techpoint_g_frame_interval,
	.querystd = techpoint_querystd,
};


static const struct v4l2_subdev_core_ops techpoint_core_ops = {
	.s_power = techpoint_power,
	.ioctl = techpoint_ioctl,
#ifdef CONFIG_COMPAT
	.compat_ioctl32 = techpoint_compat_ioctl32,
#endif
};


static const struct v4l2_subdev_ops techpoint_subdev_ops = {
	.core = &techpoint_core_ops,
	.video = &techpoint_video_ops,
	.pad   = &techpoint_subdev_pad_ops,
};



#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
static const struct v4l2_subdev_internal_ops techpoint_internal_ops = {
	.open = techpoint_open,
};
#endif


/*
1 填充了subdev的相关成员信息 struct v4l2_subdev *sd;

		sd = &techpoint->subdev; 绑定 techpoint -- v4l2_subdev
		sd->ops = &imx291_subdev_ops;
		sd->v4l2_dev = NULL;
		sd->flags = V4L2_SUBDEV_FL_IS_I2C

2 记录 v4l2_subdev 到 异步通知notifier  notifier->sd = sd
  并将notifier挂载到全局链表notifier_list上
  
3 subdev 挂载到 全局链表subdev_list上
*/
static int techpoint_probe(struct i2c_client *client,
			 const struct i2c_device_id *id)
{
	
	struct device *dev = &client->dev;
	struct techpoint *techpoint;
	struct v4l2_subdev *sd;
	
	
	techpoint = devm_kzalloc(dev, sizeof(*techpoint), GFP_KERNEL);
	if (!techpoint)
		return -ENOMEM;

	techpoint->client = client;
	techpoint->supplies = NULL;
...
	
	//注册
	/*
	sd = &techpoint->subdev; 绑定 techpoint -- v4l2_subdev
	sd->ops = &imx291_subdev_ops;
	sd->v4l2_dev = NULL;
	sd->flags = V4L2_SUBDEV_FL_IS_I2C
	*/
	sd = &techpoint->subdev;
	v4l2_i2c_subdev_init(sd, client, &techpoint_subdev_ops);
	
...
	
	/* 
	1 创建了异步通知notifier 关联subdev,并将notifier挂载到全局链表notifier_list上
	2 subdev挂载到 全局链表subdev_list上
	*/
	ret = v4l2_async_register_subdev_sensor_common(sd);

}


static const struct of_device_id techpoint_of_match[] = {
	{ .compatible = "techpoint,tp2855" },
	{ .compatible = "techpoint,tp2815" },
	{ .compatible = "techpoint,tp9930" },
	{},
};

static const struct i2c_device_id techpoint_match_id[] = {
	{ "techpoint", 0 },
	{ },
};

static struct i2c_driver techpoint_i2c_driver = {
	.driver = {
		.name = TECHPOINT_NAME,
		.pm = &techpoint_pm_ops,
		.of_match_table = of_match_ptr(techpoint_of_match),
	},
	.probe		= &techpoint_probe,
	.remove		= &techpoint_remove,
	.id_table	= techpoint_match_id,
};

static int __init sensor_mod_init(void)
{
	return i2c_add_driver(&techpoint_i2c_driver);
}

static void __exit sensor_mod_exit(void)
{
	i2c_del_driver(&techpoint_i2c_driver);
}

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

/*
1 创建了异步通知notifier 关联subdev,并将notifier挂载到全局链表notifier_list上
2 subdev挂载到 全局链表subdev_list上
*/
int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev *sd)
{
	struct v4l2_async_notifier *notifier;
	int ret;

	if (WARN_ON(!sd->dev))
		return -ENODEV;

	//初始化为空
	notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
	if (!notifier)
		return -ENOMEM;

...

	/* 主要就是将异步通知notifier挂载到 全局notifier_list链表上 
		
		1 记录v4l2_subdev 到 异步通知notifier  notifier->sd = sd
		2 将异步通知notifier挂载到 全局notifier_list链表上 
		
		v4l2_subdev
		v4l2_async_notifier
	*/
	ret = v4l2_async_subdev_notifier_register(sd, notifier);
	if (ret < 0)
		goto out_cleanup;

	//将当前subdev挂载到 全局链表subdev_list上
	ret = v4l2_async_register_subdev(sd);
	if (ret < 0)
		goto out_unregister;

	
	/* subdev和notifier你中有我,我中有你 */
	sd->subdev_notifier = notifier;

	return 0;

out_unregister:
	v4l2_async_notifier_unregister(notifier);

out_cleanup:
	v4l2_async_notifier_cleanup(notifier);
	kfree(notifier);

	return ret;
}

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

static LIST_HEAD(notifier_list); //异步通知链表
static LIST_HEAD(subdev_list);//v4l2_subdev 链表


/*

		参数1 struct mipidphy_priv -> v4l2_subdev
		参数2 struct mipidphy_priv -> v4l2_async_notifier
*/
int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd,
					struct v4l2_async_notifier *notifier)
{
	int ret;

	if (WARN_ON(!sd || notifier->v4l2_dev))
		return -EINVAL;

	/*
         * 记录subdev
         */

	notifier->sd = sd;

	/*
	参数 struct mipidphy_priv -> v4l2_async_notifier
	
	异步通知注册 主要就是操作notifier 
	*/
	ret = __v4l2_async_notifier_register(notifier);
	if (ret)
		notifier->sd = NULL;

	return ret;
}


/*
参数 struct mipidphy_priv -> v4l2_async_notifier
*/
static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
{
	struct device *dev =
		notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
	struct v4l2_async_subdev *asd;
	int ret;
	int i;
	//不满足条件 跳出
	if (notifier->num_subdevs > V4L2_MAX_SUBDEVS)
		return -EINVAL;
		
	mutex_lock(&list_lock);
	//对于 sensor驱动 无,跳过
	for (i = 0; i < notifier->num_subdevs; i++) {
		...
	}
	/*
该函数只能从V4L2顶层设备:rkcif_mipi设备 开始执行。因为其他三个subdev设备自己刚开始是没有初始化 自己的 父通知器 以及 自己的通知器所管理的 v4l2_device设备的
所以这里 sensor 不执行
*/
	ret = v4l2_async_notifier_try_all_subdevs(notifier);

	 /*  	参数1  当前设备异步通知器				
     * 条件不满足,暂时不进入分析,不满足原因如下
     * 1. notifier->parent == NULL
     * 2. notifier->v4l2_dev == NULL
	 
	 所以其他三个subdev设备 独自初始化时 不满足该函数运行条件
	 只有 rkcif_mipi 能执行该函数
     */

	ret = v4l2_async_notifier_try_complete(notifier);

		  /*
     * 以上2个函数可以看出来,v4l2_dev为空时都不会执行
     * 将这个notifer挂载到链表notifier_list上
     */
	list_add(¬ifier->list, ¬ifier_list);
	
}


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驱动,链表,数据结构)