码迷,mamicode.com
首页 > 其他好文 > 详细

总线设备驱动模型

时间:2015-02-17 00:42:28      阅读:317      评论:0      收藏:0      [点我收藏+]

标签:

一、总线模型(转自国嵌论坛)
  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);

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

总线设备驱动模型

标签:

原文地址:http://www.cnblogs.com/51qianrushi/p/4294680.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!