• 上一节视频中,使用左右分离的思想,写出的程序很容易扩展;但是对于LED定义了一个led_resource,难道对于按键又要定义一个key_resource吗?Linux要支持很多很多的设备,对每种设备都定义一个结构体是不现实的
    • 把分离的概念再扩充一下,对于硬件资源使用platform_device表示,里面会定义使用哪个引脚、寄存器是多少;对于硬件的操作放在platform_driver结构体中,里面实现分配/设置/注册file_operations等操作
    • image.png
    • 引入 platform_device/platform_driver,将“资源”与“驱动”分离开来。
      • 对于每一个platform_device都有一个platform_driver与之对应;通过总线bus来管理platform_device和platform_driver,在bus左边有一系列的platform_device,右边有一系列的platform_driver
      • image.png
      • 更换引脚时,platform_driver基本不用改,但是需要修改 platform_device;针对不同的硬件需要提供不同的platform_device结构体,对于每一块单板、每一个引脚都要提供对应的platform_device
      • 冗余代码太多,修改引脚时设备端的代码需要重新编译(导致了Linux内核的代码非常庞大、臃肿)
    • 在内核之外,给每个单板都定义一个配置文件dts(设备树文件),在文件中会指定相关硬件资源
      • dts文件会编译成dtb文件传给内核,内核会解析dtb文件构造出一系列的platform_device
      • dts、dtb这些文件都是放在内核之外的,这就保持了Linux内核代码的简洁、优雅
      • 传统的bus设备驱动模型和使用设备树来构造platform_device是类似的,并不涉及驱动程序的核心
      • image.png
      • 通过配置文件──设备树来定义“资源”
      • 无冗余代码,修改引脚时只需要修改 dts 文件并编译得到 dtb 文件,把它传给内核。
      • 无需重新编译内核/驱动。
    • platform_device/platform_driver长什么样子呢?
      • image.png
      • platform_driver中有probe函数用来做驱动程序相关的事情
      • platform_device和platform_driver通过name来进行匹配建立联系
      • platform_device和platform_driver只不过是Linux内核中为了实现分离的设计思想而提出的概念,platform_device可以用来表示所有设备的资源,platform_driver可以在probe函数中做任何事情,并不局限于分配/设置/注册结构体这些事,可以做任何事情
    • 内核中怎么使用platform_device/platform_driver?
      • 内核中platform_device.h
      • image.png
      • platform_device/platform_driver两者都会注册到内核中,两者在内核中怎么建立联系呢?
      • image.png
      • 内核中有一个总线platform_bus_type,它是虚拟的总线,有两个链表:device链表、driver链表
      • 当注册一个platform_device时,platform_device就会放入device链表;platform_driver也一样
      • platform_device/platform_driver结构体放入链表后就会马上和对方的成员一一比较
      • image.png
      • 怎么直到是否匹配成功,通过platform_bus_type的match函数
      • image.png
      • 具体函数调用关系为: ```c platform_device_register platform_device_add device_add bus_add_device // 放入链表 bus_probe_device // probe 枚举设备,即找到匹配的(dev, drv)
        1. device_initial_probe
        2. __device_attach
        3. bus_for_each_drv(...,__device_attach_driver,...)
        4. __device_attach_driver
        5. driver_match_device(drv, dev) // 是否匹配
        6. driver_probe_device // 调用 drv 的 probe

    platform_driver_register platform_driver_register driver_register bus_add_driver // 放入链表 driver_attach(drv) bus_for_each_dev(drv->bus, NULL, drv, driver_attach); __driver_attach driver_match_device(drv, dev) // 是否匹配 driver_probe_device // 调用 drv 的 probe
    ```

    • 怎么将原来的程序改造成总线驱动模型?
      • 分配/设置/注册 platform_device 结构体
        • 在里面定义所用资源,指定设备名字。
      • 分配/设置/注册 platform_driver 结构体
        • 在其中的 probe 函数里,分配/设置/注册 file_operations 结构体,
        • 并从 platform_device 中确实所用硬件资源。
        • 指定 platform_driver 的名字。