20200409-01 Linux 三言两句努力说清 platform 架构

platform 驱动

这是 linux 设备驱动分离与分层思想的一种架构产物,由总线(bus)、驱动(driver)、设备(device),这样我们只需要根据不同驱动和设备,采用统一的 API 来提高程序的重用率

platform 总线

需要使用 bus_type 结构体 include/linux/device.h

//实例: driver/base/platform.c 定义实例
struct bus_type {
......
    int (*match)(struct device *dev, struct device_driver *drv); //用于匹配驱动和设备
......

};
驱动与设备的匹配方式

驱动与设备有 4 种方式来进行,驱动和设备的匹配

//实例:drivers/base/platform.c
static int platform_match(struct device *dev, struct device_driver *drv)
{
    struct platform_device *pdev = to_platform_device(dev);
    struct platform_driver *pdrv = to_platform_driver(drv);

    //when driver_override is set, only bind to the matching driver
    //比较一下两者是否相同,如果相同 strcmp 返回的是 0,有所差别返回的就是非0 A<B => <0, A>B => >0, A=B => =0
    if (pdev->driver_override)
        return !strcmp(pdev->driver_override, dev->name);

    //方式1: 采用 of 匹配(设备树)
    if (of_driver_match_device(dev, drv))
        return 1;
    //方式2: 采用 acpi 方式匹配
    if (acpi_driver_match_device(dev, drv))
        return 1;
    //方式3: 采用 id 表
    if (pdrv->id_table)
        return platform_match_id(pdrv->id_table, pdev) != NULL;
    //方式4: 直接比较驱动和设备的 name 字段看看是否匹配
    return (strcmp(pdev->name, drv->name) == 0);
}

ACPI:由国外开发的电源管理标准,主要用于控制电脑开、关、低功耗等状态,以及对于即插即用设备控制并为其供电

ID table: 在 linux 存在很长时间,基于 struct device_id(include/linux/mod_devicetable.h)

方式3与方式4都属于适配无设备树情况下的驱动设备驱动设备匹配方式,一般使用方式4多一点,比较简单


platform 驱动

基于 platform_driver 结构体(include/linux/platform_device.h)

struct platform_driver {
......

    int (*probe)(struct platform_device *);//设备匹配成功之后,会执行该函数
    struct device_driver driver; //基础驱动框架
    const struct platfrom_device_id *id_table;
......
};
struct platform_device_id {
    char name[PLATFORM_NAME_SIZE];
    kernel_ulong_t driver_data;
}
//include/linux/device.h
struct device_driver {
......
const struct of_device_id *of_match_table;
const struct acpi_device_id *acpi_match_table;
......
};

//include/linux/mod_devicetable.h
struct of_device_id {
    char name[32];
    char type[32];
    char compatible[128];
    const void *data;
};
函数描述
int platform_driver_register(struct platform_driver *driver)向内核注册驱动,0成功;<0 失败
void platform_driver_unregister(struct platform_driver *drv)卸载驱动
//platform 驱动框架

//设备结构体
struct xxx_dev {
    struct cdev cdev;
    ......
};
struct xxx_dev xxxdev; //定义设备结构体变量

static int xxx_open(struct inode *inode, struct file *filp)
{
    //具体内容
    return 0;
}

static ssize_t xxx_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
    //具体内容
    return 0;
}

//字符设备驱动操作
static struct file_operations xxx_fops = {
    .owner = THIS_MODULE,
    .open = xxx_open,
    .write = xxx_write,
};

//platform 驱动的 probe 函数,由驱动与设备匹配函数执行
static int xxx_probe(struct platform_device *dev)
{
    ......
    cdev_init(&xxxdev.cdev, &xxx_fops); //注册字符设备驱动
    //具体内容
    return 0;
}

static int xxx_remove(struct platform_device *dev)
{
    ......
    cdev_dev(&xxxdev.cdev); //删除 dev
    //具体内容
    return 0;
}

//platform 匹配列表,必须最后留空
static const struct of_device_id xxx_of_match[] = {
    { .compatible = "xxx-gpio" },
    { }
};

//platform 平台驱动结构体
static struct platform_driver xxx_driver = {
    .driver = {
        .name = "xxx",
        .of_match_table = xxx_of_match,
    },
    .probe = xxx_probe,
    .remove = xxx_remove
};

//加载
static int __init xxxdriver_init(void)
{
    return platform_driver_register(&xxx_driver);
}
//卸载
static void __exit xxxdriver_exit(void)
{
    platform_driver_unregister(&xxx_driver);
}

module_init(xxxdriver_init);
module_exit(xxxdriver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("xxx");


platform 设备

若使用设备树,直接在设备树中定义即可

以下内容属于非设备树使用

//include/linux/platform_device.h
struct platform_device {
    const char *name;
    struct resource *resource;
    ......
};
//设备信息
struct resource {
    ......
    resource_size_t start;//对于内存类资源
    resource_size_t end;
    const char *name;
    unsigned long flags; //资源类型 
    struct resource *parent, *sibling, *child;
};
//资源类型 include/linux/ioport.h
#define IORESOURCE_BITS    0xff
#define IORESOURCE_TYPE_BITS    0x1f00
.......
函数描述
int platform_device_register(struct platform_device *pdev)注册设备信息向内核
void platform_device_unregister(struct platform_device *pdev)卸载设备
//platform 设备写程序框架

//寄存器地址
#define PERIPH1_REGISTER_BASE   (0x20000000)    //外设 1 寄存器首地址
#define PERIPH2_REGISTER_BASE   (0x020E0068)    //外设 2 寄存器首地址
#define REGISTER_LENGTH         4
//资源
static struct resource xxx_resources[] = {
    [0] = {
        .start = PERIPH1_REGISTER_BASE,
        .end = (PERIPH1_REGISTER_BASE + REGISTER_LENGTH - 1);
        .flags = IORESOURCE_MEN,
    },
    [1] = {
        .start = PERIPH2_REGISTER_BASE,
        .end = (PERIPH2_REGISTER_BASE + REGISTER_LENGTH - 1),
        .flags = IORESOURCE_MEN,
    },
};
//设备结构体
static struct platform_device xxxdevice = {
    .name = "xxx-gpio",
    .id = -1,
    .num_resources = ARRAY_SIZE(xxx_resources),
    .resource = xxx_resources,
};
//加载设备
static int __init xxxdevice_init(void)
{
    return platform_device_register(&xxxdevice);
}
//卸载设备
static void __exit xxxdevice_exit(void)
{
    platform_device_unregister(&xxxdevice);
}

module_init(xxxdevice_init);
moduel_exit(xxxdevice_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("xxx");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值