您的位置:首页 > 其它

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]);产生文件的。此函数在其他文章中会介绍。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: