總線是處理器和一個或多個設(shè)備之間的通道,在設(shè)備模型中,所有的設(shè)備都通過總線相連,甚至是內(nèi)部的虛擬"platform"總線??梢酝ㄟ^ls -l /sys/bus看到系統(tǒng)加載的所有總線。
drwxr-xr-x root root 1970-01-01 00:02 platform
drwxr-xr-x root root 1970-01-01 00:02 spi
drwxr-xr-x root root 1970-01-01 00:02 scsi
drwxr-xr-x root root 1970-01-01 00:02 usb
drwxr-xr-x root root 1970-01-01 00:02 serio
drwxr-xr-x root root 1970-01-01 00:02 i2c
drwxr-xr-x root root 1970-01-01 00:02 mmc
drwxr-xr-x root root 1970-01-01 00:02 sdio
drwxr-xr-x root root 1970-01-01 00:02 ac97
總線可以相互插入。設(shè)備模型展示了總線和它們所控制的設(shè)備之間的實際連接。在Linux 設(shè)備模型中,總線由bus_type 結(jié)構(gòu)表示,定義在 <linux/device.h> :
struct bus_type {
const char *name; /*總線類型名稱*/
struct bus_attribute *bus_attrs; /*總線屬性*/
struct device_attribute *dev_attrs; /*設(shè)備屬性,指為每個加入總線的設(shè)備建立的默認屬性鏈表*/
struct driver_attribute *drv_attrs; /*驅(qū)動程序?qū)傩?/
int (*match)(struct device *dev, struct device_driver *drv); /*總線操作函數(shù)*/
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
int (*probe)(struct device *dev);
int (*remove)(struct device *dev);
void (*shutdown)(struct device *dev);
int (*suspend)(struct device *dev, pm_message_t state); /*電源管理函數(shù)*/
int (*suspend_late)(struct device *dev, pm_message_t state);
int (*resume_early)(struct device *dev);
int (*resume)(struct device *dev);
struct pm_ext_ops *pm;
struct bus_type_private *p;
};
1,總線的注冊和刪除,總線的主要注冊步驟:
(1)申明和初始化bus_type 結(jié)構(gòu)體。只有很少的bus_type 成員需要初始化,大部分都由設(shè)備模型核心控制。但必須為總線指定名字及一些必要的方法。例如:
struct bus_type ldd_bus_type = {
.name = "ldd",
.match = ldd_match,
.uevent = ldd_uevent,
};
(2)調(diào)用bus_register函數(shù)注冊總線。int bus_register(struct bus_type *bus),該調(diào)用可能失敗,所以必須始終檢查返回值。
ret = bus_register(&ldd_bus_type);
if (ret)
return ret;
若成功,新的總線子系統(tǒng)將被添加進系統(tǒng),之后可以向總線添加設(shè)備。當(dāng)必須從系統(tǒng)中刪除一個總線時,調(diào)用:
void bus_unregister(struct bus_type *bus);
2,總線方法
在 bus_type
結(jié)構(gòu)中定義了許多方法,它們允許總線核心作為設(shè)備核心與單獨的驅(qū)動程序之間提供服務(wù)的中介,主要介紹以下兩個方法: int
(*match)(struct device * dev, struct device_driver * drv);
/*當(dāng)一個新設(shè)備或者驅(qū)動被添加到這個總線時,這個方法會被調(diào)用一次或多次,若指定的驅(qū)動程序能夠處理指定的設(shè)備,則返回非零值。*/
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
/*在為用戶空間產(chǎn)生熱插拔事件之前,這個方法允許總線添加環(huán)境變量*/
對設(shè)備和驅(qū)動的迭代:若要編寫總線層代碼,可能不得不對所有已經(jīng)注冊到總線的設(shè)備或驅(qū)動進行一些迭代操作,這可能需要仔細研究嵌入到 bus_type 結(jié)構(gòu)中的其他數(shù)據(jù)結(jié)構(gòu),但最好使用內(nèi)核提供的輔助函數(shù):
int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, int (*fn)(struct device *, void *));
int bus_for_each_drv(struct bus_type *bus, struct device_driver *start, void *data, int (*fn)(struct device_driver *, void *));
/*
這兩個函數(shù)迭代總線上的每個設(shè)備或驅(qū)動程序(內(nèi)部分別有next_device和next_driver),將關(guān)聯(lián)的device或
device_driver傳遞給 fn,同時傳遞data
值。若start為NULL,則從第一個設(shè)備開始;否則從start之后的第一個設(shè)備開始。若fn返回非零值,迭代停止并且那個值從
bus_for_each_dev 或bus_for_each_drv 返回。*/
3,總線屬性
幾乎Linux 設(shè)備模型中的每一層都提供添加屬性的函數(shù),總線層也不例外。bus_attribute 類型定義在<linux/device.h> 如下:
struct bus_attribute {
struct attribute attr;
ssize_t (*show)(struct bus_type *, char * buf);
ssize_t (*store)(struct bus_type *, const char * buf, size_t count);
};
內(nèi)核提供了一個宏在編譯時創(chuàng)建和初始化bus_attribute 結(jié)構(gòu):
BUS_ATTR(_name,_mode,_show,_store)/*這個宏聲明一個結(jié)構(gòu),將bus_attr_作為給定_name 的前綴來創(chuàng)建總線的真正名稱*/
/*總線的屬性必須顯式調(diào)用bus_create_file 來創(chuàng)建:*/
int bus_create_file(struct bus_type *bus, struct bus_attribute *attr);
/*刪除總線的屬性調(diào)用:*/
void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr);
例如創(chuàng)建一個包含源碼版本號簡單屬性方法如下:
static ssize_t show_bus_version(struct bus_type *bus, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s/n", Version);
}
static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL); //得到bus_attr_version
/*在模塊加載時創(chuàng)建屬性文件:*/
if (bus_create_file(&ldd_bus_type, &bus_attr_version))
printk(KERN_NOTICE "Unable to create version attribute/n");
/*這個調(diào)用創(chuàng)建一個包含 lddbus 代碼的版本號的屬性文件(/sys/bus/ldd/version)*/
本文來自CSDN博客,轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/funy_liu/archive/2010/02/25/5322040.aspx