從現(xiàn)在開始,我們開始來實(shí)現(xiàn) 總線-設(shè)備-驅(qū)動模型中的總線。、
我們這個程序的目標(biāo)是在 sysfs文件系統(tǒng)的/sys/bus/ 目錄下面建立一個文件夾。
一、總線介紹
1. 總線數(shù)據(jù)結(jié)構(gòu)bus_type
struct bus_type 結(jié)構(gòu)體的定義如下:
struct bus_type { const char *name; --總線名 struct bus_attribute *bus_attrs; --總線屬性 struct device_attribute *dev_attrs; --總線設(shè)備屬性 struct driver_attribute *drv_attrs; --總線驅(qū)動屬性 以下的函數(shù)會在設(shè)備注冊或驅(qū)動注冊的時候調(diào)用。
int (*match)(struct device *dev, struct device_driver *drv); --實(shí)現(xiàn)設(shè)備與驅(qū)動的匹配。不同的總線實(shí)現(xiàn)匹配的方法不同,如platform總線采用name匹配,而usb_bus采用id匹配
int (*uevent)(struct device *dev, struct kobj_uevent_env *env); int (*probe)(struct device *dev); --在2.6的內(nèi)核中實(shí)現(xiàn)一個設(shè)備與驅(qū)動的探測。主要是因?yàn)?a href="http://www.nncyjs.com/zhuanti/90Oan1" style="color:#4595e6;" target="_blank">熱插拔的設(shè)備的增多。
int (*remove)(struct device *dev); --移除設(shè)備 void (*shutdown)(struct device *dev); --關(guān)閉設(shè)備 int (*suspend)(struct device *dev, pm_message_t state); int (*suspend_late)(struct device *dev, pm_message_t state); int (*resume_early)(struct device *dev); int (*resume)(struct device *dev);
struct dev_pm_ops *pm; --電源管理 struct bus_type_private *p; --bus_type私有成員, 這個結(jié)構(gòu)體中主要包括了kset以及klist,用于管理其掛載其總線下的設(shè)備和驅(qū)動 }; |
下面我們來看看bus_type_private結(jié)構(gòu)體
struct bus_type_private { struct kset subsys; /*代表該bus子系統(tǒng),里面的kobj是該bus的主kobj,最頂層*/ struct kset *drivers_kset; /* 掛接到該總線上所有的驅(qū)動的集合 */ struct kset *devices_kset; /* 掛接到該總線上所有的設(shè)備的集合 */ struct klist klist_devices; /* 總線上所有設(shè)備的的列表 */ struct klist klist_drivers; /* 總線上所有驅(qū)動的的列表 */ struct blocking_notifier_head bus_notifier; unsigned int drivers_autoprobe:1; /*設(shè)置是否在注冊驅(qū)動時,自動探測(probe)設(shè)備*/ struct bus_type *bus; /*回指包含自己的總線*/ }; |
2. 注冊總線
內(nèi)核中采用bus_register來注冊一個新的總線。
其使用如:ret = bus_register(&my_bus_type);
bus_register函數(shù)的源碼如下(剔除一些錯誤處理):
int bus_register(struct bus_type *bus) { int retval; struct bus_type_private *priv; priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL); priv->bus = bus; bus->p = priv; BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier); retval = kobject_set_name(&priv->subsys.kobj, '%s', bus->name); //設(shè)置kobject名稱,有時會使用snprintf來設(shè)置,不過會出現(xiàn)bug,最好使用該函數(shù)。
priv->subsys.kobj.kset = bus_kset; //kobj中的kset指向父kset priv->subsys.kobj.ktype = &bus_ktype; //kobj中的ktype指向父ktype priv->drivers_autoprobe = 1; //設(shè)置總線下的設(shè)備和驅(qū)動自動探測 retval = kset_register(&priv->subsys); //注冊kset,關(guān)于kset,kobject,以及ktype的關(guān)系以后在學(xué)習(xí)
retval = bus_create_file(bus, &bus_attr_uevent); //創(chuàng)建bus的文件屬性 priv->devices_kset = kset_create_and_add('devices', NULL,&priv->subsys.kobj); //在父kset下創(chuàng)建和加入名為devices和drivers的kset
priv->drivers_kset = kset_create_and_add('drivers', NULL,&priv->subsys.kobj); klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put); //初始化klist,這個函數(shù)主要是實(shí)現(xiàn)一些賦值及初始化的功能
klist_init(&priv->klist_drivers, NULL, NULL); retval = add_probe_files(bus); //主要是創(chuàng)建該bus下probe的屬性文件,可以通過cat file 和cat x > file 向?qū)傩晕募x出和寫入數(shù)據(jù)。
retval = bus_add_attrs(bus); --添加bus自帶的屬性文件 return 0; } |
從上面的程序得知,總線注冊主要工作如下
創(chuàng)建bus_type_ private,并申請相應(yīng)的內(nèi)存,通過賦值bus_type的一些屬性,然后添加進(jìn)入list
下面函數(shù)其實(shí)是實(shí)現(xiàn)一個從鏈表的節(jié)點(diǎn),查詢到該節(jié)點(diǎn)所屬的設(shè)備,并且減少dev的計(jì)數(shù)。
static void klist_devices_get(struct klist_node *n) { struct device *dev = container_of(n, struct device, knode_bus); get_device(dev); } |
其實(shí)bus的注冊比較簡單,說到底還是kset和kobject控制著這一切,拋開kset和kobject的具體實(shí)現(xiàn),bus還是很好理解的。
3. 創(chuàng)建屬性文件
static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);
通過BUS_ATTR宏定義定義一個屬性文件,其參數(shù)依次是屬性文件名,屬性文件的mode,顯示屬性文件函數(shù)和存儲屬性文件函數(shù)。
顯示屬性文件的函數(shù)如下所示:
static ssize_t show_bus_version(struct bus_type *bus, char *buf){ return snprintf(buf, PAGE_SIZE, '%sn', Version); } |
創(chuàng)建屬性文件:
bus_create_file(&my_bus_type, &bus_attr_version)
其實(shí)原理上,它就是調(diào)用sysfs_create_file函數(shù)來實(shí)現(xiàn)的。
4. bus的注銷
bus的卸載函數(shù)如下所示:
bus_unregister(&my_bus_type);
二、總線實(shí)例介紹
1. 定義bus_type結(jié)構(gòu)體
以及實(shí)現(xiàn).match的my_match函數(shù),用于檢測驅(qū)動與設(shè)備是否匹配
2. 定義bus屬性文件結(jié)構(gòu)體
上面的version是我們前面定義的一個字符串
3. 在init函數(shù)中注冊總線
如圖所示,
bus_register(&my_bus_type); 用于注冊我們的總線,加入總線列表list,具體功能看前面
bus_create_file(&my_bus_type, &bus_attr_version); 創(chuàng)建我們my_bus_type 的屬性文件
&bus_attr_version 這個結(jié)構(gòu)體就是前面我們
static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL); 得到的。
查看linux源碼如下:
4. 在exit函數(shù)中卸載總線
至止,我們已經(jīng)實(shí)現(xiàn)了 總線-驅(qū)動-設(shè)備 模型中的總線了
5. 編譯測試
附上源代碼:
1 #include 2 #include 3 #include 4 #include 5 #include 6 7 static char *Version = '$LoverXueEr : 1.0 $'; 8 9 //檢測驅(qū)動是否匹配設(shè)備,dev->bus_id 和 driver->name相等的 10 static int my_match(struct device *dev ,struct device_driver *driver){ 11 return !strncmp(dev_name(dev),driver->name,strlen(driver->name)); 12 } 13 14 struct bus_type my_bus_type = { 15 .name = 'my_bus', 16 .match = my_match, 17 }; 18 //顯示總線版本號 19 static ssize_t show_bus_version(struct bus_type *bus,char *buf){ 20 return snprintf(buf,PAGE_SIZE,'%sn',Version); 21 } 22 23 //產(chǎn)生后面的 bus_attr_version 結(jié)構(gòu)體 24 static BUS_ATTR(version,S_IRUGO, show_bus_version, NULL); 25 26 static int __init my_bus_init(void){ 27 int ret; 28 /* 注冊總線 */ 29 ret = bus_register(&my_bus_type); 30 if(ret) 31 return ret; 32 /* 創(chuàng)建屬性文件 */ 33 if(bus_create_file(&my_bus_type, &bus_attr_version)) 34 printk('<0>Fail to create version attribute! n'); 35 return ret; 36 } 37 38 static void my_bus_exit(void){ 39 bus_unregister(&my_bus_type); 40 } 41 42 module_init(my_bus_init); 43 module_exit(my_bus_exit); 44 45 46 MODULE_AUTHOR('Lover雪兒'); 47 MODULE_LICENSE('GPL');
上一篇:IMX257 總線設(shè)備驅(qū)動模型編程之總線篇(二)
下一篇:IMX257設(shè)備驅(qū)動模型之Kset
推薦閱讀最新更新時間:2025-06-07 23:40
設(shè)計(jì)資源 培訓(xùn) 開發(fā)板 精華推薦
- 意法半導(dǎo)體推出用于匹配遠(yuǎn)距離無線微控制器STM32WL33的集成的匹配濾波芯片
- ESP32開發(fā)板連接TFT顯示屏ST7789跳坑記
- 如何讓ESP32支持analogWrite函數(shù)
- LGVL配合FreeType為可變字體設(shè)置字重-ESP32篇
- 使用樹莓派進(jìn)行 ESP32 Jtag 調(diào)試
- ESP32怎么在SPIFFS里面存儲html,css,js文件,以及網(wǎng)頁和arduino的通訊
- ESP32 freeRTOS使用測試
- API調(diào)用小記(Touchdesigner和ESP32)
- 關(guān)于ESP32/8266使用async-mqtt-client庫的一些基本介紹
- LTM4602HV 演示板、28V、6A 降壓模塊穩(wěn)壓器
- PCB書簽 尺子 卡片
- PeanutPI
- 平衡自行車+獨(dú)輪車
- AM1DR-1209SZ 9V 1 瓦 DC-DC 轉(zhuǎn)換器的典型應(yīng)用
- NCV33074ADR2G 直流耦合反相放大器最大輸出擺幅的典型應(yīng)用
- 【明日方舟】羅德島本艦主控板V6.2
- DC795A,使用 LT5527EUF 4.5V 至 5.25V 高線性下變頻混頻器的演示板
- XL4016可調(diào)恒壓恒流實(shí)驗(yàn)電源
- 帶內(nèi)部開關(guān)的 PAM2863 2A LED 驅(qū)動器的典型應(yīng)用
- 芯原超低能耗NPU可為移動端大語言模型推理提供超40 TOPS算力
- 芯原AI-ISP芯片定制方案助力客戶智能手機(jī)量產(chǎn)出貨
- AI加持,安森美一站式服務(wù)推動助聽器市場持續(xù)進(jìn)步
- 意法半導(dǎo)體推出用于匹配遠(yuǎn)距離無線微控制器STM32WL33的集成的匹配濾波芯片
- 如何為您的應(yīng)用選擇光傳感器
- Samtec新型農(nóng)業(yè)漫談系列二 | 垂直農(nóng)業(yè)案列分享
- Samtec應(yīng)用科普 | C-V2X技術(shù)在汽車領(lǐng)域的應(yīng)用
- 尼得科運(yùn)動&能源事業(yè)本部在印度卡納塔克邦胡布利舉行新工廠竣工儀式
- 貿(mào)澤開售Qorvo適用于5G和mMIMO應(yīng)用的新型QPA9822線性5G高增益/高驅(qū)動放大器
- 邊緣計(jì)算網(wǎng)關(guān)工業(yè)物聯(lián)網(wǎng)應(yīng)用:空壓機(jī)遠(yuǎn)程運(yùn)維監(jiān)控管理
- OPPO A16手機(jī)在Geekbench現(xiàn)身:Helio G35芯片,3GB內(nèi)存
- 傳音新機(jī)支持160W快充:前所未有
- 小黃車快黃了,你的押金也黃了?
- 小米正在招募團(tuán)隊(duì),重新殺入手機(jī)芯片賽道
- 三星電子將量產(chǎn)Micro LED電視,LED芯片誰來供應(yīng)?
- 單片機(jī)+PCF8591實(shí)現(xiàn)數(shù)字電壓表
- 51單片機(jī)簡易電子稱程序
- NVIDIA收購Arm確認(rèn),迎接萬物計(jì)算時代的到來
- NDT電容壓感觸控技術(shù)掀起TWS行業(yè)交互變革新浪潮
- 2020中國汽車測試展:Elektrobit將展示車輛架構(gòu)尖端技術(shù)