📄 am79c970.c
字号:
//
pCurrentTxDesc = (PTX_DESCRIPTOR_FORMAT) dwTRANSMIT_DESCRIPTORS_HEAD;
pLastTxDesc = (PTX_DESCRIPTOR_FORMAT) (pCurrentTxDesc + dwTRANSMIT_RING_SIZE - 1);
for (i = 0 ; i < dwTRANSMIT_RING_SIZE ; i++)
{
InitTxDescriptor ((PTX_DESCRIPTOR_FORMAT) (pCurrentTxDesc + i),
(DWORD) (dwTRANSMIT_BUFFER_START + i * MAX_BUFFER_SIZE));
}
//DumpTxDescriptors();
/////////////////////////////////////////////////////////////////////////////
// Initialize RX Descriptors...
//
pCurrentRxDesc = (PRX_DESCRIPTOR_FORMAT) dwRECEIVE_DESCRIPTORS_HEAD;
pLastRxDesc = (PRX_DESCRIPTOR_FORMAT) (pCurrentRxDesc + dwRECEIVE_RING_SIZE - 1) ;
for (i = 0 ; i < dwRECEIVE_RING_SIZE ; i++)
{
InitRxDescriptor ((PRX_DESCRIPTOR_FORMAT) (pCurrentRxDesc + i),
(DWORD) (dwRECEIVE_BUFFER_START + i * MAX_BUFFER_SIZE));
}
//DumpRxDescriptors();
/////////////////////////////////////////////////////////////////////////////
// All aboard... Let the engine roar...
//
WriteCSR (0, (ReadCSR(0) | 0x02) & ~0x04); // Turn on START bit...and turn off STOP bit.
/*
DumpOneRxDescriptor (pCurrentRxDesc);
while (pCurrentRxDesc->RMD1.OWN)
;
localDEBUGMSG ("Data received...%d bytes\r\n", pCurrentRxDesc->RMD2.MCNT);
DumpOneRxDescriptor (pCurrentRxDesc);
DumpOneRxDescriptor (pCurrentRxDesc + 1);
DumpMemory ((PUCHAR) (TO_VIRT(pCurrentRxDesc->RBADR)), pCurrentRxDesc->RMD2.MCNT);
for (;;)
;
*/
SleepLoop(5000);
localDEBUGMSG ("CSR0 == 0x%x \r\n", ReadCSR(0));
return TRUE;
} // AM79C970Init()
/////////////////////////////////////////////////////////////////////////////////
// AM79C970EnableInts()
// For Ether Debug, we only need Receive Interrupt.
// Hence, turn on IENA and mask all other interrupts except Receive Interrupt.
//
void AM79C970EnableInts (void)
{
/////////////////////////////////////////////////////////////////////////////
// First, make sure all interrupts are mask, except the receive interrupt...
//
WriteCSR (3, ReadCSR(3) | CSR3_MASK_ALL_INTS);
WriteCSR (4, ReadCSR(4) | CSR4_MASK_ALL_INTS);
WriteCSR (5, ReadCSR(5) | CSR5_MASK_ALL_INTS);
WriteCSR (3, ReadCSR(3) & ~CSR3_RINTM);
/////////////////////////////////////////////////////////////////////////////
// Then enable IENA in CSR0, the father of all interrupts !!!
//
WriteCSR (0, ReadCSR(0) | CSR0_IENA);
{
//RETAILMSG (1, (TEXT("CSR0 = 0x%x \r\n"), ReadCSR(0)));
//RETAILMSG (1, (TEXT("CSR3 = 0x%x \r\n"), ReadCSR(3)));
//RETAILMSG (1, (TEXT("CSR4 = 0x%x \r\n"), ReadCSR(4)));
//RETAILMSG (1, (TEXT("CSR5 = 0x%x \r\n"), ReadCSR(5)));
//RETAILMSG (1, (TEXT("BCR2 = 0x%x \r\n\r\n\r\n"), ReadBCR(2)));
}
} // AM79C970EnableInts()
/////////////////////////////////////////////////////////////////////////////////
// AM79C970DisableInts()
// Simply turn off CSR0_IOENA...
//
void AM79C970DisableInts(void)
{
WriteCSR (0, (ReadCSR(0) & ~CSR0_IENA));
} // AM79C970DisableInts()
/////////////////////////////////////////////////////////////////////////////////
//
//
DWORD AM79C970GetPendingInts(void)
{
//RETAILMSG (1, (TEXT("GetPending: CSR0 = 0x%x \r\n"), ReadCSR(0)));
WriteCSR (0, ReadCSR(0) | CSR0_RINT);
return INTR_TYPE_RX;
} // AM79C970EnableInts()
/////////////////////////////////////////////////////////////////////////////////
// AM79C970GetFrame()
//
// This routine is used to find out if a frame has been
// received. If there are no frames in the RX FIFO, the routine will return 0.
// If there is a frame that was received correctly, it will be stored in pwData,
// otherwise it will be discarded.
//
void SkipAllErrorDescriptors(void)
{
/////////////////////////////////////////////////////////////////////////
// FM-FM-FM Should investigate properly what causes this, instead of
// just blowing them away...
// ASSUMING that OWN will be set even for ERRORNEOUS packets...
//
while (pCurrentRxDesc->RMD1.OWN && pCurrentRxDesc->RMD1.ERR)
{
localDEBUGMSG ("Error Descriptor: %d\r\n",
pCurrentRxDesc - (PRX_DESCRIPTOR_FORMAT) dwRECEIVE_DESCRIPTORS_HEAD);
InitRxDescriptor (pCurrentRxDesc, 0);
pCurrentRxDesc = GetNextRxDesc (pCurrentRxDesc);
}
} // SkipAllErrorDescriptors()
BOOL Broadcast(PBYTE pHeader)
{
int i = 0;
while (1)
{
if (pHeader[i++] != 0xff)
break;
if (i == 6)
return TRUE;
}
return FALSE;
} // Broadcast()
UINT16 AM79C970GetFrame(BYTE *pbData, UINT16 *pwLength, BOOL bBootLoaderCall)
{
BOOL bDone = FALSE; // When we loop for ENP.
UINT16 dwOffset = 0; // Offset to User's pbData...
UINT16 dwBytesToCopy = 0;
BOOL bTossedPacket = FALSE;
PBYTE pHeader;
*pwLength = 0;
/////////////////////////////////////////////////////////////////////////////
// Bail out immediately if there is no data avail...
//
if (pCurrentRxDesc->RMD1.OWN)
return 0;
/////////////////////////////////////////////////////////////////////////////
// Okay, at least we must have all or part of data available...
// ASSUMING AMD is doing the right thing, I won't detect STP but just the
// ENP. If error happens in between packets, whatever received will be
// tossed away.
// [stjong 11/14/98]
// Alright, it is a WRONG assumption, if STP is set without ENP, it means
// the whole buffer is filled, eventhough MCNT reports zero !!!
// What's more, the last packet contains the exact total number of packets
// received... (what a bummer !!!)
//
while (!bDone)
{
//localDEBUGMSG ("Using RX Descriptor Number: %d \r\n",
// (pCurrentRxDesc - (PRX_DESCRIPTOR_FORMAT) dwRECEIVE_DESCRIPTORS_HEAD));
/////////////////////////////////////////////////////////////////////////
// If it is error packets, throw away until we get to descriptor not
// yet used. And return zero to user...
//
if (pCurrentRxDesc->RMD1.ERR)
{
SkipAllErrorDescriptors();
return 0;
}
/////////////////////////////////////////////////////////////////////////
// So here is the logic,
// If it is ENP (End Of Packet) and STP (Start Of Packet),
// number of bytes to copy is the number of bytes pointed to by MCNT.
// If it is NOT end of packet, then MAX_BUFFER_SIZE takes effect.
// For multi buffer packet (ONLY ENP set and NOT STP), we just need to
// copy whatever less to make up MCNT.
//
if (!bBootLoaderCall && pCurrentRxDesc->RMD1.STP)
{
/////////////////////////////////////////////////////////////////////
// Determine if we need to toss this packet away...
// Toss this away if it is non ARP broadcast...
//
pHeader = (PVOID)TO_VIRT(pCurrentRxDesc->RBADR);
if (Broadcast(pHeader))
{
if (pHeader[12] != 0x08 && pHeader[13] != 0x06)
{
/////////////////////////////////////////////////////////////
// This packet is tossed...
//
bTossedPacket = TRUE;
}
}
}
if (pCurrentRxDesc->RMD1.ENP)
{
bDone = TRUE;
if (pCurrentRxDesc->RMD1.STP)
dwBytesToCopy = (UINT16) pCurrentRxDesc->RMD2.MCNT;
else
dwBytesToCopy = (UINT16) (pCurrentRxDesc->RMD2.MCNT - dwOffset);
}
else
dwBytesToCopy = MAX_BUFFER_SIZE;
if (bTossedPacket)
dwBytesToCopy = 0x00;
// localDEBUGMSG ("BYTES COPIED : %d\r\n", dwBytesToCopy);
memcpy (pbData + dwOffset,
(PVOID) TO_VIRT(pCurrentRxDesc->RBADR),
dwBytesToCopy);
dwOffset += dwBytesToCopy; // Increase what we have copied so far.
InitRxDescriptor(pCurrentRxDesc, 0); // Initialize the used RX Descriptor.
pCurrentRxDesc = GetNextRxDesc (pCurrentRxDesc); // Forward to next descriptor...
/////////////////////////////////////////////////////////////////////////
// Now, if I am not done yet and the next packet is now owned by me,
// just loop till it is owned by me...
// In interrupt mode, it should be Okay, because by the time RX interrupt
// received, I am guaranteed to have received the entirety of the packet.
// For Bootloader download, I don't care, it is single task and I will
// have nothing else to do except waiting for the data...
// But becareful not to poll too fast, as it affects the DMA transfer
// that must be going on...
//
if (!bDone)
{
while (pCurrentRxDesc->RMD1.OWN)
{
localDEBUGMSG (">>> Waiting for descriptor %d to complete packet.\r\n",
pCurrentRxDesc - (PRX_DESCRIPTOR_FORMAT) dwRECEIVE_DESCRIPTORS_HEAD);
SleepLoop(10000000);
}
}
}
// DumpSenderAddr (pbData);
if (dwOffset >= 4)
dwOffset -=4; // Takeout CRC.
*pwLength = (UINT16)dwOffset;
return (UINT16)dwOffset;
} // AM79C970GetFrame()
/////////////////////////////////////////////////////////////////////////////////
// AM79C970SendFrame()
//
// This routine should be called with a pointer to the ethernet frame data.
// It is the caller's responsibility to fill in all information including the
// destination and source addresses and the frame type.
// The length parameter gives the number of bytes in the ethernet frame.
// The routine will return immediately regardless of whether transmission
// has successfully been performed.
//
UINT16 AM79C970SendFrame(BYTE *pbData, DWORD dwLength)
{
UINT dwTotalCopied = 0;
UINT dwBytesToCopy = 0;
volatile PTX_DESCRIPTOR_FORMAT pFirstTxDesc = pCurrentTxDesc;
volatile PTX_DESCRIPTOR_FORMAT pNextTxDesc;
// localDEBUGMSG ("\r\n*** Sending: %d bytes.\r\n", dwLength);
/////////////////////////////////////////////////////////////////////////////
// Loop until all data has been copied to the descriptor's buffer.
// Depending on buffer size, all data may fit into one buffer or span
// through multiple descriptors' buffers.
//
while (dwTotalCopied < dwLength)
{
localDEBUGMSG ("Using TX Descriptor Number: %d \r\n",
(pCurrentTxDesc - (PTX_DESCRIPTOR_FORMAT) dwTRANSMIT_DESCRIPTORS_HEAD));
/////////////////////////////////////////////////////////////////////////
// Figure out how many bytes to copy to descriptor's buffer...
//
if ((dwLength - dwTotalCopied) < MAX_BUFFER_SIZE)
dwBytesToCopy = (dwLength - dwTotalCopied);
else
dwBytesToCopy = MAX_BUFFER_SIZE;
memcpy ((PVOID)TO_VIRT(pCurrentTxDesc->TBADR),
pbData + dwTotalCopied,
dwBytesToCopy);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -