目录
一、概述
驱动模型描述的是bus,driver,device三者的关系。
二 、BUS
2.1 说明
* A bus is a channel between the processor and one or more devices. For the
* purposes of the device model, all devices are connected via a bus, even if
* it is an internal, virtual, "platform" bus. Buses can plug into each other.
* A USB controller is usually a PCI device, for example. The device model
* represents the actual connections between buses and the devices they control.
* A bus is represented by the bus_type structure. It contains the name, the
* default attributes, the bus' methods, PM operations, and the driver core's
* private data.
*/
2.2 数据抽象
[linux/linux/device.h]
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);
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);
int (*num_vf)(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;
};
2.3 接口
- int bus_register(struct bus_type *bus);
2.4 实现
通过分析看一下bus注册后怎么将bus信息通过sysfs构建起来
[drivers/base/bus.c]
int __init buses_init(void)
{
bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
if (!bus_kset)
return -ENOMEM;
system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj);
if (!system_kset)
return -ENOMEM;
return 0;
}
根据在Linux设备驱动——驱动模型之kobject/kset中的分析,上面两次调用是顶层的kset,对“bus”来说参数指定为NULL,说明其在/sys的根下,而“system”位于devices_kset下的kset,后面会讲到devices_kset是device顶级kset
[root@localhost ~]# ls /sys/
block bus class dev devices firmware fs hypervisor kernel module power[root@localhost ~]# ls /sys/devices/
breakpoint cpu LNXSYSTM:00 msr pci0000:00 platform pnp0 power software system tracepoint virtual
接下来分析bus注册及过程中的sys文件系统的变化,假设新注册的总线名称为“new_bus”
int bus_register(struct bus_type *bus)
{
retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
if (retval)
goto out;
priv->subsys.kobj.kset = bus_kset;
priv->subsys.kobj.ktype = &bus_ktype;
priv->drivers_autoprobe = 1;
retval = kset_register(&priv->subsys);
}
第一个片段,为该bus创建一个kset,所有总线都属于顶级总线kset
另外,在调用kset_registger时,指定了name,ktype,kset(其实就是parent了),这时候,在sys中出现:
- /sys/bus/new_bus
retval = bus_create_file(bus, &bus_attr_uevent);
if (retval)
goto bus_uevent_fail;
priv->devices_kset = kset_create_and_add("devices", NULL, &priv->subsys.kobj);
if (!priv->devices_kset) {
retval = -ENOMEM;
goto bus_devices_fail;
}
priv->drivers_kset = kset_create_and_add("drivers", NULL, &priv->subsys.kobj);
if (!priv->drivers_kset) {
retval = -ENOMEM;
goto bus_drivers_fail;
}
接下来通过bus_create_file创建event文件
- /sys/bus/new_bus/event
然后通过kset_create_and_add在当前new_bus下创建devices,和drivers的kset
- /sys/bus/new_bus/devices
- /sys/bus/new_bus/drivers
retval = add_probe_files(bus);
if (retval)
goto bus_probe_files_fail;
retval = bus_add_groups(bus, bus->bus_groups);
if (retval)
goto bus_groups_fail;
最后通过add_probe_files创建probe和autoprobe
- /sys/bus/new_bus/drivers_probe
- /sys/bus/new_bus/drivers_autoprobe
bus_add_groups创建文件属性
以i2c为例,看下bus注册后的结构:
[root@localhost ~]# tree /sys/bus/i2c/
/sys/bus/i2c/
├── devices
├── drivers
│ └── dummy
│ ├── bind
│ ├── module -> ../../../../module/i2c_core
│ ├── uevent
│ └── unbind
├── drivers_autoprobe
├── drivers_probe
└── uevent
kset的情况画了个图:
相同颜色代表属于一个kset。
三、device
3.1 说明
* At the lowest level, every device in a Linux system is represented by an
* instance of struct device. The device structure contains the information
* that the device model core needs to model the system. Most subsystems,
* however, track additional information about the devices they host. As a
* result, it is rare for devices to be represented by bare device structures;
* instead, that structure, like kobject structures, is usually embedded within
* a higher-level representation of the device.
*/
3.2 数据抽象
[include/linux/device.h]
struct device {
struct device *parent;
struct device_private *p;
struct kobject kobj;
const char *init_name; /* initial name of the device */
const 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 */
void *driver_data; /* Driver data, set and get with
dev_set/get_drvdata */
struct dev_links_info links;
struct dev_pm_info power;
struct dev_pm_domain *pm_domain;
#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
struct irq_domain *msi_domain;
#endif
#ifdef CONFIG_PINCTRL
struct dev_pin_info *pins;
#endif
#ifdef CONFIG_GENERIC_MSI_IRQ
struct list_head msi_list;
#endif
#ifdef CONFIG_NUMA
int numa_node; /* NUMA node this device is close to */
#endif
const struct dma_map_ops *dma_ops;
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. */
unsigned long dma_pfn_offset;
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 */
#ifdef CONFIG_DMA_CMA
struct cma *cma_area; /* contiguous memory area for dma
allocations */
#endif
/* arch specific additions */
struct dev_archdata archdata;
struct device_node *of_node; /* associated device tree node */
struct fwnode_handle *fwnode; /* firmware device node */
dev_t devt; /* dev_t, creates the sysfs "dev" */
u32 id; /* device instance */
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);
struct iommu_group *iommu_group;
struct iommu_fwspec *iommu_fwspec;
bool offline_disabled:1;
bool offline:1;
};
3.3 接口
- int device_register(struct device *dev);
- struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...);
3.4 实现
[driver/base/core.c]
int __init devices_init(void)
{
devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
if (!devices_kset)
return -ENOMEM;
dev_kobj = kobject_create_and_add("dev", NULL);
if (!dev_kobj)
goto dev_kobj_err;
sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
if (!sysfs_dev_block_kobj)
goto block_kobj_err;
sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
if (!sysfs_dev_char_kobj)
goto char_kobj_err;
}
在device初始化时,创建devices_kset容器,这在/sys/下建立devices文件夹,接着是dev,在dev下建立block,char文件夹
[root@localhost ~]# ls /sys/
block bus class dev devices firmware fs hypervisor kernel module power[root@localhost ~]# ls /sys/dev
block char
接下来看设备是如何注册的,假设设备名称new_device
[driver/base/core.c]
int device_register(struct device *dev)
{
device_initialize(dev);
return device_add(dev);
}
device是基于kobject的,我们看它是如何操作的:
void device_initialize(struct device *dev)
{
dev->kobj.kset = devices_kset; /* 注意这 */
kobject_init(&dev->kobj, &device_ktype);
INIT_LIST_HEAD(&dev->dma_pools);
mutex_init(&dev->mutex);
lockdep_set_novalidate_class(&dev->mutex);
spin_lock_init(&dev->devres_lock);
INIT_LIST_HEAD(&dev->devres_head);
device_pm_init(dev);
set_dev_node(dev, -1);
INIT_LIST_HEAD(&dev->links.consumers);
INIT_LIST_HEAD(&dev->links.suppliers);
dev->links.status = DL_DEV_NO_DRIVER;
}
可以看出,这里指定了ktype,并且该device的parent默认为顶级device下的kset
上述片段,展示了初始化基类kobj的过程,名称遵循dev->init_name, dev->bus->dev_name的过程
- /sys/devices/new_device
接下来是:
error = device_create_file(dev, &dev_attr_uevent);
error = device_add_class_symlinks(dev);
error = device_add_attrs(dev);
error = bus_add_device(dev);
error = dpm_sysfs_add(dev);
device_pm_add(dev);
- bus_add_device 将device加入到对应的bus中klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);
最后:
if (MAJOR(dev->devt)) {
error = device_create_file(dev, &dev_attr_dev);
if (error)
goto DevAttrError;
error = device_create_sys_dev_entry(dev);
if (error)
goto SysEntryError;
devtmpfs_create_node(dev);
}
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_ADD_DEVICE, dev);
kobject_uevent(&dev->kobj, KOBJ_ADD);
bus_probe_device(dev);
if (parent)
klist_add_tail(&dev->p->knode_parent,
&parent->p->klist_children);
if (dev->class) {
mutex_lock(&dev->class->p->mutex);
/* tie the class to the device */
klist_add_tail(&dev->knode_class,
&dev->class->p->klist_devices);
/* notify any interfaces that the device is here */
list_for_each_entry(class_intf,
&dev->class->p->interfaces, node)
if (class_intf->add_dev)
class_intf->add_dev(dev, class_intf);
mutex_unlock(&dev->class->p->mutex);
}
上面的函数我们重点关注bus_probe_device->device_initial_probe->__device_attach:
[driver/base/Dd.c]
static int __device_attach(struct device *dev, bool allow_async)
{
int ret = 0;
device_lock(dev);
if (dev->driver) {
if (device_is_bound(dev)) {
ret = 1;
goto out_unlock;
}
ret = device_bind_driver(dev);
if (ret == 0)
ret = 1;
else {
dev->driver = NULL;
ret = 0;
}
} else {
struct device_attach_data data = {
.dev = dev,
.check_async = allow_async,
.want_async = false,
};
...
ret = bus_for_each_drv(dev->bus, NULL, &data,
__device_attach_driver);
...
}
out_unlock:
device_unlock(dev);
return ret;
}
上面的函数是设备注册的核心——寻找并绑定对应的驱动,看下匹配driver的过程__device_attach_driver
首先进行driver_match_device,这个就是bus上的match
static inline int driver_match_device(struct device_driver *drv,
struct device *dev)
{
return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}
如果driver和device成功的match,接下来就要driver_probe_device
static int really_probe(struct device *dev, struct device_driver *drv)
{
...
re_probe:
dev->driver = drv;
...
if (driver_sysfs_add(dev)) {
printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
__func__, dev_name(dev));
goto probe_failed;
}
...
if (dev->bus->probe) {
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
} else if (drv->probe) {
ret = drv->probe(dev);
if (ret)
goto probe_failed;
}
...
driver_bound(dev);
...
}
- 关键步骤dev->driver = drv 此时device和driver就绑定在一起了!
- 接下来按照优先级执行dev->bus->probe, drv->probe
四、driver
4.1 说明
* The device driver-model tracks all of the drivers known to the system.
* The main reason for this tracking is to enable the driver core to match
* up drivers with new devices. Once drivers are known objects within the
* system, however, a number of other things become possible. Device drivers
* can export information and configuration variables that are independent
* of any specific device.
*/
4.2 数据抽象
[include/linux/device.h]
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 */
enum probe_type probe_type;
const struct of_device_id *of_match_table;
const struct acpi_device_id *acpi_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;
};
4.3 接口
- int driver_register(struct device_driver *drv)
4.4 实现
具体看一下:
int driver_register(struct device_driver *drv)
{
int ret;
struct device_driver *other;
BUG_ON(!drv->bus->p);
...
other = driver_find(drv->name, drv->bus);
ret = bus_add_driver(drv);
ret = driver_add_groups(drv, drv->groups);
kobject_uevent(&drv->p->kobj, KOBJ_ADD);
return ret;
}
driver_find确定当前driver有没有注册过
int bus_add_driver(struct device_driver *drv)
{
struct bus_type *bus;
struct driver_private *priv;
int error = 0;
bus = bus_get(drv->bus);
if (!bus)
return -EINVAL;
pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
error = -ENOMEM;
goto out_put_bus;
}
klist_init(&priv->klist_devices, NULL, NULL);
priv->driver = drv;
drv->p = priv;
priv->kobj.kset = bus->p->drivers_kset;
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
if (error)
goto out_unregister;
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
if (drv->bus->p->drivers_autoprobe) {
if (driver_allows_async_probing(drv)) {
pr_debug("bus: '%s': probing driver %s asynchronously\n",
drv->bus->name, drv->name);
async_schedule(driver_attach_async, drv);
} else {
error = driver_attach(drv);
if (error)
goto out_unregister;
}
}
module_add_driver(drv->owner, drv);
error = driver_create_file(drv, &driver_attr_uevent);
if (error) {
printk(KERN_ERR "%s: uevent attr (%s) failed\n",
__func__, drv->name);
}
error = driver_add_groups(drv, bus->drv_groups);
if (error) {
/* How the hell do we get out of this pickle? Give up */
printk(KERN_ERR "%s: driver_create_groups(%s) failed\n",
__func__, drv->name);
}
if (!drv->suppress_bind_attrs) {
error = add_bind_files(drv);
if (error) {
/* Ditto */
printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
__func__, drv->name);
}
}
return 0;
}
简单列一下函数做的几件事:
- 分配driver_private,在对应bus_type的driver下建立文件
- driver纳入bus_type的管理
- driver_attach,这些内容在device中已经说过了。
五、class
5.1 说明
/*
* A class is a higher-level view of a device that abstracts out low-level
* implementation details. Drivers may see a SCSI disk or an ATA disk, but,
* at the class level, they are all simply disks. Classes allow user space
* to work with devices based on what they do, rather than how they are
* connected or how they work.
*/
class是更高层次对设备的抽象。
5.2 数据抽象
[inclde/linux/device.h]
struct class {
const char *name;
struct module *owner;
const struct attribute_group **class_groups;
const struct attribute_group **dev_groups;
struct kobject *dev_kobj;
int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
char *(*devnode)(struct device *dev, umode_t *mode);
void (*class_release)(struct class *class);
void (*dev_release)(struct device *dev);
int (*shutdown_pre)(struct device *dev);
const struct kobj_ns_type_operations *ns_type;
const void *(*namespace)(struct device *dev);
const struct dev_pm_ops *pm;
struct subsys_private *p;
};
5.3 接口
- class_register
5.4 实现
[driver/base/class.c]
int __init classes_init(void)
{
class_kset = kset_create_and_add("class", NULL, NULL);
if (!class_kset)
return -ENOMEM;
return 0;
}
再来看class的注册:
int __class_register(struct class *cls, struct lock_class_key *key)
{
struct subsys_private *cp;
int error;
pr_debug("device class '%s': registering\n", cls->name);
cp = kzalloc(sizeof(*cp), GFP_KERNEL);
if (!cp)
return -ENOMEM;
klist_init(&cp->klist_devices, klist_class_dev_get, klist_class_dev_put);
INIT_LIST_HEAD(&cp->interfaces);
kset_init(&cp->glue_dirs);
__mutex_init(&cp->mutex, "subsys mutex", key);
error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name);
if (error) {
kfree(cp);
return error;
}
/* set the default /sys/dev directory for devices of this class */
if (!cls->dev_kobj)
cls->dev_kobj = sysfs_dev_char_kobj;
#if defined(CONFIG_BLOCK)
/* let the block class directory show up in the root of sysfs */
if (!sysfs_deprecated || cls != &block_class)
cp->subsys.kobj.kset = class_kset;
#else
cp->subsys.kobj.kset = class_kset;
#endif
cp->subsys.kobj.ktype = &class_ktype;
cp->class = cls;
cls->p = cp;
error = kset_register(&cp->subsys);
if (error) {
kfree(cp);
return error;
}
error = class_add_groups(class_get(cls), cls->class_groups);
class_put(cls);
error = add_class_attrs(class_get(cls));
class_put(cls);
return error;
}
六、小结
上面描述了驱动模型各个部件之间的关系,实际上就是完成在特定bus_type下,device和driver的attach在一起,这是通过match行为完成的,随后执行probe的过程,这个过程发生在:
- 设备注册
- 驱动注册
具体来说,device的attach就是遍历bus下所有的driver,执行driver->bus->match匹配对应的driver。driver的attach则是遍历bus下所有的设备,同样执行driver->bus->match匹配对应的device。无论从哪个角度进行attach,一旦match成功就将device->driver指向具体的driver。此时代表二者attach完成。
attach完成,也反应在sysfs上:
static int driver_sysfs_add(struct device *dev)
{
int ret;
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_BIND_DRIVER, dev);
ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,
kobject_name(&dev->kobj));
if (ret == 0) {
ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,
"driver");
if (ret)
sysfs_remove_link(&dev->driver->p->kobj,
kobject_name(&dev->kobj));
}
return ret;
}
可以看到,主要建立了两个软连接,这里用图进行说明:
这之后,调用probe进一步对device进行探测。