? ? ?platform總線是一種虛擬的總線,相應的設(shè)備則為platform_device,而驅(qū)動則為platform_driver。Linux 2.6的設(shè)備驅(qū)動模型中,把I2C、RTC、LCD等都歸納為platform_device。
總線將設(shè)備和驅(qū)動綁定,在系統(tǒng)每注冊一個設(shè)備的時候,會尋找與之匹配的驅(qū)動;相反的,在系統(tǒng)每注冊一個驅(qū)動的時候,會尋找與之匹配的設(shè)備,而匹配由總線完成。
Linux2.6系統(tǒng)中定義了一個bus_type的實例platform_bus_type
[cpp]?view plain?copy
print?
struct?bus_type?platform_bus_type?=?{??
.name???????=?"platform",??
.dev_attrs??=?platform_dev_attrs,??
.match??????=?platform_match,???????//設(shè)備和驅(qū)動使用match函數(shù)來判斷是否匹配??
.uevent?????=?platform_uevent,??
.pm?????=?PLATFORM_PM_OPS_PTR,??
};??
[cpp]?view plain?copy
print?
/*?platform_match函數(shù)用于匹配總線中的驅(qū)動和設(shè)備?*/??
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);??
/*?match?against?the?id?table?first?*/??
if?(pdrv->id_table)??
return?platform_match_id(pdrv->id_table,?pdev)?!=?NULL;??
/*?fall-back?to?driver?name?match?*/??
return?(strcmp(pdev->name,?drv->name)?==?0);??
}??
platform_match函數(shù)首先判斷是否由id_table,如果有則使用id_table來進行匹配,否則,判斷platform_device和platform_driver成員里的name,如果二者的name字段相同則匹配,如果匹配則調(diào)用platform_driver的probe函數(shù)。
platform_device結(jié)構(gòu)體的定義
[cpp]?view plain?copy
print?
struct?platform_device?{??
const?char??*?name;?????????/*?名字?*/??
int?????id;??
struct?device???dev;??
u32?????num_resources;??????/*?資源總數(shù)?*/??
struct?resource?*?resource;?/*?資源?*/??
struct?platform_device_id???*id_entry;??
};??
其中有個重要的成員是resource,是設(shè)備的資源信息,如IO地址,中斷號等。
[cpp]?view plain?copy
print?
struct?resource?{??
resource_size_t?start;??????//資源的起始值??
resource_size_t?end;????????//資源的結(jié)束值??
const?char?*name;??
unsigned?long?flags;????????//資源的類型,如IORESOURCE_IO,IORESOURCE_MEM,IORESOURCE_IRQ,IORESOURCE_DMA??
struct?resource?*parent,?*sibling,?*child;??
};??
有的設(shè)備可能有多個資源,通常使用platform_get_resource函數(shù)來獲取資源
[cpp]?view plain?copy
print?
/**?
*?platform_get_resource?-?get?a?resource?for?a?device?
*?@dev:?platform?device?
*?@type:?resource?type?
*?@num:?resource?index?
*/??
struct?resource?*platform_get_resource(struct?platform_device?*dev,??
unsigned?int?type,?unsigned?int?num)??
{??
int?i;??
for?(i?=?0;?i?num_resources;?i++)?{??
struct?resource?*r?=?&dev->resource[i];??
if?(type?==?resource_type(r)?&&?num--?==?0)??
return?r;??
}??
return?NULL;??
}??
平臺設(shè)備的注冊,使用platform_device_register函數(shù)
[cpp]?view plain?copy
print?
int?platform_device_register(struct?platform_device?*pdev)??
{??
device_initialize(&pdev->dev);??
return?platform_device_add(pdev);??
}??
platform_device_register函數(shù)先通過device_initialize函數(shù)初始化platform_device的device成員,然后調(diào)用platform_device_add向內(nèi)核添加一個平臺設(shè)備。
[cpp]?view plain?copy
print?
int?platform_device_add(struct?platform_device?*pdev)??
{??
int?i,?ret?=?0;??
if?(!pdev)??/*?如果pdev為空則返回EINVAL?*/??
return?-EINVAL;??
/*?如果pdev->dev.parent為空則將pdev->dev.parent設(shè)置為platform_bus?*/??
if?(!pdev->dev.parent)??
pdev->dev.parent?=?&platform_bus;??
pdev->dev.bus?=?&platform_bus_type;??/*?設(shè)置總線類型?*/??
if?(pdev->id?!=?-1)??????/*?如果id?=?-1則表示自動分配name?*/??
dev_set_name(&pdev->dev,?"%s.%d",?pdev->name,??pdev->id);??
else??
dev_set_name(&pdev->dev,?pdev->name);??
for?(i?=?0;?i?num_resources;?i++)?{??
struct?resource?*p,?*r?=?&pdev->resource[i];?/*?獲取資源?*/??
if?(r->name?==?NULL)??
r->name?=?dev_name(&pdev->dev);??
p?=?r->parent;??
if?(!p)?{??
if?(resource_type(r)?==?IORESOURCE_MEM)?/*?設(shè)置資源類型?*/??
p?=?&iomem_resource;??
else?if?(resource_type(r)?==?IORESOURCE_IO)??
p?=?&ioport_resource;??
}??
if?(p?&&?insert_resource(p,?r))?{??
printk(KERN_ERR??
"%s:?failed?to?claim?resource?%d\n",??
dev_name(&pdev->dev),?i);??
ret?=?-EBUSY;??
goto?failed;??
}??
}??
pr_debug("Registering?platform?device?'%s'.?Parent?at?%s\n",??
dev_name(&pdev->dev),?dev_name(pdev->dev.parent));??
/*?向內(nèi)核添加一個device?*/??
ret?=?device_add(&pdev->dev);??
if?(ret?==?0)??
return?ret;??
failed:??
while?(--i?>=?0)?{??
struct?resource?*r?=?&pdev->resource[i];??
unsigned?long?type?=?resource_type(r);??
if?(type?==?IORESOURCE_MEM?||?type?==?IORESOURCE_IO)??
release_resource(r);??
}??
return?ret;??
}??
platform_device_add最終調(diào)用device_add來完成平臺設(shè)備的注冊。
相反地,如果要注銷平臺設(shè)備則使用platform_device_unregister函數(shù)
[cpp]?view plain?copy
print?
void?platform_device_unregister(struct?platform_device?*pdev)??
{??
platform_device_del(pdev);??
platform_device_put(pdev);??
}??
platform_device_unregister函數(shù)調(diào)用platform_device_del函數(shù)來注銷平臺設(shè)備
[cpp]?view plain?copy
print?
void?platform_device_del(struct?platform_device?*pdev)??
{??
int?i;??
if?(pdev)?{??
device_del(&pdev->dev);??
for?(i?=?0;?i?num_resources;?i++)?{??
struct?resource?*r?=?&pdev->resource[i];??
unsigned?long?type?=?resource_type(r);??
if?(type?==?IORESOURCE_MEM?||?type?==?IORESOURCE_IO)??
release_resource(r);??
}??
}??
}??
platform_device_del函數(shù)調(diào)用device_del函數(shù)來刪除平臺設(shè)備,相應地,要釋放資源應調(diào)用release_resource函數(shù),前提是資源的類型必須為IORESOURCE_MEM或者IORESOURCE_IO
platform_driver的定義:
[cpp]?view plain?copy
print?
struct?platform_driver?{??
int?(*probe)(struct?platform_device?*);??
int?(*remove)(struct?platform_device?*);??
void?(*shutdown)(struct?platform_device?*);??
int?(*suspend)(struct?platform_device?*,?pm_message_t?state);??
int?(*resume)(struct?platform_device?*);??
struct?device_driver?driver;??
const?struct?platform_device_id?*id_table;??
};??
?
device_driver的定義:
[cpp]?view plain?copy
print?
struct?device_driver?{??
const?char??????*name;??
struct?bus_type?????*bus;??
struct?module???????*owner;??
const?char??????*mod_name;??/*?used?for?built-in?modules?*/??
bool?suppress_bind_attrs;???/*?disables?bind/unbind?via?sysfs?*/??
const?struct?of_device_id???*of_match_table;??
const?struct?acpi_device_id?*acpi_match_table;??
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);??
const?struct?attribute_group?**groups;??
const?struct?dev_pm_ops?*pm;??
struct?driver_private?*p;??
};??
platform_driver結(jié)構(gòu)體有device_driver成員,該成員的各自字段如上所示,device_driver也有probe、remove、shutdown等函數(shù),在平臺驅(qū)動注冊的時候被初始化。
前面說過,當系統(tǒng)中存在有平臺設(shè)備和平臺驅(qū)動通過總線的match函數(shù)匹配后則會調(diào)用platform_driver的probe函數(shù),參數(shù)為platform_device,有時候也通過id_table來判斷是否匹配。
[cpp]?view plain?copy
print?
struct?platform_device_id?{??
char?name[PLATFORM_NAME_SIZE];??
kernel_ulong_t?driver_data??
__attribute__((aligned(sizeof(kernel_ulong_t))));??
};??
平臺驅(qū)動的注冊使用platform_driver_register函數(shù)
[cpp]?view plain?copy
print?
int?platform_driver_register(struct?platform_driver?*drv)??
{??
drv->driver.bus?=?&platform_bus_type;??
if?(drv->probe)??
drv->driver.probe?=?platform_drv_probe;??
if?(drv->remove)??
drv->driver.remove?=?platform_drv_remove;??
if?(drv->shutdown)??
drv->driver.shutdown?=?platform_drv_shutdown;??
if?(drv->suspend)??
drv->driver.suspend?=?platform_drv_suspend;??
if?(drv->resume)??
drv->driver.resume?=?platform_drv_resume;??
return?driver_register(&drv->driver);??
}??
先初始化platform_driver里的driver,該driver的類型為device_driver,設(shè)置driver的bus為platform_bus_type;設(shè)置driver的probe為platform_drv_probe;設(shè)置driver的remove為platform_drv_remove;設(shè)置driver的shutdown為platform_drv_shutdown;設(shè)置driver的suspend為platform_drv_suspend;設(shè)置driver的resume為platform_drv_resume,最后調(diào)用driver_register函數(shù)來注冊平臺驅(qū)動。
相反地,要注銷平臺驅(qū)動的話,使用platform_driver_unregister函數(shù)
[cpp]?view plain?copy
print?
void?platform_driver_unregister(struct?platform_driver?*drv)??
{??
driver_unregister(&drv->driver);??
}??
?
評論
查看更多