---恢复内容开始---node
1: 首先回顾一下以前的学习内容:linux
1:register_chrdev来注册字符设备驱动,用这种方法的好处是简单,只须要一个函数就能够注册字符设备驱动了,缺点是没法设置次设备号;app
2:register_chrdev_region/allco_chrdev_region、cdev_XXX这些函数来配合注册设备驱动,单纯使用这些函数存在一个问题就是没法自动在/dev目录下面建立ide
驱动设备文件,咱们在嵌入式设备中通常使用busybox中的mdev来实现驱动设备文件的自动建立,可是驱动设备文件的建立须要一个uevent文件;函数
3:uevent文件是有kobject_uevent函数来实现的;因此咱们为了设备文件的自动生成,首先使用class_create函数来建立一个设备类,在用device_create函数学习
把子目录建立了,这时候就会有一个uevent文件,而后mdev会自动的根据uevent建立/dev/目录下面的设备文件;测试
4:因此咱们在module_init的时候要把sys目录下的类建立了,以及把device也建立了;ui
下面是详细分析:this
class_create函数:spa
class_create
__class_create
__class_register
kset_register
kobject_uevent
class是建立了一个类即结构体struct class,对应的是在sysfs目录下面建立了一个关于这个类的文件夹
owner:THIS_MODULE name : leds 而后是用device_create在建立相应的设备文件;
#define class_create(owner, name) ({ static struct lock_class_key __key; __class_create(owner, name, &__key); })
class_create实际上是一个宏,调用的是__class_create这个函数
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); }
struct class { const char *name; struct module *owner; struct class_attribute *class_attrs; struct device_attribute *dev_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 class_private *p; };
device_create
struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...)
例子:device_create(batman_class, NULL, MKDEV(tmp_major, 0), NULL, "batman-adv");
struct device { struct device *parent; struct device_private *p; struct kobject kobj; const char *init_name; /* initial name of the device */
struct device_type *type; struct mutex mutex; /* mutex to synchronize calls to * its driver. */
struct bus_type *bus; /* type of bus device is on */
struct device_driver *driver; /* which driver has allocated this device */
void *platform_data; /* Platform specific data, device core doesn't touch it */
struct dev_pm_info power; #ifdef CONFIG_NUMA int numa_node; /* NUMA node this device is close to */
#endif u64 *dma_mask; /* dma mask (if dma'able device) */ u64 coherent_dma_mask;/* Like dma_mask, but for alloc_coherent mappings as not all hardware supports 64 bit addresses for consistent allocations such descriptors. */
struct device_dma_parameters *dma_parms; struct list_head dma_pools; /* dma pools (if dma'ble) */
struct dma_coherent_mem *dma_mem; /* internal for coherent mem override */
/* arch specific additions */
struct dev_archdata archdata; #ifdef CONFIG_OF struct device_node *of_node; #endif dev_t devt; /* dev_t, creates the sysfs "dev" */ spinlock_t devres_lock; struct list_head devres_head; struct klist_node knode_class; struct class *class; const struct attribute_group **groups; /* optional groups */
void (*release)(struct device *dev); };
device_create
device_create_vargs:对device类中的变量赋值,devt name release等初始化这个结构体中的变量
device_register : 对设备的初始化,就是把这个结构体,插入到链表中;
device_add :建立设备文件
device_create_file
device_create_sys_dev_entry
device_add_class_symlinks
device_add_attrs
bus_add_device
dpm_sysfs_add
kobject_uevent
相似的还有DRIVER_ATTR,BUS_ATTR,CLASS_ATTR。这几个东东的区别就是,DEVICE_ATTR对应的文件在/sys/devices/目录中对应的device下面。
而其余几个分别在driver,bus,class中对应的目录下。此次主要介绍DEVICE_ATTR,其余几个相似。
struct device_attribute { struct attribute attr; ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf); ssize_t (*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); };
struct attribute { const char *name; struct module *owner; mode_t mode; #ifdef CONFIG_DEBUG_LOCK_ALLOC struct lock_class_key *key; struct lock_class_key skey; #endif };
http://blog.csdn.net/wujiangguizhen/article/details/37929963
device_attribute的主要是由 name、owner、show、store四个元素组成;
先看看DEVICE_ATTR的原型:
DEVICE_ATTR(_name, _mode, _show, _store)
_name:名称,也就是将在sys fs中生成的文件名称。
_mode:上述文件的访问权限,与普通文件相同,UGO的格式。
_show:显示函数,cat该文件时,此函数被调用。
_store:写函数,echo内容到该文件时,此函数被调用。
这就是真正建立class目录下的文件的函数:
咱们看一下在i2c-0目录下有6个文件,这些文件就是用上面的那些函数生成的,有了uevent文件之后咱们在安装驱动模块的时候mdev会自动生成/dev/ 下的设备文件节点
注意:在删除模块的时候记得使用
device_destroy
class_destroy
这两个函数把建立的文件删除;
下面写代码来测试一下:
struct class这个结构体在include/linux/device.h头文件中定义的;
---恢复内容结束---