在輸入子系統(tǒng)框架學習中踪蹬,可以看到將其分為上下兩層,和左右兩邊漱牵;這就是我們今天要引入的另一個概念疚漆,驅(qū)動程序的分離分層。
一闻镶、什么是總線設(shè)備驅(qū)動模型
可以從三個概念丸升,來理解。
-
總線
?????? 一個總線是處理器和一個或多個設(shè)備之間的通道. 為設(shè)備模型的目的, 所有的設(shè)備都通過一個總線連接, 甚至它是一個內(nèi)部虛擬的"平臺"總線发钝。
?????? 在 Linux 內(nèi)核中, 總線由 bus_type 結(jié)構(gòu)表示, 定義在 <linux/device.h> 。
struct bus_type {
const char *name; /*總線名稱*/
int (*match) (struct device *dev, struct
device_driver *drv); /*驅(qū)動與設(shè)備的匹配函數(shù)*/
………
}
-
設(shè)備
代表著一個實際的硬件涛碑。
在 Linux內(nèi)核中, 設(shè)備由struct device結(jié)構(gòu)表示孵淘。
struct device {
{
const char *init name; /*設(shè)備的名字*/
struct bus_type *bus; /*設(shè)備所在的總線*/
………
}
-
驅(qū)動
代表具體操作設(shè)備的方式和流程。
在 Linux內(nèi)核中, 驅(qū)動由device_driver結(jié)構(gòu)表示:
struct device_driver {
{
const char *name; /*驅(qū)動名稱*/
struct bus_type *bus; /*驅(qū)動程序所在的總線*/
int (*probe) (struct device *dev);
………
}
二揉阎、為什么使用總線設(shè)備驅(qū)動模型
隨著技術(shù)的不斷進步背捌,系統(tǒng)的拓撲結(jié)構(gòu)也越來越復(fù)雜,對熱插拔坑赡,跨平臺移植性的要求也越來越高,2.4內(nèi)核已經(jīng)難以滿足這些需求毅否。為適應(yīng)這種形勢的需要,從Linux 2.6內(nèi)核開始提供了全新的設(shè)備模型徘溢。其優(yōu)勢在于采用了總線的模型對設(shè)備與驅(qū)動進行了管理捆探,提高了程序的可移植性。
三徐许、實例
- 1.0 總線由bus_type定義(位于<linux/device.h>
struct bus_type {
const char *name; /*總線名稱*/
/*總線屬性*/
struct bus_attribute *bus_attrs;
int (*match) (struct device *dev, struct
device_driver *drv); /*驅(qū)動與設(shè)備的匹配函數(shù)*/
/*為用戶空間產(chǎn)生熱插拔事件之前雌隅,這個方法允許總線添加環(huán)境變量*/
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
………
}
- 1 總線的注冊
bus_register(struct bus_type *bus)
若成功,新的總線將被添加進系統(tǒng)恰起,并可在/sys/bus 下看到相應(yīng)的目錄。
- 1.2總線的注銷
void bus_unregister(struct bus_type *bus)
- 1.3總線的匹配
參照bus_type:
int (*match)(struct device * dev, struct device_driver * drv)
當一個新設(shè)備或者新驅(qū)動被添加到這個總線時肯污,該函數(shù)被調(diào)用吨枉。用于判斷指定的驅(qū)動程序是否能處理指定的設(shè)備。若可以貌亭,則返回非零。
創(chuàng)建一條總線:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jalyn Fang");
/*比較設(shè)備的bus_id與驅(qū)動的名字是否匹配锄奢,
匹配一致則在insmod驅(qū)動 時候調(diào)用probe函數(shù)*/
int my_match(struct device *dev, struct device_driver *drv)
{
return !strncmp(dev->kobj.name,drv->name,strlen(drv->name));
}
struct bus_type my_bus_type = {
.name = "my_bus",
.match = my_match,
};
int my_bus_init()
{
int ret;
/*注冊總線*/
ret = bus_register(&my_bus_type);
return ret;
}
void my_bus_exit()
{
bus_unregister(&my_bus_type);
}
/*符號導(dǎo)出
* Export a simple attribute.
*/
EXPORT_SYMBOL(my_bus_type);
module_init(my_bus_init);
module_exit(my_bus_exit);
- 2.0 驅(qū)動device_driver定義剧腻,當加載驅(qū)動時候,會在總線上找到它能夠處理的設(shè)備灰伟。
- 1 驅(qū)動的注冊
int driver_register(struct device_driver *drv)
- 2.2驅(qū)動的注銷
void driver_unregister(struct device_driver *drv)
在總線上掛載驅(qū)動:
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jalyn Fang");
extern struct bus_type my_bus_type;
int my_probe(struct device *dev)
{
printk("driver found the device it can handle!\n");
return 0;
}
struct device_driver my_driver = {
.name = "my_dev",
/*指明這個驅(qū)動程序是屬于my_bus_type這條總線上的設(shè)備*/
.bus = &my_bus_type,
/*在my_bus_type總線上找到它能夠處理的設(shè)備儒旬,
就調(diào)用my_probe;刪除設(shè)備調(diào)用my_remove*/
.probe = my_probe,
/*能夠處理的設(shè)備?
1遏乔、什么時候驅(qū)動程序從總線找能夠處理的設(shè)備发笔;
答:驅(qū)動注冊時候
2凉翻、憑什么說能夠處理呢?(或者說標準是什么)前计;
答:驅(qū)動與設(shè)備都是屬于總線上的垃杖,利用總線的
結(jié)構(gòu)bus_type中match函數(shù)
*/
};
int my_driver_init()
{
int ret;
ret = driver_register(&my_driver);
return ret;
}
void my_driver_exit()
{
driver_unregister(&my_driver);
}
module_init(my_driver_init);
module_exit(my_driver_exit);
- 3.0
- 1 設(shè)備的注冊
int device_register(struct device *dev)
- 2 設(shè)備的注銷
void device_unregister(struct device *dev)
在總線上掛載設(shè)備:
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
extern struct bus_type my_bus_type;
struct device my_dev = {
.init_name = "my_dev",
.bus = &my_bus_type,
.release = my_dev_release,
};
int my_device_init()
{
int ret;
ret = device_register(&my_dev);
return ret;
}
void my_device_exit()
{
device_unregister(&my_dev);
}
module_init(my_device_init);
module_exit(my_device_exit);
參考:
https://blog.csdn.net/wh_19910525/article/details/7398051