詳解Linux2.6內(nèi)核中基于platform機(jī)制地驅(qū)動(dòng)模型_第1頁
詳解Linux2.6內(nèi)核中基于platform機(jī)制地驅(qū)動(dòng)模型_第2頁
詳解Linux2.6內(nèi)核中基于platform機(jī)制地驅(qū)動(dòng)模型_第3頁
詳解Linux2.6內(nèi)核中基于platform機(jī)制地驅(qū)動(dòng)模型_第4頁
詳解Linux2.6內(nèi)核中基于platform機(jī)制地驅(qū)動(dòng)模型_第5頁
已閱讀5頁,還剩25頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(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ì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論