platform的学习和使用

本文深入解析Linux平台框架的核心概念,包括platform_bus、device与driver之间的交互机制,以及它们的注册和匹配过程。通过实例展示了不同注册顺序的影响,并探讨了probe函数的作用及应用场景。

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

标签(空格分隔): linux子系统 platform平台框架


http://blog.youkuaiyun.com/ufo714/article/details/8595021
platform的灵魂是:device(设备)driver(驱动)platform_bus(platform总线),其特点是设备,驱动分层动态的管理和加载
其中platform_bus是一个虚拟的总线,当我们将设备和驱动注册到虚拟总线上(内核)时,如果该设备是该驱动的设备,该驱动是该设备的驱动,在他们注册时,会互相寻找
一次对方(只在注册的时候寻找一次,找完了就玩了)。这个找的过程是platform_bus来完成的,我们暂不管他如何让寻找。如果device和driver中的name这个字符串是想相同的话
platform_bus就会调用driver中的.probe函数.这个匹配到调用probe的过程是自动的,有总线自己完成。这个过程从注册开始,从probe结束
设备和驱动的关系是多对一的关系,即多个相同设备可使用一个driver,靠device(设备)中的id号来区别
platform的使用其实就四步:

1)初始化 resource 结构变量
2)初始化 platform_device 结构变量
3)向系统注册设备:platform_device_register。
4)想系统注册驱动:[platform_driver_register()]

drvier和device匹配的方法有3种:
* 当一个设备注册的时候,他会在总线上寻找匹配的driver,platform device一般在系统启动很早的时候就注册了
* 当一个驱动注册[platform_driver_register()]的时候,他会遍历所有总线上的设备来寻找匹配,在启动的过程驱动的注册一般比较晚,或者在模块载入的时候
* 当一个驱动注册[platform_driver_probe()]的时候, 功能上和使用platform_driver_register()是一样的,唯一的区别是它不能被以后其他的device probe了,也就是说这个driver只能和 一个device绑定
eg:定义一个driver

static struct platform_driver test_platform_driver = {
	.probe   = dev_test_probe, 
	.remove   = dev_test_remove,
	.suspend  = dev_test_suspend,
	.resume   = dev_test_resume,
	.driver  = {
			.owner  = THIS_MODULE,
			.name   = "cx2837_test",
			},
};

定义一个device (设备)

static struct platform_device dev_fb0 = {
	.name		  = "cx2837_test",
	.id		         = 1,
};

下面看上三种使用platform的模型
1.

static struct platform_driver test_platform_driver = {
	.probe   = dev_test_probe, 
	.remove   = dev_test_remove,
	.suspend  = dev_test_suspend,
	.resume   = dev_test_resume,
	.driver  = {
			.owner  = THIS_MODULE,
			.name   = "cx2837_test",
			},
};  //先在文件中定一个驱动结构体
__init()
{
	struct platform_device * test_platform_device;          //定一个device设备结构体
	for(i=0;i<MAX_TUNER_SUPPORT_NUM;i++)
	{
		suspend_output_string("Function device_alloc");
		test_platform_device = platform_device_alloc("cx2837_test",i);//初始化这个结构体,初始化形式多样,包括上面的直接初始化方式也可以,name要保持和driver中的name一致。
		if(tets_platform_device == NULL)
		{
			TEST_PRINTF("[%s]line=%d,fail to alloc device\n", __FUNCTION__, __LINE__);
			return ERR_NO_MEM;
		}
		test_platform_device->dev.platform_data = NULL;
		platform_device_add(test_platform_device);//将在这个设备注册到内核中,如果注册成功,则总线将按照你注册的名字去找相同名字的驱动(注意这里即我说的注册的时候即是寻找的时候),此时只找一次,找不到就找不到,此时总线中没有一个相同名字的驱动被注册,所以找不到,我们接着往下看;
	}
platform_driver_register(&test_platform_driver);//此时向内核注册驱动,如果注册成功,则总线将按照你注册的名字去找相同名字的设备,此时也是只找一次,但此时我们之前在总线中注册了一个相同name的device设备,所以找到了,匹配成功,调用driver中的probe函数做你想做的事情。
}
2.
static struct platform_driver test_platform_driver = {
	.probe   = dev_test_probe, 
	.remove   = dev_test_remove,
	.suspend  = dev_test_suspend,
	.resume   = dev_test_resume,
	.driver  = {
			.owner  = THIS_MODULE,
			.name   = "cx2837_test",
			},
};  //先在文件中定一个驱动结构体
__init()
{
//注意这次我们的顺序是反的
platform_driver_register(&test_platform_driver);//此时向内核注册驱动,如果注册成功,则总线将按照你注册的名字去找相同名字的设备,此时也是只找一次,此时只找一次,找不到就找不到,此时总线中没有一个相同名字的设备被注册,所以找不到,我们接着往下看;
	struct platform_device * test_platform_device;          //定一个device设备结构体
	for(i=0;i<MAX_TUNER_SUPPORT_NUM;i++)
	{
		suspend_output_string("Function device_alloc");
		test_platform_device = platform_device_alloc("cx2837_test",i);//初始化这个结构体,初始化形式多样,包括上面的直接初始化方式也可以,name要保持和driver中的name一致。
		if(test_platform_device == NULL)
		{
			TEST_PRINTF("[%s]line=%d,fail to alloc test device\n", __FUNCTION__, __LINE__);
			return ERR_NO_MEM;
		}
		test_platform_device->dev.platform_data = NULL;
		platform_device_add(test_platform_device);//将在这个设备注册到内核中,如果注册成功,则总线将按照你注册的名字去找相同名字的驱动(注意这里即我说的注册的时候即是寻找的时候),此时只找一次,找不到就找不到,但此时我们之前在总线中注册了一个相同name的driver驱动,所以找到了,匹配成功,调用driver中的probe函数做你想做的事情。
	}
	对于1,2的总结:这两种只是注册的顺序不一样而已,主要是为了说明设备和驱动的匹配条件,从上面可以看出,不管谁注册,只要注册就会去寻找一次,当两个都注册以后,匹配成功,就会调用
probe函数
3.static struct platform_device uart8250_device = {
	.name		= "se_uart",
	.id			= -1,
};

/* really no use !!*/
#if 0
static struct platform_device hcd_device = {
	.name		= "hcd",
	.id			= -2,
};
#endif

/* FB platformat device0 for the GMA1. 
support CLUT8, ARGB1555 and ARGB8888 */
static struct platform_device dev_fb0 = {
	.name		  = "dev_fb",
	.id		  = 1,
};//先在文件中把我们需要的所有设备提前在一个文件中初始化好。
static struct platform_device *nxm_platform_devices[] __initdata = {
	&uart8250_device,	
	&usb_gadget_device,
	&usb1_ohci_device,
	&usb1_ehci_device,
		.
		.
};//然后找一个数组把这些设备装起来
platform_add_devices(nxm_platform_devices, ARRAY_SIZE(nxm_platform_devices));//然后使用这个函数批量注册这些设备
对于驱动,后面我们用到什么驱动就注册哪个驱动,只要名字一样就可以了。
到这里,我们明白了设备和驱动的调用方式,那么问题来了,这个匹配成功后自动调用的probe函数是干什么用的 ?
probe(struct platform_device *)
1.
platform_device 中有个device结构体成员,这个结构体有一个platform_data这个空指针。
我们可以利用这个传进来的参数中的这个指针指向本地的数据结构,这样就可以把本地的数据和设备参数挂起来了。
2.
我们在probe中注册字符设备包括注册file_operation这个结=结构体,从而去提供read,ioct等些io接口

platform框架:
static struct platform_driver test_platform_driver = {
	.probe   = dev_test_probe, 
	.remove   = dev_test_remove,
	.suspend  = dev_test_suspend,
	.resume   = dev_test_resume,
	.driver  = {
			.owner  = THIS_MODULE,
			.name   = "cx2837_test",
			},
};
static int dev_test_probe(struct platform_device * pdev)
{在这个函数中我们实现字符设备的注册,提供哪些IOCTL接口
}
static int dev_test_remove(struct platform_device * pdev)
{在这个函数中我们注销在probe中申请的资源
}
module_platform_driver(test_platform_driver);//使用这个宏来注册driver结构体,这个宏不需要我们关心设备的注册和注销。即不需要
platform_driver_register(&test_platform_driver);和platform_driver_unregister(&test_platform_driver);这两个函数了。所以我们也就不需要使用
module_init(cxd2837_test_init);
module_exit(cxd2837_test_exit);这两个函数了,init的工作放在了probe中,exit的工作放在了remove中了
MODULE_AUTHOR("Leo");
MODULE_DESCRIPTION("SONY CXD2837 driver");
但是这样子我们注册了驱动,但设备在哪里注册呢,设备我们可以在其他早期加载的文件中使用上述3中描述的方法统一注册设备,其实最新的内核我们都是用
device tree的方式去注册设备了,就不用这种方式了

在使用中突然发现,我注册了三个同名(同name)设备,只是注册id不一样,但我的驱动只注册了一次同名driver,启动后发现probe被调用了3次。传入的id分别是
注册时的三个不同的id。这也恰好验证了多个device对应一个driver这种情况,platform bus是依据device和driver的name去匹配的,注册了几次,驱动就会被匹配几次。
驱动中去区别同名device时就是靠的传入的不同的device id
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值