linux筆記5

linux設備模型bus,device,driver
作者 codercjg10 十一月 2015, 2:43 下午

linux2.6提供了新的設備模型:總線、驅動、設備?;娟P系簡要的概括如下:
驅動核心可以注冊多種類型的總線。
每種總線下面可以掛載許多設備。(通過kset devices)
每種總線下可以用很多設備驅動。(通過包含一個kset drivers)}
每個驅動可以處理一組設備。按照我的理解就是所有的設備都掛載到總線上,當加載驅動時,驅動就支總線上找到自己對應的設備?;蛘呦劝羊寗蛹虞d上,來了一個設備就去總線找驅動。
一:總線
總線是處理器與設備之間通道,在設備模型中,所有的設備都通過總線相連。
關于總線的一些結構體:bus_type,
(1)bus_type:
struct bus_type {
const char * name;//設備名稱
struct subsystem subsys;//代表自身
struct kset drivers; //當前總線的設備驅動集合
struct kset devices; //所有設備集合
struct klist klist_devices;
struct klist klist_drivers;
struct bus_attribute * bus_attrs;//總線屬性
struct device_attribute * dev_attrs;//設備屬性
struct driver_attribute * drv_attrs;
int (match)(struct device * dev, struct device_driver * drv);//設備驅動匹配函數
int (
uevent)(struct device dev, char envp, int num_envp, char buffer, int buffer_size);//熱拔插事件
int (
probe)(struct device * dev);
int (
remove)(struct device * dev);
void (
shutdown)(struct device * dev);
int (
suspend)(struct device * dev, pm_message_t state);
int (*resume)(struct device * dev);
};
在后面的實例當中用到了里面的兩個成員
1:const char name;
2:int (
match)(struct device * dev, struct device_driver * drv);
設備驅動匹配函數,這個匹配函數是很關鍵的東西,這是建立總線上設備與驅動的橋梁,當一個新的設備或驅動被添加到一個總線上時被調用。
(2)總線的操作:
注冊:int bus_register(struct bus_type * bus)
注銷:void bus_unregister(struct bus_type bus);
(3)總線屬性 bus_attribute
struct bus_attribute {
struct attribute attr;
ssize_t (
show)(struct bus_type *bus, char buf);
ssize_t (
store)(struct bus_type *bus, const char *buf,size_t count);
};
BUS_ATTR(name, mode, show, store);
這個宏聲明一個結構, 產生它的名子通過前綴字符串 bus_attr_ 到給定的名子(bus_attr_name),然后利用bus_create_file來創建總線屬性
int bus_create_file(struct bus_type *bus, struct bus_attribute *attr);
參數中的attr,即為bus_attr_name。
另外, 就是參數中的 show 方法,設置方法如下
static ssize_t show_bus_version(struct bus_type *bus, char *buf) {
return snprintf(buf, PAGE_SIZE, “%s\n”, Version);
}
總線屬性的刪除, 使用:
void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr);
(4)總線實例:
1:首先是要準備一個總線bus_type.也就是定義一個bus_type,然后給它填上一些成員。定義如下:
struct bus_type my_bus_type = {
.name = “my_bus”,
.match = my_match,
};
這里就對其兩個成員賦值了。一個是名稱。另一個則是匹配函數:
2,總線本身也是要對應一個設備的。還要為總線創建設備。
struct device my_bus = {
.bus_id = “my_bus0″,
.release = my_bus_release
};
源代碼:

include <linux/module.h>

include <linux/kernel.h>

include <linux/init.h>

include <linux/device.h>

include <linux/string.h>

static char *version = “version 1.0″;
//用于判斷指定的驅動程序是否能處理指定的設備。
static int my_match(struct device *dev, struct device_driver *driver) {
return !strncmp(dev->bus_id, driver->name, strlen(driver->name));
}
static int my_bus_release(struct device *dev) {
return 0;
}
static ssize_t show_bus_version(struct bus_type *bus, char buf) {
return sprintf(buf, PAGE_SIZE, “%s\n”, version);
}
static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);
struct device my_bus = {//定義總線設備
.bus_id = “my_bus0″,
.release = my_bus_release,
};
EXPORT_SYMBOL(my_bus);
struct bus_type my_bus_type = { //定義總線類型
.name = “my_bus”,
.match = my_match,
};
EXPORT_SYMBOL(my_bus_type);
static int __init my_bus_init(void){
int ret;
ret = bus_register(&my_bus_type);//注冊總線
if(ret)
printk(“bus_register failed!\n”);
if(bus_create_file(&my_bus_type, &bus_attr_version))//創建總線屬性
printk(“Creat bus failed!\n”);
ret = device_register(&my_bus);//注冊總線設備
if (ret)
printk(“device_register failed!\n”);
return ret;
}
static void __exit my_bus_exit(void) {
bus_unregister(&my_bus_type);//刪除總線屬性
device_unregister(&my_bus);//刪除總線設備
}
module_init(my_bus_init);
module_exit(my_bus_exit);
MODULE_AUTHOR(“Fany”);
MODULE_LICENSE(“GPL”);
(5)測試
將bus.c以動態加載的方式加載到內核,insmod bus.ko,在/sys/bus/目錄下會有一個my_bus目錄,這就是我們添加的總線。該目錄下有devices,drivers目錄,因為該總線上沒有掛載任何設備和驅動,所以這兩個目錄都為空;同時,在/sy/devices目錄下,還可看到my_bus0設備(總線本身也是一種設備)。
二:設備:
關于設備的一些常用結構體:device,
1:
struct device {
struct device * parent; //父設備,一般一個bus也對應一個設備。
struct kobject kobj;//代表自身
char bus_id[BUS_ID_SIZE];
struct bus_type * bus; /
所屬的總線 /
struct device_driver driver; / 匹配的驅動
/
void driver_data; / data private to the driver 指向驅動 /
void platform_data; / Platform specific data,由驅動定義并使用
/
………..更多字段忽略了
};
注冊設備:int device_register(sruct device *dev)
注銷設備:void device_unregister(struct device dev);
2:設備屬性:
sysfs 中的設備入口可有屬性. 相關的結構是:
struct device_attribute {
struct attribute attr;
ssize_t (
show)(struct device *dev, char buf);
ssize_t (
store)(struct device *dev, const char *buf,
size_t count);
};
這些屬性結構可在編譯時建立, 使用這些宏:
DEVICE_ATTR(name, mode, show, store);
結果結構通過前綴 dev_attr_ 到給定名子上來命名. 屬性文件的實際管理使用通常的函數對來處理:
int device_create_file(struct device *device, struct device_attribute *entry);
void device_remove_file(struct device *dev, struct device_attribute *attr);
3:創建設備實例:

include <linux/module.h>

include <linux/kernel.h>

include <linux/init.h>

include <linux/device.h>

include <linux/string.h>

extern struct device my_bus; //這里用到了總線設備中定義的結構體
extern struct bus_type my_bus_type;
static int my_device_release() {
return 0;
}
struct device my_dev={ //創建設備屬性
.bus = &my_bus_type,//定義總線類型
.parent = &my_bus,//定義my_dev的父設備。
.release = my_device_release,
};
static ssize_t mydev_show(struct device dev, char buf) {
return sprintf(buf, “%s\n”, “This is my device!”);
}
static DEVICE_ATTR(dev, S_IRUGO, mydev_show, NULL);
static int __init my_device_init(void){
int ret;
strncpy(my_dev.bus_id, “my_dev”, BUS_ID_SIZE); //初始化設備
ret = device_register(&my_dev); //注冊設備
if (ret)
printk(“device register!\n”);
device_create_file(&my_dev, &dev_attr_dev); //創建設備文件
return ret;
}
static void __exit my_device_exit(void) {
device_unregister(&my_dev);//卸載設備
}
module_init(my_device_init);
module_exit(my_device_exit);
MODULE_AUTHOR(“Fany”);
MODULE_LICENSE(“GPL”);
4:測試
將設備device.c,編譯成模塊,以動態加載的方式加載到內核。會發現在sys/bus/my_bus/devices/目錄下有一個my_dev設備,查看屬性,它是掛在/sys/devices/my_bus0/my_dev目錄下,至此添加設備成功。
三:設備驅動:
1:關于驅動的常用結構體:device_driver
struct device_driver {
const char name; /驅動程序的名字( 在 sysfs 中出現 )
/
struct bus_type bus; /驅動程序所操作的總線類型
/
struct module *owner;
const char mod_name; / used for built-in modules /
int (
probe) (struct device dev);
int (
remove) (struct device dev);
void (
shutdown) (struct device dev);
int (
suspend) (struct device dev, pm_message_t state);
int (
resume) (struct device *dev);
struct attribute_group *groups;
struct pm_ops pm;
struct driver_private p;
};
2:驅動程序的注冊和注銷
/
注冊device_driver 結構的函數是:
/
int driver_register(struct device_driver drv);
void driver_unregister(struct device_driver drv);
3:驅動程序的屬性
/
driver的屬性結構在:
/
struct driver_attribute {
struct attribute attr;
ssize_t (
show)(struct device_driver *drv, char buf);
ssize_t (
store)(struct device_driver drv, const char buf, size_t count);
};
DRIVER_ATTR(_name,_mode,_show,_store) /
屬性文件創建的方法:
/
int driver_create_file(struct device_driver * drv, struct driver_attribute * attr);//創建設備驅動的屬性
void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr);
4:驅動實例

include <linux/module.h>

include <linux/kernel.h>

include <linux/init.h>

include <linux/device.h>

include <linux/string.h>

extern struct bus_type my_bus_type;
static int my_probe(struct device *dev) {
printk(“Driver found device!\n”);
return 0;
};
static int my_remove(struct device *dev) {
printk(“Driver unpluged!\n”);
return 0;
};
struct device_driver my_driver = {
.name = “my_dev”,
.bus = &my_bus_type,
.probe = my_probe,
.remove = my_remove,
};
//定義設備驅動屬性
static ssize_t my_driver_show(struct device_driver *driver, char *buf) {
return sprintf(buf, “%s\n”, “This is my driver!”);
};
static DRIVER_ATTR(drv, S_IRUGO, my_driver_show, NULL);
static int __init my_driver_init(void){
int ret;
//注冊設備驅動
ret = driver_register(&my_driver);
if(ret)
printk(“driver_register failed!\n”);
//創建設備驅動屬性
ret = driver_create_file(&my_driver, &driver_attr_drv);
if(ret)
printk(“create_driver_file failed!\n”);
return ret;
}
static void __exit my_driver_exit(void){
driver_unregister(&my_driver);//注銷設備驅動
}
module_init(my_driver_init);
module_exit(my_driver_exit);
MODULE_AUTHOR(“Fany”);
MODULE_LICENSE(“GPL”);
5:測試
當加載驅動程序時,終端界面上打印
Driver found device!
說明驅動找到了匹配的設備,看到打印這個時,想到在windows下插U盤,立馬彈出“發現可移動設備”,有點相像!
再看看相應的目錄:/sys/bus/my_bus/drivers/,多了一個my_dev。

說明添加驅動成功
原文地址:http://blog.chinaunix.net/uid-23254875-id-341060.html

分類: Linux驅動 | 評論

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,106評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,441評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,211評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,736評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,475評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,834評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,829評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,009評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,559評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,306評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,516評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,038評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,728評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,132評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,443評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,249評論 3 399
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,484評論 2 379

推薦閱讀更多精彩內容