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

  __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头文件中定义的;

---恢复内容结束---

转载于:https://www.cnblogs.com/biaohc/p/6628457.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值