Linux学习——platform机制实现驱动层分离

本文深入探讨了Linux平台的Platform机制,详细分析了bus、device、driver三者之间的关系及其实现原理,并以GPIO驱动为例,展示了如何利用Platform机制进行驱动开发。

1.输入子系统涉及到的分层概念

如上图所示,分层就是将一个复杂的工作分成了4层, 分而做之,降低难度,每一层专注于自己的事情, 系统只将其中的核心层和事件处理层写好了,所以我们只需要来写驱动层即可,接下来我们来分析platform机制以及分离概念

2.分离概念

1.bus结构体:即platform总线

是个全局变量,为platform_bus_type,属于虚拟设备总线,通过这个总线将设备和驱动联系起来,属于Linux中bus的一种

总线里有一个match函数,用于判断driver能否支持device,支持的话就调用probe函数

platform_bus_type结构体如下:

struct bus_type platform_bus_type = {
	.name		= "platform",
	.dev_attrs	= platform_dev_attrs,
	.match		= platform_match,
	.uevent		= platform_uevent,
	.suspend	= platform_suspend,
	.suspend_late	= platform_suspend_late,
	.resume_early	= platform_resume_early,
	.resume		= platform_resume,
};

2.device结构体:存放硬件相关的代码

挂接在platform总线下的设备, platform_device结构体类型,使用device_add函数实现挂接

3.driver结构体:存放不会经常修改、较通用的代码

挂接在platform总线下,是个与某种设备相对应的驱动, platform_driver结构体类型

使用driver_register函数实现

小总结:bus_drv_dev模型

a.device_add( )函数

①把device放入bus的dev链表

②从bus的drv链表取出每一个drv,用bus的match函数判断该driver能否支持这个device,判断方法是drv的名字

③如果可以支持,调用probe函数

b.driver_register( )函数

①放入drv链表

②从dev链表取出每一个dev,调用match函数判断该dev能不能支持这个drv,判断方法是名字

③能支持,则调用probe函数

只要有一方注册,就会调用platform_bus_type的.match匹配函数,来找对方,成功就调用driver驱动结构体里的.probe函数来使总线将设备和驱动联系起来

这个只是一种机制,probe函数里面做什么由自己编写,可以放在任何地方,类似于输入子系统

4.示例:分析下GPIO驱动

我们以/drivers/input/keybard/gpio_keys.c内核自带的示例程序为例,

它的代码中只有driver驱动,因为是个示例程序,所以没有device硬件设备代码

(1)在gpio_keys.c中有1个全局变量driver驱动:

struct platform_driver gpio_keys_device_driver = {
	.probe		= gpio_keys_probe,
	.remove		= __devexit_p(gpio_keys_remove),
	.driver		= {
		.name	= "gpio-keys",
	}
};

(2)找找这个gpio_keys_device_driver被谁用到

在驱动层init入口函数中通过platform_driver_register()来注册diver驱动

在驱动层exit出口函数中通过platform_driver_unregister()函数来注销diver驱动

代码如下:

static int __init gpio_keys_init(void)    //init出口函数
{
   return platform_driver_register(&gpio_keys_device_driver);   //注册driver驱动
}
 
static void __exit gpio_keys_exit(void)   //exit出口函数
{
   platform_driver_unregister(&gpio_keys_device_driver);   //注销driver驱动
}

(3)platform_driver_register(),看它是如何注册diver的,注册到哪里?

int platform_driver_register(struct platform_driver *drv)
{
   drv->driver.bus = &platform_bus_type;                //(1)挂接到虚拟总线platform_bus_type上
   if (drv->probe)
         drv->driver.probe = platform_drv_probe;
   if (drv->remove)
        drv->driver.remove = platform_drv_remove;
   if (drv->shutdown)
        drv->driver.shutdown = platform_drv_shutdown;
   if (drv->suspend)
        drv->driver.suspend = platform_drv_suspend;
    if (drv->resume)
        drv->driver.resume = platform_drv_resume;
 
   return driver_register(&drv->driver);              //(2) 注册到driver目录下
}

(1) 挂接到虚拟总线platform_bus_type上,然后会调用platform_bus_type下的platform_match匹配函数,来匹配device和driver的名字,其中driver的名字如下所示:

.name    = "gpio-keys",

platform_match()匹配函数如下所示:

static int platform_match(struct device * dev, struct device_driver * drv)
{
/*找到所有的device设备*/
struct platform_device *pdev = container_of(dev, struct platform_device, dev);
 
return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0); //找BUS_ID_SIZE次
}

若名字匹配成功,则调用device的.probe成员函数

(2)然后放到/sys/bus/platform/driver目录下,其中driver_register()函数就是用来创建dirver目录的

5. 使用platform机制,编写LED驱动层

代码暂时未上传

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值