platform平台总线驱动

我们知道linux内核中常见的的总线有I2C总线,PCI总线,串口总线,SPI总线,PCI总线,CAN总线,单总线等,所以有些设备和驱动就可以挂在这些总线上,然后通过总线上的match进行设备和驱动的匹配。但是有的设备并不属于这些常见总线,所以我们引入了一种虚拟总线,也就是platform总线的概念,对应的设备叫做platform设备,对应的驱动叫做platform驱动。当然引入platform的概念,可以做的与板子相关的代码和驱动的代码分离,使得驱动有更好的可扩展性和跨平台性。

从Linux2.6内核起,引入一套新的驱动管理和注册机制:platform_device 和 platform_driver 。Linux 中大部分的设备驱动,都可以使用这套机制,设备用 platform_device 表示;驱动用platform_driver 进行注册。

系统启动时自动在bus系统中注册platform,内核移植的人负责提供platform_device,写驱动的人负责提供platform_driver,platform的match函数发现driver和device匹配后(一般是通过名字进行匹配),调用driver的probe函数来完成驱动的初始化和安装,然后设备就工作起来了

1、相关的结构体

platform_driver结构:

struct platform_driver {
    int (*probe)(struct platform_device *);
    int (*remove)(struct platform_device *);
    void (*shutdown)(struct platform_device *);
    int (*suspend)(struct platform_device *, pm_message_t state);
    int (*resume)(struct platform_device *);
    struct device_driver driver;
    const struct platform_device_id *id_table;
};

platform_device结构(设备驱动):

struct platform_device {
       const char      * name;  //名
       int           id;  
       struct device   dev;      //内嵌设备,这个结构体中有一个platform_data的结构体,注意使用
       u32         num_resources;   //资源个数
       struct resource       * resource;   //资源结构体
       struct platform_device_id      *id_entry;
       struct pdev_archdata     archdata;
};
struct resource {
    resource_size_t start;  //起始地址
    resource_size_t end;  //结束地址
    const char *name;   //名
    unsigned long flags;  //标号
    struct resource *parent, *sibling, *child; 
};

2、相关注册函数

platform_driver_register向总线中注册driver,在model_init()中调用

int platform_driver_register(struct platform_driver *drv)
{
    drv->driver.bus = &platform_bus_type;
    if (drv->probe)
        drv->driver.probe = platform_drv_probe;
    if (drv->remove)
        drv->driver.remove = platform_drv_remove;
    if (drv->shutdown)
        drv->driver.shutdown = platform_drv_shutdown;

    return driver_register(&drv->driver);
}

platform_driver_unregister向总线中注销driver,在model_exit()中调用

void platform_driver_unregister(struct platform_driver *drv)
{
    driver_unregister(&drv->driver);
}

platform_device_register:向总线中注册device

/**
 * platform_device_register - add a platform-level device
 * @pdev: platform device we're adding
 */
int platform_device_register(struct platform_device *pdev)
{
    device_initialize(&pdev->dev);
    return platform_device_add(pdev);
}

platform_device_unregister:向总线中注销device

void platform_device_unregister(struct platform_device *pdev)
{
    platform_device_del(pdev);
    platform_device_put(pdev);
}

platdata怎么玩

platdata其实就是设备注册时提供的设备有关的一些数据(譬如设备对应的gpio、使用到的中断号、设备名称····)这些数据在设备和驱动match之后,会由设备方转给驱动方。驱动拿到这些数据后通过这些数据得知设备的具体信息,然后来操作设备。这样做的好处是:驱动源码中不携带数据,只负责算法(对硬件的操作方法)。现代驱动设计理念就是算法和数据分离,这样最大程度保持驱动的独立性和适应性。

3、注册驱动时要做的事

在我们编程的时候,只需要提供platform_device和platform_driver这两个结构体,然后再调用platform_driver_registerplatform_device_register这两个注册函数,当两个结构体中的name一样的时候,自动就会去执行probe函数。最后调用注销函数。

Last modification:November 18th, 2019 at 09:00 pm
如果觉得我的文章对你有用,请随意赞赏

Leave a Comment