总线相关的操作
注册
int
bus_register(
struct
bus_type *bus)
{
int
retval;
struct
subsys_private *priv;
priv = kzalloc(
sizeof
(
struct
subsys_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);
out:
kfree(bus->p);
bus->p = NULL;
return
retval;
}
EXPORT_SYMBOL_GPL(bus_register);
|
此函数包括如下几项工作:
1、首先会动态创建一个subsys_private结构体priv,并且设置priv与bus之间的映射关系。然后会阻塞notifier。紧接着会初始化priv->subsys.kobj,其中包括设置名称、其属于bus_kset以及类型为bus_ktype,接着就会注册此kset(关于kset_register参见前文)。紧接着会在sysfs文件系统中创建响应的目录以及文件。
2、接下来,就会创建两个kset,一个用于组织本总线上的设备对应的kobject,另一个用于组织本总线上的驱动对应的kobject。如果成功,就会创建两个klist用于组织设备和驱动的相关信息。
3、最后,就是根据默认属性在sysfs文件系统中创建相关的文件。
注销
void
bus_unregister(
struct
bus_type *bus)
{
pr_debug(
"bus: '%s': unregistering\n"
, bus->name);
bus_remove_attrs(bus);
remove_probe_files(bus);
kset_unregister(bus->p->drivers_kset);
kset_unregister(bus->p->devices_kset);
bus_remove_file(bus, &bus_attr_uevent);
kset_unregister(&bus->p->subsys);
kfree(bus->p);
bus->p = NULL;
}
|
和注册完全相反的过程。
驱动
注册
int
driver_register(
struct
device_driver *drv)
{
int
ret;
struct
device_driver *other;
BUG_ON(!drv->bus->p);
if
((drv->bus->probe && drv->probe) ||
(drv->bus->
remove
&& drv->
remove
) ||
(drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING
"Driver '%s' needs updating - please use "
"bus_type methods\n"
, drv->name);
other = driver_find(drv->name, drv->bus);
if
(other) {
put_driver(other);
printk(KERN_ERR
"Error: Driver '%s' is already registered, "
"aborting...\n"
, drv->name);
return
-EBUSY;
}
ret = bus_add_driver(drv);
if
(ret)
return
ret;
ret = driver_add_groups(drv, drv->groups);
if
(ret)
bus_remove_driver(drv);
return
ret;
}
EXPORT_SYMBOL_GPL(driver_register);
|
其实这个函数绝大部分工作都推到了函数bus_add_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;
if
(drv->bus->p->drivers_autoprobe) {
error = driver_attach(drv);
if
(error)
goto
out_unregister;
}
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
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_attrs(bus, drv);
if
(error) {
/* How the hell do we get out of this pickle? Give up */
printk(KERN_ERR
"%s: driver_add_attrs(%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);
}
}
kobject_uevent(&priv->kobj, KOBJ_ADD);
return
0;
out_unregister:
kobject_put(&priv->kobj);
kfree(drv->p);
drv->p = NULL;
out_put_bus:
bus_put(bus);
return
error;
}
|
这个函数在为驱动的私有数据分配了存储空间后,就会设置驱动模型中的核心结构,包括父节点、所属kset,以及初始化私有数据内嵌的kobject等。同时会将自己加入到所属总线的所有驱动构成的链表之中。
紧接着就会做sysfs相关的操作,包括创建对应的目录,属性文件等,同时会想用户空间发送uevent事件。
注销
和注册相反的过程
设备
注册
int
device_register(
struct
device *dev)
{
device_initialize(dev);
return
device_add(dev);
}
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);
}
int
device_add(
struct
device *dev)
{
struct
device *parent = NULL;
struct
class_interface *class_intf;
int
error = -EINVAL;
dev = get_device(dev);
if
(!dev)
goto
done;
if
(!dev->p) {
error = device_private_init(dev);
if
(error)
goto
done;
}
/*
* for statically allocated devices, which should all be converted
* some day, we need to initialize the name. We prevent reading back
* the name, and force the use of dev_name()
*/
if
(dev->init_name) {
dev_set_name(dev,
"%s"
, dev->init_name);
dev->init_name = NULL;
}
if
(!dev_name(dev)) {
error = -EINVAL;
goto
name_error;
}
pr_debug(
"device: '%s': %s\n"
, dev_name(dev), __func__);
parent = get_device(dev->parent);
setup_parent(dev, parent);
/* use parent numa_node */
if
(parent)
set_dev_node(dev, dev_to_node(parent));
/* first, register with generic layer. */
/* we require the name to be set before, and pass NULL */
error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
if
(error)
goto
Error;
/* notify platform of device entry */
if
(platform_notify)
platform_notify(dev);
error = device_create_file(dev, &uevent_attr);
if
(error)
goto
attrError;
if
(MAJOR(dev->devt)) {
error = device_create_file(dev, &devt_attr);
if
(error)
goto
ueventattrError;
error = device_create_sys_dev_entry(dev);
if
(error)
goto
devtattrError;
devtmpfs_create_node(dev);
}
error = device_add_class_symlinks(dev);
if
(error)
goto
SymlinkError;
error = device_add_attrs(dev);
if
(error)
goto
AttrsError;
error = bus_add_device(dev);
if
(error)
goto
BusError;
error = dpm_sysfs_add(dev);
if
(error)
goto
DPMError;
device_pm_add(dev);
/* Notify clients of device addition. This call must come
* after dpm_sysf_add() and before kobject_uevent().
*/
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);
|