总线设备驱动模型

一、总线模型(转自国嵌论坛)
  1.随着技术的进步,对热插拔的要求以及可移植性的要求越来越高,从Linux2.4开始虽然有了模型但是正式提出是在Linux2.6。
  2.关键词是总线,驱动,设备
  3.总线能够感知设备的插拔:
    (1)插入新设备的时候知道有设备插入,那么就去总线上已有的驱动里面查找能够处理该新设备的驱动,一旦匹配,该驱动就有了该设备的控制权
    (2)拔出的时候,总线也能感知,并且告诉相应的驱动从而使得驱动能够处理拔出事件
二、总线
  1、描述结构
    linux内核中总线由bus_type结构描述

struct bus_type {
    const char        *name;
    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 subsys_private *p;
};

  2、重要成员
    a、 const char        *name;        总线名称
    b、 int (*match)(struct device *dev, struct device_driver *drv);    match函数,用来匹配挂载在总线上的设备与驱动
  3、注册总线
    函数:bus_register    (struct    bus_type*)
    若成功,新总线被添加进系统,可在/sys/bus目录下查看到相应目录
  4、注销总线
    函数:bus_unregister    (struct    bus_type*)

三、驱动
  1、描述结构
    device_driver

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;

    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 attribute_group **groups;

    const struct dev_pm_ops *pm;

    struct driver_private *p;
};

  2、重要成员
    a、const char        *name;                    驱动名称
    b、struct bus_type        *bus;                要挂载到的总线名称
    c、 int (*probe) (struct device *dev);     当驱动和设备匹配成功时调用这个函数
  3、注册
    函数:driver_register    (struct    bus_type*)
    若成功,新驱动被添加进系统,可在对应总线目录下的drivers查看到相应目录
  4、注销
    函数:driver_unregister    (struct    bus_type*)
四、设备
    1、描述结构device

struct device {
    struct device        *parent;

    struct device_private    *p;

    struct kobject kobj;
    const char        *init_name; /* initial name of the device */
    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_power_domain    *pwr_domain;

#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 */
    /* arch specific additions */
    struct dev_archdata    archdata;

    struct device_node    *of_node; /* associated device tree node */

    dev_t            devt;    /* dev_t, creates the sysfs "dev" */

    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);
};

  2、重要成员
    a、const char        *init_name;                    设备名称
    b、struct bus_type        *bus;                要挂载到的总线名称
  3、注册
    函数:device_register    (struct    bus_type*)
    若成功,新驱动被添加进系统,可在对应总线目录下的drivers查看到相应目录
  4、注销
    函数:device_unregister    (struct    bus_type*)

五、实例验证将驱动和设备挂在到总线中并进行匹配
  1、当实际硬件设备和驱动程序进行匹配时会通过设备ID等来完成,我们此处所使用的是一个模拟的硬件,没有设备ID,所以用设备名称和驱动名称来匹配,这就要求我们在初始化device_driver和device时两者名字要一致。

struct device wsk_dev =
{
    .init_name = "my driver",
    .bus = &bus,
};
struct device_driver dev =
{
    .name = "my driver",
    .bus = &bus,
    .probe = my_probe,
};

2、match函数实现

  

/*设备匹配函数*/
int my_match(struct device *dev, struct device_driver *drv)
{

    return !strncmp(dev->kobj.name,drv->name,strlen(dev->kobj.name));
}

  这里将驱动名称和设备名称进行字符串比较,若一致strncmp返回0表示成功,但是match返回值非0才会调用probe函数,所以在前面加上叹号。
  注意这里使用的是dev->kobj.name而不是dev->init_name,原因是在注册设备函数中将dev->init_name赋值给了dev->kobj.name,而将dev->init_name清空,所以此时dev->init_name是一个空指针。以下是内核代码中清空的过程。

  

  所以用 dev->init_name进行匹配时会提示使用空指针从而导致内核崩溃。

3、符号导出
  定义设备和驱动描述结构时要初始化总线名称这个成员,要用到bus.c文件里的bus符号,所以要将它导出,然后在driver.c和device.c中将它输出

4、probe函数
  打印一串信息来提示匹配成功

int my_probe (struct device *dev)
{
    printk("driver find the device is can handle\n");

    return 0;

}

  关于probe函数在什么时候被谁调用这个问题,引用一篇博文,里面解释得很清楚了
  链接:http://www.cnblogs.com/hoys/archive/2011/04/01/2002299.html

bus.c:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>

/*设备匹配函数*/
int my_match(struct device *dev, struct device_driver *drv)
{

    return !strncmp(dev->kobj.name,drv->name,strlen(dev->kobj.name));
}

/*定义总线设备*/
struct bus_type bus =
{
    .name = "my bus",
    .match = my_match,
};

static int bus_init()
{
    /*注册总线设备驱动*/
    bus_register(&bus);

    return 0;
}

void bus_exit()
{
    /*注销总线设备驱动*/
    bus_unregister(&bus);
}

MODULE_LICENSE("GPL");
EXPORT_SYMBOL(bus);
module_init(bus_init);
module_exit(bus_exit);

driver.c:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>

extern struct bus_type bus;

int my_probe (struct device *dev)
{
    printk("driver find the device is can handle\n");

    return 0;

}

struct device_driver dev =
{
    .name = "my driver",
    .bus = &bus,
    .probe = my_probe,
};

static int my_driver_init()
{
    /*注册驱动*/
    driver_register(&dev);

    return 0;
}

void my_driver_exit()
{
    /*注销驱动*/
    driver_unregister(&dev);
}

MODULE_LICENSE("GPL");
module_init(my_driver_init);
module_exit(my_driver_exit);

devices.c:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>

extern struct bus_type bus;

struct device wsk_dev =
{
    .init_name = "my driver",
    .bus = &bus,
};

static int my_device_init()
{
    /*注册设备*/
    device_register(&wsk_dev);

    return 0;
}

void my_device_exit()
{
    /*注销设备*/
    device_unregister(&wsk_dev);
}

MODULE_LICENSE("GPL");
module_init(my_device_init);
module_exit(my_device_exit);

如果有疑问或建议,欢迎指出。

时间: 2024-10-26 01:20:14

总线设备驱动模型的相关文章

linux总线设备驱动模型

本篇文章通过平台总线设备模型为例,讲解总线设备驱动模型: platform_device_register的作用: 1.把device放入bus的device链表 2.从bus的driver链表中取出每一个driver,用bus的match函数判断driver能否支持这个device 3.若可以支持,调用driver的probe函数 platform_driver_register的作用: 1.将driver放入bus的driver链表 2.从bus的device链表中取出每一个device,用

8.总线设备驱动模型

总线设备驱动模型 总线:创建一条总线,跟我们前面的按键一样,首先是描述总线结构,接着是注册总线,注销总线.总线设备,例如usb总线,上面会有很多类型的usb的驱动,例如鼠标.键盘.....等,当我们把之一的usb插上的时候,usb总线会把每个驱动遍历一遍,找到相应的驱动程序执行. 接下来用bus.c创建一条总线. #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #in

20150225 IMX257 总线设备驱动模型编程之总线篇

20150225 IMX257 总线设备驱动模型编程之总线篇 2015-02-25 19:40 李海沿 从现在开始,我们开始来实现 总线-设备-驱动模型中的总线.. 我们这个程序的目标是在 sysfs文件系统的/sys/bus/ 目录下面建立一个文件夹. 一.总线介绍 1. 总线数据结构bus_type struct bus_type 结构体的定义如下: struct bus_type { const char *name; --总线名 struct bus_attribute *bus_att

linux嵌入式驱动-总线设备驱动模型

一个农夫想要合理的理财,他给你未来N天的每天支出(1<=N<=100000), 并计划把这N天分成M个部分(1 <=M <=N)(每个部分的天数是连续的),要求求出这些部分里花费最和最大值最小,输出这个最大值. 100 400 300 100 500 101 400 可以这么划分(100 400) (300 100) (500) (101)(400) ,五个分组里最大值是500,这个划是最佳的了,因为在其他划分里肯定有部分是大于500的,如(100) (400 300) (100

总线设备驱动模型【转】

本文转载自:http://blog.csdn.net/coding__madman/article/details/51428400 总线驱动设备模型: 1. 总线设备驱动模型概述 随着技术的不断进步,系统的拓扑结构也越来越复杂,对热插拔,跨平台移植性的要求也越来越高,2.4内核已经难以满足这些需求,为适应这宗形势的需求,从linux2.6内核开始提供了全新的设备模型 2. 总线 2.1 描述结构 2.2 注册 2.3 注销 void  bus_unregister(struct  bus_ty

16.总线设备驱动模型学习

总线设备驱动模型学习 一.总线概述 随着技术的不断进步,系统的拓扑结构也越来越复杂,对热插拔,跨平台移植性的要求也越来越高,2.4内核已经难以满足这些需求.为适应这种形势的需要,从Linux 2.6内核开始提供了全新的设备模型. 总线:创建一条总线,跟按键一样,首先是描述总线结构,接着是注册总线,注销总线.总线设备,例如usb总线,上面会有很多类型的usb的驱动,例如鼠标.键盘.....等,当我们把之一的usb插上的时候,usb总线会把每个驱动遍历一遍,找到相应的驱动程序执行. 1.1总线描述

20150226 IMX257 总线设备驱动模型编程之平台总线设备platform

20150226 IMX257 总线设备驱动模型编程之平台总线设备platform 2015-02-26 李海沿 前面我们实现了总线设备驱动模型,下面我们来了解一下平台总线,平台设备驱动 分为平台设备和平台驱动两种,和前面所说的设备驱动差不多 platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver.Linux 2.6的设备驱动模型中,把I2C.RTC.LCD等都归纳为platform_device. 一.平台设备介绍 1. p

20150226 IMX257 总线设备驱动模型编程之设备篇

20150226 IMX257 总线设备驱动模型编程之设备篇 2015-02-26 李海沿 前面我们呢实现了总线-设备-驱动模型中的总线,自然,我们的目标就是在我们建立的总线下面创建一个设备. http://www.cnblogs.com/lihaiyan/p/4301072.html 一.程序分析 1. 包含总线 既然我们的设备在总线上,自然我们既要包含总线了 如图所示,使用外部声明将我们的总线的结构体包含进来 2. 定义设备结构体 父目录为 my_bus 3. 定义属性文件结构体 属性文件结

20150226 IMX257 总线设备驱动模型编程之驱动篇

20150226 IMX257 总线设备驱动模型编程之驱动篇 2015-02-26 11:42 李海沿 前面我们已经实现了 总线和设备 的驱动程序,接下来我们的任务就是 实现 驱动 了 地址:http://www.cnblogs.com/lihaiyan/p/4301079.html http://www.cnblogs.com/lihaiyan/p/4301072.html 在实现驱动程序之前,我们来想两个问题: 一.问题分析 1.什么时候驱动程序会在总线上找它可以处理的设备? 在driver