GSC3280的ADC子系统驱动模型(三)----class的使用
2014-03-19 11:55
218 查看
一个类是一个设备的高层视图,它抽象掉了底层的实现细节。例如,在驱动层面时,你可能会见到SCSI磁盘或者ATA磁盘;但在类层面时,它们都是磁盘。类允许用户空间基于它们做什么来使用设备,而不是它们如何被连接或者它们如何工作。
在《GSC3280的ADC子系统驱动模型(一)》的3.1,程序adc_class
= class_create(THIS_MODULE,
"adc");产生一个class,class_create()函数如下:
点击(此处)折叠或打开
struct class
{
const char *name;
struct module *owner;
struct class_attribute *class_attrs;
struct device_attribute *dev_attrs;
struct bin_attribute *dev_bin_attrs;
struct kobject *dev_kobj;
int (*dev_uevent)(struct device
*dev, struct kobj_uevent_env
*env);
char *(*devnode)(struct device
*dev, mode_t
*mode);
void (*class_release)(struct
class *class);
void (*dev_release)(struct device
*dev);
int (*suspend)(struct device
*dev, pm_message_t state);
int (*resume)(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;
};
#define class_create(owner, name) \
({ \
static struct lock_class_key __key; \
__class_create(owner, name,
&__key); \
})
struct class *__class_create(struct module
*owner,
const char *name,
struct lock_class_key *key)
{
struct class
*cls;
int retval;
cls = kzalloc(sizeof(*cls), GFP_KERNEL);
if (!cls)
{
retval =
-ENOMEM;
goto error;
}
cls->name
= name;
cls->owner
= owner;
cls->class_release
= class_create_release;
retval = __class_register(cls, key);
if (retval)
goto error;
return cls;
error:
kfree(cls);
return ERR_PTR(retval);
}
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->class_interfaces);
kset_init(&cp->glue_dirs);
__mutex_init(&cp->class_mutex,
"struct class 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 = add_class_attrs(class_get(cls));
class_put(cls);
return error;
}
说明:
1) class_create()函数是一个宏定义,具体调用了__class_create()函数。
2) __class_create()函数首先申请了一个class结构体内存,然后对其结构体成员变量赋值,最后调用__class_register()函数注册类。
3) __class_register()函数中,首先申请了结构体subsys_private内存,从class结构体成员可以看到,subsys_private是其一个成员指针。
4) 然后就是对subsys_private的成员变量初始化,注册subsys的kset,增加类属性等。
在《GSC3280的ADC子系统驱动模型(二)》的2.1中,介绍了sysfs的初始化,程序如下:
点击(此处)折叠或打开
void __init adc_sysfs_init(struct
class *adc_class)
{
adc_class->dev_attrs
= adc_attrs;
}
说明:
1) 此处的类即是上面我们使用class_creat()创建的类。
2) 对类中的设备属性赋值,下面会讲述。
在《GSC3280的ADC子系统驱动模型(一)》的3.2中,首先使用程序adc->dev.class
= adc_class;将我们上面定义的类赋值给dev中的类,然后程序err
= device_register(&adc->dev);注册这个设备,在这里的设备注册函数中,我们主要关注设备结构体中类的注册。device_register()函数如下:
点击(此处)折叠或打开
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);
if (parent)
klist_add_tail(&dev->p->knode_parent,
&parent->p->klist_children);
if (dev->class)
{
mutex_lock(&dev->class->p->class_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->class_interfaces,
node)
if
(class_intf->add_dev)
class_intf->add_dev(dev, class_intf);
mutex_unlock(&dev->class->p->class_mutex);
}
done:
put_device(dev);
return error;
DPMError:
bus_remove_device(dev);
BusError:
device_remove_attrs(dev);
AttrsError:
device_remove_class_symlinks(dev);
SymlinkError:
if (MAJOR(dev->devt))
devtmpfs_delete_node(dev);
if (MAJOR(dev->devt))
device_remove_sys_dev_entry(dev);
devtattrError:
if (MAJOR(dev->devt))
device_remove_file(dev,
&devt_attr);
ueventattrError:
device_remove_file(dev,
&uevent_attr);
attrError:
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
kobject_del(&dev->kobj);
Error:
cleanup_device_parent(dev);
if (parent)
put_device(parent);
name_error:
kfree(dev->p);
dev->p
= NULL;
goto done;
}
说明:
1) device_register()函数首先调用device_initialize(dev);对dev成员初始化。
2) 然后调用device_add()函数增加设备。其中的device_add_attrs(dev)函数完成对类成员中的设备属性初始化,具体程序如下:
点击(此处)折叠或打开
static int device_add_attrs(struct device
*dev)
{
struct class
*class = dev->class;
const struct device_type
*type = dev->type;
int error;
if (class)
{
error
= device_add_attributes(dev,
class->dev_attrs);
if (error)
return error;
error
= device_add_bin_attributes(dev,
class->dev_bin_attrs);
if (error)
goto err_remove_class_attrs;
}
if (type)
{
error
= device_add_groups(dev, type->groups);
if (error)
goto err_remove_class_bin_attrs;
}
error = device_add_groups(dev, dev->groups);
if (error)
goto err_remove_type_groups;
return 0;
err_remove_type_groups:
if (type)
device_remove_groups(dev, type->groups);
err_remove_class_bin_attrs:
if (class)
device_remove_bin_attributes(dev,
class->dev_bin_attrs);
err_remove_class_attrs:
if (class)
device_remove_attributes(dev,
class->dev_attrs);
return error;
}
说明:
1) 由上面可知,dev成员中有class成员,但是class中只有对dev_attrs赋值了,dev成员中没有groups成员,所以此处执行的函数为device_add_attributes(dev,
class->dev_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;
}
说明:
1) 最后是调用device_create_file(dev,
&attrs[i]);产生文件的。此函数在其他文章中会介绍。
在《GSC3280的ADC子系统驱动模型(一)》的3.1,程序adc_class
= class_create(THIS_MODULE,
"adc");产生一个class,class_create()函数如下:
点击(此处)折叠或打开
struct class
{
const char *name;
struct module *owner;
struct class_attribute *class_attrs;
struct device_attribute *dev_attrs;
struct bin_attribute *dev_bin_attrs;
struct kobject *dev_kobj;
int (*dev_uevent)(struct device
*dev, struct kobj_uevent_env
*env);
char *(*devnode)(struct device
*dev, mode_t
*mode);
void (*class_release)(struct
class *class);
void (*dev_release)(struct device
*dev);
int (*suspend)(struct device
*dev, pm_message_t state);
int (*resume)(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;
};
#define class_create(owner, name) \
({ \
static struct lock_class_key __key; \
__class_create(owner, name,
&__key); \
})
struct class *__class_create(struct module
*owner,
const char *name,
struct lock_class_key *key)
{
struct class
*cls;
int retval;
cls = kzalloc(sizeof(*cls), GFP_KERNEL);
if (!cls)
{
retval =
-ENOMEM;
goto error;
}
cls->name
= name;
cls->owner
= owner;
cls->class_release
= class_create_release;
retval = __class_register(cls, key);
if (retval)
goto error;
return cls;
error:
kfree(cls);
return ERR_PTR(retval);
}
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->class_interfaces);
kset_init(&cp->glue_dirs);
__mutex_init(&cp->class_mutex,
"struct class 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 = add_class_attrs(class_get(cls));
class_put(cls);
return error;
}
说明:
1) class_create()函数是一个宏定义,具体调用了__class_create()函数。
2) __class_create()函数首先申请了一个class结构体内存,然后对其结构体成员变量赋值,最后调用__class_register()函数注册类。
3) __class_register()函数中,首先申请了结构体subsys_private内存,从class结构体成员可以看到,subsys_private是其一个成员指针。
4) 然后就是对subsys_private的成员变量初始化,注册subsys的kset,增加类属性等。
在《GSC3280的ADC子系统驱动模型(二)》的2.1中,介绍了sysfs的初始化,程序如下:
点击(此处)折叠或打开
void __init adc_sysfs_init(struct
class *adc_class)
{
adc_class->dev_attrs
= adc_attrs;
}
说明:
1) 此处的类即是上面我们使用class_creat()创建的类。
2) 对类中的设备属性赋值,下面会讲述。
在《GSC3280的ADC子系统驱动模型(一)》的3.2中,首先使用程序adc->dev.class
= adc_class;将我们上面定义的类赋值给dev中的类,然后程序err
= device_register(&adc->dev);注册这个设备,在这里的设备注册函数中,我们主要关注设备结构体中类的注册。device_register()函数如下:
点击(此处)折叠或打开
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);
if (parent)
klist_add_tail(&dev->p->knode_parent,
&parent->p->klist_children);
if (dev->class)
{
mutex_lock(&dev->class->p->class_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->class_interfaces,
node)
if
(class_intf->add_dev)
class_intf->add_dev(dev, class_intf);
mutex_unlock(&dev->class->p->class_mutex);
}
done:
put_device(dev);
return error;
DPMError:
bus_remove_device(dev);
BusError:
device_remove_attrs(dev);
AttrsError:
device_remove_class_symlinks(dev);
SymlinkError:
if (MAJOR(dev->devt))
devtmpfs_delete_node(dev);
if (MAJOR(dev->devt))
device_remove_sys_dev_entry(dev);
devtattrError:
if (MAJOR(dev->devt))
device_remove_file(dev,
&devt_attr);
ueventattrError:
device_remove_file(dev,
&uevent_attr);
attrError:
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
kobject_del(&dev->kobj);
Error:
cleanup_device_parent(dev);
if (parent)
put_device(parent);
name_error:
kfree(dev->p);
dev->p
= NULL;
goto done;
}
说明:
1) device_register()函数首先调用device_initialize(dev);对dev成员初始化。
2) 然后调用device_add()函数增加设备。其中的device_add_attrs(dev)函数完成对类成员中的设备属性初始化,具体程序如下:
点击(此处)折叠或打开
static int device_add_attrs(struct device
*dev)
{
struct class
*class = dev->class;
const struct device_type
*type = dev->type;
int error;
if (class)
{
error
= device_add_attributes(dev,
class->dev_attrs);
if (error)
return error;
error
= device_add_bin_attributes(dev,
class->dev_bin_attrs);
if (error)
goto err_remove_class_attrs;
}
if (type)
{
error
= device_add_groups(dev, type->groups);
if (error)
goto err_remove_class_bin_attrs;
}
error = device_add_groups(dev, dev->groups);
if (error)
goto err_remove_type_groups;
return 0;
err_remove_type_groups:
if (type)
device_remove_groups(dev, type->groups);
err_remove_class_bin_attrs:
if (class)
device_remove_bin_attributes(dev,
class->dev_bin_attrs);
err_remove_class_attrs:
if (class)
device_remove_attributes(dev,
class->dev_attrs);
return error;
}
说明:
1) 由上面可知,dev成员中有class成员,但是class中只有对dev_attrs赋值了,dev成员中没有groups成员,所以此处执行的函数为device_add_attributes(dev,
class->dev_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;
}
说明:
1) 最后是调用device_create_file(dev,
&attrs[i]);产生文件的。此函数在其他文章中会介绍。
相关文章推荐
- GSC3280的ADC子系统驱动模型(一)
- GSC3280的ADC子系统驱动模型(二)
- Linux内核驱动之GPIO子系统(一)GPIO的使用
- struts2_day02_09-属性封装操作_10-模型驱动封装操作_11-使用属性封装和模型驱动封装注意问题
- Linux内核驱动之GPIO子系统(一)GPIO的使用
- 按键驱动之使用输入子系统架构
- Linux 设备驱动模型中的class(类)
- Linux内核驱动 GPIO子系统 GPIO的使用
- Struts2 ModelDriven模型驱动的使用
- struts同时使用属性注入和模型驱动注入数据注入失败原因分析及解决方法
- Linux 设备驱动模型中的class(类)
- Linux内核驱动之GPIO子系统(一)GPIO的使用
- 使用模型驱动ModelDriven,出现对象为空问题
- Linux内核驱动之GPIO子系统(一)GPIO的使用
- 驱动中使用class_device_create()…
- Android驱动开发【NDK模型】———为什么使用JNI
- Linux内核驱动之GPIO子系统(一)GPIO的使用
- s3c2410多通道adc驱动及测试程序(使用write控制多通道)
- Linux内核驱动之GPIO子系统(一)GPIO的使用
- 驱动中使用class_device_create()报错的原因,自动创建设备节点