|   Linux下的platform機制  時間:2018-08-16作者(zhe):華(hua)清遠見 作者:楊(yang)老師,華清遠見教育(yu)科技(ji)集團講師。 從Linux2.6起,內核引入了一套新的驅(qu)動管理(li)和注冊機制(zhi):Platform_device和Platform_driver。現在Linux中大部分的設(she)備驅(qu)動都可以使用(yong)(yong)這套機制(zhi),總線為platform_bus,設(she)備用(yong)(yong)platform_device表示,驅(qu)動用(yong)(yong)platform_driver進(jin)行(xing)注冊。 Linux的(de)(de)這(zhe)種platform driver機(ji)制(zhi)和傳統的(de)(de)device_driver機(ji)制(zhi)相比,一(yi)個十分明顯的(de)(de)優勢在(zai)于platform機(ji)制(zhi)將本身(shen)的(de)(de)資(zi)(zi)源(yuan)注冊進內(nei)(nei)核,由內(nei)(nei)核統一(yi)管(guan)理(li),在(zai)驅動程序中使用這(zhe)些資(zi)(zi)源(yuan)時(shi)通過platform_device提供的(de)(de)標準接口進行申請(qing)并使用。這(zhe)樣提高了驅動和資(zi)(zi)源(yuan)管(guan)理(li)的(de)(de)獨立性,并且擁有(you)較好的(de)(de)可移植性和安(an)全(quan)性。下(xia)面是SPI驅動層(ceng)次示意圖,Linux中的(de)(de)SPI總線(xian)可理(li)解為SPI控制(zhi)器引出的(de)(de)總線(xian): 
  
 和傳統的驅動一(yi)樣(yang),platform機(ji)制也分為三個(ge)步(bu)驟: 1、總線(xian)注冊階(jie)段: 內核啟動(dong)初(chu)始化時的(de)main.c文件(jian)中的(de)start_kernel() →rest_init() →kernel_init()→do_basic_setup()→driver_init()→platform_bus_init()→ bus_register(&platform_bus_type),注冊了一條(tiao)platform總線(虛擬總線,platform_bus)。 2、添加設備階段(duan): int platform_device_register(struct platform_device *pdev); //注冊一個設備 int platform_add_devices(struct platform_device **pdevs, int ndev); //注冊(ce)多個設備 設備注冊的時候(hou)Platform_device_register()/platform_device_add()→(pdev→dev.bus = &platform_bus_type)→device_add(),就這樣把設備給(gei)掛到虛擬的總線上。 由分析可(ke)以(yi)(yi)知道: 使(shi)用(yong)逆向的分析可(ke)以(yi)(yi)知道:Platform_device_register() 這個函數在(zai)arch/arm/mach-s5pv210/mach-smdkv210.c 文件(jian)中使(shi)用(yong)了, 文件位置346行(xing): platform_add_devices(smdkv210_devices, ARRAY_SIZE(smdkv210_devices)); 然后在349行處 定(ding)義了一個宏(hong) :MACHINE_START(SMDKV210, "SMDKV210") ,跟蹤這個宏(hong)可以知道這個宏(hong)的詳細定(ding)義, #define MACHINE_START(_type,_name) \ static const struct machine_desc __mach_desc_##_type \ __used \ __attribute__((__section__(".arch.info.init"))) = { \ .nr = MACH_TYPE_##_type, \ .name = _name, #define MACHINE_END \ }; 可(ke)以(yi)知道(dao)段代碼被定義在了(le).arch.info.init段 由系統的連接腳(jiao)本指定,具(ju)體可(ke)以(yi)查(cha)看 arch/arm/kernel/vmlinux.lds 腳(jiao)本可(ke)以(yi)知道(dao) 3、驅動注(zhu)冊階段: Platform_driver_register()→driver_register()→bus_add_driver()→driver_attach()→bus_for_each_dev(), 對在(zai)每個掛在(zai)虛(xu)擬的(de)platform bus的(de)設備(bei)(bei)作(zuo)__driver_attach()→driver_probe_device(),判斷(duan)drv→bus→match()是否執行成功(gong),此時通過指針執行platform_match→strncmp(pdev→name , drv→name , BUS_ID_SIZE),如果(guo)相符就調用really_probe(實際就是執行相應設備(bei)(bei)的(de)platform_driver→probe(platform_device)。)開(kai)始真(zhen)正的(de)探測,如果(guo)probe成功(gong),則綁(bang)定設備(bei)(bei)到(dao)該驅動。 從上面可以(yi)看出,platform機制后(hou)還是調用了bus_register() , device_add() , driver_register()這三(san)個關鍵的函數(shu)。 下面看幾個結構體 struct platform_device (/include/linux/Platform_device.h) { constchar * name; int id; struct device dev; u32 num_resources; struct resource * resource; }; Platform_device結構(gou)體(ti)描述(shu)了一個(ge)platform結構(gou)的(de)設備,在其中包含了一般設備的(de)結構(gou)體(ti)struct device dev;設備的(de)資源結構(gou)體(ti)struct resource * resource;還(huan)有設備的(de)名(ming)字const char * name。(注意,這(zhe)個(ge)名(ming)字一定(ding)要和后面platform_driver.driver àname相(xiang)同,原因會在后面說(shuo)明。) 該結(jie)構體中重要(yao)的(de)就是resource結(jie)構,這也是之(zhi)所以引入platform機制的(de)原(yuan)因(yin)。 struct resource ( /include/linux/ioport.h) { resource_size_t start; resource_size_t end; constchar *name; unsigned long flags; struct resource *parent, *sibling, *child; }; 其中(zhong) flags位表示該資源的類型,start和end分別表示該資源的起始地址(zhi)和結束地址(zhi)(/include/linux/Platform_device.h): 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 (*suspend_late)(struct platform_device *, pm_message_t state); int (*resume_early)(struct platform_device *); int (*resume)(struct platform_device *); struct device_driver driver; }; Platform_driver結(jie)構(gou)體描述了(le)一(yi)個platform結(jie)構(gou)的驅(qu)動。其中除了(le)一(yi)些(xie)函數指針外(wai),還有一(yi)個一(yi)般(ban)驅(qu)動的device_driver結(jie)構(gou)。 名字(zi)要一致(zhi)的原因: 上面說的(de)(de)驅動在(zai)注冊的(de)(de)時候會調用函數(shu)bus_for_each_dev(), 對在(zai)每個掛在(zai)虛擬的(de)(de)platform bus的(de)(de)設備作(zuo)__driver_attach()→driver_probe_device(),在(zai)此(ci)函數(shu)中會對dev和drv做初步的(de)(de)匹(pi)配,調用的(de)(de)是drv- staticint platform_match(struct device * dev, struct device_driver * drv) { struct platform_device *pdev = container_of(dev, struct platform_device, dev); return (strncmp(pdev- } 是(shi)比較dev和(he)drv的name,相同(tong)則會(hui)進(jin)入(ru)really_probe()函(han)(han)數,從而進(jin)入(ru)自己(ji)寫的probe函(han)(han)數做進(jin)一步的匹配。所以dev→name和(he)driver→drv→name在初始化時一定要填一樣(yang)的。 不同類(lei)型的(de)驅動(dong),其match函數是(shi)不一樣的(de),這個platform的(de)驅動(dong),比較的(de)是(shi)dev和drv的(de)名(ming)字(zi),還記得usb類(lei)驅動(dong)里的(de)match嗎?它比較的(de)是(shi)Product ID和Vendor ID。 個(ge)人總結Platform機制的好處(chu): 1、提供platform_bus_type類(lei)型的(de)總(zong)線(xian)(xian),把那些(xie)不是總(zong)線(xian)(xian)型的(de)soc設備都添加(jia)到這(zhe)條虛擬(ni)總(zong)線(xian)(xian)上。使得(de),總(zong)線(xian)(xian)——設備——驅動的(de)模(mo)式可以得(de)到普及。 2、提供platform_device和(he)(he)platform_driver類型的數(shu)據(ju)結(jie)構(gou),將傳統的device和(he)(he)driver數(shu)據(ju)結(jie)構(gou)嵌入(ru)其中,并且加入(ru)resource成員,以便于和(he)(he)Open Firmware這種動態傳遞設(she)備資源的新(xin)型bootloader和(he)(he)kernel 接軌。 發表評論 | 
全國咨詢電話:400-611-6270,雙(shuang)休日(ri)及(ji)節假(jia)日(ri)請致電值班手機:15010390966
在線咨詢(xun): 曹老師(shi)QQ(3337544669), 徐老師(shi)QQ(1462495461), 劉(liu)老師(shi) QQ(3108687497)
企業培訓洽談(tan)專(zhuan)線:010-82600901,院(yuan)校合作洽談(tan)專(zhuan)線:010-82600350,在線咨詢:QQ(248856300)
Copyright 2004-2018 華清遠見教育科技集團 版權所有 ,京(jing)ICP備16055225號(hao)(hao),京(jing)公海網(wang)安備11010802025203號(hao)(hao)