platform總線實(shí)際上并不對(duì)應(yīng)任何硬件上的總線,有時(shí)又稱為偽總線。由于設(shè)備模型中的驅(qū)動(dòng)和設(shè)備關(guān)聯(lián)機(jī)制必須要有一條總線才能發(fā)揮作用,對(duì)于那些沒有連接在實(shí)際總線上的設(shè)備,如果想使用這種機(jī)制,就需要將它連接在一條假想的總線上。platform總線就可以起到這個(gè)作用,通常,platform總線上的設(shè)備都是直接與CPU相連的底層設(shè)備。 使用platform總線的好處是可以將驅(qū)動(dòng)與設(shè)備分離,驅(qū)動(dòng)所需的平臺(tái)相關(guān)數(shù)據(jù)則在定義設(shè)備時(shí)提供,使驅(qū)動(dòng)具有更大的跨平臺(tái)通用性。
platform總線的相關(guān)定義和聲明在頭文件中。
1.platform總線基本特征
struct bus_type platform_bus_type = {
.name = "platform",
.match = platform_match,
.uevent = platform_uevent,
......
}
匹配操作是platform_match,定義如下:
static int platform_match(struct device *dev, struct device_driver *drv)
{
struct platform_device *pdev=to_platform_device(dev);
struct platform_driver *pdrv=to_platform_driver(drv);
if(pdrv->id_table)
return platform_match_id(pdrv->id_table,pdev)!=NULL;
return (strcmp(pdev->name,drv->name)==0);
}
其中調(diào)用的platform_match_id函數(shù)定義如下:
static const struct platform_device_id *platform_match_id(
struct platform_device_id *id, struct platform_device *pdev)
{
while(id->name[0]){
if(strcmp(pdev->name, id->name) == 0){ pdev->id_entry=id; return id; }
id++;
}
return NULL;
}
顯然在匹配時(shí),先將設(shè)備的名稱與驅(qū)動(dòng)的id_table成員數(shù)組中列舉的名稱逐一比較,若相同則匹配成功,否則再將設(shè)備的名字與驅(qū)動(dòng)的名字比較,若相同則匹配成功。
platform總線的用戶態(tài)事件鉤子函數(shù)是platform_uevent,定義如下:
static int platform_uevent(struct device *dev, struct kobj_uevent_env *env){
struct platform_device *pdev = to_platform_device(dev);
add_uevent_var(env,"MODALIAS=%s%s", PLATFORM_MODULE_PREFIX, (pdev->id_entry) ? pdev->id_entry->name : pdev->name);
return 0;
}
也就是說,platform總線上的設(shè)備發(fā)送用戶態(tài)事件時(shí),會(huì)增加一個(gè)MODALIAS環(huán)境變量。
2.platform設(shè)備
struct platform_device{
const char *name;//設(shè)備名稱
int id;//設(shè)備編號(hào),-1表示只有一個(gè)
struct device dev;//內(nèi)嵌的設(shè)備對(duì)象
u32 num_resources;//資源數(shù)組中的元素的個(gè)數(shù)
struct resource *resource;//指向描述資源的數(shù)組
struct platform_device_id *id_entry;//保存與驅(qū)動(dòng)匹配后的ID
}
設(shè)備的名稱最終會(huì)被設(shè)為name.id,其中id是設(shè)備的編號(hào)。如果id的賦值為-1,表示設(shè)備的個(gè)數(shù)只可能是1個(gè),這時(shí)設(shè)備的名字為name.
num_resources和resource用于描述設(shè)備需要的全部資源,即端口號(hào),IO內(nèi)存、中斷號(hào)等,內(nèi)存將它們統(tǒng)稱為資源。
struct resource{
resource_size_t start;//資源區(qū)域的起始值
resource_size_t end;//資源區(qū)域的結(jié)束值
const char *name;//申請(qǐng)資源的設(shè)備名稱
unsigned long flags;//資源的標(biāo)志
struct resource *parent,*sibling,*child;//樹指針
}
每個(gè)struct resource類型的數(shù)據(jù)描述資源的一段區(qū)域,同一類型的所有資源以樹的形式組織在一起。資源的標(biāo)志包含了資源類型的說明,常用類型如下:
* IORESOURCE_IO :端口號(hào)資源
* IORESOURCE_MEM :IO內(nèi)存資源
* IORESOURCE_IRQ :中斷號(hào)資源
* IORESOURCE_DMA :DMA資源
平臺(tái)相關(guān)的其他數(shù)據(jù)則放在platform設(shè)備的dev成員的platform_data指針?biāo)赶虻膬?nèi)存中,。
下面是platform設(shè)備的注冊(cè)和注銷函數(shù)的原型:
int platform_device_register(struct platform_device *pdev);//注冊(cè)
void platform_device_unregister(struct platform_device *pdev);//注銷
注冊(cè)platform設(shè)備時(shí),首先向platform總線注冊(cè)相應(yīng)的設(shè)備,然后將設(shè)備的端口號(hào)和IO內(nèi)存資源添加到系統(tǒng)的資源樹種,注銷platform設(shè)備則是相反的操作。
通常一個(gè)系統(tǒng)中的platform設(shè)備的個(gè)數(shù)和類型總是固定的,因此可以把它們的地址放在一個(gè)數(shù)組中,然后用下面的接口函數(shù)同時(shí)注冊(cè):
int platform_add_devices(struct platform_device **devs, int num);
3.platform驅(qū)動(dòng)
struct platform_driver{
int (*probe)(struct platform_device *pdev)
int (*remove)(struct platform_device *pdev);
struct device_driver driver;//內(nèi)嵌的驅(qū)動(dòng)對(duì)象
struct platform_device_id *id_table;//用于匹配的ID數(shù)組
.......
}
在platform驅(qū)動(dòng)的成員driver的各種操作函數(shù)中,實(shí)際上直接回調(diào)了platform驅(qū)動(dòng)的各種操作,只是將參數(shù)的類型轉(zhuǎn)換了下。因?yàn)閜latform總線本身沒有probe和remove操作,所以當(dāng)platform驅(qū)動(dòng)注冊(cè)時(shí),若platform總線上已經(jīng)注冊(cè)了匹配的設(shè)備,就會(huì)調(diào)用驅(qū)動(dòng)的probe方法。
platform設(shè)備通常先于platform驅(qū)動(dòng)而加載,這樣探測操作就會(huì)只發(fā)生在模塊的加載過程中,從而可以安全的放入初始化數(shù)據(jù)段,以節(jié)約內(nèi)存。
注冊(cè)和注銷platform驅(qū)動(dòng)的接口函數(shù)如下:
int platform_driver_register(struct platform_driver *drv);
void platform_driver_unregister(struct platform_driver *drv);
在platform驅(qū)動(dòng)的probe函數(shù)中,可以用下面這個(gè)函數(shù)獲取設(shè)備的各種資源:
struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned num);
*dev指向要獲取資源的platform設(shè)備。
*type資源的類型
*num:資源的索引,表示要獲得設(shè)備的資源數(shù)組中第幾個(gè)此類型的資源,索引從0開始編號(hào)。
獲取中斷號(hào)的接口函數(shù):
int platform_get_irq(struct platform_device *dev, unsigned int num);
評(píng)論