linux驱动学习(四)⾃创建设备⽂件节点
---恢复内容开始---
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
linux创建文件指令
  __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;
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 */
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
};
blog.csdn/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头⽂件中定义的;---恢复内容结束---

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。