Linux设备模型(4) — bus 与 device 和 driver

前面说了 device 和 device_driver,这两者是通过一个叫 bus 的东西联系在一起,不管这个 bus 是否是真实的存在(虚拟的也算)。

 

1、Bus

Linux 中,对 bus 是由一个叫做 bus_type 的结构体进行描述:

struct bus_type {
 const char * name;//设备名称

 struct subsystem subsys;//代表自身

 struct kset drivers; //当前总线的设备驱动集合

 struct kset devices; //所有设备集合

 struct klist klist_devices;
 struct klist klist_drivers;
 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, char **envp, 
       int num_envp, char *buffer, int buffer_size);//热拔插事件

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

在后面的实例当中用到了里面的两个成员
1:const char *name;
2:int  (*match)(struct device * dev, struct device_driver * drv);
设备驱动匹配函数,这个匹配函数是很关键的东西,这是建立总线上设备与驱动的桥梁,当一个新的设备或驱动被添加到一个总线上时被调用。

总线的操作:

注册:int bus_register(struct bus_type * bus)

注销:void bus_unregister(struct bus_type *bus);

总线属性 bus_attribute:

struct bus_attribute {
struct attribute attr;
ssize_t (*show)(struct bus_type *bus, char *buf);
ssize_t (*store)(struct bus_type *bus, const char *buf,size_t count);
};

BUS_ATTR(name, mode, show, store);
这个宏声明一个结构, 产生它的名子通过前缀字符串 bus_attr_ 到给定的名子(bus_attr_name),然后利用 bus_create_file 来创建总线属性

int bus_create_file(struct bus_type *bus, struct bus_attribute *attr);

参数中的 attr,即为 bus_attr_name
另外, 参数中的 show 函数,比如定义为:

static ssize_t show_bus_version(struct bus_type *bus, char *buf) {
    return snprintf(buf, PAGE_SIZE, "%s\n", Version);
}

总线属性的删除, 使用:

void bus_remove_file (struct bus_type *bus, struct bus_attribute *attr);

例子:

1:首先是要准备一个总线bus_type.也就是定义一个bus_type,然后给它填上一些成员。定义如下:

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

这里就对其两个成员赋值了。一个是名称。另一个则是匹配函数:

2,总线本身也是要对应一个设备的。还要为总线创建设备。

struct device my_bus = {
 .bus_id = "my_bus0",
 .release = my_bus_release
};

源代码:

#include 
#include 
#include 
#include 
#include 
static char *version = "version 1.0";
//用于判断指定的驱动程序是否能处理指定的设备。

static int my_match(struct device *dev, struct device_driver *driver) {
    return !strncmp(dev->bus_id, driver->name, strlen(driver->name));
}
static int my_bus_release(struct device *dev) {
    return 0;
}
static ssize_t show_bus_version(struct bus_type *bus, char *buf) {
    return sprintf(buf, PAGE_SIZE, "%s\n", version);
}
static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);

struct device my_bus = {//定义总线设备

    .bus_id = "my_bus0",
    .release = my_bus_release,
};
EXPORT_SYMBOL(my_bus);
struct bus_type my_bus_type = { //定义总线类型

    .name = "my_bus",
    .match = my_match,
};
EXPORT_SYMBOL(my_bus_type);
static int __init my_bus_init(void){
    int ret;
    ret = bus_register(&my_bus_type);//注册总线

    if(ret)    
        printk("bus_register failed!\n");
    if(bus_create_file(&my_bus_type, &bus_attr_version))//创建总线属性    

        printk("Creat bus failed!\n");
    ret = device_register(&my_bus);//注册总线设备

    if (ret)
        printk("device_register failed!\n");
    return ret;
}
static void __exit my_bus_exit(void) {
   bus_unregister(&my_bus_type);//删除总线属性

    device_unregister(&my_bus);//删除总线设备

}
module_init(my_bus_init);
module_exit(my_bus_exit);
MODULE_AUTHOR("Fany");
MODULE_LICENSE("GPL");

测试
将bus.c以动态加载的方式加载到内核,insmod bus.ko,在/sys/bus/目录下会有一个my_bus目录,这就是我们添加的总线。该目录下有devices,drivers目录,因为该总线上没有挂载任何设备和驱动,所以这两个目录都为空;同时,在/sys/devices目录下,还可看到my_bus0设备(总线本身也是一种设备)。
 

2、Device

注册设备:int device_register(sruct device *dev)

注销设备:void device_unregister(struct device *dev);

设备属性:

sysfs 中的设备入口可有属性. 相关的结构是:

struct device_attribute {
  struct attribute attr;
  ssize_t (*show)(struct device *dev, char *buf);
  ssize_t (*store)(struct device *dev, const char *buf, size_t count);
};

这些属性结构可在编译时建立, 使用这些宏:

DEVICE_ATTR(name, mode, show, store);

结果结构通过前缀 dev_attr_ 到给定名子上来命名. 属性文件的实际管理使用通常的函数对来处理:

int device_create_file(struct device *device, struct device_attribute *entry);

void device_remove_file(struct device *dev, struct device_attribute *attr);

创建设备:

#include 
#include 
#include 
#include 
#include 
extern struct device my_bus; //这里用到了总线设备中定义的结构体

extern struct bus_type my_bus_type;
static int my_device_release() {
    return 0;    
}
struct device my_dev={ //创建设备属性

    .bus = &my_bus_type,//定义总线类型

    .parent = &my_bus,//定义my_dev的父设备。

    .release = my_device_release,    
};
static ssize_t mydev_show(struct device *dev, char *buf) {
    return sprintf(buf, "%s\n", "This is my device!");
}
static DEVICE_ATTR(dev, S_IRUGO, mydev_show, NULL);
static int __init my_device_init(void){
    int ret;
    strncpy(my_dev.bus_id, "my_dev", BUS_ID_SIZE); //初始化设备

    ret = device_register(&my_dev); //注册设备

    if (ret)
        printk("device register!\n");
    device_create_file(&my_dev, &dev_attr_dev); //创建设备文件

    return ret;
}
static void __exit my_device_exit(void) {
        device_unregister(&my_dev);//卸载设备

}
module_init(my_device_init);
module_exit(my_device_exit);
MODULE_AUTHOR("Fany");
MODULE_LICENSE("GPL");

测试

将设备device.c,编译成模块,以动态加载的方式加载到内核。会发现在sys/bus/my_bus/devices/目录下有一个my_dev设备,查看属性,它是挂在/sys/devices/my_bus0/my_dev目录下,至此添加设备成功。

 

3、device_driver

驱动程序的注册:int driver_register(struct device_driver *drv);

驱动程序的注销:void driver_unregister(struct device_driver *drv);

驱动程序的属性:

/*driver的属性结构在:*/
struct driver_attribute {
     struct attribute attr;
     ssize_t (*show)(struct device_driver *drv, char *buf);
     ssize_t (*store)(struct device_driver *drv, const char *buf, size_t count);
};

DRIVER_ATTR(_name,_mode,_show,_store) /*属性文件创建的方法:*/
int driver_create_file(struct device_driver * drv, struct driver_attribute * attr);//创建设备驱动的属性

void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr)

例子:

#include 
#include 
#include 
#include 
#include 
extern struct bus_type my_bus_type;
static int my_probe(struct device *dev) {
    printk("Driver found device!\n");
    return 0;
};
static int my_remove(struct device *dev) {
    printk("Driver unpluged!\n");
    return 0;
};
struct device_driver my_driver = {
    .name = "my_dev",
    .bus = &my_bus_type,
    .probe = my_probe,
    .remove = my_remove,
};
//定义设备驱动属性

static ssize_t my_driver_show(struct device_driver *driver, char *buf) {
    return sprintf(buf, "%s\n", "This is my driver!");
};
static DRIVER_ATTR(drv, S_IRUGO, my_driver_show, NULL);
static int __init my_driver_init(void){
    int ret;
    //注册设备驱动

    ret = driver_register(&my_driver);
    if(ret)
        printk("driver_register failed!\n");
    //创建设备驱动属性

    ret = driver_create_file(&my_driver, &driver_attr_drv);
    if(ret)
        printk("create_driver_file failed!\n");
    
    return ret;
}
static void __exit my_driver_exit(void){
    driver_unregister(&my_driver);//注销设备驱动

}
module_init(my_driver_init);
module_exit(my_driver_exit);
MODULE_AUTHOR("Fany");
MODULE_LICENSE("GPL");

测试

当加载驱动程序时,终端界面上打印

Driver found device!

再看看相应的目录:/sys/bus/my_bus/drivers/,多了一个my_dev。说明添加驱动成功

 

http://blog.chinaunix.net/uid-23254875-id-341060.html

你可能感兴趣的:(Linux,设备驱动)