首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

GSC3280的ADC子系统驱动模型

GSC3280的ADC子系统驱动模型

一个类是一个设备的高层视图,它抽象掉了底层的实现细节。例如,在驱动层面时,你可能会见到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;
  •                                 }
返回列表