文件小结:
读完这个文件的代码,其实这个文件实现的最关键的代码就是device_add函数,这个函数之前的所有函数都是为这个函数服务的。而这个函数之后的函数则很简单,基本和这个函数互相映衬了。而device_add函数在后面分析平台设备的时候,平台设备的添加platform_device_add函数则主要调用了该函数
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
函数列表:
const char *dev_driver_string(struct device *dev);
返回驱动的name。
定义了几个属性文件:
void device_initialize(struct device *dev);
初始化device,这里设置了dev->kobj->kset的关联
int device_add(struct device *dev)
这个函数很大,主要是将dev加入到他所属的总线,类,父设备等各个包含单元中。
或者说将设备添加进设备设备模型中。调用顺序一般是device_create -> device_register -> device_add()。一般device_register见得多点
这个函数可以说是core.c这个文件的主体,在这个函数之前的大部分static函数都是为他做准备的。
void device_del(struct device * dev)
add的反过程
int device_for_each_child(struct device * parent, void * data,
int (*fn)(struct device *, void *))
从parent链表中取出每一个设备,执行fn()函数
struct device * device_find_child(struct device *parent, void *data,
int (*match)(struct device *, void *))
从parent链表中取出每一个设备,执行match()函数,匹配成功则返回该设备
int __init devices_init(void)
设备的初始化,在这个地方,我们又重温了一次kobject.c文件中的kset注册
struct device *device_create(struct class *class, struct device *parent,
dev_t devt, const char *fmt, ...)
创建一个新的设备,其核心还是device_add函数
void device_destroy(struct class *class, dev_t devt)
从指定的class中找到指定版本号devt的设备,销毁
int device_rename(struct device *dev, char *new_name)
重命名device,其中调用了obj的重命名函数对dev->obj也进行重命名
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//返回驱动的name,按优先级依次寻找driver->name,bus->name,class->name,如果都没有设置,则返回NULL
const char *dev_driver_string(struct device *dev)
{
return dev->driver ? dev->driver->name :
(dev->bus ? dev->bus->name :
(dev->class ? dev->class->name : ""));
}
EXPORT_SYMBOL(dev_driver_string);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#define to_dev(obj) container_of(obj, struct device, kobj)
#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//调用attr->show()显示函数将显示内容打印进buf中。
static ssize_t dev_attr_show(
struct kobject *kobj,
struct attribute *attr,
char *buf)
{
struct device_attribute *dev_attr = to_dev_attr(attr); //获取属性结构体
struct device * dev = to_dev(kobj); //根据obj获取设备
ssize_t ret = -EIO;
if (dev_attr->show) //有显示命令,则调用show()函数显示
ret = dev_attr->show(dev, dev_attr, buf);
return ret;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//调用attr->store()函数
static ssize_t dev_attr_store(
struct kobject *kobj,
struct attribute *attr,
const char *buf,
size_t count)
{
struct device_attribute *dev_attr = to_dev_attr(attr);
struct device *dev = to_dev(kobj);
ssize_t ret = -EIO;
if (dev_attr->store)
ret = dev_attr->store(dev, dev_attr, buf, count);
return ret;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//系统操作
static struct sysfs_ops dev_sysfs_ops = {
.show = dev_attr_show,
.store = dev_attr_store,
};
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//调用release函数,按优先级顺序依次查找dev的release(),dev->type->release(),dev->class->dev_release()
static void device_release(struct kobject *kobj)
{
struct device *dev = to_dev(kobj);
if (dev->release) //设备的释放函数
dev->release(dev);
else if (dev->type && dev->type->release) //类型的释放函数
dev->type->release(dev);
else if (dev->class && dev->class->dev_release) //类的释放函数
dev->class->dev_release(dev);
else {
//没有关联release函数
WARN_ON(1);
}
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
static struct kobj_type device_ktype = {
.release = device_release, //释放函数
.sysfs_ops = &dev_sysfs_ops, //操作函数(show, store)
};
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//对uevent事件(热插拔)过滤
//从后面的一个调用可以看出,返回0则说明过滤成功,调用者将直接退出
static int dev_uevent_filter(
struct kset *kset,
struct kobject *kobj)
{
//定义在kobject.h中,返回kobj->kset的ktype或者kobj的ktype
struct kobj_type *ktype = get_ktype(kobj);
//如果是刚才设置的默认的device_ktype,则执行
if (ktype == &device_ktype) {
struct device *dev = to_dev(kobj); //获取kobj所在的dev
if (dev->uevent_suppress) //支持uevent
return 0;
if (dev->bus) //有设置总线
return 1;
if (dev->class) //有设置类
return 1;
}
return 0;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//返回总线的名字或者类的名字。
static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj)
{
struct device *dev = to_dev(kobj);
if (dev->bus)
return dev->bus->name;
if (dev->class)
return dev->class->name;
return NULL;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//依次执行kobj所在设备dev的uevent()函数,顺序分别为:bus总线,class类,设备的type
//从代码来看,这个函数似乎只是将设备ID给打印了出来
static int dev_uevent(
struct kset *kset,
struct kobject *kobj,
struct kobj_uevent_env *env)
{
struct device *dev = to_dev(kobj);
int retval = 0;
//打印主次版本号,type名,驱动名
if (MAJOR(dev->devt)) {
add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt));
add_uevent_var(env, "MINOR=%u", MINOR(dev->devt));
}
if (dev->type && dev->type->name)
add_uevent_var(env, "DEVTYPE=%s", dev->type->name);
if (dev->driver)
add_uevent_var(env, "DRIVER=%s", dev->driver->name);
//如果总线bus->uevent()函数有指定,则执行
if (dev->bus && dev->bus->uevent) {
retval = dev->bus->uevent(dev, env);
if (retval)
pr_debug ("%s: bus uevent() returned %d\n",
__FUNCTION__, retval);
}
//执行类的class->dev_uevent()函数
if (dev->class && dev->class->dev_uevent) {
retval = dev->class->dev_uevent(dev, env);
if (retval)
pr_debug("%s: class uevent() returned %d\n",
__FUNCTION__, retval);
}
//执行类型的type->uevent()函数
if (dev->type && dev->type->uevent) {
retval = dev->type->uevent(dev, env);
if (retval)
pr_debug("%s: dev_type uevent() returned %d\n",
__FUNCTION__, retval);
}
return retval;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//这个结构体我们在分析kobject.c中已经见过了。
static struct kset_uevent_ops device_uevent_ops = {
.filter = dev_uevent_filter, //热插拨过滤函数
.name = dev_uevent_name, //返回总线或类名
.uevent = dev_uevent, //执行热插拔函数
};
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//找到dev->kobj的最顶层obj,调用kset->uevent()函数
//作用似乎是调用uevent打印主次版本号,各种名字
//返回的是字符串长度
static ssize_t show_uevent(
struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct kobject *top_kobj;
struct kset *kset;
struct kobj_uevent_env *env = NULL;
int i;
size_t count = 0;
int retval;
//找到最顶层的kobj,如果没有关联uevnet,则退出
top_kobj = &dev->kobj; //获取设备的obj
while (!top_kobj->kset && top_kobj->parent) //反查到最顶层的obj
top_kobj = top_kobj->parent;
if (!top_kobj->kset)
goto out;
//获取最顶层obj的宿主
kset = top_kobj->kset;
if (!kset->uevent_ops || !kset->uevent_ops->uevent)
goto out;
//执行filter()过滤函数
if (kset->uevent_ops && kset->uevent_ops->filter)
if (!kset->uevent_ops->filter(kset, &dev->kobj))
goto out; //返回0则退出
//申请一块内存,调用uevent()函数
env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
if (!env)
return -ENOMEM;
//执行uevent函数
retval = kset->uevent_ops->uevent(kset, &dev->kobj, env);
if (retval)
goto out;
/* copy keys to file */
for (i = 0; i < env->envp_idx; i++)
count += sprintf(&buf[count], "%s\n", env->envp[i]); // sprintf返回的是字符串长度
//这里会不会overflow?
out:
kfree(env);
return count;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//调用kobject_uevent执行buf中的动作,如果buf中指定的动作不合法,则按KOBJ_ADD来执行,kobject_uevent的实现函数在kobject的uevent文件中
static ssize_t store_uevent(
struct device *dev,
struct device_attribute *attr,
const char *buf, //动作名
size_t count) //动作名长度
{
enum kobject_action action; //返回的动作类型
//查看buf中的字符串是否和aciton中的一致,一致就用该action执行
if (kobject_action_type(buf, count, &action) == 0) {
kobject_uevent(&dev->kobj, action); //buf内容合法,执行动作
goto out;
}
kobject_uevent(&dev->kobj, KOBJ_ADD); //buf内容不合法,按KOBJ_ADD执行动作
out:
return count;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
static struct device_attribute uevent_attr =
__ATTR(uevent, S_IRUGO | S_IWUSR, show_uevent, store_uevent);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//根据属性attrs创建文件
//这个函数在下面的device_add_attrs函数中被调用
static int device_add_attributes(
struct device *dev,
struct device_attribute *attrs)
{
int error = 0;
int i;
if (attrs) {
//根据属性创建文件
for (i = 0; attr_name(attrs[i]); i++) {
error = device_create_file(dev, &attrs[i]);
if (error)
break;
}
if (error) //出错,删除刚创建的文件
while (--i >= 0)
device_remove_file(dev, &attrs[i]);
}
return error;
}
//删除属性文件
//这个函数在下面的device_add_attrs函数中被调用
static void device_remove_attributes(
struct device *dev,
struct device_attribute *attrs)
{
int i;
if (attrs)
for (i = 0; attr_name(attrs[i]); i++)
device_remove_file(dev, &attrs[i]);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//创建文件夹
//这个函数在下面的device_add_attrs函数中被调用
static int device_add_groups(
struct device *dev,
struct attribute_group **groups)
{
int error = 0;
int i;
if (groups) {
for (i = 0; groups[i]; i++) {
error = sysfs_create_group(&dev->kobj, groups[i]);
if (error) {
while (--i >= 0)
sysfs_remove_group(&dev->kobj, groups[i]);
break;
}
}
}
return error;
}
//删除文件夹
//这个函数在下面的device_add_attrs函数中被调用
static void device_remove_groups(struct device *dev,
struct attribute_group **groups)
{
int i;
if (groups)
for (i = 0; groups[i]; i++)
sysfs_remove_group(&dev->kobj, groups[i]);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//为设备创建属性文件
static int device_add_attrs(struct device *dev)
{
struct class *class = dev->class;
struct device_type *type = dev->type;
int error;
if (class) {
//类存在,则根据设备属性创建文件
error = device_add_attributes(dev, class->dev_attrs);
}
if (type) {
//type存在,则根据组创建文件夹
error = device_add_groups(dev, type->groups);
}
error = device_add_groups(dev, dev->groups);
return 0;
}
//删除相关的文件
static void device_remove_attrs(struct device *dev)
{
struct class *class = dev->class;
struct device_type *type = dev->type;
device_remove_groups(dev, dev->groups);
if (type)
device_remove_groups(dev, type->groups);
if (class)
device_remove_attributes(dev, class->dev_attrs);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//又是一个属性文件
static struct device_attribute devt_attr =
__ATTR(dev, S_IRUGO, show_dev, NULL);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
decl_subsys(devices, &device_ktype, &device_uevent_ops);
//kset的结构体可以参照kobject.h来看
#define decl_subsys(_name, _type, _uevent_ops) \
struct kset _name##_subsys = { \ //devices_subsys
.kobj = { .k_name = __stringify(_name) }, \
.ktype = _type, \
.uevent_ops =_uevent_ops, \
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//根据属性attr创建设备的属性文件(节点)
int device_create_file(
struct device *dev,
struct device_attribute *attr)
{
int error = 0;
if (get_device(dev)) { //dev的引用记数加1
error = sysfs_create_file(&dev->kobj, &attr->attr);
put_device(dev); //释放dev的引用计数
}
return error;
}
//删除属性文件
void device_remove_file(struct device * dev, struct device_attribute * attr)
{
if (get_device(dev)) {
sysfs_remove_file(&dev->kobj, &attr->attr);
put_device(dev);
}
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//创建二进制的属性文件
int device_create_bin_file(struct device *dev, struct bin_attribute *attr)
{
int error = -EINVAL;
if (dev)
error = sysfs_create_bin_file(&dev->kobj, attr);
return error;
}
EXPORT_SYMBOL_GPL(device_create_bin_file);
//删除二进制的属性文件
void device_remove_bin_file(struct device *dev, struct bin_attribute *attr)
{
if (dev)
sysfs_remove_bin_file(&dev->kobj, attr);
}
EXPORT_SYMBOL_GPL(device_remove_bin_file);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//这个函数先不管,和任务调度有关的
int device_schedule_callback_owner(
struct device *dev,
void (*func)(struct device *),
struct module *owner)
{
return sysfs_schedule_callback(&dev->kobj,
(void (*)(void *)) func, dev, owner);
}
EXPORT_SYMBOL_GPL(device_schedule_callback_owner);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//根据node获取device结构体,然后引用/释放一个记数
//这里的计数实际是引用dev->kobj的计数
static void klist_children_get(struct klist_node *n)
{
struct device *dev = container_of(n, struct device, knode_parent);
get_device(dev);
}
static void klist_children_put(struct klist_node *n)
{
struct device *dev = container_of(n, struct device, knode_parent);
put_device(dev);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//对device进行初始化,最需要注意的一个操作就是将kobj->kset关联上了devices_subsys
void device_initialize(struct device *dev)
{
//dev->kobj.kset = & devices_subsys,设置kset
kobj_set_kset_s(dev, devices_subsys);
kobject_init(&dev->kobj); //初始化obj
//初始化设备的子设备链表为空
klist_init(&dev->klist_children,
klist_children_get,
klist_children_put);
//初始化设备的DMA,节点链表为空
INIT_LIST_HEAD(&dev->dma_pools);
INIT_LIST_HEAD(&dev->node);
//初始化设备的互斥锁
init_MUTEX(&dev->sem);
spin_lock_init(&dev->devres_lock); //自旋锁
INIT_LIST_HEAD(&dev->devres_head);
device_init_wakeup(dev, 0); //初始化本设备无唤醒功能
set_dev_node(dev, -1); //非NUMA下是空函数
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//在devices_subsys下创建挂载一个虚拟子obj,取名为virtual
//这个函数的输入参数无意义
static struct kobject *virtual_device_parent(struct device *dev)
{
static struct kobject *virtual_dir = NULL;
//由于初始给的值就是NULL,所以这个if恒满足
if (!virtual_dir)
virtual_dir = kobject_add_dir(&devices_subsys.kobj, "virtual");
return virtual_dir;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//获取父设备的obj
static struct kobject *get_device_parent(
struct device *dev,
struct device *parent)
{
//设备有注册类
if (dev->class) {
struct kobject *kobj = NULL;
struct kobject *parent_kobj;
struct kobject *k;
if (parent == NULL) //没有父设备,创建一个虚拟的obj
parent_kobj = virtual_device_parent(dev); //输入参数dev无意义,虚拟设备在devices_subsys下,返回的是新建立的那个虚拟kobj
else if (parent->class) //父设备有类
return &parent->kobj; //返回父设备的obj
else
parent_kobj = &parent->kobj; //父设备无关联的类
//从dev->class的所有目录中找寻parent相同的obj
spin_lock(&dev->class->class_dirs.list_lock);
list_for_each_entry(k, &dev->class->class_dirs.list, entry)
if (k->parent == parent_kobj) {
kobj = kobject_get(k); //引用计数加1
break;
}
spin_unlock(&dev->class->class_dirs.list_lock);
//obj找到
if (kobj)
return kobj;
//obj没有找到,新建一个obj
return kobject_kset_add_dir(&dev->class->class_dirs,
parent_kobj, dev->class->name);
}
//dev->class没有注册,返回父设备的obj
if (parent)
return &parent->kobj;
return NULL;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//设置dev的父设备
static int setup_parent(struct device *dev, struct device *parent)
{
struct kobject *kobj;
kobj = get_device_parent(dev, parent); //获取dev的父设备obj
if (IS_ERR(kobj))
return PTR_ERR(kobj);
if (kobj) //设置dev的父设备
dev->kobj.parent = kobj;
return 0;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//创建一些文件链接
static int device_add_class_symlinks(struct device *dev)
{
}
//删除文件链接
static void device_remove_class_symlinks(struct device *dev)
{
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//本函数所做工作是一大串的关联函数,将设备dev加入到总线,类等链表中
int device_add(struct device *dev)
{
struct device *parent = NULL;
struct class_interface *class_intf;
int error = -EINVAL;
//将dev->kobj的引用加1
dev = get_device(dev);
if (!dev || !strlen(dev->bus_id)) //dev为空,或则bus_id为空
goto Error;
//获取dev的父设备
parent = get_device(dev->parent); //父设备的引用加1,由于parent初始为NULL,所以这里没有引用,返回NULL
error = setup_parent(dev, parent); //dev->kobj.parent=parent.kobj,由于parent为NULL,所以这里关联的也就是NULL了
if (error)
goto Error;
//将dev->bus_id的名字(总线名)设置给dev->kobj
kobject_set_name(&dev->kobj, "%s", dev->bus_id);
error = kobject_add(&dev->kobj); //将kobj添加进kset链表
if (error)
goto Error;
//如果这个函数不为空,则执行这个函数
//实际这个函数是空的,平台函数
if (platform_notify)
platform_notify(dev);
//设备有指定总线,调用总线的bus_notifier()函数,通知系统加了一个设备
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->bus_notifier,
BUS_NOTIFY_ADD_DEVICE, dev);
//根据uevent属性创建文件
error = device_create_file(dev, &uevent_attr);
if (error)
goto attrError;
//如果devt的主版本号存在,创建属性文件
if (MAJOR(dev->devt)) {
error = device_create_file(dev, &devt_attr);
if (error)
goto ueventattrError;
}
//添加类链接
error = device_add_class_symlinks(dev);
if (error)
goto SymlinkError;
//添加属性文件
error = device_add_attrs(dev);
if (error)
goto AttrsError;
//这个函数和文件系统有关,先忽略
error = dpm_sysfs_add(dev);
if (error)
goto PMError;
//添加设备到电源管理链表中
device_pm_add(dev);
//添加设备属性到dev->bus中
error = bus_add_device(dev);
if (error)
goto BusError;
//执行dev->kobj->kset的uevent函数
kobject_uevent(&dev->kobj, KOBJ_ADD);
//attach设备(设备关联到总线上)
bus_attach_device(dev);
//如果父设备存在,将本设备挂在父设备的链表(parent->klist_children)上
if (parent)
klist_add_tail(&dev->knode_parent, &parent->klist_children);
//如果类存在,将设备挂在类链表上
//获取dev->class的所有接口,调用接口的add_dev函数,将dev关联上去
if (dev->class) {
down(&dev->class->sem);
list_add_tail(&dev->node, &dev->class->devices);
list_for_each_entry(class_intf, &dev->class->interfaces, node)
if (class_intf->add_dev)
class_intf->add_dev(dev, class_intf);
up(&dev->class->sem);
}
Done:
put_device(dev);
return error;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//设备的注册
int device_register(struct device *dev)
{
device_initialize(dev); //将dev的设置全部初始化
return device_add(dev); //添加设备
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//引用/释放dev,其实核心操作只是对dev->kobj进行引用和释放计数
struct device *get_device(struct device * dev)
{
return dev ? to_dev(kobject_get(&dev->kobj)) : NULL;
}
void put_device(struct device * dev)
{
if (dev)
kobject_put(&dev->kobj);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//删除只是add的反过程
void device_del(struct device * dev)
{
struct device *parent = dev->parent;
struct class_interface *class_intf;
if (parent) //从父设备链表中删除自己
klist_del(&dev->knode_parent);
if (MAJOR(dev->devt)) //如果设备版本号存在,则删除设备的属性文件
device_remove_file(dev, &devt_attr);
if (dev->class) { //如果设备的类存在
sysfs_remove_link(&dev->kobj, "subsystem"); //删除subsystem下的链接
if (dev->kobj.parent != &dev->class->subsys.kobj)
sysfs_remove_link(&dev->class->subsys.kobj,
dev->bus_id);
if (parent) { //在device文件夹下删除目标
sysfs_remove_link(&dev->kobj, "device");
}
//遍历类的接口,调用remove()函数删除设备
down(&dev->class->sem);
list_for_each_entry(class_intf, &dev->class->interfaces, node)
if (class_intf->remove_dev)
class_intf->remove_dev(dev, class_intf);
list_del_init(&dev->node);
up(&dev->class->sem);
//kset为class的目录
if (dev->kobj.parent->kset == &dev->class->class_dirs) {
struct device *d;
int other = 0;
//遍历class的devices链表,取出每一个节点,查找是否有dev的兄弟节点存在,如果兄弟节点不存在,则删除dev的父节点
down(&dev->class->sem);
list_for_each_entry(d, &dev->class->devices, node) {
if (d == dev)
continue;
if (d->kobj.parent == dev->kobj.parent) {
other = 1;
break;
}
}
if (!other)
kobject_del(dev->kobj.parent);
kobject_put(dev->kobj.parent); //父节点的引用计数释放
up(&dev->class->sem);
}
}
//删除文件,删除属性,从总线上删除设备
device_remove_file(dev, &uevent_attr);
device_remove_attrs(dev);
bus_remove_device(dev);
//释放全部节点
devres_release_all(dev);
//调用总线上的函数
if (platform_notify_remove)
platform_notify_remove(dev);
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->bus_notifier,
BUS_NOTIFY_DEL_DEVICE, dev);
device_pm_remove(dev);
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
kobject_del(&dev->kobj);
if (parent)
put_device(parent);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//设备的反注册函数
void device_unregister(struct device *dev)
{
device_del(dev); //直接调用设备的删除函数
put_device(dev); //释放设备的计数
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//从链表中获取下一个设备
static struct device *next_device(struct klist_iter * i)
{
struct klist_node *n = klist_next(i);
return n ? container_of(n, struct device, knode_parent) : NULL;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//从parent链表中取出每一个设备,执行fn()函数
struct device *parent,
void *data, //fn的参数
int (*fn)(struct device *, void *))
{
struct klist_iter i; //klist_iter是klist的集合
struct device * child;
int error = 0;
klist_iter_init(&parent->klist_children, &i);
while ((child = next_device(&i)) && !error)
error = fn(child, data);
klist_iter_exit(&i);
return error;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//从parent链表中取出每一个设备,执行match()函数,匹配成功则返回该设备
struct device *device_find_child(struct device *parent, void *data,
int (*match)(struct device *, void *))
{
struct klist_iter i;
struct device *child;
if (!parent) //父设备为空,返回NULL
return NULL;
klist_iter_init(&parent->klist_children, &i);
while ((child = next_device(&i)))
if (match(child, data) && get_device(child))
break;
klist_iter_exit(&i);
return child;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//注册子系统,这个函数的实现在kobject.c中
int __init devices_init(void)
{
return subsystem_register(&devices_subsys);
}
struct kset devices_subsys={
.kobj={ .k_name = devices, },
.ktype = &device_ktype,
.uevent_ops = &device_uevent_ops,
}
int subsystem_register(struct kset *s)
{
return kset_register(s);
}
int kset_register(struct kset * k)
{
//k->kobj->refcount=1
//k->kobj->entry=NULL
//k->kobj->kset= k->kobj->kset (NULL)
//k->list=NULL
kset_init(k);
//这一步只是根据k->kobj的属性创建文件
err = kset_add(k);
//执行kset-> uevent_ops->uevent,参数传的是ADD,也就是执行dev_uevent函数
kobject_uevent(&k->kobj, KOBJ_ADD);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//创建设备,这个函数中会依次调用reg和add设备
//这个函数其实很简单,所以最后关键的核心还是在于device_add函数
struct device *device_create(
struct class *class, //类
struct device *parent, //父指针
dev_t devt, //设备的版本号
const char *fmt, ...) //设置为dev->bus_id
{
va_list args;
struct device *dev = NULL;
int retval = -ENODEV;
//类为空,类错误,返回
if (class == NULL || IS_ERR(class))
goto error;
//申请一块内存,并设置成员
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev) {
retval = -ENOMEM;
goto error;
}
dev->devt = devt;
dev->class = class;
dev->parent = parent;
dev->release = device_create_release; //默认的release函数,kfree(dev);
va_start(args, fmt);
vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args);
va_end(args);
//调用注册函数注册设备
retval = device_register(dev);
if (retval)
goto error;
return dev;
error:
kfree(dev);
return ERR_PTR(retval);
}
EXPORT_SYMBOL_GPL(device_create);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
void device_destroy(struct class *class, dev_t devt)
{
struct device *dev = NULL;
struct device *dev_tmp;
//从class的设备链表中取出devt(版本号)相等的设备
down(&class->sem);
list_for_each_entry(dev_tmp, &class->devices, node) {
if (dev_tmp->devt == devt) {
dev = dev_tmp;
break;
}
}
up(&class->sem);
//设备存在,卸载设备
if (dev)
device_unregister(dev);
}
EXPORT_SYMBOL_GPL(device_destroy);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//设备重命名
int device_rename(struct device *dev, char *new_name)
{
char *old_class_name = NULL;
char *new_class_name = NULL;
char *old_device_name = NULL;
int error;
dev = get_device(dev); //dev引用计数加1
if (!dev)
return -EINVAL;
//申请一片内存保存旧名
old_device_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL);
if (!old_device_name) {
error = -ENOMEM;
goto out;
}
strlcpy(old_device_name, dev->bus_id, BUS_ID_SIZE);
strlcpy(dev->bus_id, new_name, BUS_ID_SIZE);
//将dev所带的kobj也重命名
error = kobject_rename(&dev->kobj, new_name);
if (error) { //出错,恢复旧名
strlcpy(dev->bus_id, old_device_name, BUS_ID_SIZE);
goto out;
}
//设备类存在
if (dev->class) { //重建链接
sysfs_remove_link(&dev->class->subsys.kobj, old_device_name);
error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
dev->bus_id);
}
}
out:
put_device(dev); //释放dev引用计数
kfree(new_class_name);
kfree(old_class_name);
kfree(old_device_name); //释放内存
return error;
}
EXPORT_SYMBOL_GPL(device_rename);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//移除/重新关联联接
static int device_move_class_links(
struct device *dev,
struct device *old_parent,
struct device *new_parent)
{
int error = 0;
if (old_parent)
sysfs_remove_link(&dev->kobj, "device");
if (new_parent)
error = sysfs_create_link(&dev->kobj, &new_parent->kobj,
"device");
return error;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//设备移动
int device_move(
struct device *dev,
struct device *new_parent)
{
int error;
struct device *old_parent;
struct kobject *new_parent_kobj;
dev = get_device(dev);
if (!dev)
return -EINVAL;
//获取设备,父设备的obj
new_parent = get_device(new_parent);
new_parent_kobj = get_device_parent (dev, new_parent);
if (IS_ERR(new_parent_kobj)) {
error = PTR_ERR(new_parent_kobj);
put_device(new_parent);
goto out;
}
//移动kobj
error = kobject_move(&dev->kobj, new_parent_kobj);
if (error) {
put_device(new_parent);
goto out;
}
//修正父设备指向
old_parent = dev->parent;
dev->parent = new_parent;
if (old_parent) //断开设备在旧父设备中的链接
klist_remove(&dev->knode_parent);
if (new_parent) //将设备插入到新父设备的链表中
klist_add_tail(&dev->knode_parent, &new_parent->klist_children);
//下面这部分是修正class中的链接,其实原理都一样的
if (!dev->class)
goto out_put;
error = device_move_class_links(dev, old_parent, new_parent);
if (error) {
device_move_class_links(dev, new_parent, old_parent);
if (!kobject_move(&dev->kobj, &old_parent->kobj)) {
if (new_parent)
klist_remove(&dev->knode_parent);
if (old_parent)
klist_add_tail(&dev->knode_parent,
&old_parent->klist_children);
}
put_device(new_parent);
goto out;
}
out_put:
put_device(old_parent);
out:
put_device(dev);
return error;
}
EXPORT_SYMBOL_GPL(device_move);