本文为读书笔记,详细内容参考《存储原理技术分析》
1- 驱动模型
2- 总线类型
2.1- 重要数据结构
总线bus_type 和 bus_type_private 互相可以找到对方
struct bus_type {
const char *name;
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, struct kobj_uevent_env *env);
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 dev_pm_ops *pm;
struct bus_type_private *p;
};
/**
* struct bus_type_private - structure to hold the private to the driver core portions of the bus_type structure.
*
* @subsys - the struct kset that defines this bus. This is the main kobject
* @drivers_kset - the list of drivers associated with this bus
* @devices_kset - the list of devices associated with this bus
* @klist_devices - the klist to iterate over the @devices_kset
* @klist_drivers - the klist to iterate over the @drivers_kset
* @bus_notifier - the bus notifier list for anything that cares about things
* on this bus.
* @bus - pointer back to the struct bus_type that this structure is associated
* with.
*
* This structure is the one that is the actual kobject allowing struct
* bus_type to be statically allocated safely. Nothing outside of the driver
* core should ever touch these fields.
*/
struct bus_type_private {
struct kset subsys;
struct kset *drivers_kset;
struct kset *devices_kset;
struct klist klist_devices;
struct klist klist_drivers;
struct blocking_notifier_head bus_notifier;
unsigned int drivers_autoprobe:1;
struct bus_type *bus;
};
数据结构说明:
2.2- 总线注册
以PCI总线注册为例
2.2.1- pci总线注册
向系统中注册pci总线信息,总线名字为pci,总线的回调接口定义在pci_bus_type
drivers\pci\pci-driver.c
struct bus_type pci_bus_type = {
.name= "pci",
.match= pci_bus_match,
.uevent= pci_uevent,
.probe= pci_device_probe,
.remove= pci_device_remove,
.shutdown= pci_device_shutdown,
.dev_attrs= pci_dev_attrs,
.bus_attrs= pci_bus_attrs,
.pm= PCI_PM_OPS_PTR,
};
static int __init pci_driver_init(void)
{
return bus_register(&pci_bus_type);
}
2.2.2- 总线注册
主要动作:
1- kset_register : 在/sys/bus/路径下创建pci文件夹。
a- pci总线类型注册到的路径由priv->subsys.kobj.kset = bus_kset决定。buses_init中定义bus_kset为/sys/bus路径
b- 注册的pci总线名字在pci_bus_type.name定义。
2- 创建必要的文件
a- 创建/sys/bus/pci/uevent文件。用于通知用户态程序。bus_create_file(bus, &bus_attr_uevent);
b- 创建/sys/bus/pci/device文件。用于挂接pci设备。 kset_create_and_add("devices", NULL, &priv->subsys.kobj);
c- 创建/sys/bus/pci/drivers文件。用于挂接pci驱动。 kset_create_and_add("drivers", NULL, &priv->subsys.kobj);
d- 添加/sys/bus/pci/xxx_prob文件,包括drives_prob和drives_autoprob。add_probe_files(bus);
e- 添加属性文件/sys/bus/pci/xxx。例如rescan。 bus_add_attrs(bus);
注: 具体在系统/sys/bus/pci下注册了那些信息,可以自己去系统下看下。
drivers\base\bus.c
/**
* bus_register - register a bus with the system.
* @bus: bus.
*
* Once we have that, we registered the bus with the kobject
* infrastructure, then register the children subsystems it has:
* the devices and drivers that belong to the bus.
*/
int bus_register(struct bus_type *bus)
{
int retval;
struct bus_type_private *priv;
priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->bus = bus;
bus->p = priv;
BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
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);
if (retval)
goto out;
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;
}
klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
klist_init(&priv->klist_drivers, NULL, NULL);
retval = add_probe_files(bus);
if (retval)
goto bus_probe_files_fail;
retval = bus_add_attrs(bus);
if (retval)
goto bus_attrs_fail;
pr_debug("bus: '%s': registered\n", bus->name);
return 0;
bus_attrs_fail:
remove_probe_files(bus);
bus_probe_files_fail:
kset_unregister(bus->p->drivers_kset);
bus_drivers_fail:
kset_unregister(bus->p->devices_kset);
bus_devices_fail:
bus_remove_file(bus, &bus_attr_uevent);
bus_uevent_fail:
kset_unregister(&bus->p->subsys);
kfree(bus->p);
out:
bus->p = NULL;
return retval;
}