📄 if_ex.c
字号:
int shMemSize; /* size of shared memory area */ caddr_t pShMem; /* pointer to shared memory area */ DEV_CTRL *pDev; /* device address */ EX_MSG *pH2XNext; /* host pointer to request queue */ EX_MSG *pX2HNext; /* host pointer to reply queue */ /* Pointers to shared memory members. * These are static after initialization. */ CFG_MSG *pCfgMsg; /* configuration message */ STAT_ARRAY *pStatArray; /* EXOS writes stats here */ u_short *pH2XHdr; /* ptr to EXOS' host outgoing header */ u_short *pX2HHdr; /* ptr toEXOS' host incoming header */ EX_MSG *pH2XQueue; /* request msg buffers */ EX_MSG *pX2HQueue; /* reply msg buffers */ caddr_t pWriteBuf; /* pointer to write buffer */ caddr_t pReadBuf; /* pointer to read buffer */ } DRV_CTRL;/* Some values for the flags */#define EX_XPENDING 1 /* xmit rqst pending on EXOS */#define EX_STATPENDING (1<<1) /* stats rqst pending on EXOS */#define EX_RUNNING (1<<2) /* board is running */#define EX_SETADDR (1<<3) /* physaddr has been changed *//***** GLOBALS *****//***** LOCALS *****//* The array of driver control structures, one per unit supported */LOCAL DRV_CTRL drvCtrl [MAX_UNITS];#undef EX_RESETLOCAL int EX_RESET = 0; /* because using constant causes "clr" inst. */LOCAL BOOL exBit32 = FALSE; /* TRUE = in VME extended address space *//* * VME address space that the EXOS should use to access host buffers, etc. * This is normally standard space but can be changed through the exattach * argument (exDmaAm). */LOCAL int exBusAdrsSpace;/* forward static functions */static void exReset (int unit);static STATUS exConfig (int unit, int itype);#ifdef BSD43_DRIVERstatic void exStart (int unit);#elsestatic void exStart (DRV_CTRL *pDrvCtrl);#endifstatic void exIntr (int unit);static EX_MSG *exMsgBlkGet (DRV_CTRL *pDrvCtrl);static void exRecvAndHang (int unit, int len, int status);static void exRecv (int unit, int len, int status);static void exRxRqst (int unit);#ifdef BSD43_DRIVERstatic int exOutput (IDR *pIDR, MBUF *pMbuf, SOCK *pDest);#endifstatic int exIoctl (IDR *pIDR, int cmd, caddr_t data);static char *exHostAdrs (char *localAdrs);static void exGiveRequest (EX_MSG *pMsg, DEV_CTRL *pDev);/********************************************************************************* exattach - publish the `ex' network interface and initialize the driver and device** This routine publishes the `ex' interface by filling in a network * interface record and adding this record to the system list. It also* initializes the driver and the device to the operational state.** RETURNS: OK or ERROR.*/STATUS exattach ( int unit, /* logical number of this interface */ char *pDev, /* bus address of EXOS device ports */ int ivec, /* interrupt vector */ int ilevel, /* interrupt level */ int exDmaAm, /* VME addr modifier to access CPU memory */ int exAdrsAm /* VME addr modifier to access EXOS ports */ ) { int loopy; STATUS ret; /* return value of called funcs */ EX_MSG *pMsg; DRV_CTRL *pDrvCtrl; /* Sanity check the unit number */ if (unit < 0 || unit >= MAX_UNITS) return (ERROR); /* Ensure single invocation per system life */ pDrvCtrl = & drvCtrl [unit]; if (pDrvCtrl->attached) return (OK); /* Save some parms */ pDrvCtrl->ivec = ivec; pDrvCtrl->ilevel= ilevel; /* Convert the buss address of the EXOS board's registers to the local * address to use for the specified address space. */ if ( sysBusToLocalAdrs (exAdrsAm, pDev, (char **) & pDrvCtrl->pDev) == ERROR ) return (ERROR); /* Publish the interface data record */#ifdef BSD43_DRIVER ether_attach (&pDrvCtrl->idr.ac_if, unit, "ex", (FUNCPTR) NULL, (FUNCPTR) exIoctl, (FUNCPTR) exOutput, (FUNCPTR) exReset);#else ether_attach ( &pDrvCtrl->idr.ac_if, unit, "ex", (FUNCPTR) NULL, (FUNCPTR) exIoctl, ether_output, (FUNCPTR) exReset ); pDrvCtrl->idr.ac_if.if_start = (FUNCPTR)exStart;#endif /* setup address modifier */ if ( (VME_AM_EXT_USR_DATA <= exDmaAm) && (exDmaAm <= VME_AM_STD_SUP_ASCENDING) ) exBusAdrsSpace = exDmaAm; else exBusAdrsSpace = VME_AM_STD_SUP_DATA; exBit32 = VME_AM_IS_EXT(exBusAdrsSpace); { /***** Obtain memory area that will be shared with the EXOS board *****/ /* this driver can't handle incoherent caches */ if ( !CACHE_DMA_IS_WRITE_COHERENT () || !CACHE_DMA_IS_READ_COHERENT () ) { printErr ( "\nex%d: requires cache coherent memory\n", unit ); return (ERROR); } pDrvCtrl->shMemSize = CFG_MSG_SIZ + /* the config message */ STAT_ARRAY_SIZ + /* the status array */ /* the EXOS firmware headers */ sizeof (*pDrvCtrl->pH2XHdr) + sizeof (*pDrvCtrl->pX2HHdr) + (EX_MSG_SIZ * NH2X) + /* outbound message queue */ (EX_MSG_SIZ * NX2H) + /* inbound message queue */ EXMAXRBUF + /* one packet write buffer */ EXMAXRBUF + /* one packet read buffer */ 16; /* to allow alignment */ /* Attempt to get cache coherent memory */ pDrvCtrl->pShMem = cacheDmaMalloc (pDrvCtrl->shMemSize); if ( pDrvCtrl->pShMem == NULL ) {#ifdef EX_DEBUG printErr ( "\nex%d: no memory available\n", unit );#endif return ( ERROR ); } /* Clear the whole block */ bzero (pDrvCtrl->pShMem, pDrvCtrl->shMemSize); } /* Block end */ { /***** Carve up the shared memory *****/ caddr_t pCur; /* pointer to current location */ pCur = pDrvCtrl->pShMem; /* start at location assigned above */ pCur = (caddr_t) ((int)pCur + 15); /* bump up to next 16 byte page */ pCur = (caddr_t) ((int) pCur & ~0xf); /* This 16-byte-page aligned address is used as the base address of the * shared memory area. This base address is used in offset calculations * for various values communicated to the EXOS firmware. The config * message starts at this base address, and can therefore be used as an * alias. */ pDrvCtrl->pCfgMsg = (CFG_MSG *) pCur; pCur = (caddr_t)((int)pCur + CFG_MSG_SIZ); pDrvCtrl->pStatArray = (STAT_ARRAY *) pCur; pCur = (caddr_t)((int)pCur + STAT_ARRAY_SIZ); pDrvCtrl->pH2XHdr = (u_short *) pCur; pCur = (caddr_t)((int)pCur + sizeof (*pDrvCtrl->pH2XHdr)); pDrvCtrl->pX2HHdr = (u_short *) pCur; pCur = (caddr_t)((int)pCur + sizeof (*pDrvCtrl->pX2HHdr)); pDrvCtrl->pH2XQueue = (EX_MSG *) pCur; pCur = (caddr_t)((int)pCur + (EX_MSG_SIZ * NH2X)); pDrvCtrl->pX2HQueue = (EX_MSG *) pCur; pCur = (caddr_t)((int)pCur + (EX_MSG_SIZ * NX2H)); pDrvCtrl->pWriteBuf = pCur; pCur = (caddr_t)((int)pCur + EXMAXRBUF); pDrvCtrl->pReadBuf = pCur; } /* Block end */ { /***** Initialize the message queues and headers *****/ int base; u_short offset; /* The offset of certain objects from a base address is a common theme * in the shared data. The config message happens to start at the base * address of the shared memory region, so we cast it and store it as an * integer once, to make the multiple uses easier to read. */ base = (int) pDrvCtrl->pCfgMsg; /* First the request queue (host-to-EXOS) */ pMsg = pDrvCtrl->pH2XQueue; for ( loopy = NH2X; loopy--; ) { /* The link is the offset of the next message from the base of * the shared memory area. */ offset = (u_short) ((int)(pMsg+1) - base); pMsg->mb_link = offset; pMsg->mb_rsrv = 0; pMsg->mb_length = MBDATALEN; pMsg->mb_status = MH_HOST; /* we own it */ pMsg->mb_next = pMsg+1; /* our ptr to next */ pMsg++; } /* Fix up the last message to point back at first message */ pMsg--; offset = (u_short) ((int)pDrvCtrl->pH2XQueue - base); pMsg->mb_link = offset; pMsg->mb_next = pDrvCtrl->pH2XQueue; /* Initialize the variables that indicate the next message. * Ours is a direct pointer, while the EXOS firmware uses an offset. */ *pDrvCtrl->pH2XHdr = offset; pDrvCtrl->pH2XNext = pDrvCtrl->pH2XQueue; /* Now the reply queue (EXOS-to-host) */ pMsg = pDrvCtrl->pX2HQueue; for ( loopy = NX2H; loopy--; ) { /* The link is the offset of the next message from the base of * the shared memory area. */ offset = (u_short) ((int)(pMsg+1) - base); pMsg->mb_link = offset; pMsg->mb_rsrv = 0; pMsg->mb_length = MBDATALEN; pMsg->mb_status = MH_EXOS; /* EXOS owns it */ pMsg->mb_next = pMsg+1; /* our ptr to next */ pMsg++; } /* Fix up the last message to point back at first message */ pMsg--; offset = (u_short) ((int)pDrvCtrl->pX2HQueue - base); pMsg->mb_link = offset; pMsg->mb_next = pDrvCtrl->pX2HQueue; /* Initialize the variables that indicate the next message. * Ours is a direct pointer, while the EXOS firmware uses an offset. */ *pDrvCtrl->pX2HHdr = offset; pDrvCtrl->pX2HNext = pDrvCtrl->pX2HQueue; } /* Block end */ /* Configure the board */ if (sysBus == VME_BUS) ret = exConfig (unit, 4); /* with vectored interrupts */ else ret = exConfig (unit, 3); /* with level interrupts */ if (ret != OK) return (ERROR); /* Connect interrupt handler, enable interrupt */ (void) intConnect (INUM_TO_IVEC (ivec), exIntr, unit); (void) sysIntEnable (ilevel); /* Ask the board for its physical Ethernet address. The reply will be * processed by the interrupt handler. We wait for the handler to complete * by using the ethernet address field as a sync flag: it will be zero * until filled in by the reply processing. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -