⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 if_ne2kd.c

📁 与ucos 的网络实现部份
💻 C
📖 第 1 页 / 共 2 页
字号:

    // ***** Update statistics
    Statistics.OverrunErrors++;

    // ***********************************************************************************
    // ***** The following buffer ring overflow procedure is taken from the datasheet 
    // ***** DP8390D/NS32490D NIC Network Interface Controller (July 1995) from National 
    // ***** Semiconductor. This procedure is mandatory!

    // ***** 1. Read and store the value of the TXP bit (from command register)
    TxpBit = (INPORTB(NIC_CR) & CR_TXP); 
    PAUSE;

    // ***** 2. Issue a stop command
    OUTPORTB(NIC_CR, CR_STOP | CR_NO_DMA | CR_PAGE0);
    PAUSE;

    // ***** 3. Wait for at least 1.6 ms
    LONGPAUSE;

    // ***** 4. Clear NIC's Remote Byte Count registers (RBCR0 and RBCR1)
    OUTPORTB(PG0W_RBCR0, 0x00);
    PAUSE;
    OUTPORTB(PG0W_RBCR1, 0x00);
    PAUSE;

    // ***** 5. Read the stored value of the TXP bit from step 1 (determine if we stopped the NIC 
    // *****    when it was transmitting).
    // ***** IF TXP bit = 1 THEN
    if (TxpBit)
      // ***** IF PTX = 1 OR TXE = 1 THEN 
      if (INPORTB(PG0R_ISR) & (ISR_PTX | ISR_TXE))
      {
        PAUSE;
        // ***** Resend = FALSE
        Resend = FALSE;
      }
      else
      {
        PAUSE;
        // ***** Resend = TRUE
        Resend = TRUE;
      }
    else
      // ***** Resend = FALSE
      Resend = FALSE;

    // ***** 6. Place the NIC in mode 1 (internal loopback)
    OUTPORTB(PG0W_TCR, TCR_LB0);
    PAUSE;

    // ***** 7. Start the NIC
    OUTPORTB(NIC_CR, CR_START | CR_NO_DMA | CR_PAGE0);
    PAUSE;
  } 
  else PAUSE;

  // ***** 8. Remove one or more packets from the NIC
  // ***** IF (packet = NULL) OR (length = 0) THEN - Just remove one packet from the receive buffer ring
  if (!PacketLength) 
  {
    // ***** IF ReadBuffer(header, NULL, 0) THEN
    if (ReadBuffer(&Header, NULL, 0))
    {
      // ***** Remove packet!
      // ***** NextPacket = Header.NextPage;
      NextPacket = Header.NextPage;

      // ***** Initialize Boundary (read) Pointer to the value of NextPacket - 1
      // ***** IF Boundary Pointer < RSTART_PG THEN BNDRY = RSTOP_PG - 1
      if ( (NextPacket - 1) < RSTART_PG )
          OUTPORTB(PG0W_BNRY, RSTOP_PG - 1);
      else
          OUTPORTB(PG0W_BNRY, NextPacket - 1);
      PAUSE;

      // ***** Success = TRUE
      Success = TRUE;

      // ***** Update statistics
      Statistics.BytesReceived += Header.Length - 4; 
      Statistics.PacketsReceived++;
    }
  }
  else
  {
    // ***** IF ReadBuffer(header, packet, length) THEN
    if (ReadBuffer(&Header, packet, PacketLength))
    {
      // ***** Remove packet!
      // ***** NextPacket = Header.NextPage;
      NextPacket = Header.NextPage;

      // ***** Initialize Boundary (read) Pointer to the value of NextPacket - 1
      // ***** IF Boundary Pointer < RSTART_PG THEN BNDRY = RSTOP_PG - 1
      if ( (NextPacket - 1) < RSTART_PG )
          OUTPORTB(PG0W_BNRY, RSTOP_PG - 1);
      else
          OUTPORTB(PG0W_BNRY, NextPacket - 1);
      PAUSE;

      // ***** Success = TRUE
      Success = TRUE;

      // ***** Update statistics
      Statistics.BytesReceived += Header.Length - 4; 
      Statistics.PacketsReceived++;
    }
  }

  // ***** IF NIC buffer overwrite warning THEN
  if (INPORTB(PG0R_ISR) & ISR_OVW) 
  {
    PAUSE;

    // ***** 9. Reset the overwrite warning bit in the Interrupt Status Register.
    OUTPORTB(PG0W_ISR, ISR_OVW);
    PAUSE;


    // ***** 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 Success;
}



int 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;

  // ***** 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;
}



void Ne2kGetStatistics(Ne2kStatistics *statistics)
{
  DISABLE_INTERRUPTS;

  // Copy statistics to caller
  memcpy(statistics, &Statistics, sizeof(Statistics));

  ENABLE_INTERRUPTS;
}


int ReadBuffer(BufferHeader *header, u_char *packet, u_short length)
{
  u_char Save_curr;
  Word Word;
  int OddLength;
  int Count = 0;

  // ***** IF packet pointer = NULL THEN length = 0
  if (!packet) length = 0;

  // ***** Clear REMOTE DMA COMPLETE bit in ISR
  OUTPORTB(PG0W_ISR, ISR_RDC);
  PAUSE;

  // ***** Make length an even value
  OddLength = length & 0x0001;
  length++;
  length &= 0xfffe;

  // ***** Read CURR
  // Read Current Page of rcv ring
  // Go to page 1
  OUTPORTB(NIC_CR, CR_START | CR_NO_DMA | CR_PAGE1);
  PAUSE;

  // Read CURR
  Save_curr = INPORTB(PG1R_CURR);
  PAUSE;

  // Go to page 0
  OUTPORTB(NIC_CR, CR_START | CR_NO_DMA | CR_PAGE0);
  PAUSE;

  // ***** LOOP WHILE CURR <> NextPacket  - While we have a packet in buffer
  while (Save_curr != NextPacket)
  {
    // Setup Remote Byte Counts and Remote Start Address to read length + 4 bytes for buffer header 
    OUTPORTB(PG0W_RBCR0, (length + 4) & 0xFF);
    PAUSE;
    OUTPORTB(PG0W_RBCR1, ((length + 4) >> 8) & 0xFF);
    PAUSE;
    OUTPORTB(PG0W_RSAR0, 0);
    PAUSE;
    OUTPORTB(PG0W_RSAR1, NextPacket);
    PAUSE;

    // ***** Issue the Remote Read command
    OUTPORTB(NIC_CR, CR_START | CR_DMA_READ);
    PAUSE;

    // ***** Read buffer header (4 bytes)
    Word.Word = INPORTW(NIC_DATAPORT);
    header->Status = Word.Uchar[0];
    header->NextPage = Word.Uchar[1];
    header->Length = INPORTW(NIC_DATAPORT);

    if (length)
    {
      for (Count = 0; Count < (length - 2); Count+=2)
      {
        Word.Word = INPORTW(NIC_DATAPORT);
        packet[Count] = Word.Uchar[0];
        packet[Count+1] = Word.Uchar[1];
        // The line below might very well be a bit faster...
        //   *((u_short *)(packet+Count)) = INPORTW(NIC_DATAPORT);
      }
      Word.Word = INPORTW(NIC_DATAPORT);
    }
    
    // ***** Stop REMOTE DMA
    OUTPORTB(NIC_CR, CR_START | CR_NO_DMA);
    PAUSE;

    if (length) 
    {
      packet[Count] = Word.Uchar[0];
      if (!OddLength) packet[Count+1] = Word.Uchar[1];
    }

    // Clear REMOTE DMA COMPLETE bit in ISR
    OUTPORTB(PG0W_ISR, ISR_RDC);
    PAUSE;

    // ***** IF next page pointer is out of receive buffer range THEN
    //       We have a serious problem
    if ( (header->NextPage < RSTART_PG) || (header->NextPage > RSTOP_PG) )
    {
      // ***** Initialize NextPacket pointer to last known good value of the Current (write) Pointer.
      // This means that we drop a lot of packets, but beats winding up in the weeds!
      NextPacket = Save_curr;

      // ***** Initialize Boundary (read) Pointer to the value of NextPacket - 1
      // ***** IF Boundary Pointer < RSTART_PG THEN BNDRY = PSTOP - 1
      if ( (NextPacket - 1) < RSTART_PG )
          OUTPORTB(PG0W_BNRY, RSTOP_PG - 1);
      else
          OUTPORTB(PG0W_BNRY, NextPacket - 1);
      PAUSE;

      // ***** This will drop a lot of packets! Count this error!
      Statistics.NextPageErrors++;
    }   
    else
    {
      // ***** Packets should always be OK, but you never know
      // (the NIC is configured to only store valid packets)
      // ***** IF status field is OK (valid packet) THEN RETURN length
      if (header->Status & RSR_PRX) 
      {
        return header->Length - 4;
      }
      else
      {
        // ***** Discard packet in receive buffer 
        // ***** Set NextPacket to next page pointer
        NextPacket = header->NextPage;

        // ***** Initialize Boundary (read) Pointer to the value of NextPacket - 1
        // ***** IF Boundary Pointer < RSTART_PG THEN BNDRY = RSTOP - 1
        // (drops invalid packet)
        if ( (NextPacket - 1) < RSTART_PG )
            OUTPORTB(PG0W_BNRY, RSTOP_PG - 1);
        else
            OUTPORTB(PG0W_BNRY, NextPacket - 1);
        PAUSE;
      }
    }
  }

  // ***** No valid packets in buffer, RETURN FALSE
  return FALSE;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -