Linux驱动程序--虚拟平台总线
虚拟平台总线:
虚拟平台总线(platform bus)是总线模型的一种,由系统定义了总线类型platform_bus_type,并对驱动和设备进行了封装;
相关头文件:
#include <linux/platform_device.h>
设备资源: plat_device.c
1.定义用到的资源
/*************** 以下是平台设备(资源) ***************/
static struct resource device_resource[] = {
[0]={
.start = S3C24XX_PA_GPIO, //MEM类表示的是起始物理地址
.end = S3C24XX_PA_GPIO + S3C24XX_SZ_GPIO - 1,
.flags = IORESOURCE_MEM, // 存储器(寄存器)资源
},
[1]={
.start = IRQ_EINT8,
.end = IRQ_EINT8,
.flags = IORESOURCE_IRQ, // 中断资源
},
[2]={
.start = 164, // GPIO(164)~GPIO(167)
.end = 167,
.flags = IORESOURCE_IO, // IO资源
},
};
2.注册虚拟平台设备
static struct platform_device *plat_device;
plat_device = platform_device_alloc("buttons",-1);
platform_device_add_resources(plat_device ,&device_resource ,2);
platform_device_register(plat_device);
3.删除虚拟平台设备:
platform_device_unregister(plat_device);
注意事项:
1.platform_device_alloc动态分配的资源,删除时要释放(platform_device_unregister函数已做处理),也可以采用静态指定的方法实现;
2.platform_device_register/platform_device_add函数,
platform_device_register注册设备时,在函数的最后调用了platform_device_add;
驱动程序:plat_driver.c
/****************** 以下是平台驱动 ******************/
/*平台驱动定义*/
static struct platform_driver plat_driver = {
.probe = plat_probe, //加载驱动时要执行的程序
.remove = plat_remove, //删除驱动时要执行的程序
.driver = { //struct device_driver
.owner = THIS_MODULE,
.name = "buttons", //这里的名子要和平台的device的名子匹配
},
};
注册驱动:
platform_driver_register(&plat_driver);
卸载驱动
platform_driver_unregister(&plat_driver);
实现probe函数:
static int plat_probe(struct platform_device *pdev)
{
}
实现remove函数:
static int plat_remove(struct platform_device *pdev)
{
}
获取资源(在probe函数中调用):
struct resource *res_irq;
res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res_irq) {
printk("platform_get_resource fail\n");
return -1;
}
struct resource *res_mem;
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res_mem) {
printk("platform_get_resource fail\n");
return -1;
}
参数1: 匹配设备,由probe参数中传入;
参数2:设备类型,在device的资源flag中定义;
参数3:资源序号,用于区分多个类型相同的资源,下标从0开始;不同资源序号无关联,本例中IORESOURCE_IRQ只有一个,所以序号为0(多个连续的资源在一个结构中算1个资源);
返回值: 如果获取成功,则返回相关结构体,获取失败返回空指针;
工作机理:
当加载设备(驱动)时,内核自动遍历一遍该该总线驱动(设备);
如果匹配成功,内核就会调用driver中的probe函数;
设备和驱动的加载先后顺序无关;
当加载设备(驱动)时,内核就会调用driver中定义的remove函数;
注意事项:
1.模块必须声明为GPL,否则模块加载时内核会报怨找不到符号;
2.platform平台驱动本身不会产生设备文件,需要在probe函数中自行实现;
3.通过/sys/bus/platform/device中查看平台设备,名子与.name定义相同
4.通过/sys/bus/platform/driver中查看驱动程序,名子与.name定义相同
5.在3.0(或者更前一些,无须考证了)以后的版本中platform_device.h添加了宏定义module_platform_driver用于自动添加平台总线模块,以省去module_init/module_exit等繁杂操作;
module_platform_driver(&plat_driver);
在后续的内核版本中,platform总线已经用的淋(xiang)漓(dang)尽(fan)致(lan)了;