Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2161182
  • 博文数量: 361
  • 博客积分: 10828
  • 博客等级: 上将
  • 技术积分: 4161
  • 用 户 组: 普通用户
  • 注册时间: 2010-01-20 14:34
文章分类

全部博文(361)

文章存档

2011年(132)

2010年(229)

分类: LINUX

2011-04-22 10:32:21

类 子系统

类是一个设备的高层视图, 它抽象出了底层的实现细节,从而允许用户空间使用设备所提供的功能, 而不用关心设备是如何连接和工作的。类成员通常由上层代码所控制, 而无需驱动的明确支持。但有些情况下驱动也需要直接处理类。

几乎所有的类都显示在 /sys/class 目录中。出于历史的原因,有一个例外:块设备显示在 /sys/block目录中。在许多情况, 类子系统是向用户空间导出信息的最好方法。当类子系统创建一个类时, 它将完全拥有这个类,根本不用担心哪个模块拥有那些属性,而且信息的表示也比较友好。

为了管理类,驱动程序核心导出了一些接口,其目的之一是提供包含设备号的属性以便自动创建设备节点,所以udev的使用离不开类。 类函数和结构与设备模型的其他部分遵循相同的模式,所以真正崭新的概念是很少的。

注意:class_simple 是老接口,在2.6.13中已被删除,这里不再研究。



管理类的接口

类由 struct class 的结构体来定义:

/*
 * device classes
 */

struct class {
    const char        * name;/*每个类需要一个唯一的名字, 它将显示在 /sys/class 中*/
    struct module        * owner;

    struct kset        subsys;
    struct list_head    children;
    struct list_head    devices;
    struct list_head    interfaces;
    struct kset        class_dirs;
    struct semaphore    sem;    /* locks both the children and interfaces lists */

    struct class_attribute        * class_attrs;/* 指向类属性的指针(以NULL结尾) */
    struct class_device_attribute    * class_dev_attrs;/* 指向类中每个设备的一组默认属性的指针 */
    struct device_attribute        * dev_attrs;

    int    (*uevent)(struct class_device *dev, char **envp,
             int num_envp, char *buffer, int buffer_size);/* 类热插拔产生时添加环境变量的函数 */
    int    (*dev_uevent)(struct device *dev, char **envp, int num_envp,
                char *buffer, int buffer_size);/* 类中的设备热插拔时添加环境变量的函数 */

    void    (*release)(struct class_device *dev);/* 把设备从类中删除的函数 */
    void    (*class_release)(struct class *class);/* 删除类本身的函数 */
    void    (*dev_release)(struct device *dev);

    int    (*suspend)(struct device *, pm_message_t state);
    int    (*resume)(struct device *);
};


/*类注册函数:*/
int class_register(struct class *cls);
void class_unregister(struct class *cls);

/*类属性的接口:*/
struct class_attribute {
 struct attribute attr;
 ssize_t (*show)(struct class *cls, char *buf);
 ssize_t (*store)(struct class *cls, const char *buf, size_t count); 
}; 
CLASS_ATTR(_name,_mode,_show,_store); 
int class_create_file(struct class *cls, const struct class_attribute *attr);
void class_remove_file(struct class *cls, const struct class_attribute *attr);


在更新的内核里,这个结构体变得简洁了,删除了一些成员:

/*in Linux 2.6.26.5*/

/*
 * device classes
 */

struct class {
    const char        *name;
    struct module        *owner;

    struct kset        subsys;
    struct list_head    devices;
    struct list_head    interfaces;
    struct kset        class_dirs;
    struct semaphore    sem; /* locks children, devices, interfaces */
    struct class_attribute        *class_attrs;
    struct device_attribute        *dev_attrs;

    int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);

    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);
};

类设备(在新内核中已被删除)

类存在的真正目的是给作为类成员的各个设备提供一个容器,成员由 struct class_device 来表示:

struct class_device {
    
struct list_head    node;/*for internal use by the driver core only*/
    
struct kobject        kobj;/*for internal use by the driver core only*/
    
struct class        * class;    /* 指向该设备所属的类,必须*/
    dev_t            devt
;        /* dev_t, creates the sysfs "dev" ,for internal use by the driver core only*/
    
struct class_device_attribute *devt_attr;/*for internal use by the driver core only*/
    
struct class_device_attribute uevent_attr;
    
struct device        * dev;        /* 指向此设备相关的 device 结构体,可选。若不为NULL,应是一个从类入口到/sys/devices 下相应入口的符号连接,以便用户空间查找设备入口*/
    
void            * class_data;    /* 私有数据指针 */
    
struct class_device    *parent;    /* parent of this child device, if there is one */
    
struct attribute_group ** groups;    /* optional groups */

    
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_ID_SIZE];    /* 此类中的唯一的名字 */
};

/*类设备注册函数:*/
int class_device_register(struct class_device *cd);
void class_device_unregister(struct class_device *cd);

/*重命名一个已经注册的类设备入口:*/
int class_device_rename(struct class_device *cd, char *new_name); 

/*类设备入口属性:*/
struct class_device_attribute {
 
struct attribute attr;
 ssize_t 
(*show)(struct class_device *cls, char *buf);
 ssize_t 
(*store)(struct class_device *cls, const char *buf,
 
size_t count);
};

CLASS_DEVICE_ATTR
(_name, _mode, _show, _store); 

/*创建和删除除struct class中设备默认属性外的属性*/
int class_device_create_file(struct class_device *cls, const struct class_device_attribute *attr);
void class_device_remove_file(struct class_device *cls, const struct class_device_attribute *attr);

类接口

类子系统有一个 Linux 设备模型的其他部分找不到的附加概念,称为“接口”, 可将它理解为一种设备加入或离开类时获得信息的触发机制,结构体如下:

struct class_interface {
    struct list_head    node;
    struct class        *class;/* 指向该接口所属的类*/

    int (*add) (struct class_device *, struct class_interface *);

/*当一个类设备被加入到在 class_interface 结构中指定的类时, 将调用接口的 add 函数,进行一些设备需要的额外设置,通常是添加更多属性或其他的一些工作*/
    void (*remove)    (struct class_device *, struct class_interface *);/*一个接口的功能是简单明了的. 当设备从类中删除, 将调用remove 方法来进行必要的清理*/
    int (*add_dev)     (struct device *, struct class_interface *);
    void (*remove_dev) (struct device *, struct class_interface *);
};

/*注册或注销接口的函数:*/
int class_interface_register(struct class_interface *class_intf);
void class_interface_unregister(struct class_interface *class_intf);
/*一个类可注册多个接口*/

阅读(902) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~