总线设备驱动模型

摘要

随着技术的不断进步,系统的拓扑结构也越来越复杂,对热插拔、跨平台移植性的要求也越来越高,2.4内核已经难以满足这些需求。为适应这种形势的需要,从Linux 2.6内核开始提供了全新的设备模型。
ps:热插拔即带电插拔,允许热插拔就是允许用户在不关闭系统,不切断电源的情况下插拔硬件。插上硬件时,系统驱动需要识别出该硬件,拔下硬件时也需要识别。

总线设备驱动模型的要素有三个:总线、设备、驱动。
总线设备驱动模型:有一根总线,总线上挂载着多个设备驱动。当有硬件插入该总线的时候,总线根据它挂载着的驱动去一一匹配处理该硬件,当某个设备驱动匹配该硬件时,总线就调用该设备驱动。当硬件拔下时,总线根据驱动做出相应的处理。ps:总线先挂载有设备,再有驱动添加到总线上时也会进行匹配

以usb总线为例。假设usb总线上挂载着多个驱动,如鼠标驱动,键盘驱动,网卡驱动。当接入usb网卡时,usb总线就根据它挂载的驱动程序去匹配网卡,直至匹配到网卡驱动并调用网卡驱动。


总线

在Linux 内核中,总线由 bus_type 结构表示,该结构定义在<linux/device.h>。bus_type 结构含有多个结构成员,重要的成员有name和match。

struct bus_type 
{
const char *name; /*总线名称*/
int (*match) (struct device *dev, struct device_driver *drv); /*驱动与设备的匹配函数*/
…
}

name为总线名称;match为函数指针,指向的函数的功能为匹配设备与驱动,需要程序员自己编写。当有新设备或者新驱动添加到该总线时,match函数被调用,用于判定指定的程序能够处理指定的设备,若可以,则返回非零。

不同的总线匹配驱动和设备的方法不同。如在usb总线中,每一个usb设备里面都有相应的设备标识id,当有usb设备挂载时,usb总线可通过设备标识id来进行匹配;而对于一些虚拟总线,一般给设备取名时,让其名称与该设备要匹配的驱动名称一样,总线则可通过名称来进行匹配,以下的程序为虚拟总线的程序。

总线的注册使用如下函数:bus_register(struct bus_type *bus)
若成功,新的总线将被添加进系统,并可在/sys/bus 下看到相应的目录。
总线的注销使用:void bus_unregister(struct bus_type *bus)

创建一条总线:

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

MODULE_LICENSE("GPL");

int my_match(struct device *dev, struct device_driver *drv)
{
    return !strncmp(dev->kobj.name,drv->name,strlen(drv->name));

    /*匹配dev->kobj.name和drv->name是否一致,其中dev->kobj.name实质为dev->init_name*/

}  

struct bus_type my_bus_type = {
    .name = "my_bus",
    .match = my_match,
    };

EXPORT_SYMBOL(my_bus_type);

int my_bus_init()
{
    int ret;    
    ret = bus_register(&my_bus_type);   
    return ret;

}

void my_bus_exit()
{
    bus_unregister(&my_bus_type);
}

module_init(my_bus_init);
module_exit(my_bus_exit);

驱动

在 Linux内核中,驱动由 device_driver结构表示,该结构拥有多个成员,其中重要的成员有:

struct device_driver 
{
    const char *name; /*驱动名称*/
    struct bus_type *bus; /*驱动程序所在的总线*/
    int (*probe)(struct device *dev);
    …
}

probe为函数指针。在总线驱动中,总线会一一匹配设备与驱动,当该驱动与某一设备匹配成功后,总线会调用probe指向的函数,该函数的功能需要包括硬件初始化等。

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

在总线上挂载一个驱动程序:

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

MODULE_LICENSE("GPL");

extern struct bus_type my_bus_type;

int my_probe(struct device *dev)
{
    printk("driver found the device it can handle!\n");
    return 0;
}

struct device_driver my_driver = {
    .name = "my_dev",
    .bus = &my_bus_type,    
    .probe = my_probe,
};

int my_driver_init()
{
    int ret;    
    ret = driver_register(&my_driver);  
    return ret;
}

void my_driver_exit()
{
    driver_unregister(&my_driver);  
}

module_init(my_driver_init);
module_exit(my_driver_exit);

设备

在Linux内核中,设备由struct device结构表示。重要的成员有:

struct device 
{
    const char *init_name; /*设备的名字*/
    struct bus_type *bus; /*设备所在的总线*/
    …
}

init_name为设备名字,虚拟总线中,设备名字需要与驱动名字一样。

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

在总线上挂载一个设备:

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

MODULE_LICENSE("GPL");

extern struct bus_type my_bus_type;

struct device my_dev = {
     .init_name = "my_dev",
     .bus = &my_bus_type,   
};

int my_device_init()
{
     int ret;
     ret = device_register(&my_dev);
     return ret;  
}

void my_device_exit()
{
    device_unregister(&my_dev);
}

module_init(my_device_init);
module_exit(my_device_exit);

当先安装总线驱动,再安装驱动程序,最后挂载设备,则会调用函数my_probe,即会打印driver found the device it can handle;
当先安装总线驱动,接着挂载设备,然后才安装驱动程序,依然会调用函数my_probe,即会打印driver found the device it can handle。
由此可知,无论是往总线上添加设备还是添加驱动,总线都会执行匹配函数去匹配新的驱动/设备。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值