---恢复内容开始---
1: 首先回顾一下之前的学习内容:
1:register_chrdev来注册字符设备驱动,用这种方法的好处是简单,只需要一个函数就可以注册字符设备驱动了,缺点是无法设置次设备号;
2:register_chrdev_region/allco_chrdev_region、cdev_XXX这些函数来配合注册设备驱动,单纯使用这些函数存在一个问题就是无法自动在/dev目录下面创建
驱动设备文件,我们在嵌入式设备中一般使用busybox中的mdev来实现驱动设备文件的自动创建,但是驱动设备文件的创建需要一个uevent文件;
3:uevent文件是有kobject_uevent函数来实现的;所以我们为了设备文件的自动生成,首先使用class_create函数来创建一个设备类,在用device_create函数
把子目录创建了,这时候就会有一个uevent文件,然后mdev会自动的根据uevent创建/dev/目录下面的设备文件;
4:所以我们在module_init的时候要把sys目录下的类创建了,以及把device也创建了;
下面是详细分析:
class_create函数:
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头文件中定义的;
---恢复内容结束---