linux驅動學習(四)自建立設備文件節點

---恢復內容開始---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頭文件中定義的;

---恢復內容結束---

相關文章
相關標籤/搜索