TP学习笔记(七)——Linux驱动的platform机制

linux的bus、device、driver三个概念:
Bus:总线,除了i2c、spi、usb等总线之外,Linux中还有一个很重要的总线platform总线(虚拟)
device和driver都挂在总线上,也就是总线上会维护一个devices链表和一个drivers的链表

新添加一个device:  

        1. 将其加入所属bus的devices链表,
        2. 扫描此bus的drivers链表,调用对应match函数,
        3. 匹配->调用probe函数(初始化设备,注册设备访问接口等)


加载一个驱动:        

        1. 将其加入所属bus的drivers链表,
        2. 扫描此bus的devices链表,调用对应match函数,
        3. 匹配->调用probe函数


##总结:linux设备驱动有bus、device、driver三个重要的组成部分,先有bus,然后在bus上挂device和driver,有匹配的才调驱动的probe函数真正的初始化设备并注册API;

—————————————— 手动分割线 ——————————————————————

和传统的驱动一样,platform机制也分为三个步骤:

1、总线注册阶段:

内核启动初始化时的 main.c 文件中的 kernel_init()→do_basic_setup() →driver_init()→ platform_bus_init()→bus_register(&platform_bus_type) ,注册了一条 platform 总线(虚拟总线,platform_bus)。

2、添加设备阶段:

设备注册的时候 Platform_device_register()→platform_device_add()→ (pdev→dev.bus = &platform_bus_type)→device_add() ,就这样把设备给挂到虚拟的总线上。

3、驱动注册阶段:

Platform_driver_register()→driver_register()→bus_add_driver()→driver_attach()→bus_for_each_dev(), 对在每个挂在虚拟的platform bus的设备作 __driver_attach()→driver_probe_device(),判断 drv→bus→match() 是否执行成功,此时通过指针执行 platform_match→strncmp(pdev→name , drv→name , BUS_ID_SIZE ),如果相符就调用really_probe(实际就是执行相应设备的 platform_driver→probe(platform_device) 。)开始真正的探测,如果probe成功,则绑定设备到该驱动。

从上面可以看出,platform机制最后还是调用了bus_register() , device_add() , driver_register()这三个关键的函数。

下面看几个结构体:

 (/include/linux/Platform_device.h)

struct platform_device 
{ 
    const char * name; 
    int id; 
    struct device dev; 
    u32 num_resources; 
    struct resource * resource;
};

Platform_device结构体描述了一个platform结构的设备,在其中包含了一般设备的结构体 struct device dev; 设备的资源结构体 struct resource * resource; 还有设备的名字const char * name。(注意,这个名字一定要和后面platform_driver.driver àname相同,原因会在后面说明。)

该结构体中最重要的就是resource结构,这也是之所以引入platform机制的原因。

( /include/linux/ioport.h)

struct resource 
{ 
    resource_size_t start; 
    resource_size_t end; 
    const char *name; 
    unsigned long flags; 
    struct resource *parent, *sibling, *child;
};

其中 flags位表示该资源的类型,start和end分别表示该资源的起始地址和结束地址(/include/linux/Platform_device.h):

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 (*suspend_late)(struct platform_device *, pm_message_t state); 
    int (*resume_early)(struct platform_device *); 
    int (*resume)(struct platform_device *); 
    struct device_driver driver;
};

Platform_driver结构体描述了一个platform结构的驱动。其中除了一些函数指针外,还有一个一般驱动的device_driver结构。

名字要一致的原因:

上面说的驱动在注册的时候会调用函数bus_for_each_dev(), 对在每个挂在虚拟的platform bus的设备作__driver_attach()→driver_probe_device() ,在此函数中会对dev和drv做初步的匹配,调用的是 drv->bus->match 所指向的函数。 platform_driver_register 函数中 drv-> driver.bus = &platform_bus_type ,所以 drv->bus->matc 就为platform_bus_type→match, 为platform_match 函数,该函数如下:

static int platform_match(struct device * dev, struct device_driver * drv) 
{ 
    struct platform_device *pdev = container_of(dev, struct platform_device, dev);
    return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);
}

是比较dev和drv的name,相同则会进入really_probe()函数,从而进入自己写的probe函数做进一步的匹配。所以dev→name和driver→drv→name在初始化时一定要填一样的。

不同类型的驱动,其match函数是不一样的,这个platform的驱动,比较的是dev和drv的名字。

  • 13
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值