一 平台总线
1 真实的计算机系统中,通常各种常见总线的代码都编写好,一般不需要我们去创建,比如i2c,pci,usb这些总线
2 PC中,多数外设都没有直接连到CPU的前端总线上
但是在嵌入式领域,有很多简单的外设是直接连到CPU的(前端)总线上的
3 为了表示这种和CPU直接相连的前端总线,Linux内核中发明了一种虚拟总线,称为平台总线
4 所以在嵌入式领域,很多的外设都是连接到平台总线上的,所以经常要编写的简单外设的驱动,都是平台驱动.
二 如何编写平台设备和平台驱动
内核用struct platform_device来表示平台设备,它是从struct device继承来的
所以当我们添加注册了平台设备后,在/sys下是能看到对应的目录
内核用struct platform_driver来表示平台驱动,它是从struct device_driver继承来的
所以当我们添加注册了平台驱动后,在/sys下是能看到对应的目录
平台总是已经编写好的,它要负责平台设备和平台驱动的匹配工作
以前的原始驱动是将设备的硬件信息编码到了驱动中,这样一旦硬件信息有变,就必须修改驱动
成熟优雅的方案要把变与不变分离开来,所以我们要实现设备(硬件信息)与驱动的分离
在设备存储硬件信息,而让驱动从设备获取硬件信息,硬件变化,只需要修改设备,驱动可以保持不变
设备中的资源就是指设备的硬件信息
三 主要函数
1
platform_add_devices用于一次注册多个平台设备
platform_device_register一次只注册一个平台设备,其实platform_add_devices是通过多次调用platform_device_register来实现的
platform_device_unregister用于注销平台设备
2 向平台总线注册和注销平台驱动的函数为
platform_driver_register
platform_driver_unregister
3
由于加载函数,卸载函数基本上做固定的事情,写起来麻烦,我们可以用module_platform_driver(pdrv);这句会自动扩展为加载和卸载函数,加载函数完成pdrv的注册,卸函数进行注销
平台驱动,主要工作会放在probe和remove函数中,当驱动和设备匹配成功后,会自动调用probe函数,当设备移除或驱动卸载时,会自动调用remove函数
四 程序框架代码
平台设备出现的目的是为了实现驱动设备分离
代码分两块:设备部分和驱动部分
1 设备部分 dev.c
#include
#include
#include
#include
//平台设备注销所用函数
static void pdev_release(struct device *dev)
{
}
//用一个结构体表示硬件设备
struct platform_device pdev0 = {
.name="pdev",
.id=0,
.num_resources=0,
.resource=NULL,
.dev={
.release=pdev_release,
},
};
struct platform_device pdev1 = {
.name="pdev",
.id=1,
.num_resources=0,
.resource=NULL,
.dev={
.release=pdev_release,
},
};
//加载函数
static int __init pltdev_init(void)
{
platform_device_register(&pdev0);
platform_device_register(&pdev1);
return 0;
}
//卸载函数
static void __exit pltdev_exit(void)
{
platform_device_unregister(&pdev1);
platform_device_unregister(&pdev0);
}
module_init(pltdev_init);//指定加载函数
module_exit(pltdev_exit);//指定卸载函数
MODULE_LICENSE("GPL");//指定许可
2 驱动部分 drv.c
#include
#include
#include
#include
//停止中断函数
static int pdrv_suspend(struct device *dev)
{
printk("pdev: suspend\n");
return 0;
}
//重新开始函数
static int pdrv_resume(struct device *dev)
{
printk("pdev: resume\n");
return 0;
}
//封装电源管理的结构体 作者君用这个主要是为了实现去抖
static const struct dev_pm_ops pdrv_pm_ops = {
.suspend = pdrv_suspend,
.resume = pdrv_resume,
};
//当设备和驱动匹配成功后,会自动调用本函数,传进来的参数是匹配成功的设备
static int pdrv_probe(struct platform_device *pdev)
{
return 0;
}
//当设备被移除,或驱动被卸时,会自动调用本函数
static int pdrv_remove(struct platform_device *pdev)
{
return 0;
}
struct platform_driver pdrv = {
.driver = {
.name="pdev",
.owner=THIS_MODULE,
.pm=&pdrv_pm_ops,
},
.probe=pdrv_probe,
.remove=pdrv_remove,
};
module_platform_driver(pdrv);
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:pdev");