📄 if_ne2kd.c
字号:
// ***** 10. Take the NIC out of loopback mode (that means normal operation) OUTPORTB(PG0W_TCR, 0x00); PAUSE; // ***** 11. IF Resend = 1 THEN reissue a transmit if (Resend) { // Reissue transmit OUTPORTB(NIC_CR, CR_START | CR_NO_DMA | CR_TXP); PAUSE; } }else{ PAUSE; } // ***** Restore NIC IMR OUTPORTB(PG0W_IMR, Imr); PAUSE; // ***** RETURN Success return rtn;}static u_short Ne2kTransmitReady(void){ // ***** IF transmitting THEN RETURN FALSE if (INPORTB(NIC_CR) & CR_TXP) return FALSE; // ***** RETURN TRUE return TRUE;}int Ne2kTransmit(const u_char *packet, u_short length){ int Timeout, Count; u_char Imr; u_char CrdaLow, CrdaHigh;// printf("Ne2kTransmit\n"); // ***** IF transmitting THEN RETURN FALSE if (!Ne2kTransmitReady()) return FALSE; // ***** IF (length < 14) OR (length > 1514) THEN RETURN FALSE if ((length < 14) || (length > 1514)) return FALSE; // ***** Remember NIC IMR and disable interrupt from NIC (ATOMIC OPERATION!) DISABLE_INTERRUPTS; // Select PAGE 2 OUTPORTB(NIC_CR, CR_PAGE2 | CR_NO_DMA | CR_START); PAUSE; // Read IMR register Imr = INPORTB(PG2R_IMR); PAUSE; // Select PAGE 0 again OUTPORTB(NIC_CR, CR_PAGE0 | CR_NO_DMA | CR_START); PAUSE; // Disable interrupts from NIC OUTPORTB(PG0W_IMR, 0x00); PAUSE; ENABLE_INTERRUPTS; // ***** Clear REMOTE DMA COMPLETE bit in ISR OUTPORTB(PG0W_ISR, ISR_RDC); PAUSE; // *********************************************************************************** // ***** Due to two non synchronized state machines in the NIC, you should always do a // ***** Remote Read (called a dummy read) before a Remote Write. // ***** This is stated in the datasheet DP8390D/NS32490D NIC Network Interface Controller // ***** (July 1995) from National Semiconductor. // ***** 1. Set Remote Byte Count to a value > 0 and Remote Start Address to unused RAM // (like transmit start page - 1) (REMEMBER THESE VALUES!) CrdaLow = 0; CrdaHigh = TSTART_PG - 1; OUTPORTB(PG0W_RBCR0, 1); PAUSE; OUTPORTB(PG0W_RBCR1, 0); PAUSE; OUTPORTB(PG0W_RSAR0, CrdaLow); PAUSE; OUTPORTB(PG0W_RSAR1, CrdaHigh); PAUSE; // ***** 2. Issue the "dummy" Remote Read command OUTPORTB(NIC_CR, CR_START | CR_DMA_READ); PAUSE; // ***** 3. Read the current remote DMA address (CRDA) (both bytes) // ***** 4. Compare to previous CRDA value, if different go to step 6 // ***** 5. Delay and go to step 3. // timeout < 100 === leave us with appr. 200us timeout (which is a lot) // (this timeout is not impl. in NS' datasheet, but it's better to be on the safe side) for (Timeout = 0; Timeout < 50; Timeout++) { if (CrdaLow != INPORTB(PG0R_CRDA0)) break; PAUSE; if (CrdaHigh != INPORTB(PG0R_CRDA1)) break; PAUSE; } // ***** 6. Setup for the Remote Write command // ***** Stop REMOTE DMA OUTPORTB(NIC_CR, CR_START | CR_NO_DMA); PAUSE; // ***** Initialize Transmit Byte Count Registers to packet length and MIN. MIN_PACKET_SIZE bytes if (length < MIN_PACKET_SIZE) { // Padding required OUTPORTB(PG0W_TBCR0, MIN_PACKET_SIZE); PAUSE; OUTPORTB(PG0W_TBCR1, 0); PAUSE; } else { // No padding required OUTPORTB(PG0W_TBCR0, (length & 0xFF)); PAUSE; OUTPORTB(PG0W_TBCR1, ((length >> 8) & 0xFF) ); PAUSE; } // ***** Update statistics (before making length an even value!) Statistics.BytesTransmitted += length; Statistics.PacketsTransmitted++; // ***** We use word transfer mode, so make length an even value length &= 0xfffe; length++; // ***** Initialize Remote Byte Count Register (DMA) to packet length OUTPORTB(PG0W_RBCR0, (length & 0xFF)); PAUSE; OUTPORTB(PG0W_RBCR1, ((length >> 8) & 0xFF)); PAUSE; // ***** Initialize Remote Start Address Register to address of NIC transmit buffer OUTPORTB(PG0W_RSAR0, 0); PAUSE; OUTPORTB(PG0W_RSAR1, TSTART_PG); PAUSE; // ***** 7. Issue the Remote DMA WRITE // ***** Start DMA Write OUTPORTB(NIC_CR, CR_START | CR_DMA_WRITE); PAUSE; // ***** Write data to NIC for (Count = 0; Count < length; Count += 2) OUTPORTW(NIC_DATAPORT, packet[Count] | (packet[Count+1] << 8)); // ***** Wait for Remote DMA to complete (should be instantly, but we have to wait anyway) // timeout < 200 === leave us with appr. 200us timeout (which is a lot) // (this timeout is not impl. in NS' datasheet, but it's better to be on the safe side) for (Timeout = 0; Timeout < 200; Timeout++) { if (INPORTB(PG0R_ISR) & ISR_RDC) break; PAUSE; } // ***** Clear REMOTE DMA COMPLETE bit in ISR OUTPORTB(PG0W_ISR, ISR_RDC); PAUSE; // ***** Initialize Transmit Page Start Register OUTPORTB(PG0W_TPSR, TSTART_PG); PAUSE; // ***** Start transmission OUTPORTB(NIC_CR, CR_START | CR_NO_DMA | CR_TXP); PAUSE; // ***** Restore NIC IMR OUTPORTB(PG0W_IMR, Imr); PAUSE; // ***** RETURN TRUE return TRUE;}static void Ne2kTxNBuf(NBuf *pNBuf){ u_short d; unsigned char *p_d; long l; int i; NBuf *n;// printf("TxNBuf:\n"); n=pNBuf; l=pNBuf->len; p_d=pNBuf->data; i=0; while(n) { if(l==0) { // next nBuf n=n->nextBuf; if(n) { l=n->len; p_d=n->data; } }else{ d=(d<<8)|*p_d++; l--; if(++i==2) { i=0; OUTPORTW(NIC_DATAPORT, d);// printf("0x%lx\n",d); } } } if(i) { // as we were writing words, we might have a single trailling byte, so just send it... d<<=8; OUTPORTW(NIC_DATAPORT, d);// printf("odd 0x%lx\n",d); }}//static u_char dbgseq=1;static u_char Ne2kTxPacket(NBuf *pNBuf){ int Timeout;// int Count; u_char Imr; u_char CrdaLow, CrdaHigh; u_short length;//,padding,lTx;// printf("Ne2kTxPacket\n"); // ***** IF transmitting THEN RETURN FALSE if (!Ne2kTransmitReady()) return FALSE; length=nChainLen(pNBuf);// printf("Ne2kTxPacket: length=%d\n",length); // ***** IF (length < 14) OR (length > 1514) THEN RETURN FALSE if ((length < 14) || (length > 1514)) return FALSE; // ***** Remember NIC IMR and disable interrupt from NIC (ATOMIC OPERATION!) DISABLE_INTERRUPTS; // Select PAGE 2 OUTPORTB(NIC_CR, CR_PAGE2 | CR_NO_DMA | CR_START); PAUSE; // Read IMR register Imr = INPORTB(PG2R_IMR); PAUSE; // Select PAGE 0 again OUTPORTB(NIC_CR, CR_PAGE0 | CR_NO_DMA | CR_START); PAUSE; // Disable interrupts from NIC OUTPORTB(PG0W_IMR, 0x00); PAUSE; ENABLE_INTERRUPTS; // ***** Clear REMOTE DMA COMPLETE bit in ISR OUTPORTB(PG0W_ISR, ISR_RDC); PAUSE; // *********************************************************************************** // ***** Due to two non synchronized state machines in the NIC, you should always do a // ***** Remote Read (called a dummy read) before a Remote Write. // ***** This is stated in the datasheet DP8390D/NS32490D NIC Network Interface Controller // ***** (July 1995) from National Semiconductor. // ***** 1. Set Remote Byte Count to a value > 0 and Remote Start Address to unused RAM // (like transmit start page - 1) (REMEMBER THESE VALUES!) CrdaLow = 0; CrdaHigh = TSTART_PG - 1; OUTPORTB(PG0W_RBCR0, 1); PAUSE; OUTPORTB(PG0W_RBCR1, 0); PAUSE; OUTPORTB(PG0W_RSAR0, CrdaLow); PAUSE; OUTPORTB(PG0W_RSAR1, CrdaHigh); PAUSE; // ***** 2. Issue the "dummy" Remote Read command OUTPORTB(NIC_CR, CR_START | CR_DMA_READ); PAUSE; // ***** 3. Read the current remote DMA address (CRDA) (both bytes) // ***** 4. Compare to previous CRDA value, if different go to step 6 // ***** 5. Delay and go to step 3. // timeout < 100 === leave us with appr. 200us timeout (which is a lot) // (this timeout is not impl. in NS' datasheet, but it's better to be on the safe side) for (Timeout = 0; Timeout < 50; Timeout++) { if (CrdaLow != INPORTB(PG0R_CRDA0)) break; PAUSE; if (CrdaHigh != INPORTB(PG0R_CRDA1)) break; PAUSE; } // ***** 6. Setup for the Remote Write command // ***** Stop REMOTE DMA OUTPORTB(NIC_CR, CR_START | CR_NO_DMA); PAUSE; // ***** Initialize Transmit Byte Count Registers to packet length and MIN. MIN_PACKET_SIZE bytes if (length < MIN_PACKET_SIZE) {// printf("padding: length=%d, actual sent packet=%d\n",length,MIN_PACKET_SIZE);// padding=MIN_PACKET_SIZE-length;// length=MIN_PACKET_SIZE; // Padding required OUTPORTB(PG0W_TBCR0, MIN_PACKET_SIZE); PAUSE; OUTPORTB(PG0W_TBCR1, 0); PAUSE; }else{// padding=0;// } // No padding required OUTPORTB(PG0W_TBCR0, (length & 0xFF)); PAUSE; OUTPORTB(PG0W_TBCR1, ((length >> 8) & 0xFF) ); PAUSE; } // ***** Update statistics (before making length an even value!) Statistics.BytesTransmitted += length; Statistics.PacketsTransmitted++; // ***** We use word transfer mode, so make length an even value length += length&1; // ***** Initialize Remote Byte Count Register (DMA) to packet length OUTPORTB(PG0W_RBCR0, (length & 0xFF)); PAUSE; OUTPORTB(PG0W_RBCR1, ((length >> 8) & 0xFF)); PAUSE; // ***** Initialize Remote Start Address Register to address of NIC transmit buffer OUTPORTB(PG0W_RSAR0, 0); PAUSE; OUTPORTB(PG0W_RSAR1, TSTART_PG); PAUSE; // ***** 7. Issue the Remote DMA WRITE // ***** Start DMA Write OUTPORTB(NIC_CR, CR_START | CR_DMA_WRITE); PAUSE; // ***** Write data to NIC Ne2kTxNBuf(pNBuf); // send padding/* while(padding>0) { padding-=2; OUTPORTW(NIC_DATAPORT,dbgseq); } dbgseq++;*/ // ***** Wait for Remote DMA to complete (should be instantly, but we have to wait anyway) // timeout < 200 === leave us with appr. 200us timeout (which is a lot) // (this timeout is not impl. in NS' datasheet, but it's better to be on the safe side) for (Timeout = 0; Timeout < 200; Timeout++) { if (INPORTB(PG0R_ISR) & ISR_RDC) break; PAUSE; } // ***** Clear REMOTE DMA COMPLETE bit in ISR OUTPORTB(PG0W_ISR, ISR_RDC); PAUSE; // ***** Initialize Transmit Page Start Register OUTPORTB(PG0W_TPSR, TSTART_PG); PAUSE; // ***** Start transmission OUTPORTB(NIC_CR, CR_START | CR_NO_DMA | CR_TXP); PAUSE; // ***** Restore NIC IMR OUTPORTB(PG0W_IMR, Imr); PAUSE; // ***** RETURN TRUE return TRUE;}void Ne2kGetStatistics(Ne2kStatistics *statistics)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -