Yuhang Zheng

第十三节、平台总线模型——注册platform设备

N 人看过

本节用于介绍平台总线模型——注册platform设备

1、什么是平台总线模型?

平台总线模型也叫platform总线模型。是Linux内核虚拟出来的一条总线,不是真实的导线。

平台总线模型就是把原来的驱动C文件给分成了俩个C文件,一个是device.c,一个是driver.c

把稳定不变的放在driver.c里面,需要变得就放在了device.c里面。

2、为什么会有平台总线模型?

  1. 可以提高代码的重用性
  2. 减少重复性代码。
设备 总线 驱动
device.c driver.c

3、平台总线模型的优点。

4、怎么编写以平台总线模型设计的驱动?

一个是device.c,一个是driver.c,然后分别注册 device.c和 driver.c

平台总线是以名字来匹配的,实际上就是字符串比较。


1、平台总线注册一个platform_device

设备文件device.c里面写的是硬件资源,这里的硬件资源是指寄存器的地址,中断号,时钟等硬件资源。

在Linux内核里面,我们是用一个结构体来描述硬件资源的。

文件位置路径:include/linux/platform_device.h

struct platform_device {
        const char      *name;            //常用,用于平台设备与平台驱动的匹配,会在/sys/bus/platform/devices/下生成name的节点
        int             id;                //常用,设备id,一般为-1,为相同name的设备进行编号的
        bool            id_auto;
        struct device   dev;            //常用,内嵌的device结构体,
        u32             num_resources;    //常用,资源的个数
        struct resource *resource;        //常用,device里面的硬件资源,可以看到这是一个指针,指向的是resource结构体数组

        const struct platform_device_id *id_entry;
        char *driver_override; /* Driver name to force a match */

        /* MFD cell pointer */
        struct mfd_cell *mfd_cell;

        /* arch specific additions */
        struct pdev_archdata    archdata;
};

2、填写platform_device里面的resource硬件资源结构体数组

文件位置路径:include/linux/ioport.h

struct resource {
        resource_size_t start;        //资源的起始地址
        resource_size_t end;        //资源的结束地址
        const char *name;            //资源的名字
        unsigned long flags;        //资源的类型
        unsigned long desc;
        struct resource *parent, *sibling, *child;
};

这里面的资源的类型有哪些呢?下面是几个常用的类型

#define IORESOURCE_IO           //IO的内存
#define IORESOURCE_MEM          //最常用,表示一段地址
#define IORESOURCE_IRQ          //最常用,表示中断号
#define IORESOURCE_DMA          //表示DMA的地址
#define IORESOURCE_BUS          //表示总线号

注意:platform_device结构体内的内嵌的device结构体中如果void (*release)(struct device *dev);函数没有实现的话,可能会有内核报警。

[ 2901.445771] Device 'beep_test' does not have a release() function, it is broken and must be fixed.

3、填写platform_device里面的device结构体

文件位置路径:include/linux/device.h

struct device {
    ...
    void    (*release)(struct device *dev);
    ...
}

示例:

void beep_release(struct device *dev)
{
        printk("beep_release\n");
}

struct resource beep_res[] = {                    //resource是一个结构体数组。这个是结构体数组赋值的方式
        [0] = {
                .start = 0x02310008,
                .end   = 0x0231000b,
                .name  = "GPDAT_1",
                .flags = IORESOURCE_MEM
        }
};

struct platform_device beep_device = {
        .name = "beep_test",
        .id = -1,
        .dev = {
                .release = beep_release            //函数没有实现的话,可能会有内核报警。这个是结构体内结构体赋值的方式
        },
        .num_resources = ARRAY_SIZE(beep_res),    //资源的个数可以通过ARRAY_SIZE函数来计算长度
        .resource = beep_res
};

4、注册和注销平台设备函数

当使用上节的函数创建完成一个platform_device后,使用platform_device_register函数进行平台设备的注册

文件位置路径:include/linux/platform_device.h

实际函数位置路径:drivers/base/platform.c

extern int platform_device_register(struct platform_device *);
int platform_device_register(struct platform_device *pdev)
{
        device_initialize(&pdev->dev);
        arch_setup_pdev_archdata(pdev);
        return platform_device_add(pdev);
}
EXPORT_SYMBOL_GPL(platform_device_register);
//参数
//pdev:要注册的平台设备
extern void platform_device_unregister(struct platform_device *);
void platform_device_unregister(struct platform_device *pdev)
{
        platform_device_del(pdev);
        platform_device_put(pdev);
}
EXPORT_SYMBOL_GPL(platform_device_unregister);
//参数
//pdev:要注销的平台设备