详解Linux26内核中基于platform机制的驱动模型Word文件下载.docx
《详解Linux26内核中基于platform机制的驱动模型Word文件下载.docx》由会员分享,可在线阅读,更多相关《详解Linux26内核中基于platform机制的驱动模型Word文件下载.docx(28页珍藏版)》请在冰豆网上搜索。
![详解Linux26内核中基于platform机制的驱动模型Word文件下载.docx](https://file1.bdocx.com/fileroot1/2022-12/17/9e175870-8576-43c6-9d12-28b9613de042/9e175870-8576-43c6-9d12-28b9613de0421.gif)
注册platform_driver
29
8.6
操作设备
32
Linux系统中许多部分对设备是如何链接的并不感兴趣,但是他们需要知道哪些类型的设备是可以使用的。
设备模型提供了一种机制来对设备进行分类,在更高的功能层面上描述这些设备,并使得这些设备对用户空间可见。
因此从2.6内核开始引入了设备模型。
总线是处理器和一个或多个设备之间的通道,在设备模型中,所有的设备都通过总线相连。
总线可以相互插入。
设备模型展示了总线和它们所控制的设备之间的实际连接。
Platform总线是2.6kernel中最近引入的一种虚拟总线,主要用来管理CPU的片上资源,具有更好的移植性,因此在2.6kernel中,很多驱动都用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);
//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};
总线名称是"
,其只是bus_type的一种,定义了总线的属性,同时platform_bus_type还有相关操作方法,如挂起、中止、匹配及hotplug事件等。
总线bus是联系driver和device的中间枢纽。
Device通过所属的bus找到driver,由match操作方法进行匹配。
Bus、driver及devices的连接关系
device和platform_device
Plarformdevice会有一个名字用于driverbinding(在注册driver的时候会查找driver的目标设备的bus位置,这个过程称为driverbinding),另外IRQ以及地址空间等资源也要给出。
platform_device结构体用来描述设备的名称、资源信息等。
该结构被定义在http:
//lxr.linux.no/#linux+v2.6.25/include/linux/platform_device.h#L16中,定义原型如下:
16structplatform_device{
17
*name;
//定义平台设备的名称,此处设备的命名应和相应驱动程序命名一致
18
int
id;
19
structdevice
dev;
20
u32
num_resources;
21
structresource*resource;
//定义平台设备的资源
22};
在这个结构里封装了structdevice及structresource。
可知:
platform_device由device派生而来,是一种特殊的device。
下面来看一下platform_device结构体中最重要的一个成员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{
resource_size_tstart;
//定义资源的起始地址
resource_size_tend;
//定义资源的结束地址
constchar*name;
//定义资源的名称
22
unsignedlongflags;
定义资源的类型,比如MEM,IO,IRQ,DMA类型
23
structresource*parent,*sibling,*child;
24};
这个结构表示设备所拥有的资源,即I/O端口、I/O映射内存、中断及DMA等。
这里的地址指的是物理地址。
另外还需要注意platform_device中的device结构,它详细描述了设备的情况,其为所有设备的基类,定义如下:
//lxr.linux.no/#linux+v2.6.25/include/linux/device.h#L422
422structdevice{
423
structklist
klist_children;
424
structklist_node
knode_parent;
/*nodeinsiblinglist*/
425
knode_driver;
426
knode_bus;
427
*parent;
428
429
structkobjectkobj;
430
char
bus_id[BUS_ID_SIZE];
/*positiononparentbus*/
431
structdevice_type
*type;
432
unsigned
is_registered:
1;
433
uevent_suppress:
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
*platform_data;
/*Platformspecificdata,device
444
coredoesn'
'
ttouchit*/
445
structdev_pm_info
power;
446
447#ifdefCONFIG_NUMA
448
numa_node;
/*NUMAnodethisdeviceiscloseto*/
449#endif
450
u64
*dma_mask;
/*dmamask(ifdma'
abledevice)*/
451
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
devres_head;
468
469
/*class_devicemigrationpath*/
470
node;
471
structclass
*class;
472
dev_t
devt;
/*dev_t,createsthesysfs"
dev"
473
structattribute_group
**groups;
/*optionalgroups*/
474
475
(*release)(structdevice*dev);
476};
477
device_register和platform_device_register
//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}
初始化一个设备,然后加入到系统中。
//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);
我们看到注册一个platformdevice分为了两部分,初始化这个platform_device,然后将此platform_device添加到platform总线中。
输入参数platform_device可以是静态的全局设备。
另外一种机制就是动态申请platform_device_alloc一个platform_device设备,然后通过platform_device_add_resources及platform_device_add_data等添加相关资源和属性。
无论哪一种platform_device,最终都将通过platform_device_add这册到platform总线上。
229/**
230*platform_device_add-addaplatformdevicetodevicehierarchy
231*@pdev:
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
初始化设备的parent为platform_bus,初始化驱备的总线为platform_bus_type。
243
dev.parent)
244
pdev->
dev.parent=&
platform_bus;
245
246
dev.bus=&
platform_bus_type;
247
/*++++++++++++++
Theplatform_device.dev.bus_idisthecanonicalnameforthedevices.
It'
sbuiltfromtwocomponents:
*platform_device.name...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"
.While"
my_rtc"
/-1wouldbebus_id"
(noinstanceid)
andusetheplatform_drivercalled"
.
++++++++++++++*/
248
if(pdev->
id!
=-1)
249
snprintf(pdev->
dev.bus_id,BUS_ID_SIZE,"
%s.%d"
pdev->
name,
250
id);
251
else
252
strlcpy(pdev->
dev.bus_id,pdev->
name,BUS_ID_SIZE);
253
设置设备structdevice的bus_id成员,留心这个地方,在以后还需要用到这个的。
254
for(i=0;
i<
num_resources;
i++){
255
structresource*p,*r=&
resource[i];
256
257