• 设备类class理解


    http://blog.chinaunix.net/uid-20729583-id-1884552.html

    设备类struct class
    一个类是一个设备的高级视图,它抽象出低级的实现细节。例如,驱动可以见到一个SCSI磁盘或者一个ATA磁盘,在类的级别,他们都是磁盘,类允许用户空间基于它们作什么来使用设备,而不是它们如何被连接或者它们如何工作。

    设备类表示一类设备,所有的class对象都属于class_subsys子系统
    struct class
    {
        const char *name;//类名称
        struct module *owner;//对应模块
        struct subsystem subsys;//对应的subsystem;
        struct list_head children;//class_device链表
        struct list_head  interfaces;//class_interface链表
        struct semaphore  sem;//children和interfaces链表锁
        struct class_attribute *class_attrs;//类属性
        int (*uevent)(struct class_device *dev,char **envp,int num_envp,char *buffer,int buffer_size);//事件
        void (*release)(struct class_device *dev);//释放类设备的方法
        void (*class_release)(struct class *class);    //释放类的方法
    }
    一、struct list_head结构体
      struct list_head {
              struct list_head *next, *prev;  //此处进行了结构体list_head的定义系统使用这个链表的形式进行系统文件资源的管理
      };
    二、semaphore 结构体
     struct semaphore {
              atomic_t count;       // 右边是atomic 的定义 typedef struct { volatile int counter; } atomic_t;   (这里的volatile int 指的是counter变量可以被其他的程序更改,但是不能被你自己更改)此处使用了atomic_t类型
    //是为了是引用计数不被自己更改,增强安全性,由于这个计数变量只能由其他程序更改,而其他程序只能是系统中的管理类设备的程序,所以增强了安全性
              wait_queue_head_t wait;    //即等待队列头,(在linux驱动中,可以通过等待队列来实现阻塞进程的呼唤)右边是wait_queue_head_t的定义   typedef struct __wait_queue_head wait_queue_head_t;
       //下面是__wait_queue_head 的定义
      /*
          struct __wait_queue_head {
              spinlock_t  lock;
    下面是spinlock_t的定义
     /*
    #include 
      19
      20typedef struct {
      21        raw_spinlock_t raw_lock;
      22#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP)
      23        unsigned int break_lock;
      24#endif
      25#ifdef CONFIG_DEBUG_SPINLOCK
      26        unsigned int magic, owner_cpu;
      27        void *owner;
      28#endif
      29#ifdef CONFIG_DEBUG_LOCK_ALLOC
      30        struct lockdep_map dep_map;
      31#endif
      32} spinlock_t;
    */
              struct list_head task_list;
      };
      */
      };

    struct semaphore {
              atomic_t count;
              int sleepers;
              wait_queue_head_t wait;
      };
    三、类属性class_attribute
    下面是结构体class_attribute的定义
    struct class_attribute {
     210        struct attribute        attr;
    /*
    28struct attribute {
      29        const char              * name;    //类属性的名称
      30        struct module           * owner;   //类属性所述模块
      31        mode_t                  mode;     //保护位,如果是只读,就要设置成 S_IRUGO,读写就是 S_IWUSR。
      32};
    */
     211        ssize_t (*show)(struct class *, char * buf);  //具体实现在用户空间/sys下面的读操作
      /*

    */
     212        ssize_t (*store)(struct class *, const char * buf, size_t count);     //存储用户通过buffer传入的属性值
     213};
    对于这个属性结构体,可以使用函数来进行新属性的添加
    int device_create_file(struct device *,struct device_attribute *);
    void device_remove_file(struct device *,struct device_attribute *);
    四、用户事件 uevent(struct class_device *dev,char **envp,int num_envp,char *buffer,int buffer_size);(即user event)
    下面介绍一个与此十分相似的相关函数
    static int class_uevent(struct kset *kset, struct kobject *kobj, char **envp,int num_envp, char *buffer, int buffer_size);
               
    五、void (*release)(struct class_device *dev)
    六、class_release
    static void class_release(struct kobject * kobj)
      51{
      52        struct class *class = to_class(kobj);//此处的to_class()为一个宏定义,这个宏定义用来指向设备类,定义如右:#define to_class(obj) container_of(obj, struct class, subsys.kobj)
      53
      54        pr_debug("class '%s': release. ", class->name);
      55
      56        if (class->class_release)
      57                class->class_release(class);
      58        else
      59                pr_debug("class '%s' does not have a release() function, "   "be careful ", class->name); //  这是一个宏定义:#define pr_debug(fmt,arg...)      printk(KERN_DEBUG fmt,##arg)
    /*上面的这个宏是一个可变参数宏,详细的解释如下:
    在 GNU C 中,宏可以接受可变数目的参数,就象函数一样,例如:

     include/linux/kernel.h
    110: #define pr_debug(fmt,arg...)
    111:         printk(KERN_DEBUG fmt,##arg)

    这里 arg 表示其余的参数,可以是零个或多个,这些参数以及参数之间的逗号构
    成 arg 的值,在宏扩展时替换 arg,例如:

        pr_debug("%s:%d",filename,line)

    扩展为

        printk("<7>" "%s:%d", filename, line)

    使用 ## 的原因是处理 arg 不匹配任何参数的情况,这时 arg 的值为空,GNU
    C 预处理器在这种特殊情况下,丢弃 ## 之前的逗号,这样

        pr_debug("success! ")

    扩展为

        printk("<7>" "success! ")

    注意最后没有逗号。


    */
      60}

    下面是注册和注销class的两个函数:
    int class_register(struct class *cls);
    void class_unregister(struct class *cls);

    int class_register(struct class * cls)
     138{
     139        int error;
     140
     141        pr_debug("device class '%s': registering ", cls->name);
     142
     143        INIT_LIST_HEAD(&cls->children);//这个函数用来初始化class_device链表
    /*内联函数INIT_LIST_HEAD的定义
    static inline void INIT_LIST_HEAD(struct list_head *list)
      31{
      32        list->next = list;
      33        list->prev = list;
      34}
    */
     144        INIT_LIST_HEAD(&cls->devices);    //功能同上
     145        INIT_LIST_HEAD(&cls->interfaces);      //功能同上
     146        kset_init(&cls->class_dirs);

     147        init_MUTEX(&cls->sem);           //初始化信号量
     148        error = kobject_set_name(&cls->subsys.kobj, "%s", cls->name);   //设置相应的kobject对象的名称
     149        if (error)
     150                return error;
     151
     152        subsys_set_kset(cls, class_subsys);     //设置相应的subsystem中的kset对象
     153
     154        error = subsystem_register(&cls->subsys);  //注册subsystem
     155        if (!error) {
     156                error = add_class_attrs(class_get(cls));  //添加类属性
     157                class_put(cls);  //减少类的计数
     158        }
     159        return error;
     160}
     161
     162void class_unregister(struct class * cls)
     163{
     164        pr_debug("device class '%s': unregistering ", cls->name);
     165        remove_class_attrs(cls);  //进行类属性移除操作
     166        subsystem_unregister(&cls->subsys);   //从所挂载的subsystem中移除
     167}
     168

    二、class_device结构体
    一个class可以看成是一个容器,容器总包含了很多的class_device,这些class_device是由class这个大的容器来管理的,而每个class_device都对应着一个具体的设备。
    一个类的真正目的是作为一个是该类成员的设备的容器. 一个成员由 struct class_device 来表示:

    每个class对象包括一个class_device链表,每个class_device对象表示一个逻辑设备并通过struct class_device中的dev成员(一个指向struct device的指针)关联一个物理设备。一个逻辑设备总是对应一个物理设备,而一个物理设备却可以对应多个逻辑设备。

    struct class_device
    {
        struct list_head node;

        struct kobject  kobj;//内嵌的kobject;

        struct class   *class;//所属的类;

        dev_t   devt;//dev_t设备号

        struct class_device_attribute  *devt_attr;

        struct class_device_attribute  uevent_attr;

        struct device  *dev;//如果存在,创建到/sys/devices相应入口的符号链接

        void *class_data;//私有数据

        struct class_device  *parent;//父设备

        void (*release)(struct class_device *dev);//释放对应类实际设备的方法

        int(*uevent)(struct class_device *dev,char **envp,int num_envp,char *buffer,int buffer_size);

        char class_id[BUS_IO_SIZE];  //  u32 class_id;类标志
    }
    class_id 成员持有设备名子, 如同它在 sysfs 中的一样. class 指针应当指向持有这个设备的类, 并且 dev 应当指向关联的设备结构. 设置 dev 是可选的; 如果它是非 NULL, 它用来创建一个符号连接从类入口到对应的在 /sys/devices 下的入口, 使得易于在用户空间找到设备入口. 类可以使用 class_data 来持有一个私有指针.
    一、class_device_attribute  
    这个结构体为类设备属性,定义如下:
    struct class_device_attribute
    {
        struct attribute attr;
        ssize_t (*show)(struct class_device *,char *buf);//对相应的类设备进行读。
        ssize_t (*store)(struct class_device *,const char *buf, size)t count);//对相应的类设备进行写操作
    }




    注册和注销class_device
    int class_device_register(struct class_device *class_dev);    //注册
    void class_device_unregister(struct class_device *class_dev);   //注销



     675int class_device_register(struct class_device *class_dev)
     676{
     677        class_device_initialize(class_dev);   //初始化类的对应的类设备
     678        return class_device_add(class_dev);    //返回class_device_add(class_dev);
     679}
    下面是class_device_register中两个函数的具体实现代码:

     567int class_device_add(struct class_device *class_dev)   //该函数用于进行设备的添加
     568{
     569        struct class *parent_class = NULL;           //初始化父指针为空,
     570        struct class_device *parent_class_dev = NULL;    //初始化设备类父指针为空,实现功能和上面的函数想类似
     571        struct class_interface *class_intf;
     572        int error = -EINVAL;//初始化error为-EINVAL(对应数值22)
     573
     574        class_dev = class_device_get(class_dev);   //此函数是class_device对象的计数加1,返回class_device对象的指针
     575        if (!class_dev)     
     576                return -EINVAL;    
     577
     578        if (!strlen(class_dev->class_id))    
     579                goto out1;
     580
     581        parent_class = class_get(class_dev->class);     
     582        if (!parent_class)
     583                goto out1;
     584
     585        parent_class_dev = class_device_get(class_dev->parent);
     586
     587        pr_debug("CLASS: registering class device: ID = '%s' ",
     588                 class_dev->class_id);
     589
     590        /* first, register with generic layer. */
     591        error = kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id);
     592        if (error)
     593                goto out2;
     594
     595        if (parent_class_dev)
     596                class_dev->kobj.parent = &parent_class_dev->kobj;
     597        else
     598                class_dev->kobj.parent = &parent_class->subsys.kobj;
     599
     600        error = kobject_add(&class_dev->kobj);
     601        if (error)
     602                goto out2;
     603
     604        /* add the needed attributes to this device */
     605        error = sysfs_create_link(&class_dev->kobj,
     606                                  &parent_class->subsys.kobj, "subsystem");
     607        if (error)
     608                goto out3;
     609
     610        error = class_device_create_file(class_dev, &class_uevent_attr);
     611        if (error)
     612                goto out3;
     613
     614        if (MAJOR(class_dev->devt)) {
     615                error = class_device_create_file(class_dev, &class_devt_attr);
     616                if (error)
     617                        goto out4;
     618        }
     619
     620        error = class_device_add_attrs(class_dev);
     621        if (error)
     622                goto out5;
     623
     624        if (class_dev->dev) {
     625                error = sysfs_create_link(&class_dev->kobj,
     626                                          &class_dev->dev->kobj, "device");
     627                if (error)
     628                        goto out6;
     629        }
     630
     631        error = class_device_add_groups(class_dev);
     632        if (error)
     633                goto out7;
     634
     635        error = make_deprecated_class_device_links(class_dev);
     636        if (error)
     637                goto out8;
     638
     639        kobject_uevent(&class_dev->kobj, KOBJ_ADD);
     640
     641        /* notify any interfaces this device is now here */

     642        down(&parent_class->sem);
     643        list_add_tail(&class_dev->node, &parent_class->children);
     644        list_for_each_entry(class_intf, &parent_class->interfaces, node) {
     645                if (class_intf->add)
     646                        class_intf->add(class_dev, class_intf);
     647        }
     648        up(&parent_class->sem);
     649
     650        goto out1;
     651
     652 out8:
     653        class_device_remove_groups(class_dev);
     654 out7:
     655        if (class_dev->dev)
     656                sysfs_remove_link(&class_dev->kobj, "device");
     657 out6:
     658        class_device_remove_attrs(class_dev);
     659 out5:
     660        if (MAJOR(class_dev->devt))
     661                class_device_remove_file(class_dev, &class_devt_attr);
     662 out4:
     663        class_device_remove_file(class_dev, &class_uevent_attr);
     664 out3:
     665        kobject_del(&class_dev->kobj);
     666 out2:
     667        if(parent_class_dev)
     668                class_device_put(parent_class_dev);
     669        class_put(parent_class);
     670 out1:
     671        class_device_put(class_dev);
     672        return error;
     673}
    上面的这个函数比较容易理解,这里就不再一一的给出每个代码的解释了。

     674

    下面这个函数为初始化class_device.
    void class_device_initialize(struct class_device *class_dev)
     561{
     562        kobj_set_kset_s(class_dev, class_obj_subsys);
     563        kobject_init(&class_dev->kobj);//对于这个函数,一般情况下,在进行设备对象的初始化时都会设计到这个函数的调用,每一个设备对象都对应kobject这样的一个对象,这个对象的作用很重要,主要是用于对设备模型的结构化的描述。
     564        INIT_LIST_HEAD(&class_dev->node);
     565}


    三、类接口 class_interface
    struct class_interface
    {
        struct list_head node;   //
        struct class *class;   //相应的class
        int (*add)(struct class_device *,struct class_interface *);  //设备加入时触发
        void (*remove)(struct class_device *,struct class_interface *);//设备移出时触发
    }
    与class和class_device相似,class_interface也存在两个函数用于注册和注销class_interface
    int class_interface_register(struct class_interface *class_intf);
    void class_interface_unregister(struct class_interface *class_intf);
    如果想对上面的两个函数进行彻底的了解,请参阅http://lxr.linux.no/#linux/init/do_mounts_rd.c#L17

  • 相关阅读:
    BZOJ 3105: [cqoi2013]新Nim游戏
    informatica增量抽取图文
    informatica ETL增量抽取(时间戳)
    kafka connector 使用总结以及自定义connector开发(×××××)
    Kafka Connect JDBC-Source 源连接器配置属性
    kafka-connect-jdbc-sink配置属性
    得到自1970年1月1日以来的秒数
    kafka-connect-jdbc(重要)
    confluent kafka-connect-jdbc(非常重要)
    kafka集群版 connectors 通过REST API实现控制
  • 原文地址:https://www.cnblogs.com/yangjunhe460/p/11725013.html
Copyright © 2020-2023  润新知