mdev_笔记

来源:互联网 发布:2d图像转3d算法 编辑:程序博客网 时间:2024/06/03 15:09

参考文章:http://www.cnblogs.com/hnrainll/archive/2011/06/10/2077435.html

mdev是busybox自带的一个简化版udev,作用是在系统启动与热插拔或动态加载驱动时候,自动产生节点文件。


执行mdev -s命令,mdev扫描/sys/block和sys/class两个目录下的dev属性文件,获取设备编号,并以包含该dev属性文件的目录名称作为设备名device_name,在dev目录下创建相应的设备文件。

例如:cat /sys/class/tty/tty0/dev会得到4:0, subsystem为tty,device_name为tty0。


当mdev因为热插拔(uevent/hotplug)事件被调用,通过uevent时间传递的环境变量获取引起该事件的设备action以及该设备路径device path。然后判断该action是什么:

如果action是add,即有新设备加入系统,mdev通过device path的dev属性文件获取设备编号,以device path最后一个目录作为设备名,在dev目录下创建设备文件。

如果action是remove,则设备已从系统移除,删除对应设备文件。


由上可知:当设备加入或移除,mdev创建/删除设备文件,必须做到以下三点:

1、在/sys/class的某个subsystem目录下

2、创建以设备名device name作为名称的目录

3、该目录下包含dev属性文件,该文件以"major:minor\n"形式输出设备编号



linux设备驱动模型两个重要的数据结构 class 和 class_device。(linux 2.6.24.7)

1、class

class代表一类设备,所有class都属于class_subsys,即出现在/sys/class目录下,出了块设备可能出现在/sys/block或/sys/class/block。

/* class结构体 */ structclass{   constchar * name; /* class的名称 */   struct module * owner; /* 拥有该class的模块 */   struct kset subsys; /* 该class对应的子系统 */   struct list_head children; /* 该class的class_device列表 */   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;/* 该class的默认属性,以NULL结尾 */   struct class_device_attribute * class_dev_attrs;/* 添加到class的class_device所拥有的默认属性 */   struct device_attribute * dev_attrs;   /* 该函数提供在产生热插拔class_device事件时,添加环境变量的能力 */   int (*uevent)(struct class_device *dev,struct kobj_uevent_env *env);   /* 该函数提供在产生热插拔device(物理设备)事件时,添加环境变量的能力 */   int (*dev_uevent)(struct device *dev,struct kobj_uevent_env *env);   /* 添加到class的class_device移除时,调用该函数进行必要的清理工作 */   void(*release)(struct class_device *dev);   /* class被移除时,调用该函数进行必要的清理工作 */   void(*class_release)(structclass*class);   void(*dev_release)(struct device *dev);   int (*suspend)(struct device *, pm_message_t state);   int (*resume)(struct device *);   };   /* class注册函数 */   int __must_check class_register(structclass*);   void class_unregister(structclass*); 建立一个class有两种方法   a、根据需要,填充一个struct class,然后再调用class_register注册该class就ok了(此法比较灵活,可以自己定制很多东西)   b、就是通过下面的class_create来创建一个class,该函数会返回一个指向刚建立的class的指针(创建class的最简单方法)   /* class_create用于创建一个名为name的class,其owner参数一般为THIS_MODULE。class_create内部调用了class_register */   structclass*class_create(struct module *owner,constchar*name);   /* class_destroy用于删除一个class,实际上其内部只是简单调用了class_unregister(cls)来注销cls */    void class_destroy(structclass*cls); 一个class属性对应于/sys/class/class.name(class.name就是该class的名称)目录里的一个文件。通过这些文件, 可以向用户空间输出一些关于该class的信息,也可从用户空间获取到一些信息。   /* class属性结构体 */   struct class_attribute {   struct attribute attr;   /* 当用户空间读取该属性时,调用show函数输出一个"属性值"给用户空间 */   ssize_t (*show)(structclass*,char* buf);   /* 当用户空间写该属性时,调用store函数保存用户写入的"属性值" */   ssize_t (*store)(structclass*,constchar* buf,size_tcount);   };   struct attribute {   constchar * name;   struct module * owner;   mode_t mode;   };   /* CLASS_ATTR可以在编译时创建一个class属性,该属性的名称为class_attr_name */   #define CLASS_ATTR(_name,_mode,_show,_store) \   struct class_attribute class_attr_##_name = __ATTR(_name,_mode,_show,_store)   /* class_create_file与class_remove_file用于创建与删除class默认属性外的属性 */   int __must_check class_create_file(structclass*,   conststruct class_attribute *);   void class_remove_file(structclass*,conststruct class_attribute *); 

2、class_device

class_device对应一个具体设备。

每个class对象包括一个class_device链表,每个class_device对象表示一个逻辑设备并通过struct class_device中的dev成员(一个指向struct_device的指针)关联一个物理设备。

一个逻辑设备总是对应一个物理设备,而一个物理设备可以对应多个逻辑设备。

/* class_device结构体 */ struct class_device {   struct list_head node; /* 仅供驱动核心内部使用 */   struct kobject kobj; /* 该class_device相应的kobject,仅供驱动核心内部使用 */   structclass *class; /* 该class_device所属的class,必须有 */   dev_t devt; /* 该class_device的设备编号,用于创建其dev属性文件,仅供驱动核心内部使用 */    struct device * dev; /* 指向该class_device相关的device结构体(物理设备),可选.若不为NULL,用于创建一个从class入口到/sys/devices 下相应入口的符号连接,以便用户空间查找设备入口 */   void * class_data; /* 该class_device的私有数据指针 */   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,struct kobj_uevent_env *env);   char class_id[BUS_ID_SIZE]; /* 该class_device的名称,在其所属class中应是唯一的,不可重名 */   };   /* class_devic注册函数 */   int __must_check class_device_register(struct class_device *);   void class_device_unregister(struct class_device *); 与class一样,建立一个class_device也有两种方法   a、根据需要,填充一个struct class_device,然后再调用class_device_register注册该class_device就ok了(此法比较灵活,可以自己定制很多东西)   b、就是通过下面的class_device_create来创建一个class_device,该函数会返回一个指向刚建立的class_device的指针(创建class_device的最简单方法)   /* class_device_create用于创建一个class_device,其名称最后两个参数决定(类似于printf的格式化字符串)   * cls指明了其所属的class,可以是自己填充的class或由class_create返回的class   * parent指明了该class_device的父class_device,若没有,则为NULL   * 该class_device的设备编号,用于创建其dev属性文件,必须指明   * device指明了该class_device(逻辑设备)对应的device(物理设备),可有可无,无则为NULL   * 实际上,class_device_create也就是填充一个class_device,然后调用了class_device_register注册该class_device   */   struct class_device *class_device_create(structclass*cls,   struct class_device *parent,   dev_t devt,   struct device *device,   constchar*fmt,...)   __attribute__((format(printf,5,6)));   /* class_destroy用于删除一个class,内部调用了class_unregister(cls)来注销cls */    void class_device_destroy(structclass*cls, dev_t devt); class_device属性对应于/sys/class/class.name/class_device.class_id目录下一个文件。通过这些 文件,可以向用户空间输出一些关于该class_device的信息,也可从用户空间获取到一些信息。   /* class_device属性,其show和store函数类似于class属性的show和store函数 */   struct class_device_attribute {   struct attribute attr;   ssize_t (*show)(struct class_device *,char* buf);   ssize_t (*store)(struct class_device *,constchar* buf,size_tcount);   };   /* CLASS_DEVICE_ATTR可以在编译时创建一个class_device属性,该属性的名称为class_device_attr_name */   #define CLASS_DEVICE_ATTR(_name,_mode,_show,_store) \   struct class_device_attribute class_device_attr_##_name = \   __ATTR(_name,_mode,_show,_store)   /* class_device_create_file与class_device_remove_file用于创建与删除class_device默认属性外的属性 */   int __must_check class_device_create_file(struct class_device *,   conststruct class_device_attribute *);   void class_device_remove_file(struct class_device * class_dev,   conststruct class_device_attribute * attr); 其实,在调用class_device_register注册一个class_device时,该函数内部调用了   int class_device_add(struct class_device *class_dev)    在class_device_add内,通过class_device_create_file创建dev、uevent和该class_device 所拥有的默认属性(由class_device.class->class_dev_attrs指定)等属性文件。这样第3点也有了。   dev属性文件用于向用户空间输出该class_device的设备编号。   uevent属性文件使用户可以手动触发uevent事件(通过向该文件写,如add、remove等字符串)。   接下来是两个基于mdev的驱动例子。   struct class_interface {   struct list_head node;   struct class *class; /* 该class_interface所属的class */   int (*add) (struct class_device *, struct class_interface *); /* class属性 */   void (*remove) (struct class_device *, struct class_interface *); /* class属性 */   int (*add_dev) (struct device *, struct class_interface *);   void (*remove_dev) (struct device *, struct class_interface *);   };   /* class_interface注册函数 */   int __must_check class_interface_register(struct class_interface *);   void class_interface_unregister(struct class_interface *);







0 0
原创粉丝点击