小结:
1、热插拔模块:
这个模块的函数主要实现的是驱动和设备的绑定,解除,以及驱动的自动探测等功能
2、看本代码前最好先看一次/lib/klist.c,否则代码中关于klist和node的操作会把你绕晕
3、bus的模型:
Ø 系统一启动就会自动执行buses_init来注册总线子系统(bus_subsys),这个子系统设置了总线的过滤,show,store操作。
Ø bus的注册是将bus挂到这个子系统上,
Ø 设备device和驱动driver分别挂在bus的kset和klist对应的地方,
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
函数列表:
int bus_for_each_dev(struct bus_type * bus, struct device * start,
void * data, int (*fn)(struct device *, void *))
//从start开始,查找bus->klist_devices中的每一个设备,并执行fn函数
//每执行完一个函数,就把该设备从总线上脱开
struct device * bus_find_device(struct bus_type *bus,
struct device *start, void *data,
int (*match)(struct device *, void *))
和buf_for_each_dev类似,只是这个函数是调用match,找到匹配的设备后就退出了
int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
void * data, int (*fn)(struct device_driver *, void *))
和bus_for_each_dev函数的实现类似,只是查找的链表是bus->klist_drivers
@@@@@@
int bus_add_device(struct device * dev)
设备挂载到总线上,实际操作就是sysfs_create_link创建几个link链接
void bus_attach_device(struct device * dev)
设备关联到总线上,实际操作是调用db.c中的device_attach(dev)固定设备,如果成功就klist_add_tail将dev->knode_bus节点挂到bus->klist_devices设备总线上
void bus_remove_device(struct device * dev)
从总线上移走设备,其操作就是bus_add_device函数出错后的处理
@@@@@@
int bus_add_driver(struct device_driver *drv)
//将驱动关联到总线上,在driver.c文件中,驱动的注册最后是调用该函数,具体的操作如下:
//1、将驱动kobj的父kset设置为bus->drivers,完成与bus的obj关联
//2、kobj在对应的kset上注册
//3、如果总线drivers_autoprobe,则执行driver_attach函数关联驱动和设备
//4、将驱动节点knode挂到总线的drivers_klist链表下
//5、为驱动创建属性文件,包括:驱动自己的属性driver_attr_uevent,总线继承下来的属性,bind和unbind属性
void bus_remove_driver(struct device_driver * drv)
从总线上移除驱动,是add的反过程
int bus_rescan_devices(struct bus_type * bus)
遍历总线上的设备,调用bus_rescan_devices_helper函数来关联设备
int device_reprobe(struct device *dev)
设备的重新探测:释放设备之前关联的驱动,然后bus_rescan_devices_helper重新探测设备驱动
@@@@@@
int bus_register(struct bus_type * bus)
总线的注册
//1、总线子系统的kobj命名为bus->name
//2、将总线kobj.kset设置为bus_subsys,并完成bus_subsys的注册
//3、为bus总线创建uevent属性文件(操作)
//4、设置总线上的设备链表(kobj命名,父设备指定为bus_subsys.kobj,kset节点的注册)
//5、设置总线上驱动链表,方法同设备链表,只是多了ktype操作(show,store设置probe)
//6、初始化总线上的设备和驱动klist,设备klist上挂有get和put
//7、初始化bus带autoprobe属性,为总线加上probe和autoprobe操作
//8、为bus加上bus_attrs[]属性
总线的unregister则相反
@@@@@@
int __init buses_init(void)
总线的初始化,在系统启动时调用,作用是注册总线子系统bus_subsys
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//获取bus属性,获取bus类型
#define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr)
#define to_bus(obj) container_of(obj, struct bus_type, subsys.kobj)
struct bus_attribute {
struct attribute attr;
ssize_t (*show)(struct bus_type *, char * buf);
ssize_t (*store)(struct bus_type *, const char * buf, size_t count);
};
struct attribute {
const char *name;
struct module *owner;
mode_t mode;
};
struct bus_type {
const char * name;
struct module * owner;
struct kset subsys; //子系统
struct kset drivers;
struct kset devices;
struct klist klist_devices;
struct klist klist_drivers;
struct blocking_notifier_head bus_notifier;
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 (*suspend_late)(struct device * dev, pm_message_t state);
int (*resume_early)(struct device * dev);
int (*resume)(struct device * dev);
unsigned int drivers_autoprobe:1; //是否支持自动探测
};
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//获取驱动属性和设备驱动
#define to_drv_attr(_attr) container_of(_attr, struct driver_attribute, attr)
#define to_driver(obj) container_of(obj, struct device_driver, kobj)
struct driver_attribute {
struct attribute attr;
ssize_t (*show)(struct device_driver *, char * buf);
ssize_t (*store)(struct device_driver *, const char * buf, size_t count);
};
struct device_driver {
其他成员…
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);
};
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//总线的引用计数,实际是引用bus_type->subsys的计数
static struct bus_type *bus_get(struct bus_type *bus)
{
return bus ? container_of(kset_get(&bus->subsys),
struct bus_type, subsys) : NULL;
}
static void bus_put(struct bus_type *bus)
{
kset_put(&bus->subsys);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//类似的代码我们其实已经很熟悉了,show的执行函数(driver_attribute)
static ssize_t drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
{
struct driver_attribute * drv_attr = to_drv_attr(attr);
struct device_driver * drv = to_driver(kobj);
drv_attr->show(drv, buf);
}
static ssize_t drv_attr_store
类似的函数就不重复了
static struct sysfs_ops driver_sysfs_ops = {
.show = drv_attr_show,
.store = drv_attr_store,
};
//驱动的ktype操作
static struct kobj_type driver_ktype = {
.sysfs_ops = &driver_sysfs_ops,
.release = driver_release, //这个函数是一个空函数,所以没有COPY
};
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//总线的show函数(bus_attribute)
static ssize_t bus_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
static ssize_t bus_attr_store
static struct sysfs_ops bus_sysfs_ops = {
.show = bus_attr_show,
.store = bus_attr_store,
};
//总线的ktype操作
static truct kobj_type bus_ktype = {
.sysfs_ops = &bus_sysfs_ops,
};
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//在总线上创建和删除属性文件
int bus_create_file(struct bus_type * bus, struct bus_attribute * attr)
{
int error;
if (bus_get(bus)) { //总线引用加1,创建一个属性文件
error = sysfs_create_file(&bus->subsys.kobj, &attr->attr);
bus_put(bus); //释放总线引用
} else
error = -EINVAL;
return error;
}
void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr)
{
sysfs_remove_file(&bus->subsys.kobj, &attr->attr);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//判断kobj中的ktype是否是系统默认的bus_ktype
//参数kset未使用
static int bus_uevent_filter(struct kset *kset, struct kobject *kobj)
{
struct kobj_type *ktype = get_ktype(kobj);
if (ktype == &bus_ktype)
return 1;
return 0;
}
static struct kset_uevent_ops bus_uevent_ops = {
.filter = bus_uevent_filter,
};
//声明了bus_subsys——总线子系统
static decl_subsys(bus, &bus_ktype, &bus_uevent_ops);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//热插拔模块的支持函数
//这个模块的函数主要实现的是驱动和设备的绑定,解除,以及驱动的自动探测等功能
//这个函数名有点看似为帮助文件,实际是比较dev->bus_id(即kobj的名字)与data是否一致,是就返回1
static int driver_helper(struct device *dev, void *data)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//解除驱动的绑定,其核心操作是调用db.c文件中的device_release_driver函数
static ssize_t driver_unbind(
struct device_driver *drv,
const char *buf,
size_t count)
{
struct bus_type *bus = bus_get(drv->bus); //获取设备驱动中的总线
struct device *dev;
int err = -ENODEV;
//这个函数的实现在后面,从函数名我们不难猜出,这个函数的作用是从总线中找出和buf同名的设备来
dev = bus_find_device(bus, NULL, (void *)buf, driver_helper);
//设备找到,且设备的驱动是指定驱动
if (dev && dev->driver == drv) {
//设备的父设备存在,锁一下信号量
if (dev->parent) down(&dev->parent->sem);
device_release_driver(dev); //这个函数的实现在db.c文件中,看函数的注解,其作用是手动将驱动driver和设备device的连接断开
if (dev->parent) up(&dev->parent->sem);
err = count;
}
//释放引用计数
put_device(dev);
bus_put(bus);
return err;
}
//定义driver_attr_unbind属性
static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);
#define DRIVER_ATTR(_name,_mode,_show,_store) \
struct driver_attribute driver_attr_##_name = __ATTR(_name,_mode,_show,_store)
#define __ATTR(_name,_mode,_show,_store) { \
.attr = {.name = __stringify(_name), .mode = _mode }, \
.show = _show, \
.store = _store, \
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//驱动的绑定操作,其核心操作是调用db.c文件中的driver_probe_device函数
static ssize_t driver_bind(
struct device_driver *drv,
const char *buf,
size_t count)
{
struct bus_type *bus = bus_get(drv->bus);
struct device *dev;
int err = -ENODEV;
//从总线中找出buf指定名字的设备来
dev = bus_find_device(bus, NULL, (void *)buf, driver_helper);
//设备存在且没有绑定驱动
if (dev && dev->driver == NULL) {
//操作前锁信号量
if (dev->parent) down(&dev->parent->sem);
down(&dev->sem);
err = driver_probe_device(drv, dev); //为驱动探测对应的设备,函数的实现在db.c中,我们在分析这个文件的时候再做具体分析
up(&dev->sem);
if (dev->parent) up(&dev->parent->sem);
if (err > 0) /* success */
err = count;
else if (err == 0) /* driver didn't accept device */
err = -ENODEV;
}
//释放计数
put_device(dev);
bus_put(bus);
return err;
}
//定义driver_attr_bind属性
static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//bus->drivers_autoprobe是一个位,标记总线是否支持驱动的自动探测功能
//这个函数将该功能的支持打印进buf中
static ssize_t show_drivers_autoprobe(struct bus_type *bus, char *buf)
{
return sprintf(buf, "%d\n", bus->drivers_autoprobe);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//根据buf设置总线的drivers_autoprobe属性
static ssize_t store_drivers_autoprobe(
struct bus_type *bus,
const char *buf,
size_t count)
{
if (buf[0] == '0') bus->drivers_autoprobe = 0;
else bus->drivers_autoprobe = 1;
return count;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//在bus总线上探测buf指定名字的驱动是否存在
static ssize_t store_drivers_probe(
struct bus_type *bus,
const char *buf,
size_t count)
{
struct device *dev;
//在bus总线上找到buf指定的设备
dev = bus_find_device(bus, NULL, (void *)buf, driver_helper);
//设备不存在,错误返回
if (!dev) return -ENODEV;
//查找设备的驱动是否存在,存在就返回0,不存在就返回非0
//如果设备之前没有挂驱动,则这个函数中会调用device_attach(dev)来探测驱动
if (bus_rescan_devices_helper(dev, NULL) != 0) return -EINVAL;
return count;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
struct klist_iter {
struct klist * i_klist;
struct list_head * i_head;
struct klist_node * i_cur;
};
//找下一个设备,详细的执行代码在lib/klist.c文件中
//由于下面的代码将大量应用这个文件中的函数,所以先停下来看看这个文件的具体操作
static struct device *next_device(struct klist_iter * i)
{
struct klist_node * n = klist_next(i); //找到下一个节点
//节点存在则返回该节点所在的设备结构体宿主
return n ? container_of(n, struct device, knode_bus) : NULL;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//从start开始,查找bus->klist_devices中的每一个设备,并执行fn函数
//每执行完一个函数,就把该设备从总线上脱开
int bus_for_each_dev(
struct bus_type * bus, //总线
struct device * start, //开始设备
void * data, //fn的参数
int (*fn)(struct device *, void *))
{
struct klist_iter i;
struct device * dev;
int error = 0;
//总线为空,错误返回
if (!bus) return -EINVAL;
//初始化容器i,其klist为bus->klist_devices设备链表,当前设备为start设备
klist_iter_init_node(&bus->klist_devices, &i,
(start ? &start->knode_bus : NULL));
//找到下一个设备,执行fn函数
while ((dev = next_device(&i)) && !error)
error = fn(dev, data);
//释放当前设备
klist_iter_exit(&i);
return error;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//调用match函数,找到指定设备
struct device * bus_find_device(
struct bus_type *bus,
struct device *start,
void *data,
int (*match)(struct device *, void *))
{
struct klist_iter i;
struct device *dev;
klist_iter_init_node(&bus->klist_devices, &i,
(start ? &start->knode_bus : NULL));
while ((dev = next_device(&i)))
if (match(dev, data) && get_device(dev))
break;
klist_iter_exit(&i);
return dev;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//同next_device,查找下一个驱动
static struct device_driver * next_driver(struct klist_iter * i)
{
struct klist_node * n = klist_next(i); //获取下一个node节点
return n ? container_of(n, struct device_driver, knode_bus) : NULL;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//这个函数和bus_for_each_dev很像,不同的是他是从bus->klist_drivers链表中找驱动
int bus_for_each_drv(
struct bus_type * bus,
struct device_driver * start,
void * data,
int (*fn)(struct device_driver *, void *))
{
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//为设备创建属性(一个设备可以挂在多条总线上?)
static int device_add_attrs(struct bus_type *bus, struct device *dev)
{
int error = 0;
int i;
//总线的设备属性指针不存在,返回
if (!bus->dev_attrs) return 0;
//查找所有设置了name的attrs属性,执行create函数
for (i = 0; attr_name(bus->dev_attrs[i]); i++) {
error = device_create_file(dev, &bus->dev_attrs[i]);
if (error) {
while (--i >= 0)
device_remove_file(dev, &bus->dev_attrs[i]);
break;
}
}
return error;
}
//删除设备属性
static void device_remove_attrs(struct bus_type * bus, struct device * dev)
{
if (bus->dev_attrs) {
for (i = 0; attr_name(bus->dev_attrs[i]); i++)
device_remove_file(dev,&bus->dev_attrs[i]);
}
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//在总线上加设备,实际操作就是用sysfs_create_link函数创建链接
int bus_add_device(struct device * dev)
{
struct bus_type * bus = bus_get(dev->bus); //bus引用计数加1
int error = 0;
if (bus) { //只有总线存在时,这个函数才有意义
error = device_add_attrs(bus, dev); //添加设备属性
if (error) goto out_put;
//为两个obj创建连接
error = sysfs_create_link(&bus->devices.kobj,
&dev->kobj, dev->bus_id);
if (error) goto out_id;
//在sub子系统上创建链接
error = sysfs_create_link(&dev->kobj,
&dev->bus->subsys.kobj, "subsystem");
if (error) goto out_subsys;
//这是一个恒返回0的空函数
error = make_deprecated_bus_links(dev);
if (error) goto out_deprecated;
}
return 0;
out_deprecated:
sysfs_remove_link(&dev->kobj, "subsystem");
out_subsys: //subsystem子系统挂接失败
sysfs_remove_link(&bus->devices.kobj, dev->bus_id);
out_id: //创建链接失败
device_remove_attrs(bus, dev);
out_put: //添加设备属性失败
bus_put(dev->bus);
return error;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
void bus_attach_device(struct device * dev)
{
struct bus_type *bus = dev->bus;
int ret = 0;
//有指定总线才进行以下操作
if (bus) {
dev->is_registered = 1; //标记设备已注册
if (bus->drivers_autoprobe)
ret = device_attach(dev); //如果总线带有自动探测属性,则执行attach函数,该函数的实现在db.c中
//attach(固定)成功,ret大于0
//初始化dev->knode_bus节点,并将其挂到bus总线上
if (ret >= 0)
klist_add_tail(&dev->knode_bus, &bus->klist_devices);
else
dev->is_registered = 0; //设备没有固定到bus总线上,取消已注册标记
}
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//从总线上移走指定的设备,其操作就是add操作出错后的操作
void bus_remove_device(struct device * dev)
{
if (dev->bus) {
sysfs_remove_link(&dev->kobj, "subsystem");
remove_deprecated_bus_links(dev);
sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id);
device_remove_attrs(dev->bus, dev);
if (dev->is_registered) {
dev->is_registered = 0;
klist_del(&dev->knode_bus);
}
device_release_driver(dev); //释放驱动
bus_put(dev->bus);
}
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//关联驱动的属性,挂在指定总线下的驱动都会继承总线的全部attr属性
static int driver_add_attrs(struct bus_type * bus, struct device_driver * drv)
{
int error = 0;
int i;
if (bus->drv_attrs) {
for (i = 0; attr_name(bus->drv_attrs[i]); i++) {
error = driver_create_file(drv, &bus->drv_attrs[i]);
if (error) goto Err;
}
}
Done:
return error;
Err:
while (--i >= 0) driver_remove_file(drv, &bus->drv_attrs[i]);
goto Done;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
static void driver_remove_attrs(struct bus_type * bus, struct device_driver * drv)
驱动的移除,操作就是add操作的出错处理
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//创建驱动的属性文件
static int add_bind_files(struct device_driver *drv)
{
int ret;
//为驱动创建属性文件
ret = driver_create_file(drv, &driver_attr_unbind);
if (ret == 0) {
ret = driver_create_file(drv, &driver_attr_bind);
if (ret) driver_remove_file(drv, &driver_attr_unbind);
}
return ret;
}
//删除驱动的属性文件
static void remove_bind_files(struct device_driver *drv)
{
driver_remove_file(drv, &driver_attr_bind);
driver_remove_file(drv, &driver_attr_unbind);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//创建两个属性:bus_attr_drivers_probe和bus_attr_drivers_autoprobe
static BUS_ATTR(drivers_probe, S_IWUSR, NULL, store_drivers_probe);
static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO,
show_drivers_autoprobe, store_drivers_autoprobe);
//显示是否支持自动探测, 设置是否支持自动探测
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//为指定总线创建属性文件
static int add_probe_files(struct bus_type *bus)
{
int retval;
//bus_attr_drivers_probe和bus_attr_drivers_autoprobe这两个属性文件就在上面一点定义
retval = bus_create_file(bus, &bus_attr_drivers_probe);
if (retval) goto out;
retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);
if (retval) bus_remove_file(bus, &bus_attr_drivers_probe);
out:
return retval;
}
//删除指定总线上的探测属性文件
static void remove_probe_files(struct bus_type *bus)
{
bus_remove_file(bus, &bus_attr_drivers_autoprobe);
bus_remove_file(bus, &bus_attr_drivers_probe);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//根据buf指定的动作,执行驱动drv->uevent函数
static ssize_t driver_uevent_store(
struct device_driver *drv, //驱动
const char *buf, //指定的uevent动作
size_t count) //buf长度
{
enum kobject_action action;
if (kobject_action_type(buf, count, &action) == 0)
kobject_uevent(&drv->kobj, action);
return count;
}
//创建驱动属性driver_attr_uevent,关联上的设置函数是上面那个
static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//将驱动关联到总线上,具体的操作如下:
//1、将驱动kobj的父kset设置为bus->drivers,完成与bus的obj关联
//2、kobj在kset上注册
//3、如果总线drivers_autoprobe,则执行driver_attach函数关联驱动和设备
//4、将驱动节点knode挂到总线的drivers_klist链表下
//5、为驱动创建属性文件,包括:驱动自己的属性driver_attr_uevent,总线继承下来的属性,bind和unbind属性
int bus_add_driver(struct device_driver *drv)
{
struct bus_type * bus = bus_get(drv->bus); //总线引用加1
int error = 0;
if (!bus) return -EINVAL; //驱动没有挂上总线,失败
//给驱动的kobj赋名
error = kobject_set_name(&drv->kobj, "%s", drv->name);
if (error) goto out_put_bus;
//指定kobj的父kset,注册kobj到父kset中
drv->kobj.kset = &bus->drivers; //kobj的kset宿主指向总线的驱动宿主
error = kobject_register(&drv->kobj); //注册kobj到kset中(bus->drivers)
if (error) goto out_put_bus;
//总线带有驱动的自动探测属性
if (drv->bus->drivers_autoprobe) {
error = driver_attach(drv); //自动执行驱动的固定函数
if (error) goto out_unregister; //驱动固定失败
}
//将驱动的节点挂到总线的驱动链表上
klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
//这个函数应该是挂载模块的,我们暂时忽略
module_add_driver(drv->owner, drv);
//为驱动创建属性文件,主要是创建driver_uevent_store关联
error = driver_create_file(drv, &driver_attr_uevent);
//将总线上的属性关联到驱动中(挂在总线下的驱动都要继承总线的attr)
error = driver_add_attrs(bus, drv);
//为驱动创建bind和unbind属性
error = add_bind_files(drv);
//返回
return error;
out_unregister: //驱动在总线上关联失败
kobject_unregister(&drv->kobj);
out_put_bus: //驱动的kobj赋名失败, 注册kobj失败
bus_put(bus); //释放总线引用
return error;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//从总线上移除驱动
void bus_remove_driver(struct device_driver * drv)
{
if (!drv->bus) return;
remove_bind_files(drv);
driver_remove_attrs(drv->bus, drv);
driver_remove_file(drv, &driver_attr_uevent);
klist_remove(&drv->knode_bus);
driver_detach(drv);
module_remove_driver(drv);
kobject_unregister(&drv->kobj);
bus_put(drv->bus);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//重新扫描设备,具体的操作是,如果设备的驱动没有指定,则调用device_attach
static int bus_rescan_devices_helper(struct device *dev, void *data)
{
int ret = 0;
if (!dev->driver)
ret = device_attach(dev);
return ret < 0 ? ret : 0;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//遍历总线上的每一个设备,调用他的rescan函数
int bus_rescan_devices(struct bus_type * bus)
{
return bus_for_each_dev(bus, NULL, NULL, bus_rescan_devices_helper);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//设备的重新探测:释放设备之前关联的驱动,然后bus_rescan_devices_helper重新探测设备驱动
int device_reprobe(struct device *dev)
{
if (dev->driver) {
device_release_driver(dev);
}
return bus_rescan_devices_helper(dev, NULL);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//为总线创建属性文件
static int bus_add_attrs(struct bus_type * bus)
{
int error = 0;
if (bus->bus_attrs) {
for (i = 0; attr_name(bus->bus_attrs[i]); i++) {
error = bus_create_file(bus,&bus->bus_attrs[i]);
if (error) goto Err;
}
}
Done:
return error;
Err:
while (--i >= 0) bus_remove_file(bus,&bus->bus_attrs[i]);
goto Done;
}
//删除总线的属性文件
static void bus_remove_attrs(struct bus_type * bus)
{
int i;
if (bus->bus_attrs) {
for (i = 0; attr_name(bus->bus_attrs[i]); i++)
bus_remove_file(bus,&bus->bus_attrs[i]);
}
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//通过node获得设备,然后引用/释放设备计数
static void klist_devices_get(struct klist_node *n)
{
struct device *dev = container_of(n, struct device, knode_bus);
get_device(dev);
}
static void klist_devices_put(struct klist_node *n)
{
struct device *dev = container_of(n, struct device, knode_bus);
put_device(dev);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//执行总线的uevent函数
static ssize_t bus_uevent_store(
struct bus_type *bus,
const char *buf,
size_t count)
{
enum kobject_action action;
if (kobject_action_type(buf, count, &action) == 0)
kobject_uevent(&bus->subsys.kobj, action);
return count;
}
//声明bus_attr_uevent属性
static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//总线的注册,主要操作如下:
//1、总线子系统的kobj命名为bus->name
//2、将总线kobj.kset设置为bus_subsys,并完成bus_subsys的注册
//3、为bus总线创建uevent属性文件(操作)
//4、设置总线上的设备链表(kobj命名,父设备指定为bus_subsys.kobj,kset节点的注册)
//5、设置总线上驱动链表,方法同设备链表,只是多了ktype操作(show,store设置probe)
//6、初始化总线上的设备和驱动klist,设备klist上挂有get和put
//7、初始化bus带autoprobe属性,为总线加上probe和autoprobe操作
//8、为bus加上bus_attrs[]属性
int bus_register(struct bus_type * bus)
{
int retval;
//网上查了下这个宏,无果。从宏名可以看出,这个宏应该是初始化通知头的
BLOCKING_INIT_NOTIFIER_HEAD(&bus->bus_notifier);
//kobj命名bus->name
retval = kobject_set_name(&bus->subsys.kobj, "%s", bus->name);
if (retval) goto out;
//设置父kset为总线子系统
bus->subsys.kobj.kset = &bus_subsys;
//注册子系统
retval = subsystem_register(&bus->subsys);
if (retval) goto out;
//创建bus的属性文件
retval = bus_create_file(bus, &bus_attr_uevent);
if (retval) goto bus_uevent_fail;
//设置总线中设备节点的名字
kobject_set_name(&bus->devices.kobj, "devices");
//设备节点的父节点为总线子系统
bus->devices.kobj.parent = &bus->subsys.kobj;
//注册设备节点的kset
retval = kset_register(&bus->devices);
if (retval) goto bus_devices_fail;
//设置总线中的驱动节点,操作同设备节点
kobject_set_name(&bus->drivers.kobj, "drivers");
bus->drivers.kobj.parent = &bus->subsys.kobj;
bus->drivers.ktype = &driver_ktype; //驱动有关联ktype
retval = kset_register(&bus->drivers);
if (retval) goto bus_drivers_fail;
//初始化设备链表和驱动链表
klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put);
klist_init(&bus->klist_drivers, NULL, NULL);
//设置总线的驱动自动探测属性
bus->drivers_autoprobe = 1;
retval = add_probe_files(bus); //为总线加上probe和autoprobe属性
if (retval) goto bus_probe_files_fail;
//为总线加上bus_attrs[]属性
retval = bus_add_attrs(bus);
if (retval) goto bus_attrs_fail;
return 0;
bus_attrs_fail: //attrs属性加载失败
remove_probe_files(bus);
bus_probe_files_fail: //probe属性加载失败
kset_unregister(&bus->drivers);
bus_drivers_fail: //驱动节点注册失败
kset_unregister(&bus->devices);
bus_devices_fail: //设备节点注册失败
bus_remove_file(bus, &bus_attr_uevent);
bus_uevent_fail: //属性文件创建失败
subsystem_unregister(&bus->subsys);
out: //kobj命名失败,子系统注册失败
return retval;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
void bus_unregister(struct bus_type * bus)
{
bus_remove_attrs(bus);
remove_probe_files(bus);
kset_unregister(&bus->drivers);
kset_unregister(&bus->devices);
bus_remove_file(bus, &bus_attr_uevent); //删除总线属性
subsystem_unregister(&bus->subsys);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//注册总线通知(通过代码关联,调用这个函数的地方似乎没有)
int bus_register_notifier(struct bus_type *bus, struct notifier_block *nb)
{
return blocking_notifier_chain_register(&bus->bus_notifier, nb);
}
//反注册总线通知
int bus_unregister_notifier(struct bus_type *bus, struct notifier_block *nb)
{
return blocking_notifier_chain_unregister(&bus->bus_notifier, nb);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//总线的初始化,系统启动时调用
//操作是注册总线子系统
int __init buses_init(void)
{
return subsystem_register(&bus_subsys);
}