VXWORKS7.0版本里经常在某某驱动里看到vxbXXXAttach函数调用
pRes = vxbResourceAlloc (pDev, VXB_RES_MEMORY, 0);
该函数的作用主要是获取硬件资源参数。
STATUS vxbFdtChildScan
(
VXB_DEV_ID pDev /* device to scan */
)
{
VXB_FDT_BUS_DEV_INFO * pFdtHardware;
VXB_FDT_DEV * pFdtDev;
VXB_FDT_DEV * pNewFdtDev;
int offset;
VXB_DEV_ID pCur;
char name[MAX_DEV_NAME_LEN];
char * pUnitAddr;
pFdtDev = vxbFdtDevGet (pDev); /* req: VX7-13978 */
if (pFdtDev == NULL)
return (ERROR);
offset = pFdtDev->offset;
/* req: VX7-13979 */
for (offset = VX_FDT_CHILD(offset); offset > 0;
offset = VX_FDT_PEER(offset))
{ /* req: VX7-13980 */
if (vxFdtIsEnabled (offset) == FALSE)
continue;
/* req: VX7-13981 */
pFdtHardware = (VXB_FDT_BUS_DEV_INFO *)vxbMemAlloc (sizeof(*pFdtHardware));
if (pFdtHardware == NULL) /* req: VX7-13982 */
continue;
pNewFdtDev = &pFdtHardware->vxbFdtDev;
/* Get the device basic information */ /* req: VX7-13983 */
vxbFdtDevSetup (offset, pNewFdtDev);
/* Get the device register and interrupt information */
/* req: VX7-13984 */
if (vxbResourceInit(&pFdtHardware->vxbResList) != OK)
{ /* req: VX7-13985 */
vxbMemFree (pFdtHardware);
continue;
}
/* req: VX7-13986 */
if (vxbFdtRegGet(&pFdtHardware->vxbResList, pNewFdtDev) != OK)
{ /* req: VX7-13987 */
vxbFdtResFree (&pFdtHardware->vxbResList);
vxbMemFree(pFdtHardware);
continue;
}
/* req: VX7-13988 */
if (vxbFdtIntGet(&pFdtHardware->vxbResList, pNewFdtDev) != OK)
{ /* req: VX7-13989 */
vxbFdtResFree (&pFdtHardware->vxbResList);
vxbMemFree(pFdtHardware);
continue;
}
pCur = NULL; /* req: VX7-13990 */
if (vxbDevCreate (&pCur) != OK)
{ /* req: VX7-13991 */
vxbFdtResFree (&pFdtHardware->vxbResList);
vxbMemFree (pFdtHardware);
continue;
}
/* req: VX7-13992 */
vxbDevNameSet (pCur, pNewFdtDev->name, FALSE);
/*
* FDT nodes names are usually specified in the form
* "name@unit-address". If the name contains a unit
* address, then we should use that, otherwise use 0.
*/
pUnitAddr = vxbFdtUnitAddrGet ((UINT32)offset, name, MAX_DEV_NAME_LEN);
if (pUnitAddr == NULL)
{
(void) snprintf (name, MAX_DEV_NAME_LEN, "0");
}
else
{
(void) snprintf (name, MAX_DEV_NAME_LEN, "%s", pUnitAddr);
}
vxbDevNameAddrSet (pCur, name, TRUE);
在设备树vxbFdtChildScan函数库里,可以看到该函数初始化一个资源表(vxbResourceInit(&pFdtHardware->vxbResList),调用vxbFdtRegGet(&pFdtHardware->vxbResList, pNewFdtDev)获取寄存器地址参数,调用vxbFdtIntGet(&pFdtHardware->vxbResList, pNewFdtDev)获取中断参数。假设设备树某个设备描述如下:
qdma0: dma-controller@8380000
{
compatible = "fsl,qdma";
reg = <0x0 0x8380000 0x0 0x10000>, /* Privileged registers */
<0x0 0x8390000 0x0 0x10000>, /* Manager registers */
<0x0 0x83A0000 0x0 0x10000>; /* Block registers */
interrupt-parent = <&intc>;
interrupts = <71 0 4>;
clocks = <&dma1_en>;
dma-channels = <64>;
big-endian = <1>;
status = "disabled"; /* set "okay" to enable access */
};
其中vxbFdtRegGet 获取reg =参数节点,vxbFdtIntGet获取interrupts节点。
最后调用vxbDevAdd,把资源添加到VXBUS列表里。
有了资源列表后,接下来查看vxbResourceAlloc怎么实现的,在该函数里首先调用vxbDevParent获取父设备VXBUS指针,为啥需要调用这个指针呢?看如下设备树结构:
&i2c0
{
clocks = <&i2c1_en>;
interrupts = <88 0 4>;
status = "okay";
}
如果我们需要使用I2C下的驱动,这时候首先需要知道I2C0的父类硬件资源参数,这个资源其实就是设备树解析时,调用fdtBusResAlloc创建的,所有寄存器参数信息保存在pFdtBusDevInfo列表里,所以通过vxbDevParent获取I2C寄存器相关参数。
VXB_RESOURCE * vxbResourceAlloc
(
VXB_DEV_ID pDev, /* device from which to allocate resource */
UINT16 type, /* type of resource to allocate */
UINT16 idx /* identifier of resource to allocate */
)
{
VXB_DEV_ID pBus;
VXB_RESOURCE * pRes;
if (pDev == NULL)
{
return NULL; /* req: VX7-19825 */
}
/* req: VX7-13768 */
pBus = vxbDevParent(pDev);
if (pBus == NULL)
{
/* req: VX7-13769 */
return NULL;
}
/* req: VX7-13770 */
pRes = VXB_RESOURCE_ALLOC(pBus, pDev, (UINT32)(VXB_RES_ID_CREATE(type, idx)));
if (pRes != NULL)
pRes->owner = pDev; /* req: VX7-13771 */
return (pRes);
}
找到父类VXBUS指针后,调用VXB_RESOURCE_ALLOC 获取资源,这个是一个匹配通用方法的函数。找到对应的vxbResourceAlloc函数 ,如fslI2cResAlloc函数。
LOCAL VXB_RESOURCE * fslI2cResAlloc
(
VXB_DEV_ID pDev,
VXB_DEV_ID pChild,
UINT32 id
)
{
I2C_DEV_INFO * pFslI2cDevInfo;
VXB_RESOURCE * vxbRes;
VXB_RESOURCE_ADR * vxbAdrRes;
pFslI2cDevInfo = (I2C_DEV_INFO *) vxbDevIvarsGet (pChild);
if (pFslI2cDevInfo == NULL)
{
return NULL;
}
vxbRes = vxbResourceFind (&pFslI2cDevInfo->vxbResList, id);
if (vxbRes == NULL)
{
return NULL;
}
if ((VXB_RES_TYPE (vxbRes->id) == VXB_RES_MEMORY) ||
(VXB_RES_TYPE (vxbRes->id) == VXB_RES_IO))
{
vxbAdrRes = vxbRes->pRes;
vxbAdrRes->virtual = (VIRT_ADDR) vxbAdrRes->start;
return vxbRes;
}
else if ((VXB_RES_TYPE (vxbRes->id) == VXB_RES_IRQ) &&
(vxbIntMap (vxbRes) == OK))
{
return vxbRes;
}
else
{
return NULL;
}
}