总线、设备和驱动

一、总线
Linux中,使用struct bus_type表示一条总线,该结构定义在linux/device.h中,先只看其中的两个字段,name表示总线的名字,比如usb、i2c、spi等,match方法用于匹配添加到该总线上的设备和驱动,如果匹配成功,则调用驱动中的probe函数。注册一条总线使用bus_register函数,原型如下:
int bus_register(struct bus_type *bus);
注册成功可以在/sys/bus下看到该总线。注销使用bus_unregister函数,原型如下:
void bus_unregister(struct bus_type *bus);
总线操作实例如下:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/string.h>

MODULE_LICENSE("GPL");

static int my_bus_match(struct device *dev, struct device_driver *drv)
{
        return !strncmp(dev_name(dev), drv->name, strlen(drv->name));
}

struct bus_type my_bus_type = {
        .name = "my_bus",
        .match = my_bus_match,
};
EXPORT_SYMBOL_GPL(my_bus_type);

static void my_bus_device_release(struct device *dev)
{
        printk("My bus device released.");
}

struct device my_bus_device = {
        .init_name = "my_bus_device",
        .release = my_bus_device_release,
};
EXPORT_SYMBOL_GPL(my_bus_device);

static int __init my_bus_init(void)
{
        int ret = 0;

        ret = bus_register(&my_bus_type);
        if (ret) {
                printk("Can't register my bus!\n");
                return ret;
        }

        ret = device_register(&my_bus_device);
        if (ret) {
                printk("Can't register my bus device!\n");
                bus_unregister(&my_bus_type);
        }

        return ret;
}

static void __exit my_bus_exit(void)
{
        device_unregister(&my_bus_device);
        bus_unregister(&my_bus_type);
}

module_init(my_bus_init);
module_exit(my_bus_exit);
这里注册了一条my_bus_type的总线,同时注册了一个设备,该设备为该总线设备,可以在sys/devices下看到。该总线的match方法很简单,就是比较设备的名字和驱动的名字是否一样。

二、设备
设备使用struct device来描述,其中init_name表示设备的名字,需要注意的是,该字段在初始化完成之后被设置为null,所以以后都不能使用该字段,需要获取设备的名字使用dev_name函数,例如上面的总线中就使用了该函数。bus表示总线,即该设备挂载到什么总线上的。注册一个设备使用device_register函数,原型如下:
int device_register(struct device *dev);
注销设备使用device_unregister函数,原型如下:
void device_unregister(struct device *dev);
设备操作实例如下:

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

MODULE_LICENSE("GPL");

static void my_device_release(struct device *dev)
{
        printk("My device released.\n");
}

extern struct bus_type my_bus_type;
extern struct device my_bus_device;

struct device my_device = {
        .init_name = "my_device",
        .bus = &my_bus_type,
        .parent = &my_bus_device,
        .release = my_device_release,
};

static int __init my_device_init(void)
{
        int ret = 0;

        ret = device_register(&my_device);
        if (ret) {
                printk("Can't register my device!\n");
        }

        return ret;
}

static void __exit my_device_exit(void)
{
        device_unregister(&my_device);
}

module_init(my_device_init);
module_exit(my_device_exit);
这里还指定了parent成员为总线设备,注册成功之后将在总线设备的目录下看到该设备。由于这里使用了总线当中的my_bus_type和my_bus_device两个成员,所以这里需要使用extern声明这两个成员,同时还需记住的是在总线代码当中必须使用EXPORT_SYMBOL_GPL导出这两个符号,这样才能其它地方使用这些符号,导出符号还有一个宏EXPORT_SYMBOL,其中EXPORT_SYMBOL_GPL只能被GPL许可证下的模块使用。


三、驱动
驱动使用struct device_driver来描述,它也有个name字段,这个字段是可以一直使用的。同设备一样,也有个bus成员,含义同设备一样,都表示挂载到哪条总线上。驱动中有个probe和remove方法,其中probe方法将在总线匹配设备和该驱动成功之后被调用,remove方法将在设备或驱动卸载时被调用。注册驱动使用driver_register函数,原型如下:
int driver_register(struct device_driver *drv);
注销驱动使用driver_unregister函数,原型如下:
void driver_unregister(struct device_driver *drv);
驱动操作实例如下:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>

MODULE_LICENSE("GPL");

static int my_driver_probe(struct device *dev)
{
        printk("Driver found device which my driver can handle.\n");
        return 0;
}

static int my_driver_remove(struct device *dev)
{
        printk("Driver founc device unpluged.\n");
        return 0;
}

extern struct bus_type my_bus_type;

struct device_driver my_driver = {
        .name = "my_device",
        .bus = &my_bus_type,
        .probe = my_driver_probe,
        .remove = my_driver_remove,
};

static int __init my_driver_init(void)
{
        int ret = 0;

        ret = driver_register(&my_driver);
        if (ret) {
                printk("Can't register my driver!\n");
        }

        return ret;
}

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

module_init(my_driver_init);
module_exit(my_driver_exit);
关于总线、设备和驱动需要特别注意的是总线的match方法在匹配设备和驱动成功之后调用驱动的probe方法,设备或驱动移除时调用驱动的remove方法。

你可能感兴趣的:(总线、设备和驱动)