这篇blog主要分为三部分:
1,中断初始化
2,vxbus架构中断的挂接
3,非vxbus架构的中断的挂接
1,中断的初始化
函数调用:
usrInit->sysStart->palInit->palDescInit()
/*为了方便查看,这里对函数 进行了删减
*palDescInit()函数对默认的中断函数进行了初始化
*/
void palDescInit (void)
{
int idx;
#ifndef _WRS_MIPS_NONCOMPLIANT_CONFIG_REG
UINT32 config;
#endif /* _WRS_MIPS_NONCOMPLIANT_CONFIG_REG */
bzero((char *)&palDesc, sizeof(palDesc));
palDesc.coreNum = 0;
palDesc.version = "1.1";
/* Hopefully code further down will be able to refine these */
palDesc.iCache.present = FALSE;
palDesc.dCache.present = FALSE;
palDesc.l2Cache.present = FALSE;
palDesc.l3Cache.present = FALSE;
if (IS_KSEGM((UINT32) &palDescInit))
{
/* executing a mapped kernel */
palDesc.tVec.vectorAddr = (VIRT_ADDR *)T_VEC;
palDesc.tVec.excHandler = (VIRT_ADDR *)mmuMipsTlbVec;
palDesc.tVec.excSize = mmuMipsTlbVecSize;
palDesc.xVec.vectorAddr = (VIRT_ADDR *)X_VEC;
palDesc.xVec.excHandler = (VIRT_ADDR *)mmuMipsXtlbVec;
palDesc.xVec.excSize = (UINT)mmuMipsXtlbVecSize;
palDesc.cVec.vectorAddr = (VIRT_ADDR *)C_VEC;
palDesc.cVec.excHandler = (VIRT_ADDR*)excCacheVec;
palDesc.cVec.excSize = (UINT)excCacheVecSize;
palDesc.eVec.vectorAddr = (VIRT_ADDR *)E_VEC;
palDesc.eVec.excHandler = (VIRT_ADDR *)excNormVmVec;
palDesc.eVec.excSize = (UINT)excNormVmVecSize;
}
/* Reasonable defaults */
palDesc.tlb.supportedPageSizes = MMU_PAGE_MASK_8K;
palDesc.tlb.mmuCacheable=MMU_R4K_STATE_INVALID_STATE >> MMU_R4K_CACHE_START;
palDesc.tlb.mmuUncacheable = CFG_CCA_UNCACHED;
palDesc.tlb.mmuCacheCopyback = CFG_CCA_CACHEABLE;
palDesc.tlb.mmuCacheWritethrough = CFG_CCA_ALIAS_CACHEABLE;
palDesc.tlb.mmuCacheCoherency = CFG_CCA_COHERENT;
palDesc.iCache.modes = CACHE_MODES_SUPPORTED;
palDesc.dCache.modes = CACHE_MODES_SUPPORTED;
}
//重要的结构体说一下
#define T_VEC K0BASE /* tlbmiss vector */
#define X_VEC (K0BASE+0x80) /* xtlbmiss vector */
#define C_VEC (K1BASE+0x100) /* cache exception vector */
#define E_VEC (K0BASE+0x180) /* exception vector */
#define R_VEC (K1BASE+0x1fc00000) /* reset vector */
#define BEV_VEC (K1BASE+0x1fc00380) /* boot exception vector */
typedef struct
{
char *version; /* PAL version string */
int coreNum; /* processor number */
MIPS_EXC_VECTOR tVec; /*tlbmiss中断*/
MIPS_EXC_VECTOR xVec; /*xtlbmiss中断*/
MIPS_EXC_VECTOR cVec; /*cache异常中断*/
MIPS_EXC_VECTOR eVec; /*异常中断,包括中断(根据exccode码判别)*/
MIPS_MMU_INFO tlb; /**/
MIPS_CACHE_INFO iCache; /*指令cache相关*/
MIPS_CACHE_INFO dCache; /*数据cache相关*/
MIPS_CACHE_INFO l2Cache; /*二级cache相关*/
MIPS_CACHE_INFO l3Cache; /*三级cache相关*/
int mmuType; /* CR bits 9:7 */
BOOL hasCP2;
BOOL hasWatch;
BOOL hasFPU;
} MIPS_PAL_DESC;
函数调用:
usrInit->excVecInit
/*在这里会安装默认的中断处理函数*/
STATUS excVecInit (void)
{
ULONG srValue; /* status register placeholder */
/* Load tlb and Xtlb vectors */
vecInit (&palDesc.tVec);
vecInit (&palDesc.xVec);
/* Load cache exception vector */
vecInit (&palDesc.cVec);
/* Load normal/interrupt vector */
vecInit (&palDesc.eVec);
srValue = intSRGet();
srValue &= ~SR_BEV;
intSRSet(srValue);
return (OK);
}
LOCAL void vecInit
(
MIPS_EXC_VECTOR * vectorDesc
)
{
if (vectorDesc->excSize)
{
/*把函数拷贝到设置的地址处*/
bcopy ((const char *) vectorDesc->excHandler,
(char *) vectorDesc->vectorAddr, vectorDesc->excSize);
/*刷cache操作*/
CACHE_TEXT_UPDATE (vectorDesc->vectorAddr, vectorDesc->excSize);
}
}
到这里系统默认的中断处理函数就初始化完成。
这里找一个具体的中断控制器的初始化进行说明。(这是一个抽象出来的中断控制器,至于什么是抽象,也就是没有一个具体的物理硬件设备对应这个控制器,这只是一个软件层面的简化,这样对于中断的处理就更明显,直接。)
函数调用关系:
usrInit->sysHwInit->vxbMipsLsnIntCtlrRegister
当这个控制其注册之后:
vxbMipsLsnIntCtlrRegister->vxbDevRegister->vxbNewDriver->vxbDevInitRun
/*vxbDevInitRun函数会调用设备对应的初始化函数对设备进行初始化*/
LOCAL void vxbDevInitRun
(
VXB_DEVICE_ID devID,
struct vxbDevRegInfo * pDrv
)
{
/* first pass */
if (!(devID->flags & VXB_INST_INIT_DONE))
{
if ( pDrv->pDrvBusFuncs->devInstanceInit != NULL )
(*(pDrv->pDrvBusFuncs->devInstanceInit))(devID);
devID->flags |= VXB_INST_INIT_DONE;
}
/* second pass */
if (vxbInitPhase >= 2 && !(devID->flags & VXB_INST_INIT2_DONE))
{
if ( pDrv->pDrvBusFuncs->devInstanceInit2 != NULL )
(*(pDrv->pDrvBusFuncs->devInstanceInit2))(devID);
devID->flags |= VXB_INST_INIT2_DONE;
}
/* third pass */
if (vxbInitPhase >= 3 && !(devID->flags & VXB_INST_CONNECT_DONE))
{
if ( pDrv->pDrvBusFuncs->devInstanceConnect != NULL )
(*(pDrv->pDrvBusFuncs->devInstanceConnect))(devID);
devID->flags |= VXB_INST_CONNECT_DONE;
}
}
LOCAL VOID vxbMipsLsnIntCtlrInit
(
VXB_DEVICE_ID pInst
)
{
HCF_DEVICE *pHcf = NULL;
BOOL icw4Needed = FALSE;
pVXB_LSN_INT_DRV_CTRL pDrvCtrl = pInst->pDrvCtrl;
/*这里注意intCtlrHwConfGet,这是真正具体的初始化函数*/
intCtlrHwConfGet(pInst, pHcf, &(pDrvCtrl->isrHandle));
Loongson2H_interrupt_init();
return;
}
STATUS intCtlrHwConfGet
(
VXB_DEVICE_ID pInst,
HCF_DEVICE * pHcf,
struct intCtlrHwConf * pEntries
)
{
struct intrCtlrInputs * pCtlrInputs; /*中断控制引脚*/
struct intrCtlrXBar * pXbar; /*xbar路由*/
struct intrCtlrCpu * pCpuTable; /*对应那个cpu*/
struct intrCtlrPriority * pPrioTable; /*优先级*/
struct intrCtlrTrigger * pTrigTable; /*引发方式,上升沿,高低电平,下降沿*/
int tableSize; /*控制引脚数组的大小*/
int i;
STATUS stat;
void * pValue;
void ** ppValue;
/* save intCtlr ID */
pEntries->ctlrDev = pInst;
ppValue = &pValue;
/*获取中断控制引脚组成的数组*/
stat = devResourceGet(pHcf, "input", HCF_RES_ADDR, ppValue);
pCtlrInputs = (struct intrCtlrInputs *)pValue;
if ( stat == OK )
{
/*获取中断控制引脚数组的大小*/
stat = devResourceGet(pHcf, "inputTableSize", HCF_RES_INT, ppValue);
tableSize = (UINT32)pValue;
/*遍历表中的每个元素,并为每一个对应的引脚创建相应的结构体*/
for ( i = 0 ; i < tableSize ; i++ )
{
/*为引脚创建一个结构体*/
stat = intCtlrTableCreate(pEntries, pCtlrInputs->inputPin);
/*为创建的结构体中的元素进行赋值操作,包括引脚号(硬件上连接的引脚号),驱动名字,drvunit以及drvIndex */
intCtlrTableUserSet(pEntries, pCtlrInputs->inputPin, pCtlrInputs->drvName,pCtlrInputs->drvUnit, pCtlrInputs->drvIndex);
pCtlrInputs++;
}
}
/*获取优先级对应的数组*/
stat = devResourceGet(pHcf, "priority", HCF_RES_ADDR, ppValue);
pPrioTable = (struct intrCtlrPriority *)pValue;
if ( stat == OK )
{
/*获取优先级表的大小*/
stat = devResourceGet(pHcf, "priorityTableSize", HCF_RES_INT, ppValue);
tableSize = (UINT32)pValue;
/*遍历表中所有的元素,把值填入到对应的引脚结构体中*/
for ( i = 0 ; i < tableSize ; i++ )
{
/*再次a创建引脚结构体,防止没有创建 */
stat = intCtlrTableCreate(pEntries, pPrioTable->inputPin);
/*为结构体填入优先级 */
intCtlrTablePrioSet(pEntries, pPrioTable->inputPin,pPrioTable->priority);
pPrioTable++;
}
}
/*下面操作基本都是类似的,获取对应的中断信息,并进行遍历填入到引脚结构体中*/
/*获取引脚出发的方式*/
stat = devResourceGet(pHcf, "trigger", HCF_RES_ADDR, ppValue);
pTrigTable = (struct intrCtlrTrigger *)pValue;
if ( stat == OK )
{
stat = devResourceGet(pHcf, "triggerTableSize", HCF_RES_INT, ppValue);
tableSize = (UINT32)pValue;
for ( i = 0 ; i < tableSize ; i++ )
{
/* ensure pin record exists */
stat = intCtlrTableCreate(pEntries, pTrigTable->inputPin);
/* fill in trigger */
intCtlrTableTrigSet(pEntries, pTrigTable->inputPin, pTrigTable->trigger);
pTrigTable++;
}
}
/*获取crossbar路由表*/
stat = devResourceGet(pHcf, "crossBar", HCF_RES_ADDR, ppValue);
pXbar = (struct intrCtlrXBar *)pValue;
if ( stat == OK )
{
stat = devResourceGet(pHcf, "crossBarTableSize", HCF_RES_INT, ppValue);
tableSize = (UINT32)pValue;
for ( i = 0 ; i < tableSize ; i++ )
{
/* ensure pin record exists */
stat = intCtlrTableCreate(pEntries, pXbar->inputPin);
intCtlrTableOutputSet(pEntries, pXbar->inputPin, pXbar->outputPin);
pXbar++;
}
}
stat = devResourceGet(pHcf, "cpuRoute", HCF_RES_ADDR, ppValue);
pCpuTable = (struct intrCtlrCpu *)pValue;
#ifdef _WRS_CONFIG_SMP
if ( stat == OK )
{
stat = devResourceGet(pHcf, "cpuRouteTableSize", HCF_RES_INT, ppValue);
tableSize = (UINT32)pValue;
/* iterate through table */
for ( i = 0 ; i < tableSize ; i++ )
{
/* ensure pin record exists */
stat = intCtlrTableCreate(pEntries, pCpuTable->inputPin);
/* set destination CPU for this input pin */
if (stat == OK)
intCtlrTableCpuSet (pEntries, pCpuTable->inputPin,
pCpuTable->cpuNum);
pCpuTable++;
}
}
#endif /* _WRS_CONFIG_SMP */
return(OK);
}
/*创建中断表*/
STATUS intCtlrTableCreate
(
struct intCtlrHwConf * pInputs,
int inputPin
)
{
int tblIndx = VXB_INTCTLRLIB_TBL_IDX(pInputs,inputPin);
int startPin = inputPin - (inputPin % VXB_INTCTLRLIB_LOWLVL_SIZE);
int i;
if ( pInputs->pTop == NULL )
{
/*分配一个结构体vxbIntCtlrInpTop*/
pInputs->pTop = (struct vxbIntCtlrInpTop *)
hwMemAlloc(sizeof(struct vxbIntCtlrInpTop));
}
if ( pInputs->pTop->tbl[tblIndx] == NULL )
{
/*分配结构体vxbIntCtlrInput*/
pInputs->pTop->tbl[tblIndx] = (struct vxbIntCtlrInput *)
hwMemAlloc(sizeof(struct vxbIntCtlrInput) +
VXB_INTCTLRLIB_MIN_CACHE_LINE_SIZE);
/*进行对齐操作*/
pInputs->pTop->tbl[tblIndx] = (struct vxbIntCtlrInput *)
ROUND_UP(pInputs->pTop->tbl[tblIndx],
VXB_INTCTLRLIB_MIN_CACHE_LINE_SIZE);
/*赋值为0*/
memset(pInputs->pTop->tbl[tblIndx],0,sizeof(struct vxbIntCtlrInput));
/*为每一个引脚结构体中的中断函数以及中断函数参数赋一个系统默认的值 */
for ( i = 0 ; i < VXB_INTCTLRLIB_NUM_PINS(pInputs) ; i++ )
{
pInputs->pTop->tbl[tblIndx]->pins[i].isr = intCtlrStrayISR;
pInputs->pTop->tbl[tblIndx]->pins[i].pArg = pInputs;
pInputs->pTop->tbl[tblIndx]->pins[i].pinFlags = startPin + i;
}
}
return(OK);
}
对应引脚重要的结构体:
struct intCtlrHwConf
{
VXB_DEVICE_ID ctlrDev; /* VXB_DEVICE_ID of int ctlr */
struct vxbIntCtlrInpTop * pTop; /* top-level table of entries */
struct vxbLock vxbIntCtlrLibLock;
};
struct vxbIntCtlrInpTop
{
struct vxbIntCtlrInpTop * pNext; /* not implemented */
struct vxbIntCtlrInput * tbl[VXB_INTCTLRLIB_TOPLVL_SIZE];
UINT32 reserved;
};
#define VXB_INTCTLRLIB_TOPLVL_SIZE 496
struct vxbIntCtlrInput
{
struct vxbIntCtlrPin pins[VXB_INTCTLRLIB_LOWLVL_SIZE];
};
/*最后的运算就是 2^x ,这里的定义也就是8*/
#define VXB_INTCTLRLIB_LOWLVL_SIZE_POW 3
#define VXB_INTCTLRLIB_LOWLVL_SIZE ( 1<< VXB_INTCTLRLIB_LOWLVL_SIZE_POW)
struct vxbIntCtlrPin
{
struct intCtlrMoreDrvName * pMoreNames;
char * drvName;
int drvUnit;
int intIndex;
void (*isr)(void * pArg, int inputPin);
void * pArg;
int pinFlags;
UINT32 pinPriority;
UINT32 pinOutput;
UINT32 pinCpu;
int reserved [2];
};
这里就相当于创建了一个两级表,第一级是496的大小,第二级分别对应于第一级的每一个元素,大小为8,到这里中断的创建以及初始化就完成了。
函数调用关系:
usrRoot->sysClkInit->sysClkConnect->sysHwInit2->vxbDevInit->vxbDevInitInternal->vxbDevIterate->vxbDevInit2Helper->
LOCAL STATUS vxbDevInit2Helper
(
struct vxbDev * pInst,
void * pArg
)
{
if ( pInst->pDriver->pDrvBusFuncs->devInstanceInit2 == NULL )
return(OK);
/*这里调用第二阶段的初始化函数。*/
(*pInst->pDriver->pDrvBusFuncs->devInstanceInit2)(pInst);
pInst->flags |= VXB_INST_INIT2_DONE;
return(OK);
}
这里调用的第二阶段初始化函数对应的函数是:
LOCAL VOID lsnIntCtlrInstInit2
(
VXB_DEVICE_ID pInst
)
{
vxbIntConnect(pInst, 0, vxbMipsLsnIntCtrlIsr, (void*)pInst);
vxbIntEnable(pInst, 0, vxbMipsLsnIntCtrlIsr, (void*)pInst);
return;
}
/*可以看出这里所作的工作就只有挂接中断和使能*/
这里中断挂接函数的函数调用关系:
vxbIntConnect->vxbDevIterate->vxbIntCtlrMatch->vxbIntCtlrConnect
直接看函数:熟悉流程即可:
STATUS vxbIntConnect
(
struct vxbDev * pDev, /* Device Information */
int index, /* index of interrupt vector */
VOIDFUNCPTR pIsr, /* ISR */
void * pArg /* parameter */
)
{
VXB_ACCESS_INTERRUPT_INFO accessIntrInfo;
struct vxbintCtlrMgmt info;
VXB_ASSERT(pDev!=NULL, ERROR)
info.found = FALSE;
info.pIntCtlr = NULL;
info.inputPin = 0;
info.pDev = pDev;
info.index = index;
info.pIsr = pIsr;
info.pArg = pArg;
/*这里一次把所有实例化的设备和要注册的info进行匹配*/
vxbDevIterate(vxbIntCtlrMatch, &info, VXB_ITERATE_INSTANCES);
if ( info.found == TRUE )
return(OK);
return (vxbDevControl (pDev, (pVXB_DEVCTL_HDR)&accessIntrInfo));
}
LOCAL STATUS vxbIntCtlrMatch
(
struct vxbDev * pInst,
void * pArg
)
{
struct vxbintCtlrMgmt * pInfo = (struct vxbintCtlrMgmt *)pArg;
FUNCPTR func;
STATUS stat;
struct plbIntrEntry * pIntrEntry;
int inputPin;
struct pIntCtlrTable * pICTab;
struct plbIntCtlrTable * pICTab2;
int x;
int y;
struct plbIntCtlrEntry * pEnt;
/*在这里会调用匹配到的设备的中断挂接函数,换句话说对不同的中断控制器上的中断挂接会调用对应的中断控制器的额挂接函数*/
func = vxbDevMethodGet(pInst, DEVMETHOD_CALL(vxbIntCtlrConnect));
stat = (*func)(pInst, pInfo->pDev, pInfo->index, pInfo->pIsr, pInfo->pArg, &inputPin);
if ( stat != OK )
return(OK);
pInfo->found = TRUE;
return(OK);
}
这里对应的中断挂接函数为:
LOCAL STATUS vxbMipsLsnIntCtlrDevIsrConnect
(
VXB_DEVICE_ID pIntCtlr,
VXB_DEVICE_ID pDev,
int indx,
void (*pIsr)(void * pArg),
void * pArg,
int * pInputPin
)
{
pVXB_LSN_INT_DRV_CTRL pDrvCtrl = pIntCtlr->pDrvCtrl;
int inputPin = ERROR;
struct intCtlrHwConf * pIsrHandle = NULL;
inputPin = intCtlrPinFind (pDev, indx, pIntCtlr, &pDrvCtrl->isrHandle);
pIsrHandle = &(pDrvCtrl->isrHandle);
/*在这里调用intCtlrISRAdd函数,这个函数会真正的挂接用户的中断函数*/
if (intCtlrISRAdd(pIsrHandle, inputPin, pIsr, pArg) == ERROR)
return ERROR;
*pInputPin = inputPin;
return OK;
}
STATUS intCtlrISRAdd
(
struct intCtlrHwConf * pEntries,
int inputPin,
void (*isr),
void * pArg
)
{
struct intCtlrISRChainEntry * pChain;
struct intCtlrISRChainEntry * pChain2;
void * installedIsr;
/*这里要确保中断表已经创建 */
intCtlrTableCreate(pEntries, inputPin);
/*这里创建两个结构体,并初始化为用户中断,用于挂接中断时使用*/
pChain = (struct intCtlrISRChainEntry *)hwMemAlloc(sizeof(*pChain));
pChain2 = (struct intCtlrISRChainEntry *)hwMemAlloc(sizeof(*pChain));
pChain->isr = isr;
pChain->pArg = pArg;
/*获取目前表中现在挂接的中断函数,如果是函数intCtlrStrayISR说明已经初始化为默认的中断函数,
只需要替换为用户的中断函数即可,如果为函数intCtlrChainISR,说明已经至少挂接了一个用户中断函数(多个中断函数可以挂接在一个中断引脚上),
如果为空,说明没有进行过初始化,这时就使用pChain2保存要挂接的中断函数,并赋值为pChain,然后填写到对应引脚上*/
installedIsr = intCtlrTableIsrGet(pEntries, inputPin);
if ( installedIsr == (void *)intCtlrStrayISR )
{
intCtlrTableFill(pEntries, inputPin, pChain->isr, pChain->pArg);
}
else if ( installedIsr == (void *)intCtlrChainISR )
{
pChain->pNext = (struct intCtlrISRChainEntry *)intCtlrTableArgGet(pEntries, inputPin);
intCtlrTableFill(pEntries, inputPin, intCtlrChainISR, pChain);
}
else
{
/* create chain, add original entry and the new one */
pChain2->flags = intCtlrTableFlagsGet(pEntries, inputPin);
pChain2->pArg = intCtlrTableArgGet(pEntries, inputPin);
pChain2->isr = installedIsr;
pChain->pNext = pChain2;
pChain2->pNext = NULL;
intCtlrTableFill(pEntries, inputPin, intCtlrChainISR, pChain);
}
return(OK);
}
struct intCtlrISRChainEntry
{
struct intCtlrISRChainEntry * pNext;
void (*isr)(void * pArg, int inputPin);
void * pArg;
UINT32 flags;
};
3,非vxbus中断的挂接
下面说一下不是vxbus结构的中断函数的挂接。
不是vxbus架构的中断函数使用intConnect函数进行挂接,废话少说,看函数:
STATUS intConnect
(
VOIDFUNCPTR * vector, /* interrupt vector to attach to */
VOIDFUNCPTR routine, /* routine to be called */
int parameter /* parameter to be passed to routine */
)
{
/*这里首先看到,进行了三次判断,分别代表的三种中断的挂接,是首先第一种_func_isrConnect,
这是isrobjectn中断的挂接,目前对于isrobject还没有深入分析过,不过这必须打开#INCLUDE_ISR_OBJECT宏定义才可以,
这里不运行;intArchConnect这个函数就是结构中断的额挂接,一个中断号挂接一个中断,当然了在这里执行不到;
_func_vxbIntConnect这个函数才是这次的重点,这个函数在vxbLegacyIntInit中被赋值,
_func_vxbIntConnect = vxbLegacyIntConnect,看一下这个初始化函数*/
if (_func_isrConnect != NULL)
if (_func_isrConnect (vector, routine, parameter) == OK)
return (OK);
if (_func_vxbIntConnect != NULL)
if (_func_vxbIntConnect(vector, routine, parameter) == OK)
return (OK);
return (intArchConnect (vector, (VOIDFUNCPTR) routine,
(int) parameter));
}
void vxbLegacyIntInit()
{
VXB_DEVICE_ID devID;
struct plbIntrEntry * pIntrInfo;
/*申请一个legacy设备(legacy在这里代表不是vxbus架构设备也可以说为遗留设备)*/
devID = vxbDevStructAlloc(WAIT_FOREVER);
/*初始化设备,主要是名字和总线号,用于之后匹配挂接于那个中断控制器*/
devID->pName = "legacy";
devID->pParentBus = pPlbDev->u.pSubordinateBus;
devID->busID = VXB_BUSID_PLB;
devID->pRegBase[0] = (void *)1;
pIntrInfo = (struct plbIntrEntry *)hwMemAlloc(sizeof(*pIntrInfo));
devID->pIntrInfo = pIntrInfo;
/*声明设备已经注册到系统中*/
if ( vxbDeviceAnnounce(devID) != OK )
{
vxbDevStructFree(devID);
return;
}
vxbLegacyIntDevice = devID;
_func_vxbIntConnect = vxbLegacyIntConnect;
_func_vxbIntDisconnect = vxbLegacyIntDisconnect;
_func_vxbIntEnable = vxbLegacyIntEnable;
_func_vxbIntDisable = vxbLegacyIntDisable;
}
LOCAL STATUS vxbLegacyIntConnect
(
VOIDFUNCPTR * vector, /* interrupt vector to attach to */
VOIDFUNCPTR routine, /* routine to be called */
int parameter /* parameter to be passed to routine */
)
{
/*在这里调用vxbIntConnect函数把中断注册进vxbus架构的中断表中*/
if ((vxbIntConnect(vxbLegacyIntDevice,(int)vector,routine,
(void *)parameter)) != OK)
return ERROR;
return(vxbIntEnable(vxbLegacyIntDevice,(int)vector,routine,
(void *)parameter));
}
之后就和上面vxbus中断的挂接一样了:
vxbIntConnect->vxbDevIterate->vxbIntCtlrMatch->vxbDevMethodGet->vxbIntCtlrConnect->vxbMipsLsnIntCtlrDevIsrConnect
ok~~,分析就先到这里,如果有什么不对地方,请留言。。。