📄 cs8900a.c
字号:
{
OUTPORT16(&g_pCS8900->DATA0, *(UINT16*)pData);
pData += sizeof *(UINT16*)pData;
}
rc = FALSE; // Success
Exit:
OALMSGS(OAL_ETHER && OAL_VERBOSE, (L"-CS8900ASendFrame(rc = %d)\r\n", rc));
return (rc);
}
//------------------------------------------------------------------------------
//
// Function: CS8900AGetFrame
//
UINT16
CS8900AGetFrame(UINT8 *pData, UINT16 *pLength)
{
UINT16 isq, length, status, count, data;
UINT16 DeviceInterrupt;
BOOL GlobalInterrupt;
OALMSGS(OAL_ETHER && OAL_VERBOSE, (
L"+CS8900AGetFrame(0x%08x, %d)\r\n", pData, *pLength
));
//
// This routine could be interrupt driven, or polled.
// When polled, it keeps the emulator so busy that it
// starves other threads. The emulator already has the
// ability to recognize the polling in the bootloader
// by noting whether the interrupt for this device is
// disabled. In order to make the emulator recognize it
// here as well, we need to detect the polling by noting
// that *global* interrupts are disabled, then disable at
// the device level as well if so.
//
GlobalInterrupt = INTERRUPTS_ENABLE(FALSE); // Disable to obtain state
INTERRUPTS_ENABLE(GlobalInterrupt); // Immediately restore it.
// Mimic the global interrupt state at the device level too.
if (!GlobalInterrupt) // If polled
{
// Disable at the device level too so the emulator knows we're polling.
// Now it can yeild to other threads on the host side.
DeviceInterrupt = ReadPacketPage(BUS_CTL);
WritePacketPage(BUS_CTL, DeviceInterrupt & ~BUS_CTL_ENABLE_IRQ);
DeviceInterrupt &= BUS_CTL_ENABLE_IRQ;
}
length = 0;
isq = INPORT16(&g_pCS8900->ISQ);
if ((isq & ISQ_ID_MASK) == RX_EVENT_ID
&& (isq & RX_EVENT_RX_OK) != 0)
{
// Get RxStatus and length
status = INPORT16(&g_pCS8900->DATA0);
length = INPORT16(&g_pCS8900->DATA0);
if (length > *pLength)
{
// If packet doesn't fit in buffer, skip it
data = ReadPacketPage(RX_CFG);
WritePacketPage(RX_CFG, data | RX_CFG_SKIP_1);
length = 0;
} else {
// Read packet data
count = length;
while (count > 1)
{
data = INPORT16(&g_pCS8900->DATA0);
*(UINT16*)pData = data;
pData += sizeof *(UINT16*)pData;
count -= sizeof *(UINT16*)pData;
}
// Read last one byte
if (count > 0)
{
data = INPORT16(&g_pCS8900->DATA0);
*pData = (UINT8)data;
}
}
}
if (!GlobalInterrupt) // If polled
{
if (DeviceInterrupt) // If it was enabled at the device level,
{
// Re-enable at the device level.
CS8900AEnableInts();
}
}
// Return packet size
*pLength = length;
OALMSGS(OAL_ETHER && OAL_VERBOSE, (
L"-CS8900AGetFrame(length = %d)\r\n", length
));
return (length);
}
//------------------------------------------------------------------------------
//
// Function: CS8900AEnableInts
//
VOID
CS8900AEnableInts(VOID)
{
UINT16 data;
OALMSGS(OAL_ETHER && OAL_FUNC, (L"+CS8900AEnableInts\r\n"));
data = ReadPacketPage(BUS_CTL);
WritePacketPage(BUS_CTL, data | BUS_CTL_ENABLE_IRQ);
OALMSGS(OAL_ETHER && OAL_FUNC, (L"-CS8900AEnableInts\r\n"));
}
//------------------------------------------------------------------------------
//
// Function: CS8900ADisableInts
//
VOID
CS8900ADisableInts(VOID)
{
UINT16 data;
OALMSGS(OAL_ETHER && OAL_FUNC, (L"+CS8900ADisableInts\r\n"));
data = ReadPacketPage(BUS_CTL);
WritePacketPage(BUS_CTL, data & ~BUS_CTL_ENABLE_IRQ);
OALMSGS(OAL_ETHER && OAL_FUNC, (L"-CS8900ADisableInts\r\n"));
}
//------------------------------------------------------------------------------
//
// Function: CS8900ACurrentPacketFilter
//
VOID
CS8900ACurrentPacketFilter(UINT32 filter)
{
UINT16 rxCtl;
OALMSGS(OAL_ETHER && OAL_FUNC, (
L"+CS8900ACurrentPacketFilter(0x%08x)\r\n", filter
));
// Read current filter
rxCtl = ReadPacketPage(RX_CTL);
if ((filter & PACKET_TYPE_ALL_MULTICAST) != 0) {
WritePacketPage(LOGICAL_ADDR_FILTER_BASE + 0, 0xFFFF);
WritePacketPage(LOGICAL_ADDR_FILTER_BASE + 2, 0xFFFF);
WritePacketPage(LOGICAL_ADDR_FILTER_BASE + 4, 0xFFFF);
WritePacketPage(LOGICAL_ADDR_FILTER_BASE + 6, 0xFFFF);
} else {
WritePacketPage(LOGICAL_ADDR_FILTER_BASE + 0, g_hash[0]);
WritePacketPage(LOGICAL_ADDR_FILTER_BASE + 2, g_hash[1]);
WritePacketPage(LOGICAL_ADDR_FILTER_BASE + 4, g_hash[2]);
WritePacketPage(LOGICAL_ADDR_FILTER_BASE + 6, g_hash[3]);
}
if ((filter & PACKET_TYPE_MULTICAST)
|| (filter & PACKET_TYPE_ALL_MULTICAST))
{
rxCtl |= RX_CTL_MULTICAST;
} else {
rxCtl &= ~RX_CTL_MULTICAST;
}
if (filter & PACKET_TYPE_PROMISCUOUS)
{
rxCtl |= RX_CTL_PROMISCUOUS;
} else {
rxCtl &= ~RX_CTL_PROMISCUOUS;
}
WritePacketPage(RX_CTL, rxCtl);
// Save actual filter
g_filter = filter;
OALMSGS(OAL_ETHER && OAL_FUNC, (L"-CS8900ACurrentPacketFilter\r\n"));
}
//------------------------------------------------------------------------------
//
// Function: CS8900AMulticastList
//
BOOL
CS8900AMulticastList(UINT8 *pAddresses, UINT32 count)
{
UINT32 i, j, crc, data, bit;
OALMSGS(OAL_ETHER && OAL_FUNC, (
L"+RTL8139MulticastList(0x%08x, %d)\r\n", pAddresses, count
));
g_hash[0] = g_hash[1] = g_hash[2] = g_hash[3] = 0;
for (i = 0; i < count; i++) {
data = crc = ComputeCRC(pAddresses, 6);
for (j = 0, bit = 0; j < 6; j++) {
bit <<= 1;
bit |= (data & 1);
data >>= 1;
}
g_hash[bit >> 4] |= 1 << (bit & 0x0f);
pAddresses += 6;
}
// But update only if all multicast mode isn't active
if ((g_filter & PACKET_TYPE_ALL_MULTICAST) == 0) {
WritePacketPage(LOGICAL_ADDR_FILTER_BASE + 0, g_hash[0]);
WritePacketPage(LOGICAL_ADDR_FILTER_BASE + 2, g_hash[1]);
WritePacketPage(LOGICAL_ADDR_FILTER_BASE + 4, g_hash[2]);
WritePacketPage(LOGICAL_ADDR_FILTER_BASE + 6, g_hash[3]);
}
OALMSGS(OAL_ETHER && OAL_FUNC, (L"-CS8900AMulticastList(rc = 1)\r\n"));
return (TRUE);
}
//------------------------------------------------------------------------------
static UINT16
ReadPacketPage(UINT16 address)
{
OUTREG16(&g_pCS8900->PAGEIX, address);
return (INREG16(&g_pCS8900->PAGE0));
}
//------------------------------------------------------------------------------
static VOID
WritePacketPage(UINT16 address, UINT16 data)
{
OUTREG16(&g_pCS8900->PAGEIX, address);
OUTREG16(&g_pCS8900->PAGE0, data);
}
//------------------------------------------------------------------------------
static UINT32
ComputeCRC(UINT8 *pBuffer, UINT32 length)
{
UINT32 crc, carry, i, j;
UINT8 byte;
crc = 0xffffffff;
for (i = 0; i < length; i++) {
byte = pBuffer[i];
for (j = 0; j < 8; j++) {
carry = ((crc & 0x80000000) ? 1 : 0) ^ (byte & 0x01);
crc <<= 1;
byte >>= 1;
if (carry) crc = (crc ^ 0x04c11db6) | carry;
}
}
return (crc);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -