




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
詳解Linux2.6內(nèi)核中基于platform機(jī)制的驅(qū)動(dòng)模型【摘要】本文以Linux2.6.25內(nèi)核為例,分析了基于platform總線的驅(qū)動(dòng)模型。首先介紹了Platform總線的基本概念,接著介紹了platformdevice和platformdriver的定義和加載過程,分析了其與基類device和driver的派生關(guān)系及在此過程中面向?qū)ο蟮脑O(shè)計(jì)思想。最后以ARMS3C2440中I2C控制器為例介紹了基于platform總線的驅(qū)動(dòng)開發(fā)流程?!娟P(guān)鍵字】platform_bus,platform_device,resource,platform_driver,file_operations目錄1
何謂platformbus?
2
2
device和platform_device
3
3
device_register和platform_device_register
5
4
device_driver和platformdriver
8
5
driver_register和platform_driver_register
10
6
bus、device及driver三者之間的關(guān)系
17
7
哪些適用于plarform驅(qū)動(dòng)?
18
8
基于platform總線的驅(qū)動(dòng)開發(fā)流程
18
8.1
初始化platform_bus
19
8.2
定義platform_device
22
8.3
注冊(cè)platform_device
22
8.4
定義platform_driver
28
8.5
注冊(cè)platform_driver
29
8.6
操作設(shè)備
321
何謂platformbus?
Linux系統(tǒng)中許多部分對(duì)設(shè)備是如何鏈接的并不感興趣,但是他們需要知道哪些類型的設(shè)備是可以使用的。設(shè)備模型提供了一種機(jī)制來對(duì)設(shè)備進(jìn)行分類,在更高的功能層面上描述這些設(shè)備,并使得這些設(shè)備對(duì)用戶空間可見。因此從2.6內(nèi)核開始引入了設(shè)備模型??偩€是處理器和一個(gè)或多個(gè)設(shè)備之間的通道,在設(shè)備模型中,所有的設(shè)備都通過總線相連??偩€可以相互插入。設(shè)備模型展示了總線和它們所控制的設(shè)備之間的實(shí)際連接。Platform總線是2.6kernel中最近引入的一種虛擬總線,主要用來管理CPU的片上資源,具有更好的移植性,因此在2.6kernel中,很多驅(qū)動(dòng)都用platform改寫了。platform_bus_type的定義如下:
http://lxr.linux.no/#linux+v2.6.25/drivers/base/platform.c#L609
609structbus_typeplatform_bus_type={
610
.name
="platform",
611
.dev_attrs
=platform_dev_attrs,
612
.match
=platform_match,
613
.uevent
=platform_uevent,
614
.suspend
=platform_suspend,
615
.suspend_late
=platform_suspend_late,
616
.resume_early
=platform_resume_early,
617
.resume
=platform_resume,
618};
619EXPORT_SYMBOL_GPL(platform_bus_type);http://lxr.linux.no/#linux+v2.6.25/include/linux/device.h#L55
55structbus_type{
56
constchar
*name;
57
structbus_attribute
*bus_attrs;
58
structdevice_attribute*dev_attrs;
59
structdriver_attribute*drv_attrs;
60
61
int(*match)(structdevice*dev,structdevice_driver*drv);
62
int(*uevent)(structdevice*dev,structkobj_uevent_env*env);
63
int(*probe)(structdevice*dev);
64
int(*remove)(structdevice*dev);
65
void(*shutdown)(structdevice*dev);
66
67
int(*suspend)(structdevice*dev,pm_message_tstate);
68
int(*suspend_late)(structdevice*dev,pm_message_tstate);
69
int(*resume_early)(structdevice*dev);
70
int(*resume)(structdevice*dev);
71
72
structbus_type_private*p;
73};總線名稱是"platform",其只是bus_type的一種,定義了總線的屬性,同時(shí)platform_bus_type還有相關(guān)操作方法,如掛起、中止、匹配及hotplug事件等??偩€bus是聯(lián)系driver和device的中間樞紐。Device通過所屬的bus找到driver,由match操作方法進(jìn)行匹配。
Bus、driver及devices的連接關(guān)系2
device和platform_device
Plarformdevice會(huì)有一個(gè)名字用于driverbinding(在注冊(cè)driver的時(shí)候會(huì)查找driver的目標(biāo)設(shè)備的bus位置,這個(gè)過程稱為driverbinding),另外IRQ以及地址空間等資源也要給出。platform_device結(jié)構(gòu)體用來描述設(shè)備的名稱、資源信息等。該結(jié)構(gòu)被定義在http://lxr.linux.no/#linux+v2.6.25/include/linux/platform_device.h#L16中,定義原型如下:
16structplatform_device{
17
constchar
*name;//定義平臺(tái)設(shè)備的名稱,此處設(shè)備的命名應(yīng)和相應(yīng)驅(qū)動(dòng)程序命名一致
18
int
id;
19
structdevice
dev;
20
u32
num_resources;
21
structresource*resource;
//定義平臺(tái)設(shè)備的資源
22};在這個(gè)結(jié)構(gòu)里封裝了structdevice及structresource。可知:platform_device由device派生而來,是一種特殊的device。下面來看一下platform_device結(jié)構(gòu)體中最重要的一個(gè)成員structresource*resource。structresource被定義在http://lxr.linux.no/#linux+v2.6.25/include/linux/ioport.h#L18中,定義原型如下:
14/*
15*Resourcesaretree-like,allowing
16*nestingetc..
17*/
18structresource{
19
resource_size_tstart;
//定義資源的起始地址
20
resource_size_tend;
//定義資源的結(jié)束地址
21
constchar*name;//定義資源的名稱
22
unsignedlongflags;定義資源的類型,比如MEM,IO,IRQ,DMA類型
23
structresource*parent,*sibling,*child;
24};這個(gè)結(jié)構(gòu)表示設(shè)備所擁有的資源,即I/O端口、I/O映射內(nèi)存、中斷及DMA等。這里的地址指的是物理地址。另外還需要注意platform_device中的device結(jié)構(gòu),它詳細(xì)描述了設(shè)備的情況,其為所有設(shè)備的基類,定義如下:
http://lxr.linux.no/#linux+v2.6.25/include/linux/device.h#L422
422structdevice{
423
structklist
klist_children;
424
structklist_node
knode_parent;
/*nodeinsiblinglist*/
425
structklist_node
knode_driver;
426
structklist_node
knode_bus;
427
structdevice
*parent;
428
429
structkobjectkobj;
430
char
bus_id[BUS_ID_SIZE];
/*positiononparentbus*/
431
structdevice_type
*type;
432
unsigned
is_registered:1;
433
unsigned
uevent_suppress:1;
434
435
structsemaphore
sem;
/*semaphoretosynchronizecallsto
436
*itsdriver.
437
*/
438
439
structbus_type*bus;
/*typeofbusdeviceison*/
440
structdevice_driver*driver;
/*whichdriverhasallocatedthis
441
device*/
442
void
*driver_data;
/*dataprivatetothedriver*/
443
void
*platform_data;/*Platformspecificdata,device
444
coredoesn''ttouchit*/
445
structdev_pm_info
power;
446
447#ifdefCONFIG_NUMA
448
int
numa_node;
/*NUMAnodethisdeviceiscloseto*/
449#endif
450
u64
*dma_mask;
/*dmamask(ifdma''abledevice)*/
451
u64
coherent_dma_mask;/*Likedma_mask,butfor
452
alloc_coherentmappingsas
453
notallhardwaresupports
454
64bitaddressesforconsistent
455
allocationssuchdescriptors.*/
456
457
structdevice_dma_parameters*dma_parms;
458
459
structlist_head
dma_pools;
/*dmapools(ifdma''ble)*/
460
461
structdma_coherent_mem*dma_mem;/*internalforcoherentmem
462
override*/
463
/*archspecificadditions*/
464
structdev_archdata
archdata;
465
466
spinlock_t
devres_lock;
467
structlist_head
devres_head;
468
469
/*class_devicemigrationpath*/
470
structlist_head
node;
471
structclass
*class;
472
dev_t
devt;
/*dev_t,createsthesysfs"dev"*/
473
structattribute_group
**groups;
/*optionalgroups*/
474
475
void
(*release)(structdevice*dev);
476};
4773
device_register和platform_device_registerhttp://lxr.linux.no/#linux+v2.6.25/drivers/base/core.c#L881
870/**
871*device_register-registeradevicewiththesystem.
872*@dev:pointertothedevicestructure
873*
874*Thishappensintwocleansteps-initializethedevice
875*andaddittothesystem.Thetwostepscanbecalled
876*separately,butthisistheeasiestandmostcommon.
877*I.e.youshouldonlycallthetwohelpersseparatelyif
878*haveaclearlydefinedneedtouseandrefcountthedevice
879*beforeitisaddedtothehierarchy.
880*/
881intdevice_register(structdevice*dev)
882{
883
device_initialize(dev);
884
returndevice_add(dev);
885}
初始化一個(gè)設(shè)備,然后加入到系統(tǒng)中。http://lxr.linux.no/#linux+v2.6.25/drivers/base/platform.c#L325
316/**
317*platform_device_register-addaplatform-leveldevice
318*@pdev:platformdevicewe''readding
319*/
320intplatform_device_register(structplatform_device*pdev)
321{
322
device_initialize(&pdev->dev);
323
returnplatform_device_add(pdev);
324}
325EXPORT_SYMBOL_GPL(platform_device_register);我們看到注冊(cè)一個(gè)platformdevice分為了兩部分,初始化這個(gè)platform_device,然后將此platform_device添加到platform總線中。輸入?yún)?shù)platform_device可以是靜態(tài)的全局設(shè)備。另外一種機(jī)制就是動(dòng)態(tài)申請(qǐng)platform_device_alloc一個(gè)platform_device設(shè)備,然后通過platform_device_add_resources及platform_device_add_data等添加相關(guān)資源和屬性。無論哪一種platform_device,最終都將通過platform_device_add這冊(cè)到platform總線上。229/**
230*platform_device_add-addaplatformdevicetodevicehierarchy
231*@pdev:platformdevicewe''readding
232*
233*Thisispart2ofplatform_device_register(),thoughmaybecalled
234*separately_iff_pdevwasallocatedbyplatform_device_alloc().
235*/
236intplatform_device_add(structplatform_device*pdev)
237{
238
inti,ret=0;
239
240
if(!pdev)
241
return-EINVAL;
242
初始化設(shè)備的parent為platform_bus,初始化驅(qū)備的總線為platform_bus_type。
243
if(!pdev->dev.parent)
244
pdev->dev.parent=&platform_bus;
245
246
pdev->dev.bus=&platform_bus_type;
247
/*++++++++++++++
Theplatform_device.dev.bus_idisthecanonicalnameforthedevices.
It''sbuiltfromtwocomponents:*platform_...whichisalsousedtofordrivermatching.
*platform_device.id...thedeviceinstancenumber,orelse"-1"
toindicatethere''sonlyone.Theseareconcatenated,soname/id"serial"/0indicatesbus_id"serial.0",and
"serial/3"indicatesbus_id"serial.3";bothwouldusetheplatform_driver
named"serial".While"my_rtc"/-1wouldbebus_id"my_rtc"(noinstanceid)
andusetheplatform_drivercalled"my_rtc".
++++++++++++++*/
248
if(pdev->id!=-1)
249
snprintf(pdev->dev.bus_id,BUS_ID_SIZE,"%s.%d",pdev->name,
250
pdev->id);
251
else
252
strlcpy(pdev->dev.bus_id,pdev->name,BUS_ID_SIZE);
253
設(shè)置設(shè)備structdevice的bus_id成員,留心這個(gè)地方,在以后還需要用到這個(gè)的。
254
for(i=0;i<pdev->num_resources;i++){
255
structresource*p,*r=&pdev->resource[i];
256
257
if(r->name==NULL)
258
r->name=pdev->dev.bus_id;
259
260
p=r->parent;
261
if(!p){
262
if(r->flags&IORESOURCE_MEM)
263
p=&iomem_resource;
264
elseif(r->flags&IORESOURCE_IO)
265
p=&ioport_resource;
266
}
//resources分為兩種IORESOURCE_MEM和IORESOURCE_IO
//CPU對(duì)外設(shè)IO端口物理地址的編址方式有兩種:I/O映射方式和內(nèi)存映射方式
267
268
if(p&&insert_resource(p,r)){
269
printk(KERN_ERR
270
"%s:failedtoclaimresource%d\n",
271
pdev->dev.bus_id,i);
272
ret=-EBUSY;
273
gotofailed;
274
}
275
}
276
277
pr_debug("Registeringplatformdevice''%s''.Parentat%s\n",
278
pdev->dev.bus_id,pdev->dev.parent->bus_id);
279
280
ret=device_add(&pdev->dev);
281
if(ret==0)
282
returnret;
283
284failed:
285
while(--i>=0)
286
if(pdev->resource[i].flags&(IORESOURCE_MEM|IORESOURCE_IO))
287
release_resource(&pdev->resource[i]);
288
returnret;
289}
290EXPORT_SYMBOL_GPL(platform_device_add);由platform_device_register和platform_device_add的實(shí)現(xiàn)可知,device_register()和platform_device_register()都會(huì)首先初始化設(shè)備
區(qū)別在于第二步:其實(shí)platform_device_add()包括device_add(),不過要先注冊(cè)resources,然后將設(shè)備掛接到特定的platform總線。4
device_driver和platformdriver
Platformdevice是一種device自己是不會(huì)做事情的,要有人為它做事情,那就是platformdriver。platformdriver遵循linux系統(tǒng)的drivermodel。對(duì)于device的discovery/enumerate都不是driver自己完成的而是由由系統(tǒng)的driver注冊(cè)機(jī)制完成。driver編寫人員只要將注冊(cè)必須的數(shù)據(jù)結(jié)構(gòu)初始化并調(diào)用注冊(cè)driver的kernelAPI就可以了。接下來來看platform_driver結(jié)構(gòu)體的原型定義,在http://lxr.linux.no/#linux+v2.6.25/include/linux/platform_device.h#L48中,代碼如下:
48structplatform_driver{
49
int(*probe)(structplatform_device*);
50
int(*remove)(structplatform_device*);
51
void(*shutdown)(structplatform_device*);
52
int(*suspend)(structplatform_device*,pm_message_tstate);
53
int(*suspend_late)(structplatform_device*,pm_message_tstate);
54
int(*resume_early)(structplatform_device*);
55
int(*resume)(structplatform_device*);
56
structdevice_driverdriver;
57};可見,它包含了設(shè)備操作的幾個(gè)功能函數(shù),同時(shí)包含了一個(gè)device_driver結(jié)構(gòu),說明device_driver是platform_driver的基類。驅(qū)動(dòng)程序中需要初始化這個(gè)變量。下面看一下這個(gè)變量的定義,位于http://lxr.linux.no/#linux+v2.6.25/include/linux/device.h#L121中:
121structdevice_driver{
122
constchar
*name;
123
structbus_type
*bus;
124
125
structmodule
*owner;
126
constchar
*mod_name;
/*usedforbuilt-inmodules*/
127
128
int(*probe)(structdevice*dev);
129
int(*remove)(structdevice*dev);
130
void(*shutdown)(structdevice*dev);
131
int(*suspend)(structdevice*dev,pm_message_tstate);
132
int(*resume)(structdevice*dev);
133
structattribute_group**groups;
134
135
structdriver_private*p;
136};device_driver提供了一些操作接口,但其并沒有實(shí)現(xiàn),相當(dāng)于一些虛函數(shù),由派生類platform_driver進(jìn)行重載,無論何種類型的driver都是基于device_driver派生而來的,具體的各種操作都是基于統(tǒng)一的基類接口的,這樣就實(shí)現(xiàn)了面向?qū)ο蟮脑O(shè)計(jì)。需要注意這兩個(gè)變量:name和owner。其作用主要是為了和相關(guān)的platform_device關(guān)聯(lián)起來,owner的作用是說明模塊的所有者,驅(qū)動(dòng)程序中一般初始化為THIS_MODULE。device_driver結(jié)構(gòu)中也有一個(gè)name變量。platform_driver從字面上來看就知道是設(shè)備驅(qū)動(dòng)。設(shè)備驅(qū)動(dòng)是為誰服務(wù)的呢?當(dāng)然是設(shè)備了。內(nèi)核正是通過這個(gè)一致性來為驅(qū)動(dòng)程序找到資源,即platform_device中的resource。5
driver_register和platform_driver_register內(nèi)核提供的platform_driver結(jié)構(gòu)體的注冊(cè)函數(shù)為platform_driver_register(),其原型定義在http://lxr.linux.no/#linux+v2.6.25/drivers/base/platform.c#L458文件中,具體實(shí)現(xiàn)代碼如下:
439/**
440*platform_driver_register
441*@drv:platformdriverstructure
442*/
443intplatform_driver_register(structplatform_driver*drv)
444{
445
drv->driver.bus=&platform_bus_type;
/*設(shè)置成platform_bus_type這個(gè)很重要,因?yàn)閐river和device是通過bus聯(lián)系在一起的,具體在本例中是通過
platform_bus_type中注冊(cè)的回調(diào)例程和屬性來是實(shí)現(xiàn)的,driver與device的匹配就是通過platform_bus_type注冊(cè)的回調(diào)例程platform_match()來完成的。*/
446
if(drv->probe)
447
drv->be=platform_drv_probe;
//在really_probe函數(shù)中,回調(diào)了platform_drv_probe函數(shù)448
if(drv->remove)
449
drv->driver.remove=platform_drv_remove;
450
if(drv->shutdown)
451
drv->driver.shutdown=platform_drv_shutdown;
452
if(drv->suspend)
453
drv->driver.suspend=platform_drv_suspend;
454
if(drv->resume)
455
drv->driver.resume=platform_drv_resume;
456
returndriver_register(&drv->driver);
457}
458EXPORT_SYMBOL_GPL(platform_driver_register);不要被上面的platform_drv_XXX嚇倒了,它們其實(shí)很簡單,就是將structdevice轉(zhuǎn)換為structplatform_device和structplatform_driver,然后調(diào)用platform_driver中的相應(yīng)接口函數(shù)。那為什么不直接調(diào)用platform_drv_XXX等接口呢?這就是Linux內(nèi)核中面向?qū)ο蟮脑O(shè)計(jì)思想。device_driver提供了一些操作接口,但其并沒有實(shí)現(xiàn),相當(dāng)于一些虛函數(shù),由派生類platform_driver進(jìn)行重載,無論何種類型的driver都是基于device_driver派生而來的,device_driver中具體的各種操作都是基于統(tǒng)一的基類接口的,這樣就實(shí)現(xiàn)了面向?qū)ο蟮脑O(shè)計(jì)。在文件http://lxr.linux.no/#linux+v2.6.25/drivers/base/driver.c#L234中,實(shí)現(xiàn)了driver_register()函數(shù)。209/**
210*driver_register-registerdriverwithbus
211*@drv:drivertoregister
212*
213*Wepassoffmostoftheworktothebus_add_driver()call,
214*sincemostofthethingswehavetododealwiththebus
215*structures.
216*/
217intdriver_register(structdevice_driver*drv)
218{
219
intret;
220
//如果總線的方法和設(shè)備自己的方法同時(shí)存在,將打印告警信息,對(duì)于platformbus,其沒有probe等接口
221
if((drv->bus->probe&&drv->probe)||
222
(drv->bus->remove&&drv->remove)||
223
(drv->bus->shutdown&&drv->shutdown))
224
printk(KERN_WARNING"Driver''%s''needsupdating-pleaseuse"
225
"bus_typemethods\n",drv->name);
226
ret=bus_add_driver(drv);
227
if(ret)
228
returnret;
229
ret=driver_add_groups(drv,drv->groups);
230
if(ret)
231
bus_remove_driver(drv);
232
returnret;
233}
234EXPORT_SYMBOL_GPL(driver_register);226
其主要將驅(qū)動(dòng)掛接到總線上,通過總線來驅(qū)動(dòng)設(shè)備。644/**
645*bus_add_driver-Addadrivertothebus.
646*@drv:driver.
647*/
648intbus_add_driver(structdevice_driver*drv)
649{
650
structbus_type*bus;
651
structdriver_private*priv;
652
interror=0;
653
654
bus=bus_get(drv->bus);
655
if(!bus)
656
return-EINVAL;
657
658
pr_debug("bus:''%s'':adddriver%s\n",bus->name,drv->name);
659
660
priv=kzalloc(sizeof(*priv),GFP_KERNEL);
661
if(!priv){
662
error=-ENOMEM;
663
gotoout_put_bus;
664
}
665
klist_init(&priv->klist_devices,NULL,NULL);
666
priv->driver=drv;
667
drv->p=priv;
668
priv->kobj.kset=bus->p->drivers_kset;
669
error=kobject_init_and_add(&priv->kobj,&driver_ktype,NULL,
670
"%s",drv->name);
671
if(error)
672
gotoout_unregister;
673
674
if(drv->bus->p->drivers_autoprobe){
675
error=driver_attach(drv);
676
if(error)
677
gotoout_unregister;
678
}
679
klist_add_tail(&priv->knode_bus,&bus->p->klist_drivers);
680
module_add_driver(drv->owner,drv);
681
682
error=driver_create_file(drv,&driver_attr_uevent);
683
if(error){
684
printk(KERN_ERR"%s:ueventattr(%s)failed\n",
685
__FUNCTION__,drv->name);
686
}
687
error=driver_add_attrs(bus,drv);
688
if(error){
689
/*Howthehelldowegetoutofthispickle?Giveup*/
690
printk(KERN_ERR"%s:driver_add_attrs(%s)failed\n",
691
__FUNCTION__,drv->name);
692
}
693
error=add_bind_files(drv);
694
if(error){
695
/*Ditto*/
696
printk(KERN_ERR"%s:add_bind_files(%s)failed\n",
697
__FUNCTION__,drv->name);
698
}
699
700
kobject_uevent(&priv->kobj,KOBJ_ADD);
701
returnerror;
702out_unregister:
703
kobject_put(&priv->kobj);
704out_put_bus:
705
bus_put(bus);
706
returnerror;
707}如果總線上的driver是自動(dòng)probe的話,則將該總線上的driver和device綁定起來。http://lxr.linux.no/#linux+v2.6.25/drivers/base/dd.c#L285
272/**
273*driver_attach-trytobinddrivertodevices.
274*@drv:driver.
275*
276*Walkthelistofdevicesthatthebushasonitandtryto
277*matchthedriverwitheachone.
Ifdriver_probe_device()
278*returns0andthe@dev->driverisset,we''vefounda
279*compatiblepair.
280*/
281intdriver_attach(structdevice_driver*drv)
282{
283
returnbus_for_each_dev(drv->bus,NULL,drv,__driver_attach);
284}
285EXPORT_SYMBOL_GPL(driver_attach);掃描該總線上的每一個(gè)設(shè)備,將當(dāng)前driver和總線上的設(shè)備進(jìn)行match,如果匹配成功,則將設(shè)備和driver綁定起來。246staticint__driver_attach(structdevice*dev,void*data)
247{
248
structdevice_driver*drv=data;
249
250
/*
251
*Lockdeviceandtrytobindtoit.Wedroptheerror
252
*hereandalwaysreturn0,becauseweneedtokeeptrying
253
*tobindtodevicesandsomedriverswillreturnanerror
254
*simplyifitdidn''tsupportthedevice.
255
*
256
*driver_probe_device()willspitawarningifthere
257
*isanerror.
258
*/
259
260
if(dev->parent)
/*NeededforUSB*/
261
down(&dev->parent->sem);
262
down(&dev->sem);
263
if(!dev->driver)
264
driver_probe_device(drv,dev);
265
up(&dev->sem);
266
if(dev->parent)
267
up(&dev->parent->sem);
268
269
return0;
270}263,如果該設(shè)備尚沒有匹配的driver,則嘗試匹配。http://lxr.linux.no/#linux+v2.6.25/drivers/base/dd.c#L187
170/**
171*driver_probe_device-attempttobinddevice&drivertogether
172*@drv:drivertobindadeviceto
173*@dev:devicetotrytobindtothedriver
174*
175*First,wecallthebus''smatchfunction,ifonepresent,whichshould
176*comparethedeviceIDsthedriversupportswiththedeviceIDsofthe
177*device.Notewedon''tdothisourselvesbecausewedon''tknowthe
178*formatoftheIDstructures,norwhatistobeconsideredamatchand
179*whatisnot.
180*
181*Thisfunctionreturns1ifamatchisfound,-ENODEVifthedeviceis
182*notregistered,and0otherwise.
183*
184*Thisfunctionmustbecalledwith@dev->semheld.
Whencalledfora
185*USBinterface,@dev->parent->semmustbeheldaswell.
186*/
187intdriver_probe_device(structdevice_driver*drv,structdevice*dev)
188{
189
intret=0;
190
191
if(!device_is_registered(dev))
192
return-ENODEV;
193
if(drv->bus->match&&!drv->bus->match(dev,drv))
194
gotodone;
195
196
pr_debug("bus:''%s'':%s:matcheddevice%swithdriver%s\n",
197
drv->bus->name,__FUNCTION__,dev->bus_id,drv->name);
198
199
ret=really_probe(dev,drv);
200
201done:
202
returnret;
203}193,如果該總線上的設(shè)備需要進(jìn)行匹配,則驗(yàn)證是否匹配。對(duì)于platform總線,其匹配過程如下:
http://lxr.linux.no/#linux+v2.6.25/drivers/base/platform.c#L555
542/**
543*platform_match-bindplatformdevicetoplatformdriver.
544*@dev:device.
545*@drv:driver.
546*
547*PlatformdeviceIDsareassumedtobeencodedlikethis:
548*"",whereisashortdescriptionofthetypeof
549*device,like"pci"or"floppy",andistheenumerated
550*instanceofthedevice,like''0''or''42''.
DriverIDsaresimply
551*"".
So,extractthefromtheplatform_devicestructure,
552*andcompareitagainstthenameofthedriver.Returnwhethertheymatch
553*ornot.
554*/
555staticintplatform_match(structdevice*dev,structdevice_driver*drv)
556{
557
structplatform_device*pdev;
558
559
pdev=container_of(dev,structplatform_device,dev);
560
return(strncmp(pdev->name,drv->name,BUS_ID_SIZE)==0);
561}560,簡單的進(jìn)行字符串匹配,這也是我們強(qiáng)調(diào)platform_device和platform_driver中的name屬性需要一致的原因。匹配成功后,則調(diào)用probe接口。
http://lxr.linux.no/#linux+v2.6.25/drivers/base/dd.c#L101
98staticatomic_tprobe_count=ATOMIC_INIT(0);
99staticDECLARE_WAIT_QUEUE_HEAD(probe_waitqueue);
100
101staticintreally_probe(structdevice*dev,structdevice_driver*drv)
102{
103
intret=0;
104
105
atomic_inc(&probe_count);
106
pr_debug("bus:''%s'':%s:probingdriver%swithdevice%s\n",
107
drv->bus->name,__FUNCTION__,drv->name,dev->bus_id);
108
WARN_ON(!list_empty(&dev->devres_head));
109
110
dev->driver=drv;
111
if(driver_sysfs_add(dev)){
112
printk(KERN_ERR"%s:driver_sysfs_add(%s)failed\n",
113
__FUNCTION__,dev->bus_id);
114
gotoprobe_failed;
115
}
116
117
if(dev->bus->probe){
118
ret=dev->bus->probe(dev);
119
if(ret)
120
gotoprobe_failed;
121
}elseif(drv->probe){
122
ret=drv->probe(dev);
123
if(ret)
124
gotoprobe_failed;
125
}
126
127
driver_bound(dev);
128
ret=1;
129
pr_debug("bus:''%s'':%s:bounddevice%stodriver%s\n",
130
drv->bus->name,__FUNCTION__,dev->bus_id,drv->name);
131
gotodone;
132
133probe_failed:
134
devres_release_all(dev);
135
driver_sysfs_remove(dev);
136
dev->driver=NULL;
137
138
if(ret!=-ENODEV&&ret!=-ENXIO){
139
/*drivermatchedbuttheprobefailed*/
140
printk(KERN_WARNING
141
"%s:probeof%sfailedwitherror%d\n",
142
drv->name,dev->bus_id,ret);
143
}
144
/*
145
*Ignoreerrorsreturnedby->probesothatthenextdrivercantry
146
*itsluck.
147
*/
148
ret=0;
149done:
150
atomic_dec(&probe_count);
151
wake_up(&probe_waitqueue);
152
returnret;
153}
154如果bus和driver同時(shí)具備probe方法,則優(yōu)先調(diào)用總線的probe函數(shù)。否則調(diào)用device_driver的probe函數(shù),此probe函數(shù)是經(jīng)過各種類型的driver重載的函數(shù),這就實(shí)現(xiàn)了利用基類的統(tǒng)一方法來實(shí)現(xiàn)不同的功能。對(duì)于platform_driver來說,其就是:
http://lxr.linux.no/#linux+v2.6.25/drivers/base/platform.c#L394
394staticintplatform_drv_probe(structdevice*_dev)
395{
396
structplatform_driver*drv=to_platform_driver(_dev->driver);
397
structplatform_device*dev=to_platform_device(_dev);
398
399
returndrv->probe(dev);
400}然后調(diào)用特定platform_driver所定義的操作方法,這個(gè)是在定義某個(gè)platform_driver時(shí)靜態(tài)指定的操作接口。至此,platform_driver成功掛接到platformbus上了,并與特定的設(shè)備實(shí)現(xiàn)了綁定,并對(duì)設(shè)備進(jìn)行了probe處理。6
bus、device及driver三者之間的關(guān)系
在數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)上,總線、設(shè)備及驅(qū)動(dòng)三者相互關(guān)聯(lián)。platformdevice包含device,根據(jù)device可以獲得相應(yīng)的bus及driver。設(shè)備添加到總線上后形成一個(gè)雙向循環(huán)鏈表,根據(jù)總線可以獲得其上掛接的所有device,進(jìn)而獲得了platformdevice。根據(jù)device也可以獲得驅(qū)動(dòng)該總線上所有設(shè)備的相關(guān)driver。platformdriver包含driver,根據(jù)driver可以獲得相應(yīng)的bus,進(jìn)而獲得bus上所有的device,進(jìn)一步獲得platformdevice,根據(jù)name對(duì)driver與platformdevice進(jìn)行匹配,匹配成功后將device與相應(yīng)的driver關(guān)聯(lián)起來,即實(shí)現(xiàn)了platformdevice和platformdriver的關(guān)聯(lián)。匹配成功后調(diào)用driver的probe進(jìn)而調(diào)用platformdriver的probe,在probe里實(shí)現(xiàn)驅(qū)動(dòng)特定的功能。
7
哪些適用于plarform驅(qū)動(dòng)?
platform機(jī)制將設(shè)備本身的資源注冊(cè)進(jìn)內(nèi)核,由內(nèi)核統(tǒng)一管理,在驅(qū)動(dòng)程序中使用這些資源時(shí)通過platformdevice提供的標(biāo)準(zhǔn)接口進(jìn)行申請(qǐng)并使用。這樣提高了驅(qū)動(dòng)和資源管理的獨(dú)立性,這樣擁有更好的可移植性。platform機(jī)制的本身使用并不復(fù)雜,由兩部分組成:platform_device和platfrom_driver。Platformdriver通過platformbus獲取platform_device。通常情況下只要和內(nèi)核本身運(yùn)行依賴性不大的外圍設(shè)備,相對(duì)獨(dú)立的,擁有各自獨(dú)立的資源(地址總線和IRQs),都可以用platform_driver來管理,而timer,irq等小系統(tǒng)之內(nèi)的設(shè)備則最好不用platfrom_driver機(jī)制。platform_device最大的特定是CPU直接尋址設(shè)備的寄存器空間,即使對(duì)于其他總線設(shè)備,設(shè)備本身的寄存器無法通過CPU總線訪問,但總線的controller仍然需要通過platformbus來管理??傊?,platfrom_driver的根本目的是為了統(tǒng)一管理系統(tǒng)的外設(shè)資源,為驅(qū)動(dòng)程序提供統(tǒng)一的接口來訪問系統(tǒng)資源,將驅(qū)動(dòng)和資源分離,提高程序的可移植性。8
基于platform總線的驅(qū)動(dòng)開發(fā)流程
基于Platform總線的驅(qū)動(dòng)開發(fā)流程如下:
?
定義初始化platformbus
?
定義各種platformdevices
?
注冊(cè)各種platformdevices
?
定義相關(guān)platformdriver
?
注冊(cè)相關(guān)platformdriver
?
操作相關(guān)設(shè)備
圖platform機(jī)制開發(fā)驅(qū)動(dòng)流程以S3C24xx平臺(tái)為例,來簡單講述下platform驅(qū)動(dòng)的實(shí)現(xiàn)流程。
8.1
初始化platform_bus
Platform總線的初始化是在platform_bus_init()完成的,代碼如下:
http://lxr.linux.no/#linux+v2.6.25/drivers/base/platform.c#L621
26structdeviceplatform_bus={
27
.bus_id
="platform",
28};
29EXPORT_SYMBOL_GPL(platform_bus);621int__initplatform_bus_init(void)
622{
623
interror;
624
625
error=device_register(&platform_bus);
626
if(error)
627
returnerror;
628
error=
bus_register(&platform_bus_type);
629
if(error)
630
device_unregister(&platform_bus);
631
returnerror;
632}該函數(shù)創(chuàng)建了一個(gè)名為“platform”的設(shè)備,后續(xù)platform的設(shè)備都會(huì)以此為parent。在sysfs中表示為:所有platform類型的設(shè)備都會(huì)添加在platform_bus所代表的目錄下,即/sys/devices/platform下面。
-sh-3.1#ls/sys/devices/platform/
FixedMDIObus.0
fsl-i2c.0
serial8250
fsl-ehci.0
fsl-i2c.1
serial8250.0
fsl-gianfar.0
mpc83xx_spi.0
uevent
fsl-gianfar.1
mpc83xx_wdt.0
fsl-gianfar_mdio.-5
power-sh-3.1#ls/sys/
block/
class/
firmware/kernel/
power/
bus/
devices/
fs/
module/
-sh-3.
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025-2030中國互聯(lián)網(wǎng)理財(cái)行業(yè)市場發(fā)展現(xiàn)狀及競爭格局與投資機(jī)會(huì)研究報(bào)告
- 2025-2030眼鏡防霧清潔劑產(chǎn)業(yè)市場深度調(diào)研及發(fā)展趨勢(shì)與投資研究報(bào)告
- 拆遷置換房買賣合同6篇
- 公路工程質(zhì)量合同7篇
- 建筑工程資料承包合同范本8篇
- 電視機(jī)專利代理合同9篇
- 中海物業(yè)綠化養(yǎng)護(hù)承包合同9篇
- 合同范本之購房合同貸款流程模板
- 廣告合作合同
- 建筑門窗安裝合同
- 鎮(zhèn)村綜治中心治安防控室工作臺(tái)賬(完整打印版)
- 2020年10月自考00152組織行為學(xué)試題及答案
- 2018年順豐控股公司組織架構(gòu)和部門職能
- 中國聯(lián)通大客戶業(yè)務(wù)故障處理工作實(shí)施細(xì)則
- 華為WLAN培訓(xùn)資料課件
- 干眼(癥)診治基礎(chǔ)知識(shí)考試試題及答案
- GB/T 6488-2022液體化工產(chǎn)品折光率的測(cè)定
- GB/T 1871.1-1995磷礦石和磷精礦中五氧化二磷含量的測(cè)定磷鉬酸喹啉重量法和容量法
- FZ/T 73023-2006抗菌針織品
- 2021-2022學(xué)年高二下學(xué)期英語讀后續(xù)寫公開課課件:continuation writing-receiving and giving課件
- 2023年初中數(shù)學(xué)競賽試題中國教育學(xué)會(huì)中學(xué)數(shù)學(xué)教學(xué)專業(yè)委員會(huì)數(shù)學(xué)周報(bào)杯
評(píng)論
0/150
提交評(píng)論