以下内容都为自己理解:
1.总线bus
通常所说的总线都是cpu与设备之间通信的协议,就像两个地方,一个地方住着cpu,一个地方住着设备,总线就相当于CPU通过什么方式到达设备。(就像你要通过一个墓道,就要按照墓主人设计的方式过去,要不就会被暗器杀掉,永远也到达不了)。
但是,Linux里面的总线,我的理解就是连接设备和驱动,不是常规意义上的总线,最简单就是platform总线,它不是一个协议,它就是为了那些没有广义上协议(usb、spi、iic)的设备服务的。
bus的结构体如下所示:
struct bus_type {
const char *name; //总线的名字
const char *dev_name;
struct device *dev_root;
struct device_attribute *dev_attrs; /* use dev_groups instead */
const struct attribute_group **bus_groups;
const struct attribute_group **dev_groups;
const struct attribute_group **drv_groups;
int (*match)(struct device *dev, struct device_driver *drv); //匹配设备和驱动的函数
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
int (*probe)(struct device *dev); //如果设备和驱动匹配成功,则会调用此函数,这个函数由
//struct device_driver里面的probe函数实现,bus里面
//probe最后会调用device_driver里面的probe函数。
//这个函数用来初始化设备。这个函数Linux内核里面已经实现
int (*remove)(struct device *dev);
void (*shutdown)(struct device *dev);
int (*online)(struct device *dev);
int (*offline)(struct device *dev);
int (*suspend)(struct device *dev, pm_message_t state);
int (*resume)(struct device *dev);
const struct dev_pm_ops *pm;
const struct iommu_ops *iommu_ops;
struct subsys_private *p;
struct lock_class_key lock_key;
};
下面以platform总线为例,讲解总线的注册。
int __init platform_bus_init(void)
{
int error;
early_platform_cleanup();
error = device_register(&platform_bus);
if (error)
return error;
error = bus_register(&platform_bus_type); //这里调用总线的注册函数。
if (error)
device_unregister(&platform_bus);
of_platform_register_reconfig_notifier();
return error;
}
主要看platform_bus_type结构体
struct bus_type platform_bus_type = {
.name = "platform", //总线的名字
.dev_groups = platform_dev_groups,
.match = platform_match, //总线的匹配函数
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
platform_match函数原型如下:
static int platform_match(struct device *dev, struct device_driver *drv)
{
------------只看具体的实现-------------
return (strcmp(pdev->name, drv->name) == 0);
}
从上面可以看出,platform总线是通过设备和驱动的名字来实现匹配的。
内核实现的probe函数如下:
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
int ret = 0;
if (!device_is_registered(dev))
return -ENODEV;
pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name);
pm_runtime_get_suppliers(dev);
if (dev->parent)