zoukankan      html  css  js  c++  java
  • platform驱动模型一

     
     

    重要的结构体

    <1>struct device     <linux/device.h>
    //用于描述设备相关的信息设备之间的层次关系,以及设备与总线、驱动的关系
    重要成员:
    void *platform_data; /* Platform specific data, device core doesn't touch it */
    struct device_driver *driver;
    //指向被分配到该设备的设备驱动
    //在really_probe(struct device *dev, struct device_driver *drv)函数中dev->driver = drv;将设备和驱动绑定
    char bus_id[BUS_ID_SIZE]; /* position on parent bus */
    struct bus_type *bus;
    //在platform_device_add()中pdev->dev.bus = &platform_bus_type;
    struct device *parent; //指向其父设备在platform_device_add中被赋值为&platform_bus;
    void (*release)(struct device * dev); //释放设备描述符的回调函数
      
     

    <2>struct resource                <linux/ioport.h>

    //这个结构表示设备所拥有的资源,即I/O端口、I/O映射内存、中断及DMA等。这里的地址指的是物理地址。

    成员:

    resource_size_t start;  //定义资源的起始地址
    resource_size_t end;  //定义资源的结束地址
    const char *name; //定义资源的名称
    unsigned long flags; //定义资源的类型,比如MEM,IO,IRQ,DMA类型
    struct resource *parent, *sibling, *child;

    <3>struct device_driver         <linux/device.h>

    const char              *name;
    struct bus_type         *bus;
    struct module           *owner;
    const char              *mod_name;      /* used for built-in modules */
    int (*probe) (struct device *dev);
    int (*remove) (struct device *dev);
    void (*shutdown) (struct device *dev);
    int (*suspend) (struct device *dev, pm_message_t state);
    int (*resume) (struct device *dev);
    struct attribute_group **groups;
    struct driver_private *p;

    device_driver提供了一些操作接口,但其并没有实现,相当于一些虚函数,由派生类platform_driver进行重载,无论何种类型的driver都是基于device_driver派生而来的,具体的各种操作都是基于统一的基类接口的,这样就实现了面向对象的设计。

    device_driver结构中name变量和platform_device中name变量一致。内核正是通过这个一致性来为驱动程序找到资源,即 platform_device中的resource。

    <4>struct platform_device          <linux/platform_device.h>
    成员:

    const char      * name; //定义平台设备的名称,此处设备的命名应和相应驱动程序命名一致

    int             id;
    struct device   dev;    //描述了设备的情况,platform_device由device派生而来,是一种特殊的device
    u32             num_resources;
    struct resource * resource;  //定义平台设备的资源

     
    <4>struct platform_driver           <linux/platform_device.h>
    //该结构中需要实现 shutdown,suspend,resume这三个函数,若不支持,将他们设为null。
    成员:
    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;
     
     
    重要函数
    <1>
    platform_device_register(srtuct platform_device *pdev)      //   drivers/base/platform.c
      //调用platform_device_add(pdev)注册到platform总线上
        //platform_device_add调用device_add()
    platform_device_unregister()
     
    device_register(struct device *dev)           //     linux/drivers/base/core.c
        //调用device_add(dev)
        //将该device对象dev插入设备模型中
    device_unregister()
     
    device_register()和 platform_device_register()都会首先初始化设备,区别在于第二步:其实platform_device_add()包括 device_add(),不过要先注册resources,然后将设备挂接到特定的platform总线。
     
    <2>
    platform_driver_register(struct platform_driver *drv)                  //    drivers/base/platform.c
        //调用driver_register(&drv->driver)
    platform_driver_unregister()
     
    platform_device_alloc()   //动态申请一个platform_device设备
    然后通过platform_device_add_resources及platform_device_add_data等添加相关资源和属性。
    //最终通过platform_device_add注册到platform总线上
     
    <3>platform_add_devices()
    系统中的设备资源可以通过指针数组列举在一起

    static struct platform_device *smdk6410_devices[] __initdata = {

    ......

     &s3c_device_usbgadget,
     &s3c_device_usb,  //jeff add.

    ......

    }

    然后在初始化函数中执行

    platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices));将所有的device添加进系统。platform_add_devices的好处在于它是一次性的执行多个platform_device_register。

     
     
    device和driver的绑定的实现
    <1>虚拟总线 "platform"的属性和操作的定义: //    drivers/base/platform.c
    struct bus_type platform_bus_type = {
        .name = "platform",
        .dev_attrs = platform_dev_attrs,
        .match = platform_match,
        .uevent = platform_uevent,
        .pm = &platform_dev_pm_ops,
    };
     
    //总线bus是联系driver和device的中间枢纽。Device通过所属的bus找到driver,由match操作方法进行匹配。
    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);
        ...
        return (strcmp(pdev->name, drv->name) == 0);
    }
     
    <2>设备注册platform_device_register()->platform_device_add()->(pdev->dev.bus = &platform_bus_type)把设备挂在虚拟的platform bus下;
     
    <3>驱动注册platform_driver_register(struct platform_driver *drv)
    ->driver_register(struct device_driver *drv)
    ->bus_add_driver(struct device_driver *drv)
    ->driver_attach(struct device_driver *drv) //return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
    ->bus_for_each_dev(),对每个挂在虚拟的platform bus的设备作__driver_attach(struct device *dev, void *data)
    ->driver_probe_device(struct device_driver *drv, struct device *dev),
    判断drv->bus->match()是否存在并且是否执行成功,此时通过指针执行platform_match,比较strncmp(pdev->name, drv->name, BUS_ID_SIZE),
    如果相符就调用really_probe(struct device *dev, struct device_driver *drv)//driver_sysfs_add()
    在该函数中有drv->probe(dev):调用device_driver的probe(dev),实际就是执行的相应设备的platform_driver->probe(platform_device)
     
    probe函数一般完成硬件设备使能,struct resource的获取以及虚拟地址的动态映射和具体类型设备的注册(因为平台设备只是一种虚拟的设备类型);remove函数完成硬件设备的关闭,struct resource以及虚拟地址的动态映射的释放和具体类型设备的注销
     
    注意:platform_drv_probe的_dev参数是由bus_for_each_dev的next_device获得)开始真正的探测加载,如果probe成功则绑定该设备到该驱动。
     
    int bus_for_each_dev(struct bus_type * bus,
                         struct device * start,
                         void * data,
                         int (*fn)(struct device *, void *))
    {
        struct klist_iter i;
        struct device * dev;
        int error = 0;
        if (!bus)
            return -EINVAL;
        klist_iter_init_node(&bus->klist_devices, &i,
                     (start ? &start->knode_bus : NULL));
        while ((dev = next_device(&i)) && !error)
            error = fn(dev, data);
        klist_iter_exit(&i);
        return error;
    }
     
    <4>init/main.c中:
    start_kernel 》 rest_init 》 kernel_init 》 do_basic_setup》driver_init 》platform_bus_init初始化platform_bus(虚拟总线);(先)
    start_kernel 》 rest_init 》 kernel_init 》 do_basic_setup》do_initcalls platform driver和platform device的初始化(后)
     
    创建了platform_bus设备,后续platform的设备都会以此为parent。在sysfs中表示为:所有platform类型的设备都会添加在 platform_bus所代表的目录下,即 /sys/devices/platform下面
  • 相关阅读:
    java_设计模式_观察者模式_Observer Pattern(2016-07-27)
    java_设计模式_策略模式_Strategy pattern(2016-07-15)
    一个简单的路由,用javascript实现
    sublime 编辑器配置和构建检查
    图文列表的图片居中
    不用css3的响应式img(按比例缩小图片)
    做前端的小笔记
    javascript创建跟随鼠标好玩的东西
    几十行代码就搞定俄罗斯方块
    来看看css3中的box-shadow
  • 原文地址:https://www.cnblogs.com/zhoutian220/p/3971327.html
Copyright © 2011-2022 走看看