linux設(shè)備模型bus,device,driver
作者 codercjg 在 10 十一月 2015, 2:43 下午
linux2.6提供了新的設(shè)備模型:總線、驅(qū)動(dòng)掉蔬、設(shè)備勾习∨ǖ桑基本關(guān)系簡(jiǎn)要的概括如下:
驅(qū)動(dòng)核心可以注冊(cè)多種類型的總線。
每種總線下面可以掛載許多設(shè)備巧婶。(通過kset devices)
每種總線下可以用很多設(shè)備驅(qū)動(dòng)乾颁。(通過包含一個(gè)kset drivers)}
每個(gè)驅(qū)動(dòng)可以處理一組設(shè)備。按照我的理解就是所有的設(shè)備都掛載到總線上粹舵,當(dāng)加載驅(qū)動(dòng)時(shí)钮孵,驅(qū)動(dòng)就支總線上找到自己對(duì)應(yīng)的設(shè)備⊙勐耍或者先把驅(qū)動(dòng)加載上巴席,來了一個(gè)設(shè)備就去總線找驅(qū)動(dòng)。
一:總線
總線是處理器與設(shè)備之間通道诅需,在設(shè)備模型中漾唉,所有的設(shè)備都通過總線相連。
關(guān)于總線的一些結(jié)構(gòu)體:bus_type堰塌,
(1)bus_type:
struct bus_type {
const char * name;//設(shè)備名稱
struct subsystem subsys;//代表自身
struct kset drivers; //當(dāng)前總線的設(shè)備驅(qū)動(dòng)集合
struct kset devices; //所有設(shè)備集合
struct klist klist_devices;
struct klist klist_drivers;
struct bus_attribute * bus_attrs;//總線屬性
struct device_attribute * dev_attrs;//設(shè)備屬性
struct driver_attribute * drv_attrs;
int (match)(struct device * dev, struct device_driver * drv);//設(shè)備驅(qū)動(dòng)匹配函數(shù)
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);
};
在后面的實(shí)例當(dāng)中用到了里面的兩個(gè)成員
1:const char name;
2:int (match)(struct device * dev, struct device_driver * drv);
設(shè)備驅(qū)動(dòng)匹配函數(shù)赵刑,這個(gè)匹配函數(shù)是很關(guān)鍵的東西,這是建立總線上設(shè)備與驅(qū)動(dòng)的橋梁场刑,當(dāng)一個(gè)新的設(shè)備或驅(qū)動(dòng)被添加到一個(gè)總線上時(shí)被調(diào)用般此。
(2)總線的操作:
注冊(cè):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);
這個(gè)宏聲明一個(gè)結(jié)構(gòu), 產(chǎn)生它的名子通過前綴字符串 bus_attr_ 到給定的名子(bus_attr_name),然后利用bus_create_file來創(chuàng)建總線屬性
int bus_create_file(struct bus_type *bus, struct bus_attribute *attr);
參數(shù)中的attr牵现,即為bus_attr_name铐懊。
另外, 就是參數(shù)中的 show 方法,設(shè)置方法如下
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)總線實(shí)例:
1:首先是要準(zhǔn)備一個(gè)總線bus_type.也就是定義一個(gè)bus_type瞎疼,然后給它填上一些成員科乎。定義如下:
struct bus_type my_bus_type = {
.name = “my_bus”,
.match = my_match,
};
這里就對(duì)其兩個(gè)成員賦值了。一個(gè)是名稱贼急。另一個(gè)則是匹配函數(shù):
2茅茂,總線本身也是要對(duì)應(yīng)一個(gè)設(shè)備的。還要為總線創(chuàng)建設(shè)備太抓。
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″;
//用于判斷指定的驅(qū)動(dòng)程序是否能處理指定的設(shè)備空闲。
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 = {//定義總線設(shè)備
.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);//注冊(cè)總線
if(ret)
printk(“bus_register failed!\n”);
if(bus_create_file(&my_bus_type, &bus_attr_version))//創(chuàng)建總線屬性
printk(“Creat bus failed!\n”);
ret = device_register(&my_bus);//注冊(cè)總線設(shè)備
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);//刪除總線設(shè)備
}
module_init(my_bus_init);
module_exit(my_bus_exit);
MODULE_AUTHOR(“Fany”);
MODULE_LICENSE(“GPL”);
(5)測(cè)試
將bus.c以動(dòng)態(tài)加載的方式加載到內(nèi)核,insmod bus.ko走敌,在/sys/bus/目錄下會(huì)有一個(gè)my_bus目錄进副,這就是我們添加的總線。該目錄下有devices,drivers目錄影斑,因?yàn)樵摽偩€上沒有掛載任何設(shè)備和驅(qū)動(dòng),所以這兩個(gè)目錄都為空机打;同時(shí)矫户,在/sy/devices目錄下,還可看到my_bus0設(shè)備(總線本身也是一種設(shè)備)残邀。
二:設(shè)備:
關(guān)于設(shè)備的一些常用結(jié)構(gòu)體:device皆辽,
1:
struct device {
struct device * parent; //父設(shè)備,一般一個(gè)bus也對(duì)應(yīng)一個(gè)設(shè)備芥挣。
struct kobject kobj;//代表自身
char bus_id[BUS_ID_SIZE];
struct bus_type * bus; / 所屬的總線 /
struct device_driver driver; / 匹配的驅(qū)動(dòng)/
void driver_data; / data private to the driver 指向驅(qū)動(dòng) /
void platform_data; / Platform specific data驱闷,由驅(qū)動(dòng)定義并使用/
………..更多字段忽略了
};
注冊(cè)設(shè)備:int device_register(sruct device *dev)
注銷設(shè)備:void device_unregister(struct device dev);
2:設(shè)備屬性:
sysfs 中的設(shè)備入口可有屬性. 相關(guān)的結(jié)構(gòu)是:
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);
};
這些屬性結(jié)構(gòu)可在編譯時(shí)建立, 使用這些宏:
DEVICE_ATTR(name, mode, show, store);
結(jié)果結(jié)構(gòu)通過前綴 dev_attr_ 到給定名子上來命名. 屬性文件的實(shí)際管理使用通常的函數(shù)對(duì)來處理:
int device_create_file(struct device *device, struct device_attribute *entry);
void device_remove_file(struct device *dev, struct device_attribute *attr);
3:創(chuàng)建設(shè)備實(shí)例:
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; //這里用到了總線設(shè)備中定義的結(jié)構(gòu)體
extern struct bus_type my_bus_type;
static int my_device_release() {
return 0;
}
struct device my_dev={ //創(chuàng)建設(shè)備屬性
.bus = &my_bus_type,//定義總線類型
.parent = &my_bus,//定義my_dev的父設(shè)備。
.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); //初始化設(shè)備
ret = device_register(&my_dev); //注冊(cè)設(shè)備
if (ret)
printk(“device register!\n”);
device_create_file(&my_dev, &dev_attr_dev); //創(chuàng)建設(shè)備文件
return ret;
}
static void __exit my_device_exit(void) {
device_unregister(&my_dev);//卸載設(shè)備
}
module_init(my_device_init);
module_exit(my_device_exit);
MODULE_AUTHOR(“Fany”);
MODULE_LICENSE(“GPL”);
4:測(cè)試
將設(shè)備device.c空免,編譯成模塊空另,以動(dòng)態(tài)加載的方式加載到內(nèi)核。會(huì)發(fā)現(xiàn)在sys/bus/my_bus/devices/目錄下有一個(gè)my_dev設(shè)備蹋砚,查看屬性扼菠,它是掛在/sys/devices/my_bus0/my_dev目錄下,至此添加設(shè)備成功坝咐。
三:設(shè)備驅(qū)動(dòng):
1:關(guān)于驅(qū)動(dòng)的常用結(jié)構(gòu)體:device_driver
struct device_driver {
const char name; /驅(qū)動(dòng)程序的名字( 在 sysfs 中出現(xiàn) )/
struct bus_type bus; /驅(qū)動(dòng)程序所操作的總線類型/
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:驅(qū)動(dòng)程序的注冊(cè)和注銷
/注冊(cè)device_driver 結(jié)構(gòu)的函數(shù)是:/
int driver_register(struct device_driver drv);
void driver_unregister(struct device_driver drv);
3:驅(qū)動(dòng)程序的屬性
/driver的屬性結(jié)構(gòu)在:/
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) /屬性文件創(chuàng)建的方法:/
int driver_create_file(struct device_driver * drv, struct driver_attribute * attr);//創(chuàng)建設(shè)備驅(qū)動(dòng)的屬性
void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr);
4:驅(qū)動(dòng)實(shí)例
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,
};
//定義設(shè)備驅(qū)動(dòng)屬性
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;
//注冊(cè)設(shè)備驅(qū)動(dòng)
ret = driver_register(&my_driver);
if(ret)
printk(“driver_register failed!\n”);
//創(chuàng)建設(shè)備驅(qū)動(dòng)屬性
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);//注銷設(shè)備驅(qū)動(dòng)
}
module_init(my_driver_init);
module_exit(my_driver_exit);
MODULE_AUTHOR(“Fany”);
MODULE_LICENSE(“GPL”);
5:測(cè)試
當(dāng)加載驅(qū)動(dòng)程序時(shí)循榆,終端界面上打印
Driver found device!
說明驅(qū)動(dòng)找到了匹配的設(shè)備,看到打印這個(gè)時(shí)墨坚,想到在windows下插U盤秧饮,立馬彈出“發(fā)現(xiàn)可移動(dòng)設(shè)備”,有點(diǎn)相像泽篮!
再看看相應(yīng)的目錄:/sys/bus/my_bus/drivers/盗尸,多了一個(gè)my_dev。
說明添加驅(qū)動(dòng)成功
原文地址:http://blog.chinaunix.net/uid-23254875-id-341060.html
分類: Linux驅(qū)動(dòng) | 評(píng)論