虚拟平台总线:
虚拟平台总线(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)了;