閱讀platformdriver的代碼時,發現在probe函數直接調用platform_get_resource從pdev中擷取io記憶體,但卻沒有判斷傳給probe的pdev是否屬于這個驅動 !
後來發現原來在arch目錄下的對應目錄裡面有個devs.c檔案(這個檔案可能因不同的架構而不一樣),這個檔案裡面聲明了一個platform裝置的資源數組foo_devices,原型如下:
static struct platform_device* foo_devices[] __initdata;
這個數組裡面包含了所有platform裝置的資源資訊。例如:一個裝置的資源聲明如下:
static struct resource foo_resource[] =
{
[0] =
.start = (FOO_BASE_PA),
.end = (FOO_BASE_PA) + (0x0008000),
.flags = IORESOURCE_MEM,
},
[1] =
.start = (IRQ_FOO),
.end = (IRQ_FOO),
.flags = IORESOURCE_IRQ,
};
static struct platform_device device_foo =
.name = "device_foo",
.id = 0,
.resource = foo_resource,
.num_resources = ARRAY_SIZE(foo_resource),
.dev =
//根據源代碼,這兩個成員置成0表示不起作用
.dma_mask = 0x0,
.coherent_dma_mask = 0x0,
那麼将這個device_foo加入foo_devices數組,就能直接在probe函數中用platform_get_resource擷取資源了,但是要注意驅動的name成員必須和platform_device結構中的name成員完全相同。
那為什麼加入foo_devices數組後就能直接通路了呢?
在 相關體系的machine_desc結構體中(對于每個特定平台都有一個MACHINE_START宏用來定義machine_desc結構體),有一個 接口init_machine,這個接口中會調用platform_add_devices添加foo_devices。例如:
platform_add_devices(foo_devices);
platform_get_resource函數源碼如下:
struct resource *platform_get_resource(struct platform_device *dev,
unsigned int type, unsigned int num)
int i;
for (i = 0; i < dev->num_resources; i++) {
struct resource *r = &dev->resource[i];
if (type == resource_type(r) && num-- == 0)
return r;
}
return NULL;
}
函數分析:
struct resource *r = &dev->resource[i];
這行代碼使得不管你是想擷取哪一份資源都從第一份資源開始搜尋。
if (type == resource_type(r) && num-- == 0)
這行代碼首先通過type == resource_type(r)判斷目前這份資源的類型是否比對,如果比對則再通過num-- == 0判斷是否是你要的,如果不比對重新提取下一份資源而不會執行num-- == 0這一句代碼。
通過以上兩步就能定位到你要找的資源了,接着把資源傳回即可。如果都不比對就傳回NULL。
執行個體分析:
下面通過一個例子來看看它是如何拿到裝置資源的。
裝置資源如下:
static struct resource s3c_buttons_resource[] = {
[0]={
.start = S3C24XX_PA_GPIO,
.end = S3C24XX_PA_GPIO + S3C24XX_SZ_GPIO - 1,
.flags = IORESOURCE_MEM,
},
[1]={
.start = IRQ_EINT8,
.end = IRQ_EINT8,
.flags = IORESOURCE_IRQ,
[2]={
.start = IRQ_EINT11,
.end = IRQ_EINT11,
[3]={
.start = IRQ_EINT13,
.end = IRQ_EINT13,
[4]={
.start = IRQ_EINT14,
.end = IRQ_EINT14,
[5]={
.start = IRQ_EINT15,
.end = IRQ_EINT15,
[6]={
.start = IRQ_EINT19,
.end = IRQ_EINT19,
驅動中通過下面代碼拿到第一份資源:
struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
函數進入for裡面,i=0,num_resources=7,拿出resource[0]資源。resource_type(r)提取出該份資源 的資源類型并與函數傳遞下來的資源類型進行比較,比對。Num=0(這裡先判斷是否等于0再自減1)符合要求,進而傳回該資源。
擷取剩下資源的代碼如下:
for(i=0; i<6; i++){
buttons_irq = platform_get_resource(pdev,IORESOURCE_IRQ,i);
if(buttons_irq == NULL){
dev_err(dev,"no irq resource specified\n");
ret = -ENOENT;
goto err_map;
}
button_irqs[i] = buttons_irq->start;
分析如下:
For第一次循環:
buttons_irq = platform_get_resource(pdev,IORESOURCE_IRQ,0);
在拿出第一份資源進行resource_type(r)判斷資源類型時不符合(此時num-- == 0這句沒有執行),進而拿出第二份資源,此時i=1,num_resources=7,num傳遞下來為0,資源類型判斷時候比對,num也等于0,進而确定資源并傳回。
For第二次循環:
buttons_irq = platform_get_resource(pdev,IORESOURCE_IRQ,1);
拿出第二份資源的時候resource_type(r)資源類型比對,但是num傳遞下來時候為1,執行num-- == 0時不符合(但num開始自減1,這導緻拿出第三份資源時num==0),隻好拿出第三份資源。剩下的以此類推。
總結:
unsigned int type決定資源的類型,unsigned int num決定type類型的第幾份資源(從0開始)。即使同類型資源在資源數組中不是連續排放也可以定位得到該資源。
比如第一份IORESOURCE_IRQ類型資源在resource[2],而第二份在resource[5],那
platform_get_resource(pdev,IORESOURCE_IRQ,0);
可以定位第一份IORESOURCE_IRQ資源;
platform_get_resource(pdev,IORESOURCE_IRQ,1);
可以定位第二份IORESOURCE_IRQ資源。
之是以能定位到資源,在于函數實作中的這一行代碼:
該行代碼,如果沒有比對資源類型,num-- == 0不會執行而重新提取下一份資源,隻有資源比對了才會尋找該類型的第幾份資源,即使這些資源排放不連續。
【作者】sky
【出處】http://www.cnblogs.com/sky-heaven/
【部落格園】 http://www.cnblogs.com/sky-heaven/
【知乎】 http://www.zhihu.com/people/zhang-bing-hua
【我的作品---旋轉倒立擺】 http://v.youku.com/v_show/id_XODM5NDAzNjQw.html?spm=a2hzp.8253869.0.0&from=y1.7-2
【我的作品---自平衡自動循迹車】 http://v.youku.com/v_show/id_XODM5MzYyNTIw.html?spm=a2hzp.8253869.0.0&from=y1.7-2
【大餅教你學系列】https://edu.csdn.net/course/detail/10393
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利.