linux驱动开发:总线,设备,驱动三要素

平台总线和IIC,SPI,IIS都是总线类型,一般的,总线下,挂载对应的设备。但实际上,设备要正常运转,是需要驱动程序来未知提供驱动的。所以linux内核也把驱动挂载在对应的总线下。总线,驱动,设备三者缺一不可.
相应的,内核衍生出来的平台总线,那么便衍生出来了平台设备和凭条驱动。他们均有自己的专属函数来注册,注销。这个是成一套体系结构的.在以后的驱动开发中,很是常见与重要.

一)内核中的总线,设备,驱动
1)总线

struct bus_type {
    const char      *name;
    const char      *dev_name;
    struct device       *dev_root;
    struct bus_attribute    *bus_attrs;//总线属性
    struct device_attribute *dev_attrs;//设备属性
    struct driver_attribute *drv_attrs;//驱动属性

    int (*match)(struct device *dev, struct device_driver *drv);//匹配总线下的设备和驱动
    int (*uevent)(struct device *dev, struct kobj_uevent_env *env);//用于总线环境变量的添加
    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);

    const struct dev_pm_ops *pm;//电源管理

    struct iommu_ops *iommu_ops;

    struct subsys_private *p;//将bus device sysfs联系起来
    struct lock_class_key lock_key;
};

注册:bus_register(struct bus_type *bus);
注销:bus_unregister(struct bus_type *bus);

2)设备

struct device {
    struct device       *parent;

    struct device_private   *p;

    struct kobject kobj;
    const char      *init_name; /* initial name of the device */
    const struct device_type *type;

    struct mutex        mutex;  /* mutex to synchronize calls to
                     * its driver.
                     */

    struct bus_type *bus;       /* type of bus device is on  设备所属的总线*/
    struct device_driver *driver;   /* which driver has allocated this
                       device */
    void        *platform_data; /* Platform specific data, device
                       core doesn't touch it */
    struct dev_pm_info  power;
    struct dev_pm_domain    *pm_domain;

#ifdef CONFIG_PINCTRL
    struct dev_pin_info *pins;
#endif

#ifdef CONFIG_NUMA
    int     numa_node;  /* NUMA node this device is close to */
#endif
    u64     *dma_mask;  /* dma mask (if dma'able device) */
    u64     coherent_dma_mask;/* Like dma_mask, but for
                         alloc_coherent mappings as
                         not all hardware supports
                         64 bit addresses for consistent
                         allocations such descriptors. */

    struct device_dma_parameters *dma_parms;

    struct list_head    dma_pools;  /* dma pools (if dma'ble) */

    struct dma_coherent_mem *dma_mem; /* internal for coherent mem
                         override */
#ifdef CONFIG_CMA
    struct cma *cma_area;       /* contiguous memory area for dma
                       allocations */
#endif
    /* arch specific additions */
    struct dev_archdata archdata;

    struct device_node  *of_node; /* associated device tree node */
    struct acpi_dev_node    acpi_node; /* associated ACPI device node */

    dev_t           devt;   /* dev_t, creates the sysfs "dev" */
    u32         id; /* device instance */

    spinlock_t      devres_lock;
    struct list_head    devres_head;

    struct klist_node   knode_class;
    struct class        *class;
    const struct attribute_group **groups;  /* optional groups */

    void    (*release)(struct device *dev);
    struct iommu_group  *iommu_group;
};

设备注册:int device_register(struct device *dev)
设备注销:void device_unregister(struct device *dev)

3)设备驱动

struct device_driver {
    const char      *name;
    struct bus_type     *bus;//挂载的总线,所属的总线

    struct module       *owner;
    const char      *mod_name;  /* used for built-in modules */

    bool suppress_bind_attrs;   /* disables bind/unbind via sysfs */

    const struct of_device_id   *of_match_table;
    const struct acpi_device_id *acpi_match_table;

    int (*probe) (struct device *dev);// 设备match到驱动,则调用对应驱动的probe函数,驱动设备
    int (*remove) (struct device *dev);//当驱动或者设备被卸载,则调用对应驱动的remove函数
    void (*shutdown) (struct device *dev);
    int (*suspend) (struct device *dev, pm_message_t state);
    int (*resume) (struct device *dev);
    const struct attribute_group **groups;

    const struct dev_pm_ops *pm;

    struct driver_private *p;
};

驱动注册:int driver_register(struct device_driver *drv)
驱动注销:void driver_unregister(struct device_driver *drv)

二)平台设备总线
总线:

struct bus_type platform_bus_type = {
    .name       = "platform",
    .dev_attrs  = platform_dev_attrs,
    .match      = platform_match,
    .uevent     = platform_uevent,
    .pm     = &platform_dev_pm_ops,
};

设备:

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

    const struct platform_device_id *id_entry;

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

    /* arch specific additions */
    struct pdev_archdata    archdata;
};
平台设备的注册:platform_device_register(struct platform_device * pdev)
平台设备的注销:platform_device_unregister(struct platform_device * pdev)

驱动:

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;
};
平台驱动的注册:int platform_driver_register(struct platform_driver *drv)
平台驱动的注销:void platform_driver_unregister(struct platform_driver *drv)

平台设备匹配的流程:

先插入一个函数,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);

    /* Attempt an OF style match first */
    if (of_driver_match_device(dev, drv))
        return 1;

    /* Then try ACPI style match */
    if (acpi_driver_match_device(dev, drv))
        return 1;

    /* Then try to match against the id table */
    if (pdrv->id_table)
        return platform_match_id(pdrv->id_table, pdev) != NULL;

    /* fall-back to driver name match */
    return (strcmp(pdev->name, drv->name) == 0);
}
//match 的方式:不同的内核,可能有所不同:我的内核版本:3.10.46

1.OF style match first
2.ACPI style match
3.match against the id table
4.driver name match

大概的匹配流程:
1)平台设备注册流程:

platform_device_register()
{
--->platform_device_add()
    {
        --->device_add()
        {
            --->device_add()
            {
                --->bus_probe_device()
                {

                    --->device_attach()
                    {
                        --->bus_for_each_drv(dev->bus, NULL, dev, __device_attach)
                        {
                            --->__device_attach()
                            {
                                --->driver_match_device()//platform_match()
                                //当match到驱动后,继续下面步骤:
                                --->driver_probe_device()
                                {
                                    --->really_probe()
                                    {
                                        --->drv->probe()//调用对应驱动的probe函数
                                    }

                                }

                            }
                        }
                    }


                }
            }
        }
    }

}

2)平台驱动注册流程:

platform_driver_register()
{
    --->driver_register()
    {
        --->bus_add_driver()
        {
            --->driver_attach()
            {
                --->bus_for_each_dev(drv->bus, NULL, drv, __driver_attach)
                {
                    --->__driver_attach()
                    {
                        --->driver_match_device()//platform_match()
                        //当match到对应的设备后,继续
                        --->driver_probe_device()
                        {
                            --->really_probe()
                            {
                                --->drv->probe()//调用当前注册驱动的probe函数
                            }
                        }
                    }
                }
            }
        }
    }
}

这里写图片描述

1.设备向对应平台bus注册设备,设备挂载到平台bus下面的dev list链表中.
2.驱动向对应平台bus注册驱动,驱动挂载到平台bus下面的driver list链表中.
3.设备和对应总线下的driver list链表中每个driver进行匹配(match).匹配成功则调用对应driver的probe函数,否则匹配失败,则设备无法被驱动,设备无法工作.

match函数已经在上面列出。它有自己的匹配规则,上一篇的实例是按照match name来进行匹配的.
当设备或者驱动被卸载时,驱动的remove函数都会被调用.

平台设备总线的意义:移植性强。通过我们是不需要写平台设备文件的,只需要写对应的驱动文件。而驱动文件一般移植时并不需要修改。只需要修改对应的platform_data 平台数据和resource 平台资源列表便可.
这样修改一个驱动或者移植一个驱动到另一个内核便变得很简单。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值