驱动开发4——平台设备驱动

一 平台总线
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");

你可能感兴趣的:(linux驱动)