platform设备的添加流程.docx
- 文档编号:25654400
- 上传时间:2023-06-11
- 格式:DOCX
- 页数:23
- 大小:28.63KB
platform设备的添加流程.docx
《platform设备的添加流程.docx》由会员分享,可在线阅读,更多相关《platform设备的添加流程.docx(23页珍藏版)》请在冰豆网上搜索。
platform设备的添加流程
platform设备的添加流程
今天我以fb设备的注册过程来分析platform设备的添加流程
platform总线是kernel中最近加入的一种虚拟总线,它被用来连接处在仅有最少基本组件的总线上的那些设备.这样的总线包括许多片上系统上的那些用来整合外设的总线,也包括一些"古董"PC上的连接器;但不包括像PCI或USB这样的有庞大正规说明的总线.
平台设备
~~~~~~
平台设备通常指的是系统中的自治体,包括老式的基于端口的设备和连接外设总线的北桥(hostbridges),以及集成在片上系统中的绝大多数控制器.它们通常拥有的一个共同特征是直接编址于CPU总线上.即使在某些罕见的情况下,平台设备会通过某段其他类型的总线连入系统,它们的寄存器也会被直接编址.平台设备会分到一个名称(用在驱动绑定中)以及一系列诸如地址和中断请求号(IRQ)之类的资源.
那什么情况可以使用platformdriver机制编写驱动呢?
我的理解是只要和内核本身运行依赖性不大的外围设备(换句话说只要不在内核运行所需的一个最小系统之内的设备),相对独立的,拥有各自独自的资源(addressesandIRQs),都可以用platform_driver实现。
如:
lcd,usb,uart等,都可以用platfrom_driver写,而timer,irq等最小系统之内的设备则最好不用platfrom_driver机制,实际上内核实现也是这样的。
下面继续我们的分析过程。
1首先要定义一个platform_device,
我们先来看一下platform_device结构的定义,如下所示:
//include/linux/platform_device.h:
16structplatform_device{
17 constchar *name;
18 u32 id;
19 structdevice dev;
20 u32 num_resources;
21 structresource*resource;
22};
下面是对应的FB设备的变量定义
//arch/arm/mach-pxa/generic.c
229staticstructplatform_devicepxafb_device={
230 .name ="pxa2xx-fb",
231 .id =-1,
232 .dev ={
233 .platform_data =&pxa_fb_info,
234 .dma_mask =&fb_dma_mask,
235 .coherent_dma_mask=0xffffffff,
236 },
237 .num_resources =ARRAY_SIZE(pxafb_resources),
238 .resource =pxafb_resources,
239};
由上可以看出,name成员表示设备名,系统正是通过这个名字来与驱动绑定的,所以驱动里面相应的设备名必须与该项相符合;id表示设备编号,id的值为-1表示只有一个这样的设备。
该结构中比较重要的一个成员就是resource,Linux设计了这个通用的数据结构来描述各种I/O资源(如:
I/O端口、外设内存、DMA和IRQ等)。
它的定义如下:
//include/linux/ioport.h:
16structresource{
17 constchar*name;
18 unsignedlongstart,end;
19 unsignedlongflags;
20 structresource*parent,*sibling,*child;
21};
下面关于这方面的内容,参考了654c63d92307f0eb39012fff.html
structresource是linux对挂接在4G总线空间上的设备实体的管理方式。
一个独立的挂接在cpu总线上的设备单元,一般都需要一段线性的地址空间来描述设备自身,linux是怎么管理所有的这些外部"物理地址范围段",进而给用户和linux自身一个比较好的观察4G总线上挂接的一个个设备实体的简洁、统一级联视图的呢?
linux采用structresource结构体来描述一个挂接在cpu总线上的设备实体(32位cpu的总线地址范围是0~4G):
resource->start 描述设备实体在cpu总线上的线性起始物理地址;
resource->end 描述设备实体在cpu总线上的线性结尾物理地址;
resource->name 描述这个设备实体的名称,这个名字开发人员可以随意起,但最好贴切;
resource->flag 描述这个设备实体的一些共性和特性的标志位;
只需要了解一个设备实体的以上4项,linux就能够知晓这个挂接在cpu总线的上的设备实体的基本使用情况,也就是[resource->start,resource->end]这段物理地址现在是空闲着呢,还是被什么设备占用着呢?
linux会坚决避免将一个已经被一个设备实体使用的总线物理地址区间段[resource->start,resource->end],再分配给另一个后来的也需要这个区间段或者区间段内部分地址的设备实体,进而避免设备之间出现对同一总线物理地址段的重复引用,而造成对唯一物理地址的设备实体二义性.
以上的4个属性仅仅用来描述一个设备实体自身,或者是设备实体可以用来自治的单元,但是这不是linux所想的,linux需要管理4G物理总线的所有空间,所以挂接到总线上的形形色色的各种设备实体,这就需要链在一起,因此resource结构体提供了另外3个成员:
指针parent、sibling和child:
分别为指向父亲、兄弟和子资源的指针,它们的设置是为了以一种树的形式来管理各种I/O资源,以rootsource为例,root->child(*pchild)指向root所有孩子中地址空间最小的一个;pchild->sibling是兄弟链表的开头,指向比自己地址空间大的兄弟。
属性flags是一个unsignedlong类型的32位标志值,用以描述资源的属性。
比如:
资源的类型、是否只读、是否可缓存,以及是否已被占用等。
下面是一部分常用属性标志位的定义
//include/linux/ioport.h:
29/*
30*IOresourceshavethesedefinedflags.
31*/
32#defineIORESOURCE_BITS 0x000000ff /*Bus-specificbits*/
33
34#defineIORESOURCE_IO 0x00000100 /*Resourcetype*/
35#defineIORESOURCE_MEM 0x00000200
36#defineIORESOURCE_IRQ 0x00000400
37#defineIORESOURCE_DMA 0x00000800
38
39#defineIORESOURCE_PREFETCH 0x00001000 /*Nosideeffects*/
40#defineIORESOURCE_READONLY 0x00002000
41#defineIORESOURCE_CACHEABLE 0x00004000
42#defineIORESOURCE_RANGELENGTH 0x00008000
43#defineIORESOURCE_SHADOWABLE 0x00010000
44#defineIORESOURCE_BUS_HAS_VGA 0x00080000
45
46#defineIORESOURCE_DISABLED 0x10000000
47#defineIORESOURCE_UNSET 0x20000000
48#defineIORESOURCE_AUTO 0x40000000
49#defineIORESOURCE_BUSY 0x80000000 /*Driverhasmarkedthisresourcebusy*/
下面来看我们所使用的LCD所占用的资源,如下所示:
//arch/arm/mach-pxa/generic.c
staticstructresourcepxafb_resources[]={
[0]={
.start =0x44000000,
.end =0x4400ffff,
.flags =IORESOURCE_MEM,
},
[1]={
.start =IRQ_LCD,
.end =IRQ_LCD,
.flags =IORESOURCE_IRQ,
},
};
由上可知LCD占用的资源包括两类,一类是MEM类型,一类是IRQ类型。
MEME类型资源对应的物理地址范围是0x44000000-0x4400ffff;IRQ类型资源对应的物理地址范围是IRQ_LCD,查看相应的定义:
//include/asm-arm/arch-pxa/irqs.h:
15#ifdefCONFIG_PXA27x
16#definePXA_IRQ_SKIP 0
17#else
18#definePXA_IRQ_SKIP 7
19#endif
20
21#definePXA_IRQ(x) ((x)-PXA_IRQ_SKIP)
43#defineIRQ_LCD PXA_IRQ(17) /*LCDControllerServiceRequest*/
我们所使用的处理器为PXA255,所以对应的PXA_IRQ_SKIP应该为7,所以IRQ_LCD=10,也就是它对应的中断信号线为10。
设置完了platform_device的相关成员后,下一步就是
2调用platform_add_devices添加设备
首先来看它的定义:
//drivers/base/platform.c:
/**
* platform_add_devices-addanumbersofplatformdevices
* @devs:
arrayofplatformdevicestoadd
* @num:
numberofplatformdevicesinarray
*/
intplatform_add_devices(structplatform_device**devs,intnum)
{
inti,ret=0;
for(i=0;i ret=platform_device_register(devs[i]); if(ret){ while(--i>=0) platform_device_unregister(devs[i]); break; } } returnret; } 我们目前只关注LCD设备,所以不管for循环,关键的一句就是platform_device_register(),该函数用来进行平台设备的注册,首先来看它的定义: //drivers/base/platform.c: /** * platform_device_register-addaplatform-leveldevice * @pdev: platformdevicewe\"readding * */ intplatform_device_register(structplatform_device*pdev) { device_initialize(&pdev->dev); returnplatform_device_add(pdev); } 它首先调用device_initialize()来初始化该设备,然后调用platform_device_add()来添加该设备。 关于device_initialize()我们暂且不分析,在这里只关注 platform_device_add() //drivers/base/platform.c: 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 243 if(! pdev->dev.parent) 244 pdev->dev.parent=&platform_bus; 245 246 pdev->dev.bus=&platform_bus_type; 247 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 254 for(i=0;inum_resources;i++){ 255 structresource*p,*r=&pdev->resource; 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 } 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.flags&(IORESOURCE_MEM|IORESOURCE_IO)) 287 release_resource(&pdev->resource); 288 returnret; 289} 先看243-244两行,如果该设备的父指针为空,则将它的父指针指向platform_bus,这是一个device类型的变量,它的定义如下: //drivers/base/platform.c: 26structdeviceplatform_bus={ 27 .bus_id ="platform", 28}; 紧接着,246行设置设备的总线类型为platform_bus_type //drivers/base/platform.c: 892structbus_typeplatform_bus_type={ 893 .name ="platform", 894 .dev_attrs =platform_dev_attrs, 895 .match =platform_match, 896 .uevent =platform_uevent, 897 .pm =PLATFORM_PM_OPS_PTR, 898}; 248-252行设置设备指向的dev结构的bus_id成员,由前面可知,我们只有一个LCD设备,所以pdev->id=-1,因而对应的bus_id="pxa2xx-fb",关于这个bus_id,在定义的时候,内核开发者是后面加了一个注释: /*positiononparentbus*/ 254-275行进行资源处理,首先设置资源的名称,如果name成员为空的话,就将该成员设置为我们前面已经赋值的bus_id,也就是"pxa2xx-fb" 260-266行先将p指向我们当前处理的资源的parent指针成员,如果p指向NULL,也就是我们当前处理的资源的parent指针成员指向NULL的话,再检测当前处理的资源的类型,如果是MEM类型的,则设置p指向iomem_resource,如果是IO类型的,则使p指向ioport_resource,这两个均是structresource类型的变量,它们的定义如下: //kernel/resource.c 23structresourceioport_resource={ 24 .name ="PCIIO", 25 .start =0, 26 .end =IO_SPACE_LIMIT, 27 .flags =IORESOURCE_IO, 28}; 29EXPORT_SYMBOL(ioport_resource); 30 31structresourceiomem_resource={ 32 .name ="PCImem", 33 .start =0, 34 .end =-1, 35 .flags =IORESOURCE_MEM, 36}; 37EXPORT_SYMBOL(iomem_resource); //include/asm/io.h: #defineIO_SPACE_LIMIT0xffffffff//这并不是针对ARM平台的定义,针对ARM平台的定义我没有找到,所以暂且列一个在这里占位 关于这两个structresource类型的变量,在网络上搜到了如下的信息: (654c63d92307f0eb39012fff.html) 物理内存页面是重要的资源。 从另一个角度看,地址空间本身,或者物理存储器在地址空间中的位置,也是一种资源,也要加以管理--resource管理地址空间资源。 内核中有两棵resource树,一棵是iomem_resource,另一棵是ioport_resource,分别代表着两类不同性质的地址资源。 两棵树的根也都是resource数据结构,不过这两个数据结构描述的并不是用于具体操作对象的地址资源,而是概念上的整个地址空间。 将主板上的ROM空间纳入iomem_resource树中;系统固有的I/O类资源则纳入ioport_resource树 //kernel/resource.c ---------------------------------------- structresourceioport_resource={ .name ="PCIIO", .start =0, .end =IO_SPACE_LIMIT, .flags =IORESOURCE_IO, }
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- platform 设备 添加 流程
![提示](https://static.bdocx.com/images/bang_tan.gif)