/************************************************************************************
*本文為個人學習記錄,如有錯誤,歡迎指正。
* http://www.cnblogs.com/chen-farsight/p/6154941.html
* https://blog.csdn.net/yueqian_scut/article/details/46771595
************************************************************************************/
1. 創建設備文件的兩種方式
(1)手動創建:mknod命令
在驅動程序insmod成功之后,通過mknod命令手動創建設備文件至/dev目錄下:mknod /dev/xxx c 主設備號 次設備號。("c"表示字符設備、"b"表示塊設備、"p"表示網絡設備)
(2)自動創建設備文件:mdev
在設備驅動注冊到系統后,調用class_create為該設備在/sys/class目錄下創建一個設備類,再調用device_create函數為每個設備創建對應的設備,並通過uevent機制調用mdev(嵌入式linux由busybox提供)來調用mknod創建設備文件至/dev目錄下。
2. 自動創建設備文件過程分析
2.1 相關數據結構
struct class和struct device則通過sysfs向用戶層提供信息。
class_private是class的私有結構,class通過class_private注冊到系統中;device_private是device的私有結構,device通過device_private注冊到系統中。注冊到系統中也是將相應的數據結構加入到系統已經存在的鏈表中,但是這些鏈接的細節並不希望暴露給用戶,也沒有必要暴露出來,所以才有private的結構。
//所在文件/kernel/include/linux/device.h //設備類 struct class { const char *name; //設備類名稱 struct module *owner;//創建設備類的module struct class_attribute *class_attrs;//設備類屬性 struct device_attribute *dev_attrs;//設備屬性 struct kobject *dev_kobj;//kobject再sysfs中代表一個目錄 ..................... struct class_private *p;//設備類得以注冊到系統的連接件 }; //drivers/base/base.h struct class_private { struct klist class_devices;//設備類包含的設備(kobject) .................................. struct class *class;//指向設備類數據結構,即要創建的本級目錄信息 };
//所在文件/kernel/include/linux/device.h struct device { struct device *parent; //sysfs/devices/中的父設備 struct device_private *p; //設備得以注冊到系統的連接件 struct kobject kobj; //設備目錄 const char *init_name; //設備名稱 struct bus_type *bus; //設備所屬總線 struct device_driver *driver; //設備使用的驅動 struct klist_node knode_class;//連接到設備類的klist struct class *class; //所屬設備類 ..................... }; //所在文件/kernel/drivers/base/base.h struct device_private { struct klist klist_children; //連接子設備 struct klist_node knode_parent; //加入到父設備鏈表 struct klist_node knode_driver; //加入到驅動的設備鏈表 struct klist_node knode_bus; //加入到總線的鏈表 struct device *device; //對應設備結構 };
2.2 創建過程
step1:調用class_create函數在/sys/class目錄下創建一個設備類。
/* 功能:在/sys/class目錄下創建一個目錄,目錄名是name指定的 參數: struct module *owner - THIS_MODULE const char *name - 設備名 返回值: 成功:class指針 失敗: - bool IS_ERR(const void *ptr) 判斷是否出錯 long PTR_ERR(const void *ptr) 轉換錯誤碼 */ struct class *class_create(struct module *owner, const char *name);
step2:調用device_create函數在step1創建的設備類目錄下創建具體的設備目錄和設備屬性文件。
/* 功能: 在class指針指向的目錄下再創建一個目錄,目錄名由const char *fmt, ...指出、並導出設備信息(dev_t) 參數: struct class *cls - class指針 struct device *parent - 父對象,NULL dev_t devt - 設備號 void *drvdata - 驅動私有數據 const char *fmt, ... - fmt是目錄名字符串格式,...就是不定參數 返回值: 成功 - device指針 失敗 - bool IS_ERR(const void *ptr) 判斷是否出錯 long PTR_ERR(const void *ptr) 轉換錯誤碼 */ struct device *device_create(struct class *cls, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...);
step3:在/dev創建設備文件(系統自動進行)
step1、step2都是在sysfs文件系統中創建目錄或者文件,而應用程序訪問的設備文件則需要創建在/dev/目錄下。該項工作由mdev完成(需保證根文件系統支持mdev,由busybox配置)。
2.2 注銷過程
step1:刪除設備類目錄下的設備
/* 功能:刪除device_create創建的目錄 參數: struct class *cls - class指針 dev_t devt - 設備號 */ void device_destroy(struct class *cls, dev_t devt);
step2:刪除/sys/class目錄下的設備類
/* 功能:刪除class指針指向的目錄 參數: struct class *cls - class指針 */ void class_destroy(struct class *cls);