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