阅读:5107回复:3
原创,PCI板卡内存映射一揽子解决方案(源程序)
很早以前就想做一个这样的程序,一直懒得动手,直到自己不得不做。不过,既然做了还是给大家贴出来,免得他人再遇到问题。目前贴的是未调试版本,仅仅编译通过,不过一来留出了调试接口,二来是在原来的一个类似文件改过来的,应该不会有太大问题。之后的几天会调试一下,调试的结果和详细的使用方法可能会在几天后贴在我的空间中http://embedchinadesign.spaces.live.com/,希望大家喜欢。另外,我的调试应该只局限于x86。
文件中的一些名字我使用了最喜欢的“xxx”看到的时候可以略过。 #include "vxworks.h" #include "tasklib.h" #include "syslib.h" #include "config.h" #include "vmlib.h" #include "drv/pci/pciConfigLib.h" /*使用须知: 任何人可以将该文件用于任何目的。但是如果改动了 该程序的任何部分(宏定义除外),请通过电子邮件通 知作者。地址是hwybird@gmail.com,欢迎交流。 2003.5 形成想法,可惜没有机会做 2007.8.31 有了机会 2007.9.3正式完成未调试版 */ /*该文件通用于PCI板卡配置 板卡配置的目的就是内存映射。其实这个工作可以由 WindRiver来做。 解决的问题是: 1、每一个板卡都有不同的VID和DID,这样需要一个数组 完成, 也就是说在循环的过程中通过数组访问实 现多个板卡支持。 2、同类型板卡支持。同类型的板卡可能会存在多个实 例。每一个实例都会占用资源,不同的板卡占用的 资源是不同的,需要不同的配置。 3、每一块板卡都有不同的配置空间数量。对于每一个 板卡来说,需要配置的内存空间是不相同的,从一 个到多个不等,中间还有可能跳过一些配置,这就 需要程序可以自动完成配置。 4、内存空间大小不一。不同类型的板卡所需要映射的 内存空间都是不相同的。这时需要计算出内存地址 的容量,这样可以进行设置。 没有解决的问题: 1、该文件并不想为其他程序提供什么方便。提供方便 实际上无可厚非,但是可能会降低通用性。基于这 种考虑,该程序并不为其他程序提供任何方便的接 口。 2、用户需要对文件进行自定义,由于文件的目的是解 决通用性的问题,所以用户需要自己定义板卡的数 量和种类。另外用户需要对BSP进行改动。 3、每一个映射的类型都是VM_STATE_MASK_FOR_ALL和VM_STATE_FOR_PCI。 这个问题目前不知道应如何解决。 */ #undef xxx_DEBUG /*用于调试,平常不要定义*/ /*这里定义每一个VID和DID*/ #define xxx_VENDOR_ID 0xFFFF #define xxx_DEV_ID 0xFFFF #define xxxUNKNOWN 0 #define xxx_MAX_UNITS 2 /*这里以2个卡为例子*/ /*每一个板卡的资源*/ typedef struct xxxResource /* xxx_RESOURCE */ { int BoardVID; int BoardDID; int unitInx; } xxx_RESOURCE; /*板卡资源的定义,这里以相同的板卡为例子 板卡如果相同的话unitInx逐次递增,如果不同 的话则从零开始*/ LOCAL xxx_RESOURCE xxxRes [xxx_MAX_UNITS] = { {xxx_VENDOR_ID, xxx_DEV_ID, 0}, {xxx_VENDOR_ID, xxx_DEV_ID, 1}, }; /*这里就是PCI初始化部分了*/ void xxxPciInit (void) { xxx_RESOURCE *pReso; int pciBus; int pciDevice; int pciFunc; int unit; int iCommand; BOOL duplicate; UINT32 membaseCsr; UINT32 r_membase;/*用于计算地址映射的空间*/ char irq; int ix; for (unit = 0; unit < xxx_MAX_UNITS; unit++) { /*寻找板卡*/ if (pciFindDevice (xxxRes[unit].BoardVID, xxxRes[unit].BoardDID, xxxRes[unit].unitInx, &pciBus, &pciDevice, &pciFunc) != OK) break; /* 检查是否重复配置 ,这里应该不会有问题,所以暂时去掉*/ /* pReso = &xxxResources [0]; duplicate = FALSE; for (ix = 0; ix < xxx_MAX_UNITS; ix++, pReso++) { if ((ix != unit) && (pReso->pciBus == pciBus) && (pReso->pciDevice == pciDevice) && (pReso->pciFunc == pciFunc)) duplicate = TRUE; } if (duplicate) continue;*/ /* 应该是找到了*/ pReso = &xxxRes [unit]; /* PCI_CFG_TYPE can be defined to PCI_CFG_NONE,PC_CFG_AUTO,or PCI_CFG_FORCE.*/ /* 在X86下,BIOS会分配好资源的,所以不需要再配置了,嘿嘿*/ for(ix=0; ix<6; ix++)/*总共是6个地址*/ { pciConfigInLong (pciBus, pciDevice, pciFunc, PCI_CFG_BASE_ADDRESS_0 + 0x04 * ix, &membaseCsr); /*读回地址内容*/ /*首先需要判断是内存还是端口,如果不是端口就映射*/ if(!(membaseCsr&PCI_BAR_SPACE_IO)) { /*首先,需要判断所需内存的大小 根据PCI的规范,将内容写回就可以得到大小*/ pciConfigOutLong (pciBus, pciDevice, pciFunc, PCI_CFG_BASE_ADDRESS_0 + 0x04 * ix, 0xffffffff); pciConfigInLong (pciBus, pciDevice, pciFunc, PCI_CFG_BASE_ADDRESS_0 + 0x04 * ix, &r_membase); r_membase &= PCI_MEMBASE_MASK; /*现在r_membase就是长度了*/ /*再把地址写回去*/ pciConfigOutLong (pciBus, pciDevice, pciFunc, PCI_CFG_BASE_ADDRESS_0 + 0x04 * ix, membaseCsr); membaseCsr &= PCI_MEMBASE_MASK; #ifdef xxx_DEBUG /*如果现在是调试阶段,则不用映射,继续下一个*/ printf("\nmemory space is : 0x%x", membaseCsr); printf("\nlength is : 0x%x", r_membase); continue; #endif /*此时就可以将内存映射过去了*/ if (sysMmuMapAdd((void *)membaseCsr, r_membase, VM_STATE_MASK_FOR_ALL, VM_STATE_FOR_PCI) == ERROR) break; } } } } |
|
沙发#
发布于:2007-09-08 08:47
楼主:您程序中的 if(!(membaseCsr&PCI_BAR_SPACE_IO))是判断该空间
不是内存,是IO吧?这个if语句我看不大明白,请指点! 另,您在程序中的0x04*ix,是偏移地址吧? |
|
板凳#
发布于:2007-10-25 23:39
不错,顶.
|
|
地板#
发布于:2007-10-27 15:13
if(!(membaseCsr&PCI_BAR_SPACE_IO))这一句是判断非IO空间,请注意前面的叹号,嘿嘿
|
|